import { PaginationState, SortingState, useReactTable, getCoreRowModel, getPaginationRowModel, getSortedRowModel, getFilteredRowModel, flexRender, ColumnDef, Table, RowData, TableOptions, } from '@tanstack/react-table'; import { Pagination } from '../../molecules'; import React from 'react'; import { cn } from '@imphnen-frontend-service/utils'; interface DataTableProps { table?: Table; data?: T[]; columns?: ColumnDef[]; pageSize?: number; className?: string; // server-side pagination props manualPagination?: boolean; pageCount?: number; currentPage?: number; onPageChange?: (page: number) => void; } export const DataTable = ({ table, data = [], columns = [], pageSize = 9, className, manualPagination = false, pageCount, currentPage = 1, onPageChange, }: DataTableProps) => { const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize, }); const [sorting, setSorting] = React.useState([]); // Update pagination state when pageSize prop changes React.useEffect(() => { setPagination((prev) => ({ ...prev, pageSize, })); }, [pageSize]); // Reset pagination when data changes to prevent out-of-bounds errors React.useEffect(() => { if (data.length > 0) { setPagination((prev) => ({ ...prev, pageIndex: 0, // Reset to first page when data changes })); } }, [data.length]); // Memoize data and columns to prevent unnecessary re-renders const memoizedData = React.useMemo(() => data, [data]); const memoizedColumns = React.useMemo(() => columns, [columns]); // Memoize table configuration to prevent recreation on every render const tableConfig = React.useMemo(() => { const config: TableOptions = { data: memoizedData, columns: memoizedColumns, state: { pagination, sorting, }, onPaginationChange: setPagination, onSortingChange: setSorting, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), // server-side pagination config manualPagination, pageCount: manualPagination ? pageCount : undefined, }; return config; }, [ memoizedData, memoizedColumns, pagination, sorting, manualPagination, pageCount, ]); // Prefer external table instance if provided; otherwise create an internal one const internalTable = useReactTable(tableConfig); const t = table ?? internalTable; // Handle empty data state const isEmpty = t.getRowModel().rows.length === 0; return (
{t.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( ))} ))} {isEmpty ? ( ) : ( t.getRowModel().rows.map((row, rowIndex) => ( {row.getVisibleCells().map((cell) => ( ))} )) )}
{header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} {header.column.getCanSort() && ( {header.column.getIsSorted() === 'asc' && '▲'} {header.column.getIsSorted() === 'desc' && '▼'} {!header.column.getIsSorted() && } )}
No data available
{flexRender( cell.column.columnDef.cell, cell.getContext() )}
{manualPagination && onPageChange && pageCount ? ( // Server-side pagination controls with numbered pages
{pageCount <= 8 ? ( // Show all pages if 8 or fewer Array.from({ length: pageCount }, (_, index) => ( )) ) : ( // Show ellipsis for many pages <> {currentPage > 3 && ...} {Array.from( { length: 5 }, (_, index) => currentPage - 2 + index ) .filter((page) => page > 1 && page < pageCount) .map((page) => ( ))} {currentPage < pageCount - 2 && ...} )}
) : ( // Client-side pagination (default) )}
); }; export default DataTable;