import React, { useEffect, useState } from 'react'; import { ArrowRightIcon, ArrowLeftIcon, ChevronRightIcon, ChevronLeftIcon } from '@chakra-ui/icons'; import { Table, Tbody, Td, Th, Thead, Tooltip, Tr, Flex, IconButton, Text, Select, NumberInput, NumberInputField, NumberInputStepper, NumberIncrementStepper, NumberDecrementStepper, useColorModeValue, Box, Center, Spinner, Heading, useBreakpoint, } from '@chakra-ui/react'; import { useTranslation } from 'react-i18next'; import { useTable, usePagination, useSortBy, Row, UsePaginationInstanceProps, UseSortByInstanceProps, UsePaginationState, TableInstance, } from 'react-table'; import { v4 as uuid } from 'uuid'; import SortIcon from './SortIcon'; import { LoadingOverlay } from 'components/LoadingOverlay'; import { Column, PageInfo } from 'models/Table'; const defaultProps = { sortBy: [], }; export type DataTableProps = { columns: Column[]; data: TValue[]; count?: number; setPageInfo?: React.Dispatch>; isLoading?: boolean; onRowClick?: (row: TValue) => void; isRowClickable?: (row: TValue) => boolean; obj?: string; sortBy?: { id: string; desc: boolean }[]; hiddenColumns?: string[]; hideEmptyListText?: boolean; hideControls?: boolean; minHeight?: string | number; fullScreen?: boolean; isManual?: boolean; saveSettingsId?: string; showAllRows?: boolean; }; type TableInstanceWithHooks = TableInstance & UsePaginationInstanceProps & UseSortByInstanceProps & { state: UsePaginationState; }; const _DataTable = ({ columns, data, isLoading, obj, minHeight, fullScreen, sortBy, hiddenColumns, hideControls, hideEmptyListText, count, setPageInfo, isManual, saveSettingsId, showAllRows, onRowClick, isRowClickable, }: DataTableProps) => { const { t } = useTranslation(); const breakpoint = useBreakpoint(); const textColor = useColorModeValue('gray.700', 'white'); const hoveredRowBg = useColorModeValue('gray.100', 'gray.600'); const getPageSize = () => { try { if (showAllRows) return 1000000; const saved = saveSettingsId ? localStorage.getItem(saveSettingsId) : undefined; if (saved) return Number.parseInt(saved, 10); return 10; } catch { return 10; } }; const getPageIndex = () => { try { if (saveSettingsId) { const saved = localStorage.getItem(`${saveSettingsId}.page`); if (saved) return Number.parseInt(saved, 10); } return 0; } catch { return 0; } }; const [queryPageSize, setQueryPageSize] = useState(getPageSize()); const { getTableProps, getTableBodyProps, headerGroups, prepareRow, page, canPreviousPage, canNextPage, pageOptions, pageCount, gotoPage, nextPage, previousPage, setPageSize, setHiddenColumns, state: { pageIndex, pageSize }, } = useTable( { // @ts-ignore columns, data, // @ts-ignore initialState: { sortBy, pagination: !hideControls, pageSize: queryPageSize }, manualPagination: isManual, pageCount: isManual && count !== undefined ? Math.ceil(count / queryPageSize) : Math.ceil(data?.length ?? 0 / queryPageSize), }, useSortBy, usePagination, ) as TableInstanceWithHooks; const handleGoToPage = (newPage: number) => { if (saveSettingsId) localStorage.setItem(`${saveSettingsId}.page`, String(newPage)); gotoPage(newPage); }; const handleNextPage = () => { nextPage(); if (saveSettingsId) localStorage.setItem(`${saveSettingsId}.page`, String(pageIndex + 1)); }; const handlePreviousPage = () => { previousPage(); if (saveSettingsId) localStorage.setItem(`${saveSettingsId}.page`, String(pageIndex - 1)); }; useEffect(() => { if (setPageInfo && pageIndex !== undefined) setPageInfo({ index: pageIndex, limit: queryPageSize }); }, [queryPageSize, pageIndex]); useEffect(() => { // @ts-ignore if (saveSettingsId) localStorage.setItem(saveSettingsId, pageSize); setQueryPageSize(pageSize); }, [pageSize]); useEffect(() => { if (isManual && count !== undefined) { gotoPage(getPageIndex()); } }, [count]); useEffect(() => { if (hiddenColumns) setHiddenColumns(hiddenColumns); }, [hiddenColumns]); // If this is a manual DataTable, with a page index that is higher than 0 and higher than the max possible page, we send to index 0 useEffect(() => { if ( isManual && setPageInfo && data && isManual && pageIndex > 0 && count !== undefined && Math.ceil(count / queryPageSize) - 1 < pageIndex ) { gotoPage(0); setPageInfo({ index: 0, limit: queryPageSize }); } }, [count, queryPageSize, page, data]); const computedMinHeight = () => { if (fullScreen) return { base: 'calc(100vh - 360px)', md: 'calc(100vh - 288px)' }; return minHeight; }; if (isLoading && data.length === 0) { return (
); } // Render the UI for your table return ( <> { // @ts-ignore headerGroups.map((group) => ( { // @ts-ignore group.headers.map((column) => ( )) } )) } {data.length > 0 && ( {page.map((row: Row) => { prepareRow(row); const rowIsClickable = isRowClickable ? isRowClickable(row.original) : true; const onClick = rowIsClickable && onRowClick ? () => onRowClick(row.original) : undefined; return ( { // @ts-ignore row.cells.map((cell) => ( )) } ); })} )}
{column.render('Header')}
{ e.stopPropagation(); } : undefined } cursor={ // @ts-ignore !cell.column.stopPropagation && cell.column.id !== 'actions' && onRowClick ? 'pointer' : undefined } > {cell.render('Cell')}
{!isLoading && data.length === 0 && !hideEmptyListText && (
{obj ? ( {t('common.no_obj_found', { obj })} ) : ( {t('common.empty_list')} )}
)}
{!hideControls && ( handleGoToPage(0)} isDisabled={!canPreviousPage} icon={} mr={4} /> } /> {breakpoint !== 'base' && ( <> {t('table.page')}{' '} {pageIndex + 1} {' '} {t('common.of')}{' '} {pageOptions.length} {t('table.go_to_page')}{' '} { const newPage = numberValue ? numberValue - 1 : 0; handleGoToPage(newPage); }} defaultValue={pageIndex + 1} > )} } /> handleGoToPage(pageCount - 1)} isDisabled={!canNextPage} icon={} ml={4} /> )} ); }; _DataTable.defaultProps = defaultProps; export const DataTable = React.memo(_DataTable) as unknown as typeof _DataTable;