Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
26 kB
1
Indexable
Never
FILE 1 (the one that needs to be modified)

import {
  Filter,
  Grid,
  Table,
  TableAction,
  TableColumnType,
  Text,
  Button,
} from '@trustly/backoffice-components';
import type { FilterConfig, FilterValue } from '@trustly/backoffice-components';
import React, { useMemo, useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { startOfDay, endOfDay, formatISO } from 'date-fns';
import { useAppQuery } from '../../shared/useQuery';
import { SearchField } from '../SearchField';

const PAGE_SIZE = 30;
const COLUMN_STORAGE_KEY_PREFIX = 'ECOM_';
const MAX_COLUMNS = 7;

export interface DataTableProps<R extends object> {
  header?: string;
  columns: TableColumnType<R>[];
  apiPath: string;
  dataKey: string;
  initialFilterConfig?: FilterConfig[];
  onRowClick?: ({ row }: { row: R }) => void;
  actions?: TableAction<R>[];
  onActionClick?: ({ row, id }: { row: R; id: string }) => void;
  columnSelector?: boolean;
  isLoading?: boolean;
  showSearchField?: boolean;
  hasPagination?: boolean;
  flattenProps?: string[];
}

export function DataTable<R extends object>(props: DataTableProps<R>) {
  return <PageTable {...props} />;
}

type PageTableProps<R extends object> = DataTableProps<R>;
const buildFilterConfig = (
  searchParams: URLSearchParams,
  initialFilterConfig?: FilterConfig[],
): FilterConfig[] | undefined =>
  // @ts-ignore TODO: Fix backoffice-components?
  initialFilterConfig?.map((config) => {
    const name = String(config.name);
    const value = searchParams.get(name);

    if (value && config.type === 'date-range') {
      const { dateTimeFrom, dateTimeTo } = JSON.parse(value);
      const dateValue = {
        from: dateTimeFrom ? startOfDay(new Date(dateTimeFrom)) : config.value?.from,
        to: dateTimeTo ? endOfDay(new Date(dateTimeTo)) : config.value?.to,
      };
      return { ...config, value: dateValue };
    }

    return {
      ...config,
      value: value || config.value,
    } as FilterConfig;
  });

const buildFilterValue = (filterConfig: FilterConfig[]) =>
  filterConfig?.reduce((prev, curr) => {
    const { value, type } = curr;

    if (type === 'date-range') {
      const newValue = {
        dateTimeFrom: value?.from ? formatISO(value?.from as Date) : undefined,
        dateTimeTo: value?.to ? formatISO(value?.to as Date) : undefined,
      };

      return { ...prev, ...newValue };
    }
    return { ...prev, [curr.name as string]: value };
  }, {}) as Record<string, FilterValue | undefined>;

function PageTable<RowItem extends object>({
  columns,
  apiPath,
  dataKey,
  initialFilterConfig,
  onRowClick,
  actions,
  onActionClick,
  columnSelector,
  isLoading,
  showSearchField,
  hasPagination = true,
  flattenProps,
}: PageTableProps<RowItem>) {
  const [searchParams, setSearchParams] = useSearchParams();
  const [orderNotFound, setOrderNotFound] = useState(false);
  const [filterConfig, setFilterConfig] = useState<FilterConfig[]>(
    buildFilterConfig(searchParams, initialFilterConfig) ?? [],
  );
  const [filterValue, setFilterValue] = useState<Record<string, FilterValue | undefined>>(
    buildFilterValue(filterConfig) ?? {},
  );

  const initialPage = searchParams.get('page');
  const searchTermParam = searchParams.get('searchTerm');

  const [page, setPage] = useState(Number(initialPage) || 0);
  const [searchTerm, setSearchTerm] = useState(searchTermParam || '');

  const {
    data,
    isLoading: isFetching,
    error,
  } = useAppQuery<{ [key: string]: RowItem[] }>({
    queryKey: [apiPath, page, filterValue, searchTerm],
    apiPath: apiPath,
    params: {
      ...filterValue,
      skip: page * PAGE_SIZE,
      count: PAGE_SIZE,
      from: (filterValue.dateTimeFrom as string) || undefined,
      to: (filterValue.dateTimeTo as string) || undefined,
      searchTerm,
    },
    options: { keepPreviousData: true, staleTime: 5000 },
  });

  const rowMapper: RowItem[] = useMemo(() => {
    if (!data) {
      return [];
    }

    if (!flattenProps?.length) {
      return data[dataKey];
    }

    let flattenedData: RowItem[] = [];
    const rowData = [...data[dataKey]];

    rowData.forEach((rowItem) => {
      flattenProps.forEach((prop) => {
        const flattenPropsData = (rowItem as any)[prop];
        flattenedData = [...flattenedData, { ...rowItem, ...flattenPropsData }];
      });
    });

    return flattenedData;
  }, [data, dataKey, flattenProps]);

  const handlePageChange = ({ page }: { page: number }) => {
    searchParams.set('page', String(page));
    setSearchParams(searchParams);
    setPage(page);
  };

  const handleFilterChange = ({
    config,
    values,
  }: {
    config: FilterConfig[];
    values: Record<string, FilterValue>;
  }) => {
    const value = {
      ...values,
      dateTimeFrom: values.dateFrom ? formatISO(startOfDay(values.dateFrom as Date)) : undefined,
      dateTimeTo: values.dateTo ? formatISO(endOfDay(values.dateTo as Date)) : undefined,
    };

    setFilterConfig(config);
    setFilterValue(value);
    setPage(0);

    filterConfig.forEach((config) => {
      const name = String(config.name);
      if (config.type === 'date-range') {
        const { dateTimeFrom, dateTimeTo } = value;
        const dateFilterValues = { dateTimeFrom, dateTimeTo };

        dateTimeFrom || dateTimeTo
          ? searchParams.set(name, JSON.stringify(dateFilterValues))
          : searchParams.delete(name);
        setSearchParams(searchParams);
      } else {
        values[name] ? searchParams.set(name, String(values[name])) : searchParams.delete(name);
        setSearchParams(searchParams);
      }
    });
  };

  const scrollToTop = () => window.scrollTo({ top: 0, behavior: 'smooth' });

  const getQueryParamsValuesAndString = (localFilters, localPage, forSaving) => {
    const newQueryValues = {};
    const queryParamParts = [];
    if (localPage !== undefined && localPage !== 0) {
      queryParamParts.push(`page=${localPage}`);
    }

    localFilters.forEach(({ name, value }) => {
      const originalValue = value;
      const isDate = value instanceof Date;
      if (isDate) {
        value = formatLocalDateTime(value, "yyyy-MM-dd'T'HH:mm':00.000'xxx");
      }

      newQueryValues[name] = value;
      if (value) {
        let valueString = Array.isArray(value) ? value.join(',') : value;
        if (valueString && (!forSaving || (name !== 'dateFrom' && name !== 'dateTo'))) {
          if (isDate) {
            valueString = formatLocalDateTime(originalValue, 'yyyy-MM-dd-HH-mm');
          }

          queryParamParts.push(`${name}=${encodeURIComponent(valueString)}`);
        }
      }
    });

    return [newQueryValues, `${queryParamParts.join('&')}`];
  };

  const [selectedPersistedFilter, setSelectedPersistedFilter] = useState('');

  const onFilterSaveClicked = () => {
    const query = getQueryParamsValuesAndString(
      { name: '', type: '', label: '', value: [] },
      undefined,
      true,
    )[1];

    let defaultValue = selectedPersistedFilter || ''; // fix
    if (!defaultValue) {
      defaultValue = query.replaceAll('&', '; ');
    }

    const name = prompt('Name of filter', defaultValue);
    if (name) {
      if (window.localStorage) {
        const storageValue = window.localStorage.getItem('filters') || '{}';
        const existingFilters = JSON.parse(storageValue);
        existingFilters[name] = query;

        window.localStorage.setItem('filters', JSON.stringify(existingFilters));
        setSelectedPersistedFilter(name);
      }
    }
  };

  useEffect(() => {
    scrollToTop();
  }, [page]);

  if (error) {
    return <div>Error: {error.message}</div>;
  }
  return (
    <>
      <Grid container alignItems="flex-end" columnSpacing={2}>
        {showSearchField && (
          <Grid item>
            <SearchField
              value={searchTerm}
              onSearch={() => setOrderNotFound(false)}
              onUpdateValue={(searchTerm) => {
                setSearchTerm(searchTerm);
                searchTerm
                  ? searchParams.set('searchTerm', searchTerm)
                  : searchParams.delete('searchTerm');
                setSearchParams(searchParams);
              }}
            />
          </Grid>
        )}
        {initialFilterConfig && (
          <Grid item>
            <Filter
              config={filterConfig}
              onChange={handleFilterChange}
              returnTypeFormatting={{ flat: true }}
            />
          </Grid>
        )}
      </Grid>
      <Grid item>
        <Button onClick={() => onFilterSaveClicked()} type="primary" size="small" icon="star">
          Save filter
        </Button>
      </Grid>
      {orderNotFound ? (
        <>
          <br />
          <Text color="medium">Order not found</Text>
        </>
      ) : (
        <Table
          columns={columns}
          rows={rowMapper}
          loading={isLoading || isFetching}
          onRowClick={onRowClick}
          pagination={
            hasPagination
              ? {
                  page,
                  pageSize: PAGE_SIZE,
                  onPageChange: handlePageChange,
                }
              : undefined
          }
          actions={actions}
          onActionClick={onActionClick}
          columnSelector={columnSelector}
          columnStorageKey={COLUMN_STORAGE_KEY_PREFIX + apiPath}
          maxColumns={MAX_COLUMNS}
        />
      )}
    </>
  );
}


FILE 2: the original

import React, { useEffect, useState } from 'react';
import {
  Filter,
  Header,
  PageHead,
  Table,
  Dialog,
  Text,
  Button,
  useDebounce,
  Grid,
  Tag,
} from '@trustly/backoffice-components';
import { useNotifications } from '../../contexts/NotificationsContext';
import { PAGE_SIZE } from '../../contexts/actions';
import { useHistory } from 'react-router-dom';
import { formatLocalDateTime, parseDate } from '../../utils/dateTimeHelpers';
import NotificationTag from '../NotificationTag';
import { mapValues2LabelAndValue } from '../../utils/mapValueHelper';
import Menu from '../Menu';
import ExportToCSV from '../ExportToCSV';
import { getQueryParams } from '../../utils/queryParams';
import { parse } from 'query-string';
import { addDays } from 'date-fns';
export const debounceTime = 1000;

const numberOfSkeletonRows = 3;

const getRequestParameterValue = (queryParams, key, asArray, asDate) => {
  const stringValue = queryParams[key];
  if (!stringValue) {
    return undefined;
  }

  let values;
  if (asArray) {
    values = stringValue.split(',');
  } else {
    values = [stringValue];
  }

  if (asDate) {
    values = values.map((v) => parseDate(v));
  }

  return asArray ? values : values[0];
};

const columns = [
  {
    id: 'createdAt',
    label: 'Created',
  },
  {
    id: 'orderId',
    label: 'Order ID',
  },
  {
    id: 'processingAccountName',
    label: 'Processing Account',
  },
  {
    id: 'method',
    label: 'Method',
  },
  {
    id: 'lastTryAt',
    label: 'Last Try',
  },
  {
    id: 'state',
    label: 'Status',
  },
];

const createFilterConfig = () => {
  const queryParams = getQueryParams();

  return [
    {
      name: 'searchTerm',
      type: 'text',
      label: 'Search',
      value: getRequestParameterValue(queryParams, 'searchTerm', false) || null,
    },
    {
      name: 'states',
      type: 'select',
      label: 'Status',
      appearance: 'dropdown',
      multiple: false,
      value: getRequestParameterValue(queryParams, 'states', false) || null,
      options: [],
    },
    {
      name: 'methods',
      type: 'select',
      label: 'Methods',
      appearance: 'dropdown',
      multiple: true,
      value: getRequestParameterValue(queryParams, 'methods', true) || [],
      options: [],
    },
    {
      name: 'processingAccountNames',
      type: 'select',
      label: 'Processing Account',
      appearance: 'dropdown',
      value:
        getRequestParameterValue(
          queryParams,
          'processingAccountNames',
          false
        ) || null,
      multiple: false,
      options: [],
    },
    {
      name: 'dateFrom',
      type: 'datetime',
      label: 'Start Date',
      value:
        getRequestParameterValue(queryParams, 'dateFrom', false, true) ||
        new Date(new Date().setHours(0, 0, 0, 0)),
    },
    {
      name: 'dateTo',
      type: 'datetime',
      label: 'End Date',
      value:
        getRequestParameterValue(queryParams, 'dateTo', false, true) ||
        addDays(new Date().setHours(0, 0, 0, 0), 1),
    },
  ];
};

const populateFilterOptions = (
  filters,
  states,
  methods,
  processingAccountNames
) =>
  filters.map((filter) => {
    if (filter.name === 'states') {
      return {
        ...filter,
        options: [
          { value: '', label: '- [All] -' },
          ...states.map(({ state }) => ({
            value: state,
            label: state,
          })),
          { value: 'delayed', label: 'delayed' },
          { value: 'stopped', label: 'stopped' },
        ],
      };
    } else if (filter.name === 'methods') {
      return {
        ...filter,
        options: [
          ...methods.map((method) => ({
            value: method,
            label: method,
          })),
        ],
      };
    } else if (filter.name === 'processingAccountNames') {
      return {
        ...filter,
        options: [
          { value: '', label: '- [All] -' },
          ...mapValues2LabelAndValue(processingAccountNames),
        ],
      };
    }
    return filter;
  });

const getQueryParamsValuesAndString = (localFilters, localPage, forSaving) => {
  const newQueryValues = {};
  const queryParamParts = [];
  if (localPage !== undefined && localPage !== 0) {
    queryParamParts.push(`page=${localPage}`);
  }

  localFilters.forEach(({ name, value }) => {
    const originalValue = value;
    const isDate = value instanceof Date;
    if (isDate) {
      value = formatLocalDateTime(value, "yyyy-MM-dd'T'HH:mm':00.000'xxx");
    }

    newQueryValues[name] = value;
    if (value) {
      let valueString = Array.isArray(value) ? value.join(',') : value;
      if (
        valueString &&
        (!forSaving || (name !== 'dateFrom' && name !== 'dateTo'))
      ) {
        if (isDate) {
          valueString = formatLocalDateTime(originalValue, 'yyyy-MM-dd-HH-mm');
        }

        queryParamParts.push(`${name}=${encodeURIComponent(valueString)}`);
      }
    }
  });

  return [newQueryValues, `${queryParamParts.join('&')}`];
};

const filterNotSet = 'not-set';

const NotificationsTable = () => {
  const history = useHistory();
  const { notificationsState, actions } = useNotifications();
  const { states, methods, processingAccountNames } = notificationsState;
  const [page, setPage] = useState(() =>
    Number.parseInt(getQueryParams().page || '0')
  );
  const [openResend, setOpenResend] = useState(false);
  const [openStop, setOpenStop] = useState(false);
  const [throttled, setThrottled] = useState(false);
  const [lastActionNotificationId, setLastActionNotificationId] =
    useState(undefined);
  const [filters, setFilters] = useState(() => createFilterConfig());
  const [filterString, setFilterString] = useState(filterNotSet);
  const [selectedPersistedFilter, setSelectedPersistedFilter] = useState('');

  const goToNotification = (notificationId) => {
    const valuesAndString = getQueryParamsValuesAndString(filters, page);
    const newQueryString = valuesAndString[1];

    if (newQueryString) {
      history.push({
        pathname: notificationId,
        search: newQueryString,
      });
    } else {
      history.push(notificationId);
    }
  };

  const mapTableRows = (rows) => {
    return rows.map((row) => {
      return {
        ...row,
        __original: row,
        orderId: row.orderId,
        state: <NotificationTag {...row} />,
        createdAt: formatLocalDateTime(row.createdAt),
        lastTryAt: formatLocalDateTime(row.lastTryAt),
      };
    });
  };

  const debouncedFilters = useDebounce(filters, debounceTime);
  useEffect(() => {
    if (debouncedFilters) {
      setThrottled(false);

      const valuesAndString = getQueryParamsValuesAndString(filters, page);
      const newQueryValues = valuesAndString[0];
      const newQueryString = valuesAndString[1];

      if (newQueryString !== filterString) {
        if (newQueryString || (filterString && filterString !== filterNotSet)) {
          // We push to history if new is a filter,
          // or if we previously had a filter and it's not the initial filter.
          history.push({ search: newQueryString });
        }

        actions.loadNotifications(newQueryValues, page);

        // We only load, and push to history, if anything has actually changed
        setFilterString(newQueryString);
      }
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [debouncedFilters]);

  useEffect(() => {
    setThrottled(true);
  }, [filters]);

  const onFilterChange = ({ config }) => {
    const hasSearchTermSet =
      config.filter((f) => f.name === 'searchTerm' && !!f.value).length > 0;

    if (hasSearchTermSet) {
      for (const c of config) {
        if (c.name === 'dateFrom' || c.name === 'dateTo') {
          c.value = undefined;
        }
      }
    }

    setFilters(config);
    setPage(0);
  };

  const onPageChange = ({ page: newPage }) => {
    const valuesAndString = getQueryParamsValuesAndString(filters, newPage);
    const newQueryString = valuesAndString[1];

    if (newQueryString !== filterString) {
      setFilterString(newQueryString);
      history.push({ search: newQueryString });
      actions.loadNotifications(valuesAndString[0], newPage);
    }

    setPage(newPage);
  };

  const onActionClick = ({ id, row }) => {
    setLastActionNotificationId(row.notificationId);

    switch (id) {
      case 'resend':
        setOpenResend(true);
        break;
      case 'stop':
        setOpenStop(true);
        break;
      case 'details':
        goToNotification(row.notificationId);
        break;
    }
  };

  const handleClose = () => {
    setOpenResend(false);
    setOpenStop(false);
    setLastActionNotificationId(undefined);
  };

  const handleResend = () => {
    if (lastActionNotificationId) {
      actions.resendNotification(lastActionNotificationId);
    }

    handleClose();
  };

  const handleStop = () => {
    if (lastActionNotificationId) {
      actions.stopNotification(lastActionNotificationId);
    }

    handleClose();
  };

  const onFilterSaveClicked = () => {
    const query = getQueryParamsValuesAndString(filters, undefined, true)[1];

    let defaultValue = selectedPersistedFilter || '';
    if (!defaultValue) {
      defaultValue = query.replaceAll('&', '; ');
    }

    let name = prompt('Name of filter', defaultValue);
    if (name) {
      if (window.localStorage) {
        const storageValue = window.localStorage.getItem('filters') || '{}';
        const existingFilters = JSON.parse(storageValue);
        existingFilters[name] = query;

        window.localStorage.setItem('filters', JSON.stringify(existingFilters));
        setSelectedPersistedFilter(name);
      }
    }
  };

  const onFilterDeleteClicked = () => {
    if (selectedPersistedFilter) {
      if (confirm(`Do you really want to delete ${selectedPersistedFilter}?`)) {
        const storageValue = window.localStorage.getItem('filters') || '{}';
        const existingFilters = JSON.parse(storageValue);
        if (existingFilters[selectedPersistedFilter]) {
          delete existingFilters[selectedPersistedFilter];
        }

        window.localStorage.setItem('filters', JSON.stringify(existingFilters));
        setSelectedPersistedFilter(undefined);
      }
    }
  };

  const onFilterLoadClicked = (key) => {
    const storageValue = window.localStorage.getItem('filters') || '{}';
    const existingFilters = JSON.parse(storageValue);
    const filterQueryParams = existingFilters[key];
    if (filterQueryParams) {
      const queryParams = parse(filterQueryParams);

      const newFilters = [...filters];
      for (const filter of newFilters) {
        const isArray = Array.isArray(filter.value);
        const queryValue = getRequestParameterValue(
          queryParams,
          filter.name,
          isArray
        );

        filter.value = isArray ? queryValue || [] : queryValue || null;
      }

      setSelectedPersistedFilter(key);
      setFilters(newFilters);
    }
  };

  const persistedFilterLinks = [];
  const persistedFiltersString = window.localStorage.getItem('filters');
  if (persistedFiltersString) {
    const persistedFilters = JSON.parse(persistedFiltersString);
    for (const key in persistedFilters) {
      // eslint-disable-next-line no-prototype-builtins
      if (persistedFilters.hasOwnProperty(key)) {
        persistedFilterLinks.push(
          <Button
            key={key}
            onClick={() => onFilterLoadClicked(key)}
            type={selectedPersistedFilter === key ? 'linkSecondary' : 'link'}
            size="small"
          >
            {key}
          </Button>
        );
      }
    }
  }

  useEffect(() => {
    const filtersWithOptions = populateFilterOptions(
      filters,
      states,
      methods,
      processingAccountNames
    );
    setFilters(filtersWithOptions);

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [states, methods, processingAccountNames, populateFilterOptions]);

  useEffect(() => {
    actions.loadMethods();
    actions.loadProcessingAccountNames();
    actions.loadStates();
  }, [actions]);

  const filterClearOnClick = () => {
    const copiedFilters = [...filters];
    for (const filter of copiedFilters) {
      if (Array.isArray(filter.value)) {
        filter.value = [];
      } else {
        filter.value = null;
      }
    }

    setSelectedPersistedFilter('');
    setFilters(copiedFilters);
  };

  const filterSetCount = filters.filter((f) =>
    Array.isArray(f.value) ? f.value.length > 0 : !!f.value
  ).length;
  const tempFilterParams = getQueryParamsValuesAndString(filters, page)[1];
  return (
    <div>
      <PageHead>
        <Grid container spacing={3} alignItems={'center'}>
          <Grid item>
            <Header size="large">Notifications</Header>
          </Grid>
          <Grid item>
            {filterSetCount > 0 ? (
              <Tag border={true} type="success" label={'' + filterSetCount} />
            ) : (
              <></>
            )}
          </Grid>
          <Grid item>
            {filterSetCount > 0 ? (
              <Button
                onClick={filterClearOnClick}
                type={'link'}
                icon={'delete'}
              >
                Clear filters
              </Button>
            ) : (
              <></>
            )}
          </Grid>
          <Grid item>
            {notificationsState.isLoading ? <span>Loading ...</span> : <></>}
            {!notificationsState.isLoading && throttled ? (
              <span>Waiting ...</span>
            ) : (
              <></>
            )}
          </Grid>
        </Grid>

        <Filter config={filters} onChange={onFilterChange} />
        <br />
        {persistedFilterLinks}
        <Button
          onClick={() => onFilterSaveClicked()}
          type="primary"
          size="small"
          icon="star"
        >
          Save filter
        </Button>
        <span style={{ marginRight: '1em' }} />
        {selectedPersistedFilter ? (
          <Button
            onClick={() => onFilterDeleteClicked()}
            type="danger"
            size="small"
            icon="delete"
          >
            Delete
          </Button>
        ) : (
          <></>
        )}
      </PageHead>
      <ExportToCSV filters={filters} />
      <Menu />
      <Table
        columns={columns}
        loading={notificationsState.isLoading}
        numberOfSkeletonRows={numberOfSkeletonRows}
        rows={mapTableRows(notificationsState.notifications)}
        pagination={{
          page,
          onPageChange: onPageChange,
          pageSize: PAGE_SIZE,
        }}
        actions={[
          {
            id: 'resend',
            text: 'Resend',
            type: 'icon',
            icon: 'refresh',
            filter: (row) =>
              (row.__original.state || '').toLowerCase() !== 'verified' &&
              row.__original.stopped !== true,
          },
          {
            id: 'stop',
            text: 'Stop',
            type: 'icon',
            icon: 'close',
            filter: (row) =>
              (row.__original.state || '').toLowerCase() !== 'verified' &&
              (row.__original.state || '').toLowerCase() != 'abandoned' &&
              row.__original.stopped !== true,
          },
          {
            id: 'details',
            text: 'Details',
            type: 'icon',
            icon: 'view',
            href: (o) =>
              'notifications/' +
              o.notificationId +
              (tempFilterParams ? '?' + tempFilterParams : ''),
          },
        ]}
        onActionClick={onActionClick}
      />

      <Dialog
        title="Are you sure you want to resend?"
        open={openResend}
        icon="alert-triangle"
        onClose={handleClose}
        actions={
          <>
            <Button type="danger" onClick={handleResend}>
              Yes, resend
            </Button>
            <Button type="linkSecondary" onClick={handleClose}>
              No, thanks
            </Button>
          </>
        }
      >
        <Text>Doing this action can not be undone.</Text>
      </Dialog>

      <Dialog
        title="Are you sure you want to stop?"
        open={openStop}
        icon="alert-triangle"
        onClose={handleClose}
        actions={
          <>
            <Button type="danger" onClick={handleStop}>
              Yes, stop
            </Button>
            <Button type="linkSecondary" onClick={handleClose}>
              No, thanks
            </Button>
          </>
        }
      >
        <Text>Doing this action can not be undone.</Text>
      </Dialog>
    </div>
  );
};

export default NotificationsTable;