'use client'; import { DataTablePagination } from '@/components/data-table/data-table-pagination.js'; import { DataTableViewOptions } from '@/components/data-table/data-table-view-options.js'; import { Input } from '@/components/ui/input.js'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table.js'; import { ColumnDef, ColumnFilter, ColumnFiltersState, flexRender, getCoreRowModel, getPaginationRowModel, PaginationState, SortingState, Table as TableType, useReactTable, VisibilityState, } from '@tanstack/react-table'; import { TableOptions } from '@tanstack/table-core'; import React, { Suspense, useEffect } from 'react'; import { AddFilterMenu } from './add-filter-menu.js'; import { DataTableFacetedFilter, DataTableFacetedFilterOption } from './data-table-faceted-filter.js'; import { DataTableFilterBadge } from './data-table-filter-badge.js'; import { useChannel } from '@/hooks/use-channel.js'; export interface FacetedFilter { title: string; icon?: React.ComponentType<{ className?: string }>; optionsFn?: () => Promise; options?: DataTableFacetedFilterOption[]; } interface DataTableProps { columns: ColumnDef[]; data: TData[]; totalItems: number; page?: number; itemsPerPage?: number; sorting?: SortingState; columnFilters?: ColumnFiltersState; onPageChange?: (table: TableType, page: number, itemsPerPage: number) => void; onSortChange?: (table: TableType, sorting: SortingState) => void; onFilterChange?: (table: TableType, columnFilters: ColumnFilter[]) => void; onColumnVisibilityChange?: (table: TableType, columnVisibility: VisibilityState) => void; onSearchTermChange?: (searchTerm: string) => void; defaultColumnVisibility?: VisibilityState; facetedFilters?: { [key: string]: FacetedFilter | undefined }; disableViewOptions?: boolean; /** * This property allows full control over _all_ features of TanStack Table * when needed. */ setTableOptions?: (table: TableOptions) => TableOptions; } export function DataTable({ columns, data, totalItems, page, itemsPerPage, sorting: sortingInitialState, columnFilters: filtersInitialState, onPageChange, onSortChange, onFilterChange, onSearchTermChange, onColumnVisibilityChange, defaultColumnVisibility, facetedFilters, disableViewOptions, setTableOptions, }: DataTableProps) { const [sorting, setSorting] = React.useState(sortingInitialState || []); const [columnFilters, setColumnFilters] = React.useState(filtersInitialState || []); const { activeChannel } = useChannel(); const [pagination, setPagination] = React.useState({ pageIndex: (page ?? 1) - 1, pageSize: itemsPerPage ?? 10, }); const [columnVisibility, setColumnVisibility] = React.useState( defaultColumnVisibility ?? {}, ); let tableOptions: TableOptions = { data, columns, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), manualPagination: true, manualSorting: true, manualFiltering: true, rowCount: totalItems, onPaginationChange: setPagination, onSortingChange: setSorting, onColumnVisibilityChange: setColumnVisibility, onColumnFiltersChange: setColumnFilters, state: { pagination, sorting, columnVisibility, columnFilters, }, }; if (typeof setTableOptions === 'function') { tableOptions = setTableOptions(tableOptions); } const table = useReactTable(tableOptions); useEffect(() => { onPageChange?.(table, pagination.pageIndex + 1, pagination.pageSize); }, [pagination]); useEffect(() => { onSortChange?.(table, sorting); }, [sorting]); useEffect(() => { onFilterChange?.(table, columnFilters); }, [columnFilters]); useEffect(() => { onColumnVisibilityChange?.(table, columnVisibility); }, [columnVisibility]); return ( <>
{onSearchTermChange && (
onSearchTermChange(event.target.value)} className="max-w-sm w-md" />
)} {Object.entries(facetedFilters ?? {}).map(([key, filter]) => ( ))}
{columnFilters .filter(f => !facetedFilters?.[f.id]) .map(f => { const column = table.getColumn(f.id); const currency = activeChannel?.defaultCurrencyCode ?? 'USD'; return setColumnFilters(old => old.filter(x => x.id !== f.id))} />; })}
{!disableViewOptions && }
{table.getHeaderGroups().map(headerGroup => ( {headerGroup.headers.map(header => { return ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext(), )} ); })} ))} {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map(row => ( {row.getVisibleCells().map(cell => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : ( No results. )}
); }