import { ArrowDownTrayIcon, Bars3BottomRightIcon, ChevronLeftIcon, ChevronRightIcon, FingerPrintIcon, PencilSquareIcon, PlusCircleIcon, TrashIcon, } from '@heroicons/react/24/outline'; import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import SimpleInput from '../input/SimpleInput'; export type Column = { header: string; accessor: string; sortable?: boolean; filterable?: boolean; render?: (data: any) => JSX.Element; }; type RowAction = { label: string; onClick: (item: any) => void; }; type TableProps = { columns: Column[]; data: any[]; keyExtractor: (item: any) => string | number; sortable?: boolean; onSort?: (column: string, direction: 'asc' | 'desc') => void; onFilter?: (value: string, accessor: string) => void; filters?: Record; rowSelection?: { selectedRowKeys: (string | number)[]; onSelectRow: (selectedRowKeys: (string | number)[]) => void; }; rowActions?: RowAction[]; emptyState?: React.ReactNode; children?: React.ReactNode; }; const mapActionLabelToIcon = (label: string) => { switch (label) { case 'Add': return ; case 'Edit': return ; case 'Delete': return ; case 'Download': return ; case 'FindAudit': return ; default: return label; } }; const UITable: React.FC = ({ columns, data, keyExtractor, onSort, onFilter, filters, rowActions, emptyState, children, }) => { const { t } = useTranslation(); /** * Sorting */ const [sortField, setSortField] = useState(''); const [order, setOrder] = useState<'asc' | 'desc'>('asc'); const handleSortingChange = (accessor: string) => { if (onSort) { const sortOrder = accessor === sortField && order === 'asc' ? 'desc' : 'asc'; setSortField(accessor); setOrder(sortOrder); onSort(accessor, sortOrder); } }; /** * Pagination */ const [currentPageNumber, setCurrentPageNumber] = useState(1); const [dataToDisplay, setDataToDisplay] = useState(data); const [totalValuesPerPage, setTotalValuesPerPage] = useState(25); const goOnPrevPage = () => { if (currentPageNumber === 1 || totalValuesPerPage === 0) { return; } setCurrentPageNumber(prev => prev - 1); }; const goOnNextPage = () => { if ( currentPageNumber === Math.ceil(data.length / totalValuesPerPage) || totalValuesPerPage === 0 ) { return; } setCurrentPageNumber(prev => prev + 1); }; /** * Update displayed data */ useEffect(() => { if (totalValuesPerPage === 0) { setDataToDisplay(data); setCurrentPageNumber(1); } else { const start = (currentPageNumber - 1) * totalValuesPerPage; const end = currentPageNumber * totalValuesPerPage; setDataToDisplay(data.slice(start, end)); } }, [currentPageNumber, data, totalValuesPerPage]); return (
{children ? (
{children}

) : null}
{columns.map(column => ( ))} {rowActions ? ( {dataToDisplay.length === 0 && emptyState ? ( ) : ( dataToDisplay.map(item => ( {columns.map(column => ( ))} {rowActions ? ( ) : null} )) )}
{column.header} {column.sortable ? (
) : null}
{column.filterable && onFilter ? ( { onFilter(column.accessor, value); }} placeholder={t('search')} type="text" value={(filters && filters[column.accessor]) ?? ''} /> ) : null}
) : null}
{emptyState}
{column.render ? column.render(item[column.accessor]) : (item[column.accessor] ?? '-')} {rowActions.map(action => ( ))}
{data.length > 0 ? (
{currentPageNumber} /{' '} {totalValuesPerPage !== 0 ? Math.ceil(data.length / totalValuesPerPage) : 1}
) : null}
); }; export default UITable;