react-table#usePagination TypeScript Examples

The following examples show how to use react-table#usePagination. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Table.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 5 votes vote down vote up
Table = <T extends object>(props: TableProps<T>) => {
  const {
    columns,
    data,
    initialSortBy,
    initialFilterBy,
    pageCount = 0,
    pageSize = 20,
    fetchData,
    disableFilters = false,
    renderPagination,
    renderExpanded,
    tableRef
  } = props;

  const stateReducer = (nextState: any, action: any, prevState: any) => {
    if (action.type === 'toggleSortBy' || action.type === 'setGlobalFilter') {
      return { ...nextState, pageIndex: 0 };
    }
    return nextState;
  };

  const instance = useTable(
    {
      columns,
      data,
      disableMultiSort: true,
      manualSortBy: Boolean(fetchData),
      manualPagination: Boolean(fetchData),
      manualFilters: Boolean(fetchData),
      autoResetSortBy: false,
      disableFilters,
      pageCount,
      stateReducer,
      initialState: {
        sortBy: initialSortBy ?? [],
        pageSize,
        pageIndex: 0,
        filters: initialFilterBy ?? [],
        globalFilter: []
      }
    },
    useFilters,
    useSortBy,
    useExpanded,
    usePagination
  );

  useImperativeHandle(tableRef, () => instance);

  const {
    state: { sortBy, pageIndex, filters }
  } = instance;

  useEffect(() => {
    fetchData &&
      fetchData({
        sort: sortBy,
        page: pageIndex + 1,
        pageSize,
        filters
      });
  }, [fetchData, sortBy, filters, pageIndex, pageSize]);

  return (
    <div className={classes.root}>
      <div className={classes.tableInner}>
        <UsaTable {...instance.getTableProps()} bordered={false}>
          <TableHead<T> {...instance} />
          <TableBody<T> {...instance} renderExpanded={renderExpanded} />
        </UsaTable>
      </div>
      {props.noResults && (
        <NoResults message={props.noResultsMessage!}></NoResults>
      )}
      {renderPagination && renderPagination(instance)}
    </div>
  );
}
Example #2
Source File: Table.tsx    From solo with MIT License 5 votes vote down vote up
Table = <T extends object>({
  columns,
  data,
  initialSortBy,
  manualPagination = true,
  manualSortBy = true,
  pageCount = 0,
  fetchData,
  onSelectedRowsChange,
  renderSubComponent,
  renderPagination,
  renderFilterControls
}: TableProps<T>) => {
  const stateReducer = (nextState: any, action: any, prevState: any) => {
    if (action.type === "toggleSortBy" || action.type === "setGlobalFilter") {
      return { ...nextState, pageIndex: 0 };
    }
    return nextState;
  };

  const instance = useTable(
    {
      columns,
      data,
      manualGlobalFilter: true,
      disableMultiSort: true,
      manualSortBy,
      manualPagination,
      autoResetSortBy: !manualSortBy,
      pageCount,
      stateReducer,
      initialState: {
        sortBy: initialSortBy ?? [],
        pageSize: 20,
        globalFilter: []
      }
    },
    useGlobalFilter,
    useSortBy,
    useExpanded,
    usePagination,
    useRowSelect
  );

  const {
    state: { sortBy, pageIndex, globalFilter, selectedRowIds }
  } = instance;

  useEffect(() => {
    fetchData &&
      fetchData({
        sort: sortBy,
        page: pageIndex + 1,
        filters: globalFilter
      });
  }, [fetchData, sortBy, globalFilter, pageIndex]);

  useEffect(() => {
    onSelectedRowsChange && onSelectedRowsChange(instance);
  }, [selectedRowIds, instance, onSelectedRowsChange]);

  return (
    <>
      {renderFilterControls && renderFilterControls(instance)}
      <USWDSTable {...instance.getTableProps()}>
        <TableHead headerGroups={instance.headerGroups} />
        <TableBody {...instance} renderSubComponent={renderSubComponent} />
      </USWDSTable>
      {renderPagination && renderPagination(instance)}
    </>
  );
}
Example #3
Source File: FeTable.tsx    From frontegg-react with MIT License 5 votes vote down vote up
FeTable: FC<TableProps> = <T extends object>(props: TableProps<T>) => {
  const tableRef = useRef<HTMLDivElement>(null);
  const firstRender = useRef<boolean>(true);
  const columns = useMemo(() => {
    const columns = props.columns.map(
      ({ sortable, Filter, Header, ...rest }) =>
        ({
          ...rest,
          disableSortBy: !sortable,
          disableFilters: !Filter,
          Filter,
          Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />,
        } as FeTableColumnOptions<T>)
    );
    if (props.expandable) {
      columns.unshift({
        id: 'fe-expander',
        minWidth: 60,
        maxWidth: '60px' as any,
        Header: <div style={{ minWidth: '2rem', maxWidth: '2rem' }} />,
        Cell: (cell: Cell<T>) => {
          const row = cell.row as Row<T> & UseExpandedRowProps<T>;
          return (
            <FeButton
              className={classNames('fe-table__expand-button', { 'is-expanded': row.isExpanded })}
              {...row.getToggleRowExpandedProps()}
              variant={row.isExpanded ? 'primary' : undefined}
            >
              <FeIcon name='right-arrow' />
            </FeButton>
          );
        },
      });
    }
    if (props.selection) {
      columns.unshift({
        id: 'fe-selection',
        minWidth: 60,
        maxWidth: '60px' as any,
        Cell: (cell: Cell<T>) => {
          const row = cell.row as Row<T> & UseRowSelectRowProps<T>;
          return (
            <FeCheckbox
              {...row.getToggleRowSelectedProps()}
              checked={row.isSelected}
              onChange={(e) => onRowSelected(row.original, e.target.checked)}
            />
          );
        },
      });
    }
    return columns as Column<T>[];
  }, [props.columns, props.expandable]);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state,

    // The page controls ;)
    page,
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,

    // select props
    toggleAllRowsSelected,
    isAllRowsSelected,
    selectedFlatRows,
    toggleRowSelected,
  } = useTable(
    {
      columns,
      data: props.data,
      getRowId: (row: any) => row[props.rowKey],
      manualSortBy: !!props.onSortChange,
      manualFilters: !!props.onFilterChange,
      manualPagination: !!props.onPageChange,
      manualRowSelectedKey: props.rowKey,
      pageCount: !!props.onPageChange ? props.pageCount : undefined,
      autoResetPage: !props.onPageChange,
      useControlledState: (state1: any, meta) =>
        ({
          ...state1,
          sortBy: props.sortBy ?? state1.sortBy,
          filters: props.filters ?? state1.filters,
          selectedRowIds: props.selectedRowIds ?? state1.selectedRowIds,
        } as FeTableState<T>),
      expandSubRows: false,
      autoResetExpanded: false,
      initialState: {
        pageIndex: 0,
        pageSize: props.pageSize,
        selectedRowIds: props.selectedRowIds || {},
      },
    } as FeUseTable<T>,
    useFilters,
    useSortBy,
    useExpanded,
    usePagination,
    useRowSelect,
    useFlexLayout
  ) as FeTableInstance<T>;

  checkTableProps(props);

  const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>;

  const onSortChange = useCallback(
    (column: FeTableColumnProps<T>) => {
      if (props.hasOwnProperty('sortBy')) {
        const sortBy = props.isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : [];
        if (!column.isSorted) {
          sortBy.push({ id: column.id, desc: false });
        } else if (!column.isSortedDesc) {
          sortBy.push({ id: column.id, desc: true });
        }
        props.onSortChange?.(sortBy);
      } else {
        if (column.isSorted && column.isSortedDesc) {
          column.clearSortBy();
        } else {
          column.toggleSortBy(column.isSorted, props.isMultiSort ?? false);
        }
      }
    },
    [props.onSortChange]
  );

  const onFilterChange = useCallback(
    (column: FeTableColumnProps<T>, filterValue?: any) => {
      if (props.hasOwnProperty('filters')) {
        const filters = tableState.filters.filter(({ id }) => id !== column.id);
        if (filterValue != null) {
          filters.push({ id: column.id, value: filterValue });
        }
        props.onFilterChange?.(filters);
      } else {
        column.setFilter(filterValue);
      }
    },
    [props.onFilterChange, tableState]
  );

  const onToggleAllRowsSelected = useCallback(
    (value: boolean) => {
      if (props.hasOwnProperty('selectedRowIds')) {
        const selectedIds = props.data.reduce((p, n: any) => ({ ...p, [n[props.rowKey]]: true }), {});
        props.onRowSelected?.(value ? selectedIds : {});
      } else {
        toggleAllRowsSelected(value);
      }
    },
    [props.onRowSelected]
  );

  const onRowSelected = useCallback(
    (row: any, value: boolean) => {
      const id = row[props.rowKey];
      if (props.hasOwnProperty('selectedRowIds')) {
        const newSelectedRows: any = { ...props.selectedRowIds };
        if (value) {
          newSelectedRows[id] = true;
        } else {
          delete newSelectedRows[id];
        }
        props.onRowSelected?.(newSelectedRows);
      } else {
        toggleRowSelected(id, value);
      }
    },
    [props.onRowSelected]
  );

  const handleOnPageChange = useCallback(() => {
    if (pagination === 'pages') {
      tableRef.current?.querySelector(`.${prefixCls}__tbody`)?.scroll?.({ top: 0, left: 0, behavior: 'smooth' });
    }
    props.onPageChange?.(tableState.pageSize, tableState.pageIndex);
  }, [tableState.pageIndex]);

  useEffect(() => {
    !props.hasOwnProperty('sortBy') && props.onSortChange?.(tableState.sortBy);
  }, [props.sortBy, tableState.sortBy]);

  useEffect(() => {
    !props.hasOwnProperty('filters') && props.onFilterChange?.(tableState.filters);
  }, [props.filters, tableState.filters]);

  useEffect(() => {
    firstRender.current ? (firstRender.current = false) : handleOnPageChange();
  }, [tableState.pageIndex]);

  useEffect(() => {
    !props.hasOwnProperty('selectedRowIds') && props.onRowSelected?.(tableState.selectedRowIds as any);
  }, [tableState.selectedRowIds]);

  const tableHeadProps: FeTableTHeadProps<T> = {
    prefixCls,
    headerGroups,
    onSortChange,
    onFilterChange,
    toggleAllRowsSelected,
    isAllRowsSelected,
    selectedFlatRows,
  };

  const tableRows: (Row<T> & UseExpandedRowProps<T>)[] = useMemo(
    () => (props.pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[],
    [page, rows, props.pagination]
  );

  const tablePaginationProps: FeTablePaginationProps<T> = {
    pageIndex: tableState.pageIndex,
    pageSize: tableState.pageSize,
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
  };

  const { className, toolbar, loading, pagination, pageSize } = props;

  return (
    <div className='fe-table__container'>
      <div ref={tableRef} className={classNames(prefixCls, className)} {...getTableProps()}>
        {toolbar && <FeTableToolbar />}

        <div
          className={classNames(
            `${prefixCls}__table-container`,
            loading && pagination === 'pages' && `${prefixCls}__table-container-loading`
          )}
        >
          <FeTableTBody
            pageSize={pageSize}
            pagination={pagination}
            onInfiniteScroll={handleOnPageChange}
            loading={props.loading}
            prefixCls={prefixCls}
            prepareRow={prepareRow}
            getTableBodyProps={getTableBodyProps}
            renderExpandedComponent={props.renderExpandedComponent}
            rows={tableRows}
          />
          <FeTableTHead {...tableHeadProps} />
        </div>

        {loading && pagination === 'pages' && rows.length > 0 && <FeLoader center size={24} />}
        {pagination === 'pages' && <FeTablePagination {...tablePaginationProps} />}
      </div>
    </div>
  );
}
Example #4
Source File: table.container.tsx    From master-frontend-lemoncode with MIT License 5 votes vote down vote up
TableContainer: React.FunctionComponent<Props> = props => {
  const { className } = props;

  const labels = { ...createEmptyLabelProps(), ...props.labels };

  const columns = React.useMemo(
    () => mapColumnListFromStringToColumn(props.columns),
    [props.columns]
  );
  const data = React.useMemo(() => props.rows, [props.rows]);

  const {
    getTableProps,
    headerGroups,
    rows,
    prepareRow,
    page,
    gotoPage,
    pageOptions,
    state,
  } = useTable(
    {
      columns,
      data,
      initialState: { pageSize: props.pageSize } as any,
    },
    usePagination
  ) as TableProps;
  const { pageIndex } = state as any;

  const {
    isOpen,
    itemToDelete,
    onOpenDialog,
    onClose,
    onAccept,
  } = useConfirmationDialog();

  const handleDelete = () => {
    if (props.onDelete) {
      props.onDelete(itemToDelete.id);
      onAccept();
    }
  };

  return (
    <TableComponent
      className={className}
      tableProps={{ ...getTableProps() }}
      headerGroups={headerGroups}
      rows={props.enablePagination ? page : rows}
      prepareRow={prepareRow}
      rowRenderer={rowProps =>
        props.rowRenderer({
          ...rowProps,
          onEdit: props.onEdit,
          onDelete: Boolean(props.onDelete) ? onOpenDialog : undefined,
        })
      }
      labels={labels}
      enableSearch={props.enableSearch}
      search={props.search}
      onSearch={props.onSearch}
      enablePagination={Boolean(
        props.enablePagination && pageOptions.length > 1
      )}
      pageIndex={pageIndex}
      pageCount={pageOptions.length}
      goToPage={gotoPage}
      onCreate={props.onCreate}
      onDelete={Boolean(props.onDelete) ? handleDelete : undefined}
      isOpenConfirmation={isOpen}
      onCloseConfirmation={onClose}
      itemToDeleteName={itemToDelete.name}
    />
  );
}
Example #5
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
CollectionsTable: React.FC = () => {
  const [filteringOptions, setFilteringOptions] = useState<
    FilteringOptionProps[]
  >([])
  const [offset, setOffset] = useState(0)
  const limit = DEFAULT_PAGE_SIZE

  const [query, setQuery] = useState("")
  const [numPages, setNumPages] = useState(0)

  const debouncedSearchTerm = useDebounce(query, 500)
  const { collections, isLoading, isRefetching, count } = useAdminCollections({
    q: debouncedSearchTerm,
    offset: offset,
    limit,
  })

  useEffect(() => {
    if (typeof count !== "undefined") {
      const controlledPageCount = Math.ceil(count / limit)
      setNumPages(controlledPageCount)
    }
  }, [count])

  const [columns] = useCollectionTableColumn()

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageCount,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex },
  } = useTable(
    {
      columns,
      data: collections || [],
      manualPagination: true,
      initialState: {
        pageIndex: Math.floor(offset / limit),
        pageSize: limit,
      },
      pageCount: numPages,
      autoResetPage: false,
    },
    usePagination
  )

  const handleNext = () => {
    if (canNextPage) {
      setOffset(offset + limit)
      nextPage()
    }
  }

  const handleSearch = (q) => {
    setOffset(0)
    setQuery(q)
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      setOffset(offset - limit)
      previousPage()
    }
  }

  useEffect(() => {
    setFilteringOptions([
      {
        title: "Sort",
        options: [
          {
            title: "All",
            count: collections?.length || 0,
            onClick: () => console.log("Not implemented yet"),
          },
        ],
      },
    ])
  }, [collections])

  return (
    <div className="w-full h-full overflow-y-auto">
      <Table
        enableSearch
        handleSearch={handleSearch}
        searchPlaceholder="Search Collections"
        filteringOptions={filteringOptions}
        {...getTableProps()}
      >
        <Table.Head>
          {headerGroups?.map((headerGroup) => (
            <Table.HeadRow {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((col) => (
                <Table.HeadCell
                  className="min-w-[100px]"
                  {...col.getHeaderProps()}
                >
                  {col.render("Header")}
                </Table.HeadCell>
              ))}
            </Table.HeadRow>
          ))}
        </Table.Head>
        {isLoading || isRefetching || !collections ? (
          <div className="w-full pt-2xlarge flex items-center justify-center">
            <Spinner size={"large"} variant={"secondary"} />
          </div>
        ) : (
          <Table.Body {...getTableBodyProps()}>
            {rows.map((row) => {
              prepareRow(row)
              return <CollectionRow row={row} />
            })}
          </Table.Body>
        )}
      </Table>
      <TablePagination
        count={count!}
        limit={limit}
        offset={offset}
        pageSize={offset + rows.length}
        title="Collections"
        currentPage={pageIndex + 1}
        pageCount={pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={canNextPage}
        hasPrev={canPreviousPage}
      />
    </div>
  )
}
Example #6
Source File: selectable-table.tsx    From admin with MIT License 4 votes vote down vote up
SelectableTable: React.FC<SelectableTableProps> = ({
  showSearch = true,
  label,
  objectName,
  selectedIds = [],
  isLoading,
  pagination,
  totalCount,
  data,
  columns,
  onPaginationChange,
  onChange,
  onSearch,
}) => {
  const handleQueryChange = (newQuery) => {
    onPaginationChange(newQuery)
  }

  const currentPage = useMemo(() => {
    return Math.floor(pagination.offset / pagination.limit)
  }, [pagination])

  const numPages = useMemo(() => {
    if (totalCount && pagination.limit) {
      return Math.ceil(totalCount / pagination.limit)
    }
    return 0
  }, [totalCount, pagination])

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageCount,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex, pageSize, selectedRowIds },
  } = useTable(
    {
      columns,
      data: data || [],
      manualPagination: true,
      initialState: {
        pageIndex: currentPage,
        pageSize: pagination.limit,
        selectedRowIds: selectedIds.reduce((prev, id) => {
          prev[id] = true
          return prev
        }, {}),
      },
      pageCount: numPages,
      autoResetSelectedRows: false,
      autoResetPage: false,
      getRowId: (row) => row.id,
    },
    usePagination,
    useRowSelect,
    (hooks) => {
      hooks.visibleColumns.push((columns) => [
        // Let's make a column for selection
        {
          id: "selection",
          // The header can use the table's getToggleAllRowsSelectedProps method
          // to render a checkbox
          Header: ({ getToggleAllRowsSelectedProps }) => {
            return (
              <div>
                <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
              </div>
            )
          },
          // The cell can use the individual row's getToggleRowSelectedProps method
          // to the render a checkbox
          Cell: ({ row }) => {
            return (
              <div>
                <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
              </div>
            )
          },
        },
        ...columns,
      ])
    }
  )

  useEffect(() => {
    onChange(Object.keys(selectedRowIds))
  }, [selectedRowIds])

  const handleNext = () => {
    if (canNextPage) {
      handleQueryChange({
        ...pagination,
        offset: pagination.offset + pagination.limit,
      })
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      handleQueryChange({
        ...pagination,
        offset: Math.max(pagination.offset - pagination.limit, 0),
      })
      previousPage()
    }
  }

  return (
    <div>
      <div className="inter-base-semibold my-large">{label}</div>
      <Table
        immediateSearchFocus={showSearch}
        enableSearch={showSearch}
        searchPlaceholder="Search Products.."
        handleSearch={onSearch}
        {...getTableProps()}
      >
        <Table.Body {...getTableBodyProps()}>
          {isLoading ? (
            <Spinner size="large" />
          ) : (
            rows.map((row, i) => {
              prepareRow(row)
              return (
                <Table.Row {...row.getRowProps()}>
                  {row.cells.map((cell) => {
                    return (
                      <Table.Cell {...cell.getCellProps()}>
                        {cell.render("Cell")}
                      </Table.Cell>
                    )
                  })}
                </Table.Row>
              )
            })
          )}
        </Table.Body>
      </Table>
      <TablePagination
        count={totalCount!}
        limit={pagination.limit}
        offset={pagination.offset}
        pageSize={pagination.offset + rows.length}
        title={objectName}
        currentPage={pageIndex + 1}
        pageCount={pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={canNextPage}
        hasPrev={canPreviousPage}
      />
    </div>
  )
}
Example #7
Source File: products.tsx    From admin with MIT License 4 votes vote down vote up
RMASelectProductSubModal: React.FC<RMASelectProductSubModalProps> = ({
  onSubmit,
  selectedItems,
  isLargeModal = true,
}) => {
  const PAGE_SIZE = 12
  const { pop } = useContext(LayeredModalContext)
  const [query, setQuery] = useState("")
  const [offset, setOffset] = useState(0)
  const [numPages, setNumPages] = useState(0)
  const [currentPage, setCurrentPage] = useState(0)

  const [selectedVariants, setSelectedVariants] = useState<any[]>([])

  const debouncedSearchTerm = useDebounce(query, 500)

  const { isLoading, count, variants } = useAdminVariants({
    q: debouncedSearchTerm,
    limit: PAGE_SIZE,
    offset,
  })

  useEffect(() => {
    if (typeof count !== "undefined") {
      setNumPages(Math.ceil(count / PAGE_SIZE))
    }
  }, [count])

  const columns = useMemo(() => {
    return [
      {
        Header: "Name",
        accessor: "title",
        Cell: ({ row: { original } }) => {
          return (
            <div className="flex items-center">
              <div className="h-[40px] w-[30px] my-1.5 flex items-center mr-4">
                {original.product.thumbnail ? (
                  <img
                    src={original.product.thumbnail}
                    className="h-full object-cover rounded-soft"
                  />
                ) : (
                  <div className="flex items-center justify-center w-full h-full rounded-soft bg-grey-10">
                    <ImagePlaceholder size={16} />
                  </div>
                )}
              </div>
              <div className="flex flex-col">
                <span>{original.product.title}</span>
                {original.title}
              </div>
            </div>
          )
        },
      },
      {
        Header: "Status",
        accessor: "status",
        Cell: ({ row: { original } }) => (
          <StatusIndicator
            title={`${original.product.status
              .charAt(0)
              .toUpperCase()}${original.product.status.slice(1)}`}
            variant={getProductStatusVariant(original.product.status)}
          />
        ),
      },
      {
        Header: <div className="text-right">In Stock</div>,
        accessor: "inventory_quantity",
        Cell: ({ row: { original } }) => (
          <div className="text-right">{original.inventory_quantity}</div>
        ),
      },
    ]
  }, [])

  const {
    getTableProps,
    getTableBodyProps,
    rows,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageCount,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex, pageSize, selectedRowIds },
  } = useTable(
    {
      columns,
      data: variants || [],
      manualPagination: true,
      initialState: {
        pageIndex: currentPage,
        pageSize: PAGE_SIZE,
        selectedRowIds: selectedItems.reduce((prev, { id }) => {
          prev[id] = true
          return prev
        }, {}),
      },
      pageCount: numPages,
      autoResetSelectedRows: false,
      autoResetPage: false,
      getRowId: (row) => row.id,
    },
    usePagination,
    useRowSelect,
    (hooks) => {
      hooks.visibleColumns.push((columns) => [
        // Let's make a column for selection
        {
          id: "selection",
          // The header can use the table's getToggleAllRowsSelectedProps method
          // to render a checkbox
          Header: ({ getToggleAllRowsSelectedProps }) => {
            return (
              <div>
                <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
              </div>
            )
          },
          // The cell can use the individual row's getToggleRowSelectedProps method
          // to the render a checkbox
          Cell: ({ row }) => {
            return (
              <div>
                <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
              </div>
            )
          },
        },
        ...columns,
      ])
    }
  )

  useEffect(() => {
    setSelectedVariants((selectedVariants) => [
      ...selectedVariants.filter(
        (sv) => Object.keys(selectedRowIds).findIndex((id) => id === sv.id) > -1
      ),
      ...(variants?.filter(
        (v) =>
          selectedVariants.findIndex((sv) => sv.id === v.id) < 0 &&
          Object.keys(selectedRowIds).findIndex((id) => id === v.id) > -1
      ) || []),
    ])
  }, [selectedRowIds])

  const handleNext = () => {
    if (canNextPage) {
      setOffset((old) => old + pageSize)
      setCurrentPage((old) => old + 1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      setOffset((old) => Math.max(old - pageSize, 0))
      setCurrentPage((old) => old - 1)
      previousPage()
    }
  }

  const handleSearch = (q) => {
    setOffset(0)
    setCurrentPage(0)
    setQuery(q)
  }

  const handleSubmit = () => {
    onSubmit(selectedVariants)
    pop()
  }

  return (
    <>
      <Modal.Content isLargeModal={isLargeModal}>
        <div className="min-h-[680px]">
          <Table
            immediateSearchFocus
            enableSearch
            searchPlaceholder="Search Products.."
            handleSearch={handleSearch}
            {...getTableProps()}
          >
            <Table.Body {...getTableBodyProps()}>
              {isLoading ? (
                <Spinner size="large" />
              ) : (
                rows.map((row, i) => {
                  prepareRow(row)
                  return (
                    <Table.Row {...row.getRowProps()}>
                      {row.cells.map((cell) => {
                        return (
                          <Table.Cell {...cell.getCellProps()}>
                            {cell.render("Cell")}
                          </Table.Cell>
                        )
                      })}
                    </Table.Row>
                  )
                })
              )}
            </Table.Body>
          </Table>
          <TablePagination
            count={count!}
            limit={PAGE_SIZE}
            offset={offset}
            pageSize={offset + rows.length}
            title="Products"
            currentPage={pageIndex + 1}
            pageCount={pageCount}
            nextPage={handleNext}
            prevPage={handlePrev}
            hasNext={canNextPage}
            hasPrev={canPreviousPage}
          />
        </div>
      </Modal.Content>
      <Modal.Footer isLargeModal={isLargeModal}>
        <div className="flex w-full justify-end gap-x-xsmall">
          <Button
            variant="ghost"
            size="small"
            className="w-[112px]"
            onClick={() => pop()}
          >
            Back
          </Button>
          <Button
            variant="primary"
            className="w-[112px]"
            size="small"
            onClick={handleSubmit}
          >
            Add
          </Button>
        </div>
      </Modal.Footer>
    </>
  )
}
Example #8
Source File: selectable-table.tsx    From admin with MIT License 4 votes vote down vote up
SelectableTable = <
  T extends
    | Product
    | CustomerGroup
    | ProductCollection
    | ProductTag
    | ProductType
>({
  label,
  resourceName = "",
  selectedIds = [],
  isLoading,
  totalCount = 0,
  data,
  columns,
  onChange,
  options,
  renderRow,
  renderHeaderGroup,
  setQuery,
  queryObject,
  paginate,
}: SelectableTableProps<T>) => {
  const table = useTable<T>(
    {
      columns,
      data: data || [],
      manualPagination: true,
      initialState: {
        pageIndex: queryObject.offset / queryObject.limit,
        pageSize: queryObject.limit,
        selectedRowIds: selectedIds.reduce((prev, id) => {
          prev[id] = true
          return prev
        }, {} as Record<string, boolean>),
      },
      pageCount: Math.ceil(totalCount / queryObject.limit),
      autoResetSelectedRows: false,
      autoResetPage: false,
      getRowId: (row: any) => row.id,
    },
    useSortBy,
    usePagination,
    useRowSelect,
    useSelectionColumn
  )

  useEffect(() => {
    onChange(Object.keys(table.state.selectedRowIds))
  }, [table.state.selectedRowIds])

  const handleNext = () => {
    if (!table.canNextPage) {
      return
    }

    paginate(1)
    table.nextPage()
  }

  const handlePrev = () => {
    if (!table.canPreviousPage) {
      return
    }

    paginate(-1)
    table.previousPage()
  }

  const handleSearch = (text: string) => {
    setQuery(text)

    if (text) {
      table.gotoPage(0)
    }
  }

  const debouncedSearch = React.useMemo(() => debounce(handleSearch, 300), [])

  return (
    <div>
      <div className="inter-base-semibold my-large">{label}</div>
      <Table
        {...options}
        {...table.getTableProps()}
        handleSearch={options.enableSearch ? debouncedSearch : undefined}
      >
        {renderHeaderGroup && (
          <Table.Head>
            {table.headerGroups?.map((headerGroup) =>
              renderHeaderGroup({ headerGroup })
            )}
          </Table.Head>
        )}

        <Table.Body {...table.getTableBodyProps()}>
          {isLoading ? (
            <Spinner size="large" />
          ) : (
            table.rows.map((row) => {
              table.prepareRow(row)
              return renderRow({ row })
            })
          )}
        </Table.Body>
      </Table>

      <TablePagination
        count={totalCount!}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + table.rows.length}
        title={resourceName}
        currentPage={table.state.pageIndex + 1}
        pageCount={table.pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={table.canNextPage}
        hasPrev={table.canPreviousPage}
      />
    </div>
  )
}
Example #9
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
SelectableTable = <
  T extends Product | CustomerGroup | ProductCollection | ProductTag
>({
  label,
  resourceName = "",
  selectedIds = [],
  isLoading,
  totalCount = 0,
  data,
  columns,
  onChange,
  options,
  renderRow,
  renderHeaderGroup,
  setQuery,
  queryObject,
  paginate,
}: SelectableTableProps<T>) => {
  const table = useTable<T>(
    {
      columns,
      data: data || [],
      manualPagination: true,
      initialState: {
        pageIndex: queryObject.offset / queryObject.limit,
        pageSize: queryObject.limit,
        selectedRowIds: selectedIds.reduce((prev, id) => {
          prev[id] = true
          return prev
        }, {} as Record<string, boolean>),
      },
      pageCount: Math.ceil(totalCount / queryObject.limit),
      autoResetSelectedRows: false,
      autoResetPage: false,
      getRowId: (row: any) => row.id,
    },
    useSortBy,
    usePagination,
    useRowSelect,
    useSelectionColumn
  )

  useEffect(() => {
    if (onChange) {
      onChange(Object.keys(table.state.selectedRowIds))
    }
  }, [table.state.selectedRowIds])

  const handleNext = () => {
    if (!table.canNextPage) {
      return
    }

    paginate(1)
    table.nextPage()
  }

  const handlePrev = () => {
    if (!table.canPreviousPage) {
      return
    }

    paginate(-1)
    table.previousPage()
  }

  const handleSearch = (text: string) => {
    setQuery(text)

    if (text) {
      table.gotoPage(0)
    }
  }

  const debouncedSearch = React.useMemo(() => debounce(handleSearch, 300), [])

  return (
    <div>
      {label && <div className="inter-base-semibold my-large">{label}</div>}
      <Table
        {...options}
        {...table.getTableProps()}
        handleSearch={options.enableSearch ? debouncedSearch : undefined}
      >
        {renderHeaderGroup && (
          <Table.Head>
            {table.headerGroups?.map((headerGroup) =>
              renderHeaderGroup({ headerGroup })
            )}
          </Table.Head>
        )}

        <Table.Body {...table.getTableBodyProps()}>
          {isLoading ? (
            <Spinner size="large" />
          ) : (
            table.rows.map((row, i) => {
              table.prepareRow(row)
              return renderRow({ row })
            })
          )}
        </Table.Body>
      </Table>

      <TablePagination
        count={totalCount!}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + table.rows.length}
        title={resourceName}
        currentPage={table.state.pageIndex + 1}
        pageCount={table.pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={table.canNextPage}
        hasPrev={table.canPreviousPage}
      />
    </div>
  )
}
Example #10
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
ProductTable: React.FC<ProductTableProps> = () => {
  const location = useLocation()

  const {
    removeTab,
    setTab,
    saveTab,
    availableTabs: filterTabs,
    activeFilterTab,
    reset,
    paginate,
    setFilters,
    setLimit,
    filters,
    setQuery: setFreeText,
    queryObject,
    representationObject,
  } = useProductFilters(location.search, defaultQueryProps)

  const offs = parseInt(queryObject.offset) || 0
  const limit = parseInt(queryObject.limit)

  const [query, setQuery] = useState(queryObject.query)
  const [numPages, setNumPages] = useState(0)

  const clearFilters = () => {
    reset()
    setQuery("")
  }

  const { products, isLoading, isRefetching, count } = useAdminProducts({
    ...queryObject,
  })

  useEffect(() => {
    if (typeof count !== "undefined") {
      const controlledPageCount = Math.ceil(count / limit)
      setNumPages(controlledPageCount)
    }
  }, [count])

  const updateUrlFromFilter = (obj = {}) => {
    const stringified = qs.stringify(obj)
    window.history.replaceState(`/a/products`, "", `${`?${stringified}`}`)
  }

  const refreshWithFilters = () => {
    const filterObj = representationObject

    if (isEmpty(filterObj)) {
      updateUrlFromFilter({ offset: 0, limit: DEFAULT_PAGE_SIZE })
    } else {
      updateUrlFromFilter(filterObj)
    }
  }

  useEffect(() => {
    refreshWithFilters()
  }, [representationObject])

  const setTileView = () => {
    setLimit(DEFAULT_PAGE_SIZE_TILE_VIEW)
    setShowList(false)
  }

  const setListView = () => {
    setLimit(DEFAULT_PAGE_SIZE)
    setShowList(true)
  }
  const [showList, setShowList] = React.useState(true)
  const [columns] = useProductTableColumn({
    setTileView,
    setListView,
    showList,
  })

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    gotoPage,
    canPreviousPage,
    canNextPage,
    pageCount,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data: products || [],
      manualPagination: true,
      initialState: {
        pageIndex: Math.floor(offs / limit),
        pageSize: limit,
      },
      pageCount: numPages,
      autoResetPage: false,
    },
    usePagination
  )

  // Debounced search
  useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
      if (query) {
        setFreeText(query)
        gotoPage(0)
      } else {
        if (typeof query !== "undefined") {
          // if we delete query string, we reset the table view
          reset()
        }
      }
    }, 400)

    return () => clearTimeout(delayDebounceFn)
  }, [query])

  const handleNext = () => {
    if (canNextPage) {
      paginate(1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      paginate(-1)
      previousPage()
    }
  }

  return (
    <div className="w-full h-full overflow-y-auto">
      <>
        <Table
          filteringOptions={
            <ProductsFilter
              filters={filters}
              submitFilters={setFilters}
              clearFilters={clearFilters}
              tabs={filterTabs}
              onTabClick={setTab}
              activeTab={activeFilterTab}
              onRemoveTab={removeTab}
              onSaveTab={saveTab}
            />
          }
          enableSearch
          handleSearch={setQuery}
          {...getTableProps()}
        >
          {showList ? (
            <>
              <Table.Head>
                {headerGroups?.map((headerGroup) => (
                  <Table.HeadRow {...headerGroup.getHeaderGroupProps()}>
                    {headerGroup.headers.map((col) => (
                      <Table.HeadCell
                        className="min-w-[100px]"
                        {...col.getHeaderProps()}
                      >
                        {col.render("Header")}
                      </Table.HeadCell>
                    ))}
                  </Table.HeadRow>
                ))}
              </Table.Head>
              <LoadingContainer
                isLoading={isLoading || isRefetching || !products}
              >
                <Table.Body {...getTableBodyProps()}>
                  {rows.map((row) => {
                    prepareRow(row)
                    return <ProductRow row={row} />
                  })}
                </Table.Body>
              </LoadingContainer>
            </>
          ) : (
            <LoadingContainer
              isLoading={isLoading || isRefetching || !products}
            >
              <ProductOverview
                products={products}
                toggleListView={setListView}
              />
            </LoadingContainer>
          )}
        </Table>
        <TablePagination
          count={count!}
          limit={limit}
          offset={offs}
          pageSize={offs + rows.length}
          title="Products"
          currentPage={pageIndex + 1}
          pageCount={pageCount}
          nextPage={handleNext}
          prevPage={handlePrev}
          hasNext={canNextPage}
          hasPrev={canPreviousPage}
        />
      </>
    </div>
  )
}
Example #11
Source File: price-list-table.tsx    From admin with MIT License 4 votes vote down vote up
/*
 * Root component of the price lists table.
 */
export function PriceListTable(props: PriceListTableProps) {
  const {
    priceLists,
    queryObject,
    count,
    paginate,
    setQuery,
    columns,
    options,
  } = props

  const tableConfig: TableOptions<PriceList> = {
    columns: columns,
    data: priceLists || [],
    initialState: {
      pageSize: queryObject.limit,
      pageIndex: queryObject.offset / queryObject.limit,
    },
    pageCount: Math.ceil(count / queryObject.limit),
    manualPagination: true,
    autoResetPage: false,
  }

  const table = useTable(tableConfig, useSortBy, usePagination, useRowSelect)

  // ********* HANDLERS *********

  const handleNext = () => {
    if (!table.canNextPage) {
      return
    }

    paginate(1)
    table.nextPage()
  }

  const handlePrev = () => {
    if (!table.canPreviousPage) {
      return
    }

    paginate(-1)
    table.previousPage()
  }

  const handleSearch = (text: string) => {
    setQuery(text)

    if (text) {
      table.gotoPage(0)
    }
  }

  const debouncedSearch = React.useMemo(() => debounce(handleSearch, 300), [])

  // ********* RENDER *********

  return (
    <>
      <Table
        {...table.getTableProps()}
        {...options}
        enableSearch={options.enableSearch}
        handleSearch={options.enableSearch ? debouncedSearch : undefined}
        filteringOptions={options.filter}
      >
        {/* HEAD */}
        <Table.Head>
          {table.headerGroups?.map((headerGroup, ind) => (
            <PriceListTableHeaderRow key={ind} headerGroup={headerGroup} />
          ))}
        </Table.Head>

        {/* BODY */}
        <Table.Body {...table.getTableBodyProps()}>
          {table.rows.map((row) => {
            table.prepareRow(row)
            return <PriceListTableRow row={row} />
          })}
        </Table.Body>
      </Table>

      {/* PAGINATION */}
      <TablePagination
        count={count}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + table.rows.length}
        title="Price Lists"
        currentPage={table.state.pageIndex + 1}
        pageCount={table.pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={table.canNextPage}
        hasPrev={table.canPreviousPage}
      />
    </>
  )
}
Example #12
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
OrderTable: React.FC<RouteComponentProps> = () => {
  const location = useLocation()

  const {
    removeTab,
    setTab,
    saveTab,
    availableTabs: filterTabs,
    activeFilterTab,
    reset,
    paginate,
    setFilters,
    filters,
    setQuery: setFreeText,
    queryObject,
    representationObject,
  } = useOrderFilters(location.search, defaultQueryProps)
  const filtersOnLoad = queryObject

  const offs = parseInt(filtersOnLoad?.offset) || 0
  const lim = parseInt(filtersOnLoad.limit) || DEFAULT_PAGE_SIZE

  const [query, setQuery] = useState(filtersOnLoad?.query)
  const [numPages, setNumPages] = useState(0)

  const { orders, isLoading, count } = useAdminOrders(queryObject)

  useEffect(() => {
    const controlledPageCount = Math.ceil(count! / queryObject.limit)
    setNumPages(controlledPageCount)
  }, [orders])

  const [columns] = useOrderTableColums()

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex },
  } = useTable(
    {
      columns,
      data: orders || [],
      manualPagination: true,
      initialState: {
        pageSize: lim,
        pageIndex: offs / lim,
      },
      pageCount: numPages,
      autoResetPage: false,
    },
    usePagination
  )

  // Debounced search
  useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
      if (query) {
        setFreeText(query)
        gotoPage(0)
      } else {
        // if we delete query string, we reset the table view
        reset()
      }
    }, 400)

    return () => clearTimeout(delayDebounceFn)
  }, [query])

  const handleNext = () => {
    if (canNextPage) {
      paginate(1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      paginate(-1)
      previousPage()
    }
  }

  const updateUrlFromFilter = (obj = {}) => {
    const stringified = qs.stringify(obj)
    window.history.replaceState(`/a/orders`, "", `${`?${stringified}`}`)
  }

  const refreshWithFilters = () => {
    const filterObj = representationObject

    if (isEmpty(filterObj)) {
      updateUrlFromFilter({ offset: 0, limit: DEFAULT_PAGE_SIZE })
    } else {
      updateUrlFromFilter(filterObj)
    }
  }

  const clearFilters = () => {
    reset()
    setQuery("")
  }

  useEffect(() => {
    refreshWithFilters()
  }, [representationObject])

  return (
    <div className="w-full overflow-y-auto flex flex-col justify-between min-h-[300px] h-full ">
      <Table
        filteringOptions={
          <OrderFilters
            filters={filters}
            submitFilters={setFilters}
            clearFilters={clearFilters}
            tabs={filterTabs}
            onTabClick={setTab}
            activeTab={activeFilterTab}
            onRemoveTab={removeTab}
            onSaveTab={saveTab}
          />
        }
        enableSearch
        handleSearch={setQuery}
        searchValue={query}
        {...getTableProps()}
        className={clsx({ ["relative"]: isLoading })}
      >
        <Table.Head>
          {headerGroups?.map((headerGroup, index) => (
            <Table.HeadRow {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((col, headerIndex) => (
                <Table.HeadCell {...col.getHeaderProps()}>
                  {col.render("Header")}
                </Table.HeadCell>
              ))}
            </Table.HeadRow>
          ))}
        </Table.Head>
        {isLoading || !orders ? (
          <div className="flex w-full h-full absolute items-center justify-center mt-10">
            <div className="">
              <Spinner size={"large"} variant={"secondary"} />
            </div>
          </div>
        ) : (
          <Table.Body {...getTableBodyProps()}>
            {rows.map((row) => {
              prepareRow(row)
              return (
                <Table.Row
                  color={"inherit"}
                  linkTo={row.original.id}
                  {...row.getRowProps()}
                  className="group"
                >
                  {row.cells.map((cell, index) => {
                    return cell.render("Cell", { index })
                  })}
                </Table.Row>
              )
            })}
          </Table.Body>
        )}
      </Table>
      <TablePagination
        count={count!}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + rows.length}
        title="Orders"
        currentPage={pageIndex + 1}
        pageCount={pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={canNextPage}
        hasPrev={canPreviousPage}
      />
    </div>
  )
}
Example #13
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
DraftOrderTable: React.FC<RouteComponentProps> = () => {
  const location = useLocation()

  const {
    reset,
    paginate,
    setQuery: setFreeText,
    queryObject,
  } = useDraftOrderFilters(location.search, {})

  const filtersOnLoad = queryObject

  const offs = parseInt(filtersOnLoad?.offset) || 0
  const lim = parseInt(filtersOnLoad?.limit) || DEFAULT_PAGE_SIZE

  const [query, setQuery] = useState(filtersOnLoad?.query)
  const [numPages, setNumPages] = useState(0)

  const { draft_orders, isLoading, isRefetching, count } = useAdminDraftOrders(
    queryObject
  )

  useEffect(() => {
    const controlledPageCount = Math.ceil(count! / queryObject.limit)
    setNumPages(controlledPageCount)
  }, [count, queryObject])

  const [columns] = useDraftOrderTableColumns()

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex },
  } = useTable(
    {
      columns,
      data: draft_orders || [],
      manualPagination: true,
      initialState: {
        pageSize: lim,
        pageIndex: offs / lim,
      },
      pageCount: numPages,
      autoResetPage: false,
    },
    usePagination
  )

  // Debounced search
  useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
      if (query) {
        setFreeText(query)
        gotoPage(0)
      } else {
        // if we delete query string, we reset the table view
        reset()
      }
    }, 400)

    return () => clearTimeout(delayDebounceFn)
  }, [query])

  const handleNext = () => {
    if (canNextPage) {
      paginate(1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      paginate(-1)
      previousPage()
    }
  }

  return (
    <div className="w-full h-full overflow-y-auto flex flex-col justify-between">
      {isLoading || isRefetching || !draft_orders ? (
        <div className="w-full pt-2xlarge flex items-center justify-center">
          <Spinner size={"large"} variant={"secondary"} />
        </div>
      ) : (
        <>
          <Table
            filteringOptions={[]}
            enableSearch
            handleSearch={setQuery}
            searchValue={query}
            {...getTableProps()}
          >
            <Table.Head>
              {headerGroups?.map((headerGroup, index) => (
                <Table.HeadRow {...headerGroup.getHeaderGroupProps()}>
                  {headerGroup.headers.map((col, headerIndex) => (
                    <Table.HeadCell
                      className="w-[100px]"
                      {...col.getHeaderProps()}
                    >
                      {col.render("Header")}
                    </Table.HeadCell>
                  ))}
                </Table.HeadRow>
              ))}
            </Table.Head>
            <Table.Body {...getTableBodyProps()}>
              {rows.map((row) => {
                prepareRow(row)
                return (
                  <Table.Row
                    color={"inherit"}
                    linkTo={`/a/draft-orders/${row.original.id}`}
                    {...row.getRowProps()}
                  >
                    {row.cells.map((cell, index) => {
                      return cell.render("Cell", { index })
                    })}
                  </Table.Row>
                )
              })}
            </Table.Body>
          </Table>
          <TablePagination
            count={count!}
            limit={queryObject.limit}
            offset={queryObject.offset}
            pageSize={queryObject.offset + rows.length}
            title="Draft Orders"
            currentPage={pageIndex + 1}
            pageCount={pageCount}
            nextPage={handleNext}
            prevPage={handlePrev}
            hasNext={canNextPage}
            hasPrev={canPreviousPage}
          />
        </>
      )}
    </div>
  )
}
Example #14
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
DiscountTable: React.FC = () => {
  const {
    removeTab,
    setTab,
    saveTab,
    availableTabs: filterTabs,
    activeFilterTab,
    reset,
    paginate,
    setFilters,
    filters,
    setQuery: setFreeText,
    queryObject,
    representationObject,
  } = usePromotionFilters(location.search, defaultQueryProps)

  const offs = parseInt(queryObject?.offset) || 0
  const lim = parseInt(queryObject.limit) || DEFAULT_PAGE_SIZE

  const { discounts, isLoading, count } = useAdminDiscounts({
    is_dynamic: false,
    expand: "rule,rule.conditions,rule.conditions.products",
    ...queryObject,
  })

  const [query, setQuery] = useState("")
  const [numPages, setNumPages] = useState(0)

  useEffect(() => {
    if (count && queryObject.limit) {
      const controlledPageCount = Math.ceil(count! / queryObject.limit)
      if (controlledPageCount !== numPages) {
        setNumPages(controlledPageCount)
      }
    }
  }, [count, queryObject.limit])

  const [columns] = usePromotionTableColumns()

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex },
  } = useTable(
    {
      columns,
      data: discounts || [],
      manualPagination: true,
      initialState: {
        pageSize: lim,
        pageIndex: offs / lim,
      },
      pageCount: numPages,
      autoResetPage: false,
    },
    usePagination
  )

  // Debounced search
  useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
      if (query) {
        setFreeText(query)
        gotoPage(0)
      } else {
        // if we delete query string, we reset the table view
        reset()
      }
    }, 400)

    return () => clearTimeout(delayDebounceFn)
  }, [query])

  const handleNext = () => {
    if (canNextPage) {
      paginate(1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      paginate(-1)
      previousPage()
    }
  }

  const updateUrlFromFilter = (obj = {}) => {
    const stringified = qs.stringify(obj)
    window.history.replaceState(`/a/discounts`, "", `${`?${stringified}`}`)
  }

  const refreshWithFilters = () => {
    const filterObj = representationObject

    if (isEmpty(filterObj)) {
      updateUrlFromFilter({ offset: 0, limit: DEFAULT_PAGE_SIZE })
    } else {
      updateUrlFromFilter(filterObj)
    }
  }

  const clearFilters = () => {
    reset()
    setQuery("")
  }

  useEffect(() => {
    refreshWithFilters()
  }, [representationObject])

  return (
    <div className="w-full overflow-y-auto flex flex-col justify-between min-h-[300px] h-full ">
      <Table
        filteringOptions={
          <DiscountFilters
            filters={filters}
            submitFilters={setFilters}
            clearFilters={clearFilters}
            tabs={filterTabs}
            onTabClick={setTab}
            activeTab={activeFilterTab}
            onRemoveTab={removeTab}
            onSaveTab={saveTab}
          />
        }
        enableSearch
        handleSearch={setQuery}
        searchPlaceholder="Search by code or description..."
        searchValue={query}
        {...getTableProps()}
        className={clsx({ ["relative"]: isLoading })}
      >
        <Table.Head>
          {headerGroups?.map((headerGroup, index) => (
            <Table.HeadRow {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((col, headerIndex) => (
                <Table.HeadCell {...col.getHeaderProps()}>
                  {col.render("Header")}
                </Table.HeadCell>
              ))}
            </Table.HeadRow>
          ))}
        </Table.Head>
        {isLoading || !discounts ? (
          <div className="flex w-full h-full absolute items-center justify-center mt-10">
            <div className="">
              <Spinner size={"large"} variant={"secondary"} />
            </div>
          </div>
        ) : (
          <Table.Body {...getTableBodyProps()}>
            {rows.map((row, rowIndex) => {
              prepareRow(row)
              return <PromotionRow row={row} />
            })}
          </Table.Body>
        )}
      </Table>
      <TablePagination
        count={count!}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + rows.length}
        title="Discounts"
        currentPage={pageIndex + 1}
        pageCount={pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={canNextPage}
        hasPrev={canPreviousPage}
      />
    </div>
  )
}
Example #15
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
CustomerTable: React.FC<RouteComponentProps> = () => {
  const {
    reset,
    paginate,
    setQuery: setFreeText,
    queryObject,
    representationObject,
  } = useCustomerFilters(location.search, defaultQueryProps)

  const offs = parseInt(queryObject.offset) || 0
  const lim = parseInt(queryObject.limit) || DEFAULT_PAGE_SIZE

  const { customers, isLoading, count } = useAdminCustomers({
    ...queryObject,
  })

  const [query, setQuery] = useState(queryObject.query)
  const [numPages, setNumPages] = useState(0)

  useEffect(() => {
    if (typeof count !== "undefined") {
      const controlledPageCount = Math.ceil(count / lim)
      setNumPages(controlledPageCount)
    }
  }, [count])

  const [columns] = useCustomerColumns()

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    canPreviousPage,
    canNextPage,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex },
  } = useTable(
    {
      columns,
      data: customers || [],
      manualPagination: true,
      initialState: {
        pageSize: lim,
        pageIndex: offs / lim,
      },
      pageCount: numPages,
      autoResetPage: false,
    },
    usePagination
  )

  // Debounced search
  useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
      if (query) {
        setFreeText(query)
        gotoPage(0)
      } else {
        if (typeof query !== "undefined") {
          // if we delete query string, we reset the table view
          reset()
        }
      }
    }, 400)

    return () => clearTimeout(delayDebounceFn)
  }, [query])

  const handleNext = () => {
    if (canNextPage) {
      paginate(1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      paginate(-1)
      previousPage()
    }
  }

  const updateUrlFromFilter = (obj = {}) => {
    const stringified = qs.stringify(obj)
    window.history.replaceState(`/a/discounts`, "", `${`?${stringified}`}`)
  }

  const refreshWithFilters = () => {
    const filterObj = representationObject

    if (isEmpty(filterObj)) {
      updateUrlFromFilter({ offset: 0, limit: DEFAULT_PAGE_SIZE })
    } else {
      updateUrlFromFilter(filterObj)
    }
  }

  useEffect(() => {
    refreshWithFilters()
  }, [representationObject])

  return (
    <div className="w-full h-full overflow-y-auto flex flex-col justify-between">
      <Table enableSearch handleSearch={setQuery} {...getTableProps()}>
        <Table.Head>
          {headerGroups?.map((headerGroup) => (
            <Table.HeadRow {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((col) => (
                <Table.HeadCell className="w-[100px]" {...col.getHeaderProps()}>
                  {col.render("Header")}
                </Table.HeadCell>
              ))}
            </Table.HeadRow>
          ))}
        </Table.Head>
        {isLoading || !customers ? (
          <div className="flex w-full h-full absolute items-center justify-center mt-10">
            <div className="">
              <Spinner size={"large"} variant={"secondary"} />
            </div>
          </div>
        ) : (
          <Table.Body {...getTableBodyProps()}>
            {rows.map((row) => {
              prepareRow(row)
              return (
                <Table.Row
                  color={"inherit"}
                  actions={[
                    {
                      label: "Edit",
                      onClick: () => navigate(row.original.id),
                      icon: <EditIcon size={20} />,
                    },
                    {
                      label: "Details",
                      onClick: () => navigate(row.original.id),
                      icon: <DetailsIcon size={20} />,
                    },
                  ]}
                  linkTo={row.original.id}
                  {...row.getRowProps()}
                >
                  {row.cells.map((cell, index) => {
                    return (
                      <Table.Cell {...cell.getCellProps()}>
                        {cell.render("Cell", { index })}
                      </Table.Cell>
                    )
                  })}
                </Table.Row>
              )
            })}
          </Table.Body>
        )}
      </Table>
      <TablePagination
        count={count!}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + rows.length}
        title="Customers"
        currentPage={pageIndex + 1}
        pageCount={pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={canNextPage}
        hasPrev={canPreviousPage}
      />
    </div>
  )
}
Example #16
Source File: edit-customers-table.tsx    From admin with MIT License 4 votes vote down vote up
/*
 * Container for the "edit customers" table.
 */
function EditCustomersTable(props: EditCustomersTableProps) {
  const {
    setSelectedCustomerIds,
    selectedCustomerIds,
    handleSubmit,
    onClose,
  } = props

  const {
    paginate,
    setQuery,
    setFilters,
    filters,
    queryObject,
  } = useQueryFilters(defaultQueryProps)

  const [numPages, setNumPages] = useState(0)
  const [activeGroupId, setActiveGroupId] = useState()

  const { customer_groups } = useAdminCustomerGroups({ expand: "customers" })
  const { customers = [], count = 0 } = useAdminCustomers({
    ...queryObject,
    groups: activeGroupId ? [activeGroupId] : null,
  })

  useEffect(() => {
    if (typeof count !== "undefined") {
      const controlledPageCount = Math.ceil(count / queryObject.limit)
      setNumPages(controlledPageCount)
    }
  }, [count])

  const tableConfig = {
    columns: CUSTOMER_GROUPS_CUSTOMERS_TABLE_COLUMNS,
    data: customers,
    initialState: {
      pageSize: queryObject.limit,
      pageIndex: queryObject.offset / queryObject.limit,
      selectedRowIds: selectedCustomerIds.reduce((prev, id) => {
        prev[id] = true
        return prev
      }, {}),
    },
    pageCount: numPages,
    autoResetSelectedRows: false,
    manualPagination: true,
    autoResetPage: false,
    getRowId: (row) => row.id,
  }

  const table = useTable(tableConfig, usePagination, useRowSelect)

  useEffect(() => {
    setSelectedCustomerIds(Object.keys(table.state.selectedRowIds))
  }, [table.state.selectedRowIds])

  useEffect(() => {
    setFilters("offset", 0)
    table.gotoPage(0)
  }, [activeGroupId])

  const filteringOptions = [
    {
      title: "Groups",
      options: [
        {
          title: "All",
          onClick: () => setActiveGroupId(null),
        },
        ...(customer_groups || []).map((g) => ({
          title: g.name,
          count: g.customers.length,
          onClick: () => setActiveGroupId(g.id),
        })),
      ],
    },
  ]

  const handleNext = () => {
    if (!table.canNextPage) {
      return
    }

    paginate(1)
    table.nextPage()
  }

  const handlePrev = () => {
    if (!table.canPreviousPage) {
      return
    }

    paginate(-1)
    table.previousPage()
  }

  const handleSearch = (text: string) => {
    setQuery(text)

    if (text) {
      table.gotoPage(0)
    }
  }

  return (
    <Modal handleClose={onClose}>
      <Modal.Body>
        <Modal.Header handleClose={onClose}>
          <h3 className="inter-xlarge-semibold">Edit Customers</h3>
        </Modal.Header>

        <Modal.Content>
          <div className="w-full flex flex-col justify-between h-[650px]">
            <Table
              filteringOptions={filteringOptions}
              enableSearch
              handleSearch={handleSearch}
              searchValue={queryObject.q}
              {...table.getTableProps()}
            >
              <Table.Head>
                {table.headerGroups?.map((headerGroup) => (
                  <EditCustomersTableHeaderRow headerGroup={headerGroup} />
                ))}
              </Table.Head>

              <Table.Body {...table.getTableBodyProps()}>
                {table.rows.map((row) => {
                  table.prepareRow(row)
                  return <EditCustomersTableRow row={row} />
                })}
              </Table.Body>
            </Table>

            <TablePagination
              count={count!}
              limit={queryObject.limit}
              offset={queryObject.offset}
              pageSize={queryObject.offset + table.rows.length}
              title="Customers"
              currentPage={table.state.pageIndex + 1}
              pageCount={table.pageCount}
              nextPage={handleNext}
              prevPage={handlePrev}
              hasNext={table.canNextPage}
              hasPrev={table.canPreviousPage}
            />
          </div>
        </Modal.Content>

        <Modal.Footer>
          <div className="flex items-center justify-end gap-x-xsmall w-full">
            <Button
              variant="ghost"
              size="small"
              className="w-eventButton"
              onClick={onClose}
            >
              Cancel
            </Button>
            <Button
              variant="primary"
              size="small"
              className="w-eventButton"
              onClick={handleSubmit}
            >
              Save
            </Button>
          </div>
        </Modal.Footer>
      </Modal.Body>
    </Modal>
  )
}
Example #17
Source File: customers-list-table.tsx    From admin with MIT License 4 votes vote down vote up
/*
 * Render a list of customers that belong to a customer group.
 */
function CustomersListTable(props: CustomersListTableProps) {
  const {
    customers,
    removeCustomers,
    setQuery,
    paginate,
    filteringOptions,
    query,
    queryObject,
    count,
  } = props

  const tableConfig = {
    data: customers,
    columns: CUSTOMER_GROUPS_CUSTOMERS_LIST_TABLE_COLUMNS,
    initialState: {
      pageSize: queryObject.limit,
      pageIndex: queryObject.offset / queryObject.limit,
    },
    pageCount: Math.ceil(count / queryObject.limit),
    manualPagination: true,
    autoResetPage: false,
  }

  const table = useTable(tableConfig, useSortBy, usePagination)

  // ********* HANDLERS *********

  const handleNext = () => {
    if (!table.canNextPage) {
      return
    }

    paginate(1)
    table.nextPage()
  }

  const handlePrev = () => {
    if (!table.canPreviousPage) {
      return
    }

    paginate(-1)
    table.previousPage()
  }

  const handleSearch = (text: string) => {
    setQuery(text)

    if (text) {
      table.gotoPage(0)
    }
  }

  return (
    <>
      <Table
        enableSearch
        handleSearch={handleSearch}
        searchValue={query}
        filteringOptions={filteringOptions}
        {...table.getTableProps()}
      >
        <Table.Head>
          {table.headerGroups?.map((headerGroup, index) => (
            <CustomersListTableHeaderRow
              key={index}
              headerGroup={headerGroup}
            />
          ))}
        </Table.Head>

        <Table.Body {...table.getTableBodyProps()}>
          {table.rows.map((row) => {
            table.prepareRow(row)
            return (
              <CustomersListTableRow
                row={row}
                key={row.id}
                removeCustomers={removeCustomers}
              />
            )
          })}
        </Table.Body>
      </Table>

      <TablePagination
        count={count!}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + table.rows.length}
        title="Customers"
        currentPage={table.state.pageIndex + 1}
        pageCount={table.pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={table.canNextPage}
        hasPrev={table.canPreviousPage}
      />
    </>
  )
}
Example #18
Source File: customer-groups-table.tsx    From admin with MIT License 4 votes vote down vote up
/*
 * Root component of the customer groups table.
 */
function CustomerGroupsTable(props: CustomerGroupsTableProps) {
  const { customerGroups, queryObject, count, paginate, setQuery } = props

  const tableConfig: TableOptions<CustomerGroup> = {
    columns: CUSTOMER_GROUPS_TABLE_COLUMNS,
    data: customerGroups || [],
    initialState: {
      pageSize: queryObject.limit,
      pageIndex: queryObject.offset / queryObject.limit,
    },
    pageCount: Math.ceil(count / queryObject.limit),
    manualPagination: true,
    autoResetPage: false,
  }

  const table: TableInstance<CustomerGroup> = useTable(
    tableConfig,
    useSortBy,
    usePagination
  )

  // ********* HANDLERS *********

  const handleNext = () => {
    if (!table.canNextPage) {
      return
    }

    paginate(1)
    table.nextPage()
  }

  const handlePrev = () => {
    if (!table.canPreviousPage) {
      return
    }

    paginate(-1)
    table.previousPage()
  }

  const handleSearch = (text: string) => {
    setQuery(text)

    if (text) {
      table.gotoPage(0)
    }
  }

  // ********* RENDER *********

  return (
    <div className="w-full h-full overflow-y-auto flex flex-col justify-between">
      <Table
        enableSearch
        handleSearch={handleSearch}
        searchValue={queryObject.q}
        {...table.getTableProps()}
      >
        {/* HEAD */}
        <Table.Head>
          {table.headerGroups?.map((headerGroup, ind) => (
            <CustomerGroupsTableHeaderRow key={ind} headerGroup={headerGroup} />
          ))}
        </Table.Head>

        {/* BODY */}
        <Table.Body {...table.getTableBodyProps()}>
          {table.rows.map((row) => {
            table.prepareRow(row)
            return (
              <CustomerGroupContextContainer key={row.id} group={row.original}>
                <CustomerGroupsTableRow row={row} />
              </CustomerGroupContextContainer>
            )
          })}
        </Table.Body>
      </Table>

      {/* PAGINATION */}
      <TablePagination
        count={count}
        limit={queryObject.limit}
        offset={queryObject.offset}
        pageSize={queryObject.offset + table.rows.length}
        title="Customers"
        currentPage={table.state.pageIndex + 1}
        pageCount={table.pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={table.canNextPage}
        hasPrev={table.canPreviousPage}
      />
    </div>
  )
}
Example #19
Source File: view-products-table.tsx    From admin with MIT License 4 votes vote down vote up
ViewProductsTable: React.FC<ViewProductsTableProps> = ({
  collectionId,
  refetchCollection,
}) => {
  const limit = 10
  const [query, setQuery] = useState("")
  const [offset, setOffset] = useState(0)
  const [numPages, setNumPages] = useState(0)
  const [currentPage, setCurrentPage] = useState(0)
  const debouncedSearchTerm = useDebounce(query, 500)

  const [showDelete, setShowDelete] = useState(false)
  const [idToDelete, setIdToDelete] = useState<string | undefined>(undefined)

  const { isLoading, count, products, refetch } = useAdminProducts({
    q: debouncedSearchTerm,
    collection_id: [collectionId],
    limit: limit,
    offset,
  })

  useEffect(() => {
    refetch() // Ensure we get the latest data
  }, [collectionId])

  const handleRemoveProduct = () => {
    if (idToDelete) {
      Medusa.products
        .update(idToDelete, {
          collection_id: null,
        })
        .then(() => {
          refetch()
          refetchCollection()
        })
    }
  }

  const columns = useViewProductColumns()

  // const [sorted, sortingOptions] = useSortingOptions(products ?? []) TODO: Implement this with server side sorting

  const {
    rows,
    prepareRow,
    getTableBodyProps,
    getTableProps,
    canPreviousPage,
    canNextPage,
    pageCount,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex, pageSize },
  } = useTable(
    {
      data: products || [],
      columns: columns,
      manualPagination: true,
      initialState: {
        pageIndex: currentPage,
        pageSize: limit,
      },
      pageCount: numPages,
      getRowId: (row) => row.id,
    },
    usePagination,
    (hooks) => {
      hooks.visibleColumns.push((columns) => [
        ...columns,
        {
          id: "actions",
          Cell: ({ row }) => {
            return (
              <Table.Cell className="w-[0%] pr-2xsmall">
                <Button
                  variant="ghost"
                  size="small"
                  className="text-grey-40"
                  onClick={() => {
                    setIdToDelete(row.original.id)
                    setShowDelete(true)
                  }}
                >
                  <TrashIcon size={20} />
                </Button>
              </Table.Cell>
            )
          },
        },
      ])
    }
  )

  useEffect(() => {
    const controlledPageCount = Math.ceil(count! / limit)
    setNumPages(controlledPageCount)
  }, [products, count, limit])

  const handleNext = () => {
    if (canNextPage) {
      setOffset((old) => old + pageSize)
      setCurrentPage((old) => old + 1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      setOffset((old) => old - pageSize)
      setCurrentPage((old) => old - 1)
      previousPage()
    }
  }

  const handleSearch = (q) => {
    setOffset(0)
    setQuery(q)
  }

  return (
    <>
      <div className="w-full h-full flex flex-col justify-between overflow-y-auto">
        <Table
          enableSearch
          handleSearch={handleSearch}
          searchPlaceholder="Search Products"
          {...getTableProps()}
          className="h-full"
        >
          {!products?.length ? (
            <div className="inter-small-regular text-grey-40 flex flex-grow justify-center items-center">
              {isLoading ? (
                <Spinner size="large" variant="secondary" />
              ) : (
                "No products yet"
              )}
            </div>
          ) : (
            <Table.Body {...getTableBodyProps()}>
              {rows.map((row) => {
                prepareRow(row)
                return (
                  <Table.Row
                    color={"inherit"}
                    {...row.getRowProps()}
                    className="px-base"
                  >
                    {row.cells.map((cell, index) => {
                      return cell.render("Cell", { index })
                    })}
                  </Table.Row>
                )
              })}
            </Table.Body>
          )}
        </Table>
        <TablePagination
          count={count!}
          limit={limit}
          offset={offset}
          pageSize={offset + rows.length}
          title="Products"
          currentPage={pageIndex + 1}
          pageCount={pageCount}
          nextPage={handleNext}
          prevPage={handlePrev}
          hasNext={canNextPage}
          hasPrev={canPreviousPage}
        />
      </div>
      {showDelete && (
        <DeletePrompt
          onDelete={async () => handleRemoveProduct()}
          handleClose={() => setShowDelete(!showDelete)}
          heading="Remove product from collection"
          successText="Product removed from collection"
        />
      )}
    </>
  )
}
Example #20
Source File: index.tsx    From admin with MIT License 4 votes vote down vote up
CollectionProductTable: React.FC<CollectionProductTableProps> = ({
  addedProducts,
  setProducts,
}) => {
  const [query, setQuery] = useState("")
  const [limit, setLimit] = useState(10)
  const [offset, setOffset] = useState(0)
  const [numPages, setNumPages] = useState(0)
  const [currentPage, setCurrentPage] = useState(0)
  const [filteringOptions, setFilteringOptions] = useState<
    FilteringOptionProps[]
  >([])

  const [selectedProducts, setSelectedProducts] = useState<any[]>([])

  const debouncedSearchTerm = useDebounce(query, 500)

  const { isLoading, count, products } = useAdminProducts({
    q: debouncedSearchTerm,
    limit: limit,
    offset,
  })

  useEffect(() => {
    setFilteringOptions([
      {
        title: "Sort by",
        options: [
          {
            title: "All",
            onClick: () => {},
          },
          {
            title: "Newest",
            onClick: () => {},
          },
          {
            title: "Oldest",
            onClick: () => {},
          },
        ],
      },
    ])
  }, [products])

  const columns = useCollectionProductColumns() as readonly Column<any[]>[]

  const {
    rows,
    prepareRow,
    getTableBodyProps,
    getTableProps,
    canPreviousPage,
    canNextPage,
    pageCount,
    nextPage,
    previousPage,
    // Get the state from the instance
    state: { pageIndex, pageSize, selectedRowIds },
  } = useTable(
    {
      data: products || [],
      columns: columns,
      manualPagination: true,
      initialState: {
        pageIndex: currentPage,
        pageSize: limit,
        selectedRowIds: addedProducts?.reduce((prev, { id }) => {
          prev[id] = true
          return prev
        }, {}),
      },
      pageCount: numPages,
      autoResetSelectedRows: false,
      autoResetPage: false,
      getRowId: (row) => row.id,
    },
    usePagination,
    useRowSelect,
    (hooks) => {
      hooks.visibleColumns.push((columns) => [
        {
          id: "selection",
          Cell: ({ row }) => {
            return (
              <Table.Cell className="w-[5%] pl-base">
                <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
              </Table.Cell>
            )
          },
        },
        ...columns,
      ])
    }
  )

  useEffect(() => {
    setSelectedProducts((selectedProducts) => [
      ...selectedProducts.filter(
        (sv) => Object.keys(selectedRowIds).findIndex((id) => id === sv.id) > -1
      ),
      ...(products?.filter(
        (p) =>
          selectedProducts.findIndex((sv) => sv.id === p.id) < 0 &&
          Object.keys(selectedRowIds).findIndex((id) => id === p.id) > -1
      ) || []),
    ])
  }, [selectedRowIds])

  const handleNext = () => {
    if (canNextPage) {
      setOffset((old) => old + pageSize)
      setCurrentPage((old) => old + 1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      setOffset((old) => old - pageSize)
      setCurrentPage((old) => old - 1)
      previousPage()
    }
  }

  const handleSearch = (q) => {
    setOffset(0)
    setQuery(q)
  }

  useEffect(() => {
    console.log("products", selectedProducts)
  }, [selectedProducts])

  return (
    <div className="w-full h-full flex flex-col justify-between overflow-y-auto">
      <Table
        enableSearch
        handleSearch={handleSearch}
        searchPlaceholder="Search Products"
        filteringOptions={filteringOptions}
        {...getTableProps()}
        className="h-full"
      >
        {isLoading || !products ? null : (
          <Table.Body {...getTableBodyProps()}>
            {rows.map((row) => {
              prepareRow(row)
              return (
                <Table.Row
                  color={"inherit"}
                  {...row.getRowProps()}
                  className="px-base"
                >
                  {row.cells.map((cell, index) => {
                    return cell.render("Cell", { index })
                  })}
                </Table.Row>
              )
            })}
          </Table.Body>
        )}
      </Table>
      <TablePagination
        count={count!}
        limit={limit}
        offset={offset}
        pageSize={offset + rows.length}
        title="Products"
        currentPage={pageIndex + 1}
        pageCount={pageCount}
        nextPage={handleNext}
        prevPage={handlePrev}
        hasNext={canNextPage}
        hasPrev={canPreviousPage}
      />
    </div>
  )
}
Example #21
Source File: add-product-table.tsx    From admin with MIT License 4 votes vote down vote up
AddProductsTable: React.FC<AddProductsTableProps> = ({
  existingRelations,
  onSubmit,
  onClose,
}) => {
  const PAGE_SIZE = 10
  const [query, setQuery] = useState("")
  const [offset, setOffset] = useState(0)
  const [numPages, setNumPages] = useState(0)
  const [currentPage, setCurrentPage] = useState(0)

  const [selectedProducts, setSelectedProducts] = useState<any[]>([])
  const [removedProducts, setRemovedProducts] = useState<any[]>([])

  const debouncedSearchTerm = useDebounce(query, 500)

  const { isLoading, count, products } = useAdminProducts({
    q: debouncedSearchTerm,
    limit: PAGE_SIZE,
    offset,
  })

  const columns = useCollectionProductColumns()

  const {
    rows,
    prepareRow,
    getTableBodyProps,
    getTableProps,
    canPreviousPage,
    canNextPage,
    pageCount,
    nextPage,
    previousPage,
    state: { pageIndex, pageSize, selectedRowIds },
  } = useTable(
    {
      data: products || [],
      columns: columns,
      manualPagination: true,
      initialState: {
        pageIndex: currentPage,
        pageSize: PAGE_SIZE,
        selectedRowIds: existingRelations.reduce((prev, { id }) => {
          prev[id] = true
          return prev
        }, {}),
      },
      pageCount: numPages,
      autoResetSelectedRows: false,
      autoResetPage: false,
      getRowId: (row) => row.id,
    },
    usePagination,
    useRowSelect,
    (hooks) => {
      hooks.visibleColumns.push((columns) => [
        {
          id: "selection",
          Cell: ({ row }) => {
            return (
              <Table.Cell className="w-[5%] pl-base">
                <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
              </Table.Cell>
            )
          },
        },
        ...columns,
      ])
    }
  )

  useEffect(() => {
    setSelectedProducts((selectedProducts) =>
      [
        ...selectedProducts.filter(
          (sv) =>
            Object.keys(selectedRowIds).findIndex((id) => id === sv.id) > -1
        ),
        ...(products?.filter(
          (p) =>
            selectedProducts.findIndex((sv) => sv.id === p.id) < 0 &&
            Object.keys(selectedRowIds).findIndex((id) => id === p.id) > -1
        ) || []),
      ].filter((p) => existingRelations.findIndex((ap) => ap.id === p.id) < 0)
    )

    setRemovedProducts([
      ...existingRelations.filter(
        (ap) => Object.keys(selectedRowIds).findIndex((id) => id === ap.id) < 0
      ),
    ])
  }, [selectedRowIds])

  useEffect(() => {
    const controlledPageCount = Math.ceil(count! / PAGE_SIZE)
    setNumPages(controlledPageCount)
  }, [products, count, PAGE_SIZE])

  const handleNext = () => {
    if (canNextPage) {
      setOffset((old) => old + pageSize)
      setCurrentPage((old) => old + 1)
      nextPage()
    }
  }

  const handlePrev = () => {
    if (canPreviousPage) {
      setOffset((old) => old - pageSize)
      setCurrentPage((old) => old - 1)
      previousPage()
    }
  }

  const handleSearch = (q) => {
    setOffset(0)
    setQuery(q)
  }

  const [disabled, setDisabled] = useState(true)

  useEffect(() => {
    if (selectedProducts.length > 0 || removedProducts.length > 0) {
      setDisabled(false)
      return
    }

    setDisabled(true)
  }, [selectedProducts, removedProducts])

  const handleSubmit = () => {
    onSubmit(
      selectedProducts.map((p) => p.id),
      removedProducts.map((p) => p.id)
    )
  }

  return (
    <Modal handleClose={onClose}>
      <Modal.Body>
        <Modal.Header handleClose={onClose}>
          <h3 className="inter-xlarge-semibold">Add Products</h3>
        </Modal.Header>
        <Modal.Content>
          <div className="w-full flex flex-col justify-between h-[650px]">
            <Table
              enableSearch
              handleSearch={handleSearch}
              searchPlaceholder="Search Products"
              {...getTableProps()}
              className="flex-grow"
            >
              {isLoading || !products ? (
                <div className="inter-small-regular text-grey-40 flex flex-grow justify-center items-center">
                  <Spinner size="large" variant="secondary" />
                </div>
              ) : (
                <Table.Body {...getTableBodyProps()}>
                  {rows.map((row) => {
                    prepareRow(row)
                    return (
                      <Table.Row
                        color={"inherit"}
                        {...row.getRowProps()}
                        className="px-base"
                      >
                        {row.cells.map((cell, index) => {
                          return cell.render("Cell", { index })
                        })}
                      </Table.Row>
                    )
                  })}
                </Table.Body>
              )}
            </Table>
            <TablePagination
              count={count!}
              limit={PAGE_SIZE}
              offset={offset}
              pageSize={offset + rows.length}
              title="Products"
              currentPage={pageIndex + 1}
              pageCount={pageCount}
              nextPage={handleNext}
              prevPage={handlePrev}
              hasNext={canNextPage}
              hasPrev={canPreviousPage}
            />
          </div>
        </Modal.Content>
        <Modal.Footer>
          <div className="flex items-center justify-end gap-x-xsmall w-full">
            <Button
              variant="ghost"
              size="small"
              className="w-eventButton"
              onClick={onClose}
            >
              Cancel
            </Button>
            <Button
              variant="primary"
              size="small"
              className="w-eventButton"
              onClick={handleSubmit}
              disabled={disabled}
            >
              Save
            </Button>
          </div>
        </Modal.Footer>
      </Modal.Body>
    </Modal>
  )
}
Example #22
Source File: index.tsx    From livepeer-com with MIT License 4 votes vote down vote up
Table = <T extends Record<string, unknown>>({
  columns,
  data,
  header,
  pageSize = 100,
  rowSelection,
  onRowSelectionChange,
  initialSortBy,
  filters,
  showOverflow,
}: Props<T>) => {
  const someColumnCanSort = useMemo(() => {
    // To see if we show the sort help tooltip or not
    // @ts-ignore
    return columns.some((column) => !column.disableSortBy);
  }, [columns]);

  const getRowId = useCallback((row, relativeIndex, parent) => {
    return row?.id ? row.id : relativeIndex;
  }, []);

  const {
    getTableProps,
    getTableBodyProps,
    prepareRow,
    headerGroups,
    // @ts-ignore
    page,
    // @ts-ignore
    nextPage,
    // @ts-ignore
    previousPage,
    // @ts-ignore
    canPreviousPage,
    // @ts-ignore
    canNextPage,
    // @ts-ignore
    toggleAllRowsSelected,
    // @ts-ignore
    selectedFlatRows,
    // @ts-ignore
    setFilter,
    // @ts-ignore
    state: { filters: currentFilters },
  } = useTable(
    {
      // @ts-ignore
      columns,
      data,
      getRowId,
      initialState: {
        // @ts-ignore
        pageSize,
        pageIndex: 0,
        ...(initialSortBy ? { sortBy: initialSortBy } : undefined),
      },
      manualSortBy: false,
      autoResetFilters: false,
      autoResetSortBy: false,
      autoResetPage: false,
      autoResetSelectedRows: false,
    },
    useFilters,
    useSortBy,
    usePagination,
    useRowSelect,
    (hooks) => {
      if (rowSelection) {
        const isIndividualSelection = rowSelection === "individual";
        hooks.visibleColumns.push((columns) => [
          // Let's make a column for selection
          {
            id: "selection",
            // The header can use the table's getToggleAllRowsSelectedProps method
            // to render a checkbox
            // @ts-ignore
            Header: ({ getToggleAllPageRowsSelectedProps }) => {
              const props = getToggleAllPageRowsSelectedProps();
              return isIndividualSelection ? null : (
                <Checkbox onClick={props.onChange} value={props.checked} />
              );
            },
            // The cell can use the individual row's getToggleRowSelectedProps method
            // to the render a checkbox
            Cell: ({ row }) => {
              return (
                <Checkbox
                  // @ts-ignore
                  value={row.isSelected}
                  onClick={() => {
                    isIndividualSelection && toggleAllRowsSelected(false);
                    // @ts-ignore
                    row.toggleRowSelected(!row.isSelected);
                  }}
                />
              );
            },
          },
          ...columns,
        ]);
      }
    }
  );

  useEffect(() => {
    onRowSelectionChange?.(selectedFlatRows);
  }, [selectedFlatRows, onRowSelectionChange]);

  return (
    <div>
      {header || filters ? (
        <Box
          sx={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            mb: 3,
          }}>
          <div>{header}</div>
          {filters ? (
            <Box
              sx={{
                flex: "1",
                display: "flex",
                alignItems: "center",
                justifyContent: "flex-end",
              }}>
              {filters.map((f) => {
                let filter: JSX.Element;
                switch (f.type) {
                  case "text":
                    filter = (
                      <TextFilter
                        {...f.props}
                        setFilter={setFilter}
                        currentFilters={currentFilters}
                      />
                    );
                    break;
                  case "checkbox":
                    filter = (
                      <CheckboxFilter
                        {...f.props}
                        setFilter={setFilter}
                        currentFilters={currentFilters}
                      />
                    );
                    break;
                  default:
                    return null;
                }
                return (
                  <Box
                    key={`${f.type}-${f.props.columnId}`}
                    sx={{ ":not(:last-of-type)": { mr: 3 } }}>
                    {filter}
                  </Box>
                );
              })}
            </Box>
          ) : null}
        </Box>
      ) : null}
      <Box sx={{ overflow: showOverflow ? "visible" : "hidden" }}>
        <Box sx={{ overflowX: showOverflow ? "visible" : "auto" }}>
          <Box
            as="table"
            {...getTableProps()}
            sx={{
              minWidth: "100%",
              borderCollapse: "separate",
              borderSpacing: 0,
            }}>
            <thead>
              {headerGroups.map((headerGroup) => (
                <Box
                  as="tr"
                  {...headerGroup.getHeaderGroupProps()}
                  sx={{ borderRadius: "8px" }}>
                  {headerGroup.headers.map((column, i) => {
                    const withHelpTooltip =
                      someColumnCanSort && i === headerGroup.headers.length - 1;
                    return (
                      <Box
                        as="th"
                        scope="col"
                        {...column.getHeaderProps(
                          // @ts-ignore
                          column.getSortByToggleProps()
                        )}
                        sx={{
                          textTransform: "uppercase",
                          bg: "rgba(0,0,0,.03)",
                          border: 0,
                          borderBottom: "1px solid",
                          borderTop: "1px solid",
                          borderColor: "muted",
                          fontSize: 0,
                          color: "gray",
                          px: 4,
                          py: 2,
                          fontWeight: 400,
                          position: "relative",
                          "&:first-of-type": {
                            borderLeft: "1px solid",
                            borderColor: "muted",
                            borderTopLeftRadius: 6,
                            borderBottomLeftRadius: 6,
                          },
                          "&:last-of-type": {
                            borderRight: "1px solid",
                            borderColor: "muted",
                            borderTopRightRadius: 6,
                            borderBottomRightRadius: 6,
                          },
                        }}>
                        <Box
                          sx={{
                            display: "flex",
                            alignItems: "center",
                            mr: withHelpTooltip ? 3 : 0,
                          }}>
                          <Box as="span" sx={{ whiteSpace: "nowrap" }}>
                            {column.render("Header")}
                          </Box>
                          {/*@ts-ignore */}
                          {column.canSort && (
                            <Box as="span" sx={{ ml: 2 }}>
                              {/* @ts-ignore */}
                              {column.isSorted
                                ? // @ts-ignore
                                  column.isSortedDesc
                                  ? " ⭣"
                                  : " ⭡"
                                : " ⭥"}
                            </Box>
                          )}
                        </Box>
                        {withHelpTooltip && (
                          <Box
                            sx={{
                              alignItems: "center",
                              display: "flex",
                              position: "absolute",
                              right: 3,
                              top: "50%",
                              transform: "translateY(-50%)",
                            }}>
                            <ReactTooltip
                              id={`tooltip-multiorder`}
                              className="tooltip"
                              place="top"
                              type="dark"
                              effect="solid">
                              To multi-sort (sort by two column simultaneously)
                              hold shift while clicking on second column name.
                            </ReactTooltip>
                            <Help
                              data-tip
                              data-for={`tooltip-multiorder`}
                              sx={{
                                cursor: "pointer",
                                ml: 1,
                              }}
                            />
                          </Box>
                        )}
                      </Box>
                    );
                  })}
                </Box>
              ))}
            </thead>
            <tbody {...getTableBodyProps()}>
              {page.map((row: Row<object>) => {
                prepareRow(row);
                return (
                  <tr {...row.getRowProps()}>
                    {row.cells.map((cell) => (
                      <Box
                        as="td"
                        {...cell.getCellProps()}
                        sx={{
                          px: 4,
                          py: 3,
                          border: 0,
                          borderBottom: "1px solid",
                          borderBottomColor: "muted",
                          bg: "background",
                          fontSize: 1,
                        }}>
                        {cell.render("Cell")}
                      </Box>
                    ))}
                  </tr>
                );
              })}
            </tbody>
          </Box>
        </Box>
        <Paginator
          canPreviousPage={canPreviousPage}
          canNextPage={canNextPage}
          onPreviousPage={previousPage}
          onNextPage={nextPage}
        />
      </Box>
    </div>
  );
}
Example #23
Source File: Table.tsx    From opensaas with MIT License 4 votes vote down vote up
Table: React.FC<TableProps> = <T extends object>(props: TableProps<T>) => {
  const {
    expandable,
    selection,
    pagination,
    sortBy,
    pageCount,
    data,
    selectedRowIds,
    pageSize,
    rowKey,
    loading,
    isMultiSort,
    renderExpandedComponent,
    onPageChange,
    filters: propsFilters,
    onSortChange: propsOnSortChange,
    onRowSelected: propsOnRowSelected,
    onFilterChange: propsOnFilterChange,
    columns: propsColumns,
  } = props;
  const classes = useStyles();
  const tableRef = useRef<HTMLTableElement>(null);

  const hasSortBy = props.hasOwnProperty('sortBy');
  const hasFilters = props.hasOwnProperty('filters');
  const hasPagination = props.hasOwnProperty('pagination');
  const hasOnPageChange = props.hasOwnProperty('onPageChange');
  const hasSelectedRowIds = props.hasOwnProperty('selectedRowIds');

  const onRowSelected = useCallback(
    (row: UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>, value: boolean) => {
      const id = (row.original as any)[rowKey];
      if (hasSelectedRowIds) {
        const newSelectedRows: any = { ...selectedRowIds };
        if (value) {
          newSelectedRows[id] = true;
        } else {
          delete newSelectedRows[id];
        }
        propsOnRowSelected?.(newSelectedRows);
      } else {
        row.toggleRowSelected(value);
      }
    },
    [hasSelectedRowIds, rowKey, selectedRowIds, propsOnRowSelected],
  );

  const columns = useMemo(() => {
    const columns = propsColumns.map(
      ({ sortable, Filter, Header, ...rest }) =>
        ({
          ...rest,
          disableSortBy: !sortable,
          disableFilters: !Filter,
          Filter,
          Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />,
        } as TableColumnOptions<T>),
    );

    if (expandable) {
      columns.unshift({
        id: 'expander',
        minWidth: 60,
        maxWidth: '60px' as any,
        Cell: (cell: UseTableCellProps<T>) => {
          const row = cell.row as Row<T> & UseExpandedRowProps<T>;
          return (
            <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}>
              {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
            </IconButton>
          );
        },
      });
    }
    if (selection) {
      columns.unshift({
        id: 'selection',
        minWidth: 60,
        maxWidth: '60px' as any,
        Cell: (cell: UseTableCellProps<T>) => {
          const row = cell.row as UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>;
          return (
            <Checkbox
              className={classes.checkBox}
              {...row.getToggleRowSelectedProps()}
              checked={row.isSelected}
              onChange={(e) => onRowSelected(row, e.target.checked)}
            />
          );
        },
      });
    }
    return columns as Column<T>[];
  }, [propsColumns, expandable, classes, selection, onRowSelected]);

  const tableHooks: PluginHook<T>[] = [useFilters, useSortBy];
  if (expandable) {
    tableHooks.push(useExpanded);
  }
  if (pagination) {
    tableHooks.push(usePagination);
  }
  if (selection) {
    tableHooks.push(useRowSelect);
  }
  tableHooks.push(useFlexLayout);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state,
    page,
    pageOptions,
    gotoPage,
    nextPage,
    previousPage,
    toggleAllRowsSelected,
    isAllRowsSelected,
    selectedFlatRows,
  } = useTable(
    {
      columns,
      data,
      getRowId: (row: any) => row[rowKey],
      manualSortBy: !!propsOnSortChange,
      manualFilters: !!propsOnFilterChange,
      manualPagination: !!onPageChange,
      manualRowSelectedKey: rowKey,
      pageCount: pageCount ?? 0,
      useControlledState: (state1: any) =>
        ({
          ...state1,
          sortBy: sortBy ?? state1.sortBy,
          filters: propsFilters ?? state1.filters,
          selectedRowIds: selectedRowIds ?? state1.selectedRowIds,
        } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>),
      expandSubRows: false,
      initialState: {
        pageIndex: 0,
        pageSize: pageSize ?? 0,
        selectedRowIds: selectedRowIds || {},
      },
    } as UseTableOptions<T> &
      UseFiltersOptions<T> &
      UseSortByOptions<T> &
      UseExpandedOptions<T> &
      UseRowSelectOptions<T> &
      UsePaginationOptions<T>,
    ...tableHooks,
  ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>;

  if (expandable && !renderExpandedComponent) {
    throw Error('Table: you must provide renderExpandedComponent property if the table is expandable');
  }
  if (hasSortBy && !propsOnSortChange) {
    throw Error('Table: you must provide onSortChange property if sortBy is controlled');
  }
  if (hasFilters && !propsOnFilterChange) {
    throw Error('Table: you must provide onFilterChange property if filters is controlled');
  }
  if (hasPagination && !pageSize) {
    throw Error('Table: you must provide pageSize property if pagination enabled');
  }
  if (hasOnPageChange && !pageCount) {
    throw Error('Table: you must provide pageCount property if onPageChange is controlled');
  }

  const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>;

  const onSortChange = useCallback(
    (column: TableColumnProps<T>) => {
      if (hasSortBy) {
        const sortBy = isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : [];
        if (!column.isSorted) {
          sortBy.push({ id: column.id, desc: false });
        } else if (!column.isSortedDesc) {
          sortBy.push({ id: column.id, desc: true });
        }
        propsOnSortChange?.(sortBy);
      } else {
        if (column.isSorted && column.isSortedDesc) {
          column.clearSortBy();
        } else {
          column.toggleSortBy(column.isSorted, isMultiSort ?? false);
        }
      }
    },
    [hasSortBy, isMultiSort, tableState.sortBy, propsOnSortChange],
  );

  const onFilterChange = useCallback(
    (column: TableColumnProps<T>, filterValue?: any) => {
      if (hasFilters) {
        const filters = tableState.filters.filter(({ id }) => id !== column.id);
        if (filterValue != null) {
          filters.push({ id: column.id, value: filterValue });
        }
        propsOnFilterChange?.(filters);
      } else {
        column.setFilter(filterValue);
      }
    },
    [propsOnFilterChange, hasFilters, tableState.filters],
  );

  const onToggleAllRowsSelected = useCallback(
    (value: boolean) => {
      if (hasSelectedRowIds) {
        const selectedIds = data.reduce((p, n: any) => ({ ...p, [n[rowKey]]: true }), {});
        propsOnRowSelected?.(value ? selectedIds : {});
      } else {
        toggleAllRowsSelected(value);
      }
    },
    [hasSelectedRowIds, data, rowKey, propsOnRowSelected, toggleAllRowsSelected],
  );

  useEffect(() => {
    if (!hasSortBy) propsOnSortChange?.(tableState.sortBy);
  }, [hasSortBy, propsOnSortChange, tableState.sortBy]);

  useEffect(() => {
    if (!hasFilters) propsOnFilterChange?.(tableState.filters);
  }, [hasFilters, propsOnFilterChange, tableState.filters]);

  useEffect(() => {
    tableRef.current?.querySelector('.table-tbody')?.scroll?.({ top: 0, left: 0, behavior: 'smooth' });
    onPageChange?.(tableState.pageSize, tableState.pageIndex);
  }, [onPageChange, tableState.pageSize, tableState.pageIndex]);

  useEffect(() => {
    if (!hasSelectedRowIds) propsOnRowSelected?.(tableState.selectedRowIds as any);
  }, [hasSelectedRowIds, propsOnRowSelected, tableState.selectedRowIds]);

  const onPageChangeHandler = (page: number) => {
    if (page > tableState.pageIndex) {
      nextPage();
    } else {
      previousPage();
    }
  };

  return (
    <Paper className={classes.paper}>
      <MaterialUITable className={classes.table} ref={tableRef} {...getTableProps()}>
        <TableHead
          headerGroups={headerGroups}
          onSortChange={onSortChange}
          onFilterChange={onFilterChange}
          toggleAllRowsSelected={onToggleAllRowsSelected}
          isAllRowsSelected={isAllRowsSelected}
          selectedFlatRows={selectedFlatRows}
        />
        <TableBody
          getTableBodyProps={getTableBodyProps}
          prepareRow={prepareRow}
          loading={loading}
          rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]}
          renderExpandedComponent={renderExpandedComponent}
        />
      </MaterialUITable>
      {pagination === 'pages' && (
        <TablePagination
          className={classes.footer}
          rowsPerPageOptions={[]}
          component='div'
          count={rows.length}
          rowsPerPage={tableState.pageSize}
          page={tableState.pageIndex}
          onChangePage={(e, page) => onPageChangeHandler(page)}
          ActionsComponent={(props) => (
            <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} />
          )}
        />
      )}
    </Paper>
  );
}
Example #24
Source File: Table.tsx    From frontegg-react with MIT License 4 votes vote down vote up
Table: FC<TableProps> = <T extends object>(props: TableProps<T>) => {
  const classes = useStyles();
  const tableRef = useRef<HTMLTableElement>(null);
  const firstRender = useRef<boolean>(true);
  const columns = useMemo(() => {
    const columns = props.columns.map(
      ({ sortable, Filter, Header, ...rest }) =>
        ({
          ...rest,
          disableSortBy: !sortable,
          disableFilters: !Filter,
          Filter,
          Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />,
        } as FeTableColumnOptions<T>)
    );

    if (props.expandable) {
      columns.unshift({
        id: 'fe-expander',
        minWidth: 60,
        maxWidth: '60px' as any,
        Header: <div style={{ minWidth: '1.5rem', maxWidth: '1.5rem' }} />,
        Cell: (cell: Cell<T>) => {
          const row = cell.row as Row<T> & UseExpandedRowProps<T>;
          return (
            <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}>
              {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
            </IconButton>
          );
        },
      });
    }
    if (props.selection) {
      columns.unshift({
        id: 'fe-selection',
        minWidth: 60,
        maxWidth: '60px' as any,
        Cell: (cell: Cell<T>) => {
          const row = cell.row as Row<T> & UseRowSelectRowProps<T>;
          return (
            <Checkbox
              className={classes.checkBox}
              {...row.getToggleRowSelectedProps()}
              checked={row.isSelected}
              onChange={(e) => onRowSelected(row.original, e.target.checked)}
            />
          );
        },
      });
    }
    return columns as Column<T>[];
  }, [props.columns, props.expandable]);

  const tableHooks: PluginHook<T>[] = [useFilters, useSortBy];
  if (props.expandable) {
    tableHooks.push(useExpanded);
  }
  if (props.pagination) {
    tableHooks.push(usePagination);
  }
  if (props.selection) {
    tableHooks.push(useRowSelect);
  }
  tableHooks.push(useFlexLayout);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state,

    // The page controls ;)
    page,
    // canPreviousPage,
    // canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    // setPageSize,

    // select props
    toggleAllRowsSelected,
    isAllRowsSelected,
    selectedFlatRows,
    toggleRowSelected,
  } = useTable(
    {
      columns,
      data: props.data,
      getRowId: (row: any) => row[props.rowKey],
      manualSortBy: !!props.onSortChange,
      manualFilters: !!props.onFilterChange,
      manualPagination: !!props.onPageChange,
      manualRowSelectedKey: props.rowKey,
      pageCount: !!props.onPageChange ? props.pageCount : undefined,
      autoResetPage: !props.onPageChange,
      useControlledState: (state1: any) => {
        return {
          ...state1,
          sortBy: props.sortBy ?? state1.sortBy,
          filters: props.filters ?? state1.filters,
          selectedRowIds: props.selectedRowIds ?? state1.selectedRowIds,
        } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>;
      },
      expandSubRows: false,
      initialState: {
        pageIndex: 0,
        pageSize: props.pageSize ?? 0,
        selectedRowIds: props.selectedRowIds || {},
      },
    } as UseTableOptions<T> &
      UseFiltersOptions<T> &
      UseSortByOptions<T> &
      UseExpandedOptions<T> &
      UseRowSelectOptions<T> &
      UsePaginationOptions<T>,
    ...tableHooks
  ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>;

  if (props.expandable && !props.renderExpandedComponent) {
    throw Error('FeTable: you must provide renderExpandedComponent property if the table is expandable');
  }
  if (props.hasOwnProperty('sortBy') && !props.onSortChange) {
    throw Error('FeTable: you must provide onSortChange property if sortBy is controlled');
  }
  if (props.hasOwnProperty('filters') && !props.onFilterChange) {
    throw Error('FeTable: you must provide onFilterChange property if filters is controlled');
  }
  if (props.hasOwnProperty('pagination') && !props.pageSize) {
    throw Error('FeTable: you must provide pageSize property if pagination enabled');
  }
  if (props.hasOwnProperty('onPageChange') && !props.pageCount) {
    throw Error('FeTable: you must provide pageCount property if onPageChange is controlled');
  }

  const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>;

  const onSortChange = useCallback(
    (column: FeTableColumnProps<T>) => {
      if (props.hasOwnProperty('sortBy')) {
        const sortBy = props.isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : [];
        if (!column.isSorted) {
          sortBy.push({ id: column.id, desc: false });
        } else if (!column.isSortedDesc) {
          sortBy.push({ id: column.id, desc: true });
        }
        props.onSortChange?.(sortBy);
      } else {
        if (column.isSorted && column.isSortedDesc) {
          column.clearSortBy();
        } else {
          column.toggleSortBy(column.isSorted, props.isMultiSort ?? false);
        }
      }
    },
    [props.onSortChange]
  );

  const onFilterChange = useCallback(
    (column: FeTableColumnProps<T>, filterValue?: any) => {
      if (props.hasOwnProperty('filters')) {
        const filters = tableState.filters.filter(({ id }) => id !== column.id);
        if (filterValue != null) {
          filters.push({ id: column.id, value: filterValue });
        }
        props.onFilterChange?.(filters);
      } else {
        column.setFilter(filterValue);
      }
    },
    [props.onFilterChange, tableState]
  );

  const onToggleAllRowsSelected = useCallback(
    (value: boolean) => {
      if (props.hasOwnProperty('selectedRowIds')) {
        const selectedIds = props.data.reduce((p, n: any) => ({ ...p, [n[props.rowKey]]: true }), {});
        props.onRowSelected?.(value ? selectedIds : {});
      } else {
        toggleAllRowsSelected(value);
      }
    },
    [props.onRowSelected]
  );

  const onRowSelected = useCallback(
    (row: any, value: boolean) => {
      const id = row[props.rowKey];
      if (props.hasOwnProperty('selectedRowIds')) {
        const newSelectedRows: any = { ...props.selectedRowIds };
        if (value) {
          newSelectedRows[id] = true;
        } else {
          delete newSelectedRows[id];
        }
        props.onRowSelected?.(newSelectedRows);
      } else {
        toggleRowSelected(id, value);
      }
    },
    [props.onRowSelected]
  );

  const handleOnPageChange = useCallback(() => {
    if (pagination === 'pages') {
      tableRef.current?.scroll?.({ top: 0, left: 0, behavior: 'smooth' });
    }
    props.onPageChange?.(tableState.pageSize, tableState.pageIndex);
  }, [tableState.pageIndex]);

  useEffect(() => {
    !props.hasOwnProperty('sortBy') && props.onSortChange?.(tableState.sortBy);
  }, [props.sortBy, tableState.sortBy]);

  useEffect(() => {
    !props.hasOwnProperty('filters') && props.onFilterChange?.(tableState.filters);
  }, [props.filters, tableState.filters]);

  useEffect(() => {
    firstRender.current ? (firstRender.current = false) : handleOnPageChange();
  }, [tableState.pageIndex]);

  useEffect(() => {
    !props.hasOwnProperty('selectedRowIds') && props.onRowSelected?.(tableState.selectedRowIds as any);
  }, [tableState.selectedRowIds]);

  const onPageChangeHandler = (page: number) => {
    if (page > tableState.pageIndex) {
      nextPage();
    } else {
      previousPage();
    }
  };

  const { className, loading, pagination, totalData, pageSize } = props;

  return (
    <Paper ref={tableRef} className={classes.paper}>
      <MaUTable className={classNames(classes.table, className)} {...getTableProps()}>
        <TableHead
          headerGroups={headerGroups}
          onSortChange={onSortChange}
          onFilterChange={onFilterChange}
          toggleAllRowsSelected={onToggleAllRowsSelected}
          isAllRowsSelected={isAllRowsSelected}
          selectedFlatRows={selectedFlatRows}
        />
        <TableBody
          pageSize={pageSize}
          pagination={pagination}
          getTableBodyProps={getTableBodyProps}
          prepareRow={prepareRow}
          loading={loading}
          rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]}
          renderExpandedComponent={props.renderExpandedComponent}
          onInfiniteScroll={handleOnPageChange}
        />
      </MaUTable>

      {loading && pagination === 'pages' && rows.length > 0 && <Loader center size={24} />}
      {pagination === 'pages' && (
        <TablePagination
          className={classes.footer}
          rowsPerPageOptions={[]}
          component='div'
          count={totalData || rows.length}
          rowsPerPage={tableState.pageSize}
          page={tableState.pageIndex}
          onChangePage={(e, page) => onPageChangeHandler(page)}
          ActionsComponent={(props) => (
            <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} />
          )}
        />
      )}
    </Paper>
  );
}
Example #25
Source File: index.tsx    From platform with MIT License 4 votes vote down vote up
function Table({ columns, data, searchPlaceholder = "games...", colour = "bg-teal-700" }) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    prepareRow,
    page,
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state,
    preGlobalFilteredRows,
    setGlobalFilter,
  } = useTable(
    {
      columns,
      data,
      initialState: {
        hiddenColumns: [
          "id",
          "whiteMemberId",
          "blackMemberId",
          "liChessUrl",
          "chesscomUrl",
          "eventId",
          "formArray",
          "bulletDiff",
          "blitzDiff",
          "rapidDiff",
          "isOnline",
          "standardChange",
          "rapidChange"
        ]
      }
    },
    useFilters,
    useGlobalFilter,
    useSortBy,
    usePagination
  );

  return (
    <>
      <div className="sm:gap-x-2">
        <GlobalFilter
          preGlobalFilteredRows={preGlobalFilteredRows}
          globalFilter={state.globalFilter}
          setGlobalFilter={setGlobalFilter}
          searchPlaceholder={searchPlaceholder}
        />
        {headerGroups.map((headerGroup) =>
          headerGroup.headers.map((column) =>
            column.Filter ? (
              <div className="mt-0" key={column.id}>
                {column.render("Filter")}
              </div>
            ) : null
          )
        )}
      </div>
      {/* table */}
      <div className="relative mt-4 sm:flex sm:flex-col">
        <div className="overflow-auto w-full shadow border-b border-gray-200 rounded-lg">
          <table
            {...getTableProps()}
            className="w-full table-auto divide-y divide-gray-200"
          >
            <thead className="">
              {headerGroups.map((headerGroup) => (
                <tr {...headerGroup.getHeaderGroupProps()}>
                  {headerGroup.headers.map((column) => (
                    <th
                      scope="col"
                      className={classNames(colour, "group px-2 py-3 text-center text-xs font-medium text-gray-100 uppercase")}
                      {...column.getHeaderProps(column.getSortByToggleProps())}
                    >
                      <div className=" flex items-center text-center justify-between">
                        {column.render("Header")}
                        {/* Add a sort direction indicator */}
                        <span>
                          {column.isSorted ? (
                            column.isSortedDesc ? (
                              <SortDownIcon className="w-4 h-4 text-gray-200" />
                            ) : (
                              <SortUpIcon className="w-4 h-4 text-gray-200" />
                            )
                          ) : (
                            <SortIcon className="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100" />
                          )}
                        </span>
                      </div>
                    </th>
                  ))}
                </tr>
              ))}
            </thead>
            <tbody
              {...getTableBodyProps()}
              className="bg-white divide-y divide-gray-200"
            >
              {page.map((row, i) => {
                // new
                prepareRow(row);
                return (
                  <tr {...row.getRowProps()}>
                    {row.cells.map((cell) => {
                      return (
                        <td
                          {...cell.getCellProps()}
                          className="py-4 px-2 whitespace-nowrap"
                          role="cell"
                        >
                          {cell.column.Cell.name === "defaultRenderer" ? (
                            <div className="text-sm text-gray-500">
                              {cell.render("Cell")}
                            </div>
                          ) : (
                            cell.render("Cell")
                          )}
                        </td>
                      );
                    })}
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
      {/* Pagination */}
      <div className="py-3 flex items-center justify-between">
        <div className="flex-1 flex items-center justify-between">
          <div className="flex gap-x-2 items-baseline">
            <span className="text-xs text-gray-700">
              Page <span className="font-medium">{state.pageIndex + 1}</span> of{" "}
              <span className="font-medium">{pageOptions.length}</span>
            </span>
            <label>
              <span className="sr-only">Items Per Page</span>
              <select
                className="mt-1 block w-full text-xs rounded-md border-gray-300 shadow-sm focus:border-teal-300 focus:ring focus:ring-teal-500 focus:ring-opacity-50"
                value={state.pageSize}
                onChange={(e) => {
                  setPageSize(Number(e.target.value));
                }}
              >
                {[5, 10, 20].map((pageSize) => (
                  <option
                    className="hover:bg-teal-200"
                    key={pageSize}
                    value={pageSize}
                  >
                    Show {pageSize}
                  </option>
                ))}
              </select>
            </label>
          </div>
          <div>
            <nav
              className="relative mt-1 sm:mt-0 z-0 inline-flex rounded-md shadow-sm -space-x-px"
              aria-label="Pagination"
            >
              <PageButton
                className="rounded-l-md -mr-1 hidden sm:block"
                onClick={() => gotoPage(0)}
                disabled={!canPreviousPage}
              >
                <span className="sr-only">First</span>
                <ChevronDoubleLeftIcon
                  className="h-5 w-5 text-gray-400"
                  aria-hidden="true"
                />
              </PageButton>
              <PageButton
                className="rounded-l-md sm:rounded-none"
                onClick={() => previousPage()}
                disabled={!canPreviousPage}
              >
                <span className="sr-only">Previous</span>
                <ChevronLeftIcon
                  className="h-5 w-5 text-gray-400"
                  aria-hidden="true"
                />
              </PageButton>
              <PageButton
                className="rounded-r-md sm:rounded-none"
                onClick={() => nextPage()}
                disabled={!canNextPage}
              >
                <span className="sr-only">Next</span>
                <ChevronRightIcon
                  className="h-5 w-5 text-gray-400"
                  aria-hidden="true"
                />
              </PageButton>
              <PageButton
                className="rounded-r-md hidden sm:block"
                onClick={() => gotoPage(pageCount - 1)}
                disabled={!canNextPage}
              >
                <span className="sr-only">Last</span>
                <ChevronDoubleRightIcon
                  className="h-5 w-5 text-gray-400"
                  aria-hidden="true"
                />
              </PageButton>
            </nav>
          </div>
        </div>
      </div>
    </>
  );
}
Example #26
Source File: index.tsx    From ke with MIT License 4 votes vote down vote up
Table = ({
  resourceName,
  listFilters,
  listFilterTemplates,
  columns,
  data,
  pageCount: controlledPageCount,
  setBackendPage,
  user,
  analytics,
  filterable = false,
  provider,
}: TableProps): JSX.Element => {
  const {
    getTableProps,
    headerGroups,
    prepareRow,
    page,
    canPreviousPage,
    canNextPage,
    pageOptions,
    gotoPage,
    nextPage,
    previousPage,
    pageCount,
    state: { pageIndex },
  } = useTable(
    {
      columns,
      data,
      manualPagination: true,
      initialState: { pageIndex: 0 },
      pageCount: controlledPageCount,
      autoResetPage: false,
      stateReducer: (newState: TableState, action: ActionType) => {
        if (action.type === 'gotoPage' && setBackendPage) {
          const newPageIndex = newState.pageIndex
          setBackendPage(newPageIndex + 1)
        }
        return newState
      },
    },
    useFilters,
    usePagination
  )

  return (
    <Flex flexDirection="row" width="100%" flex={1} bg="gray.50" p={4}>
      <Flex
        flexDirection="column"
        flex={1}
        maxWidth="100%"
        bg="white"
        width="auto"
        rounded="md"
        borderWidth="1px"
        onClick={() => false}
      >
        {filterable && listFilters && (
          <FilterBlock
            listFilters={listFilters}
            listFilterTemplates={listFilterTemplates}
            user={user}
            analytics={analytics}
            resourceName={resourceName}
            provider={provider}
            gotoPage={gotoPage}
          />
        )}

        <StyledTable {...getTableProps()}>
          <TableHead>{mountHeader(headerGroups)}</TableHead>
          <Flex flexDirection="column">{mountRows(page, prepareRow)}</Flex>
        </StyledTable>

        <Bottom
          analytics={analytics}
          resourceName={resourceName}
          pageIndex={pageIndex}
          canPreviousPage={canPreviousPage}
          canNextPage={canNextPage}
          pageOptions={pageOptions}
          pageCount={pageCount}
          gotoPage={gotoPage}
          nextPage={nextPage}
          previousPage={previousPage}
        />
      </Flex>
    </Flex>
  )
}
Example #27
Source File: ViewAllTable.tsx    From devex with GNU General Public License v3.0 4 votes vote down vote up
ViewAllTable: React.FC<IViewAllTableParams<DsBlockObj | TxBlockObj | TransactionDetails>> =
  ({ columns, data, isLoading, fetchData, pageCount: controlledPageCount }) => {

    const { getTableProps,
      getTableBodyProps,
      headerGroups,
      prepareRow,
      page,
      canPreviousPage,
      canNextPage,
      pageCount,
      gotoPage,
      nextPage,
      previousPage,
      // Get the state from the instance
      state: { pageIndex } } = useTable<DsBlockObj | TxBlockObj | TransactionDetails>({
        columns,
        data,
        initialState: { pageIndex: 0 },
        manualPagination: true,
        pageCount: controlledPageCount,
      }, usePagination)

    const fetchDataDebounce = useAsyncDebounce(fetchData, 300)

    useEffect(() => {
      fetchDataDebounce({ pageIndex })
      // fetchDataDebounce changes when fetchData function changes
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [pageIndex, fetchData])

    const generatePagination = useCallback((currentPage: number, pageCount: number, delta = 2) => {
      const separate = (a: number, b: number, isLower: boolean) => {
        const temp = b - a
        if (temp === 0)
          return [a]
        else if (temp === 1)
          return [a, b]
        else if (temp === 2)
          return [a, a + 1, b]
        else
          return [a, isLower ? -1 : -2, b]
      }

      return Array(delta * 2 + 1)
        .fill(0)
        .map((_, index) => currentPage - delta + index)
        .filter(page => 0 < page && page <= pageCount)
        .flatMap((page, index, { length }) => {
          if (!index) {
            return separate(1, page, true)
          }
          if (index === length - 1) {
            return separate(page, pageCount, false)
          }
          return [page]
        })
    }, [])

    return (
      <>
        <BRow>
          <BCol className='align-self-center pl-3'>
            {data.length === 0
              ? null
              : <span className='subtext'>Items Per Page: <strong>10</strong></span>}
          </BCol>
          <BCol>
            <Pagination className='justify-content-end'>
              <Pagination.Prev onClick={() => previousPage()} disabled={!canPreviousPage} />
              {generatePagination(pageIndex + 1, pageCount).map((page) => {
                if (page === -1)
                  return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex - 5)} />
                else if (page === -2)
                  return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex + 5)} />
                else if (page === pageIndex + 1)
                  return <Pagination.Item key={page} active>{page}</Pagination.Item>
                else
                  return <Pagination.Item key={page} onClick={() => gotoPage(Number(page) - 1)}>{page}</Pagination.Item>
              })}
              <Pagination.Next onClick={() => nextPage()} disabled={!canNextPage} />
            </Pagination>
          </BCol>
        </BRow>
        <div className='viewall-table table'>
          {isLoading ? <div className='center-spinner mt-4'><Spinner animation="border" /></div> : null}
          <table {...getTableProps()}>
            <thead>
              {headerGroups.map((headerGroup: HeaderGroup<DsBlockObj | TxBlockObj | TransactionDetails>) => (
                <tr {...headerGroup.getHeaderGroupProps()} key={headerGroup.getHeaderGroupProps().key} >
                  {headerGroup.headers.map((column) => (
                    <th {...column.getHeaderProps()} key={column.getHeaderProps().key} id={column.id}>
                      {column.render('Header')}
                    </th>
                  ))}
                </tr>
              ))}
            </thead>
            <tbody style={isLoading ? { opacity: '0.5' } : {}}{...getTableBodyProps()}>
              {page.map((row: Row<DsBlockObj | TxBlockObj | TransactionDetails>) => {
                prepareRow(row)
                return (
                  <tr {...row.getRowProps()} key={row.getRowProps().key}>
                    {row.cells.map((cell: Cell<DsBlockObj | TxBlockObj | TransactionDetails>) => {
                      return (
                        <td {...cell.getCellProps()}
                          key={cell.getCellProps().key}>
                          {cell.render('Cell')}
                        </td>
                      )
                    })}
                  </tr>
                )
              })}
            </tbody>
          </table>
        </div>
      </>
    )
  }
Example #28
Source File: MinerTable.tsx    From devex with GNU General Public License v3.0 4 votes vote down vote up
MinerTable: React.FC<IMinerTableParams> = ({ addresses }) => {

  const generatePagination = useCallback((currentPage: number, pageCount: number, delta = 1) => {
    const separate = (a: number, b: number, isLower: boolean) => {
      const temp = b - a
      if (temp === 0)
        return [a]
      else if (temp === 1)
        return [a, b]
      else if (temp === 2)
        return [a, a + 1, b]
      else
        return [a, isLower ? -1 : -2, b]
    }

    return Array(delta * 2 + 1)
      .fill(0)
      .map((_, index) => currentPage - delta + index)
      .filter(page => 0 < page && page <= pageCount)
      .flatMap((page, index, { length }) => {
        if (!index) {
          return separate(1, page, true)
        }
        if (index === length - 1) {
          return separate(page, pageCount, false)
        }
        return [page]
      })
  }, [])

  const columns = useMemo(
    () => [{
      id: 'address-col',
      Header: 'Addresses',
      accessor: 'address',
      // eslint-disable-next-line react/display-name
      Cell: (props: Cell<IMinerObj>) =>
        (<>
          [{props.row.index}]
          {' '}
          <QueryPreservingLink to={`/address/${pubKeyToZilAddr(props.value)}`}>{pubKeyToZilAddr(props.value)}</QueryPreservingLink>
        </>)
    }], []
  ) as Array<Column<IMinerObj>>

  const data = useMemo(() => (addresses.map((x) => ({ address: x })) as IMinerObj[]), [addresses])

  const {
    getTableProps,
    getTableBodyProps,
    prepareRow,
    page,
    canPreviousPage,
    canNextPage,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    state: { pageIndex },
  } = useTable<IMinerObj>({
    columns,
    data,
    initialState: { pageIndex: 0 },
  }, usePagination)

  return (
    <>
      <div className='py-3'>
        <table {...getTableProps()}>
          <tbody {...getTableBodyProps()}>
            {page.map((row: Row<IMinerObj>) => {
              prepareRow(row)
              return (
                <tr {...row.getRowProps()} key={row.getRowProps().key}>
                  {row.cells.map((cell: Cell<IMinerObj>) => {
                    return (
                      <td {...cell.getCellProps()} key={cell.getCellProps().key}>
                        {cell.render('Cell')}
                      </td>
                    )
                  })}
                </tr>
              )
            })}
          </tbody>
        </table>
      </div>
      <div className='mx-auto'>
        {data.length !== 0 &&
          <Pagination className='viewall-pagination'>
            <Pagination.Prev onClick={() => previousPage()} disabled={!canPreviousPage} />
            {generatePagination(pageIndex + 1, pageCount).map((page) => {
              if (page === -1)
                return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex - 5)} />
              else if (page === -2)
                return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex + 5)} />
              else if (page === pageIndex + 1)
                return <Pagination.Item key={page} active>{page}</Pagination.Item>
              else
                return <Pagination.Item key={page} onClick={() => gotoPage(Number(page) - 1)}>{page}</Pagination.Item>
            })}
            <Pagination.Next onClick={() => nextPage()} disabled={!canNextPage} />
          </Pagination>
        }
      </div>
    </>
  )
}