import { useTable, useFilters, useGlobalFilter, useSortBy, usePagination, Column, Row, TableInstance, TableState, } from 'react-table'; import { ReactNode, useEffect } from 'react'; import { useRowSelectColumn } from '@lineup-lite/hooks'; import clsx from 'clsx'; import { PaginationControls } from '@@/PaginationControls'; import { IconProps } from '@@/Icon'; import { Table } from './Table'; import { multiple } from './filter-types'; import { SearchBar, useSearchBarState } from './SearchBar'; import { SelectedRowsCount } from './SelectedRowsCount'; import { TableSettingsProvider } from './useZustandTableSettings'; import { useRowSelect } from './useRowSelect'; import { PaginationTableSettings, SortableTableSettings } from './types'; interface DefaultTableSettings extends SortableTableSettings, PaginationTableSettings {} interface TitleOptionsVisible { title: string; icon?: IconProps['icon']; featherIcon?: IconProps['featherIcon']; hide?: never; } type TitleOptions = TitleOptionsVisible | { hide: true }; interface Props< D extends Record, TSettings extends DefaultTableSettings > { dataset: D[]; storageKey: string; columns: readonly Column[]; renderTableSettings?(instance: TableInstance): ReactNode; renderTableActions?(selectedRows: D[]): ReactNode; settingsStore: TSettings; disableSelect?: boolean; getRowId?(row: D): string; isRowSelectable?(row: Row): boolean; emptyContentLabel?: string; titleOptions: TitleOptions; initialTableState?: Partial>; isLoading?: boolean; totalCount?: number; description?: JSX.Element; initialActiveItem?: string; } export function Datatable< D extends Record, TSettings extends DefaultTableSettings >({ columns, dataset, storageKey, renderTableSettings, renderTableActions, settingsStore, disableSelect, getRowId = defaultGetRowId, isRowSelectable = () => true, titleOptions, emptyContentLabel, initialTableState = {}, isLoading, totalCount = dataset.length, description, initialActiveItem, }: Props) { const [searchBarValue, setSearchBarValue] = useSearchBarState(storageKey); const tableInstance = useTable( { defaultCanFilter: false, columns, data: dataset, filterTypes: { multiple }, initialState: { pageSize: settingsStore.pageSize || 10, sortBy: [settingsStore.sortBy], globalFilter: searchBarValue, ...initialTableState, }, isRowSelectable, autoResetSelectedRows: false, getRowId, stateReducer: (newState, action) => { switch (action.type) { case 'setGlobalFilter': setSearchBarValue(action.filterValue); break; case 'toggleSortBy': settingsStore.setSortBy(action.columnId, action.desc); break; case 'setPageSize': settingsStore.setPageSize(action.pageSize); break; default: break; } return newState; }, }, useFilters, useGlobalFilter, useSortBy, usePagination, useRowSelect, !disableSelect ? useRowSelectColumn : emptyPlugin ); const { rows, selectedFlatRows, getTableProps, getTableBodyProps, headerGroups, page, prepareRow, gotoPage, setPageSize, setGlobalFilter, state: { pageIndex, pageSize }, } = tableInstance; useEffect(() => { if (initialActiveItem && pageSize !== rows.length) { const paginatedData = [...Array(Math.ceil(rows.length / pageSize))].map( (_, i) => rows.slice(pageSize * i, pageSize + pageSize * i) ); const itemPage = paginatedData.findIndex((sub) => sub.some((row) => row.id === initialActiveItem) ); gotoPage(itemPage); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [initialActiveItem]); const tableProps = getTableProps(); const tbodyProps = getTableBodyProps(); const selectedItems = selectedFlatRows.map((row) => row.original); return (
{isTitleVisible(titleOptions) && ( {renderTableActions && ( {renderTableActions(selectedItems)} )} {!!renderTableSettings && renderTableSettings(tableInstance)} )} {headerGroups.map((headerGroup) => { const { key, className, role, style } = headerGroup.getHeaderGroupProps(); return ( key={key} className={className} role={role} style={style} headers={headerGroup.headers} /> ); })} rows={page} isLoading={isLoading} prepareRow={prepareRow} emptyContent={emptyContentLabel} renderRow={(row, { key, className, role, style }) => ( cells={row.cells} key={key} className={clsx( className, initialActiveItem && initialActiveItem === row.id && 'active' )} role={role} style={style} /> )} />
gotoPage(p - 1)} totalCount={totalCount} onPageLimitChange={setPageSize} />
); } function isTitleVisible( titleSettings: TitleOptions ): titleSettings is TitleOptionsVisible { return !titleSettings.hide; } function defaultGetRowId>(row: D): string { if (row.id && (typeof row.id === 'string' || typeof row.id === 'number')) { return row.id.toString(); } if (row.Id && (typeof row.Id === 'string' || typeof row.Id === 'number')) { return row.Id.toString(); } if (row.ID && (typeof row.ID === 'string' || typeof row.ID === 'number')) { return row.ID.toString(); } return ''; } function emptyPlugin() {} emptyPlugin.pluginName = 'emptyPlugin';