'use client'; import { ReactNode, useCallback, useEffect, useState } from 'react'; import { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, TableOptions, useReactTable, ColumnDef, FilterFn, SortingState, OnChangeFn, Row, } from '@tanstack/react-table'; import { rankItem } from '@tanstack/match-sorter-utils'; import { Icon } from '@iconify/react'; import Pagination from '@/components/Pagination'; import { cn } from '@/lib/helper'; interface TableClassNames { containerClassName?: string; tableWrapperClassName?: string; tableClassName?: string; tableHeaderClassName?: string; headerRowClassName?: string; headerColumnClassName?: string; tableBodyClassName?: string; bodyRowClassName?: string; bodyColumnClassName?: string; paginationClassName?: string; } export interface TableProps { data: TData[]; columns: ColumnDef[]; pageSize?: number; totalItems?: number; page?: number; onPageChange?: (page: number) => void; isLoading?: boolean; fuzzySearchValue?: string | null; onFuzzySearchValueChange?: (value: string) => void; className?: TableClassNames; emptyContent?: ReactNode; sorting?: SortingState; setSorting?: OnChangeFn; manualSorting?: boolean; rowSelection?: Record; setRowSelection?: OnChangeFn>; enableRowSelection?: boolean | ((row: Row) => boolean); } const DUMMY_SKELETON_DATA = [{}, {}, {}, {}, {}]; const emptyContentDefaultValue = (
Tidak ada data yang dapat ditampilkan...
); const Table = ({ data = [], columns = [], pageSize = 10, totalItems, page, onPageChange, isLoading = false, fuzzySearchValue, onFuzzySearchValueChange, className = { containerClassName: '', tableWrapperClassName: '', tableClassName: '', tableHeaderClassName: '', headerRowClassName: '', headerColumnClassName: '', tableBodyClassName: '', bodyRowClassName: '', bodyColumnClassName: '', paginationClassName: '', }, emptyContent = emptyContentDefaultValue, sorting, setSorting, manualSorting = false, rowSelection, setRowSelection, enableRowSelection, }: TableProps) => { const isServerSideTable = totalItems !== undefined && page !== undefined && onPageChange !== undefined; const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: pageSize, }); const fuzzyFilter: FilterFn = useCallback( (row, columnId, value, addMeta) => { const itemRank = rankItem(row.getValue(columnId), value); addMeta({ itemRank }); return itemRank.passed; }, [] ); const tableOptions: TableOptions = { columns, data: isLoading ? (DUMMY_SKELETON_DATA as TData[]) : data, // Type assertion getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), onPaginationChange: setPagination, manualSorting, state: { pagination, globalFilter: fuzzySearchValue, }, filterFns: { fuzzy: fuzzyFilter, }, globalFilterFn: fuzzyFilter, }; if (fuzzySearchValue !== null) { tableOptions.onGlobalFilterChange = onFuzzySearchValueChange; tableOptions.getFilteredRowModel = getFilteredRowModel(); } if (sorting && setSorting) { tableOptions.onSortingChange = setSorting; tableOptions.state = { ...tableOptions.state, sorting, }; } if (rowSelection && setRowSelection) { tableOptions.onRowSelectionChange = setRowSelection; tableOptions.state = { ...tableOptions.state, rowSelection, }; tableOptions.getRowId = (row) => (row as { id: string }).id; } if (enableRowSelection !== undefined) { tableOptions.enableRowSelection = enableRowSelection; } const table = useReactTable(tableOptions); const { setPageSize } = table; const prevPageClickHandler = () => { table.previousPage(); if (isServerSideTable) { onPageChange(page - 1); } }; const nextPageClickHandler = () => { table.nextPage(); if (isServerSideTable) { onPageChange(page + 1); } }; const pageChangeHandler = (pageNumber: number) => { const currentPage = pageNumber - 1; table.setPageIndex(pageNumber ? currentPage : 0); if (isServerSideTable) { onPageChange(pageNumber); } }; useEffect(() => { setPageSize(pageSize); }, [pageSize, setPageSize]); return (
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( ))} ))} {table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( ))} ))}
{flexRender( header.column.columnDef.header, header.getContext() )} {header.column.getCanSort() && (
)}
{!isLoading && flexRender(cell.column.columnDef.cell, cell.getContext())} {isLoading &&
}
{(data.length === 0 || table.getRowModel().rows.length === 0) && !isLoading && emptyContent} {data.length > 0 && table.getRowModel().rows.length > 0 && !isLoading && (
)}
); }; export default Table;