"use client"; import { type ColumnDef, type ColumnFiltersState, type PaginationState, type Row, type SortingState, type VisibilityState, flexRender, getCoreRowModel, getExpandedRowModel, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table"; import * as React from "react"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Fragment } from "react"; import type { DataTableActionBarProps } from "./data-table-action-bar"; import type { DataTablePaginationProps } from "./data-table-pagination"; import type { DataTableToolbarProps } from "./data-table-toobar"; export interface DataTableProps { columns: ColumnDef[]; data: TData[]; rowComponent?: React.ComponentType<{ row: Row }>; toolbarComponent?: React.ComponentType>; actionBar?: React.ComponentType>; paginationComponent?: React.ComponentType>; onRowClick?: (row: Row) => void; defaultSorting?: SortingState; defaultColumnVisibility?: VisibilityState; defaultColumnFilters?: ColumnFiltersState; defaultPagination?: PaginationState; autoResetPageIndex?: boolean; /** access the state from the parent component */ columnFilters?: ColumnFiltersState; setColumnFilters?: React.Dispatch>; sorting?: SortingState; setSorting?: React.Dispatch>; pagination?: PaginationState; setPagination?: React.Dispatch>; } export function DataTable({ columns, data, rowComponent, toolbarComponent, actionBar, paginationComponent, onRowClick, defaultSorting = [], defaultColumnVisibility = {}, defaultColumnFilters = [], defaultPagination = { pageIndex: 0, pageSize: 20 }, autoResetPageIndex = true, columnFilters, setColumnFilters, sorting, setSorting, pagination, setPagination, }: DataTableProps) { // biome-ignore lint/suspicious/noExplicitAny: const [globalFilter, setGlobalFilter] = React.useState(); const [rowSelection, setRowSelection] = React.useState({}); const [columnVisibility, setColumnVisibility] = React.useState(defaultColumnVisibility); const [internalPagination, setInternalPagination] = React.useState(defaultPagination); const [internalColumnFilters, setInternalColumnFilters] = React.useState(defaultColumnFilters); const [internalSorting, setInternalSorting] = React.useState(defaultSorting); // Use controlled or uncontrolled column filters const columnFiltersState = columnFilters ?? internalColumnFilters; const setColumnFiltersState = setColumnFilters ?? setInternalColumnFilters; const sortingState = sorting ?? internalSorting; const setSortingState = setSorting ?? setInternalSorting; const paginationState = pagination ?? internalPagination; const setPaginationState = setPagination ?? setInternalPagination; const table = useReactTable({ data, columns, state: { sorting: sortingState, columnVisibility, rowSelection, pagination: paginationState, columnFilters: columnFiltersState, globalFilter, }, enableRowSelection: true, onRowSelectionChange: setRowSelection, onSortingChange: setSortingState, onColumnFiltersChange: setColumnFiltersState, onColumnVisibilityChange: setColumnVisibility, onPaginationChange: setPaginationState, onGlobalFilterChange: setGlobalFilter, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFacetedRowModel: getFacetedRowModel(), getFacetedUniqueValues: getFacetedUniqueValues(), getExpandedRowModel: getExpandedRowModel(), autoResetPageIndex, // @ts-expect-error as we have an id in the data getRowCanExpand: (row) => Boolean(row.original.id), }); return (
{toolbarComponent ? React.createElement(toolbarComponent, { table }) : null} {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) => ( onRowClick?.(row)} className="data-[state=selected]:bg-muted/50" > {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} {row.getIsExpanded() && ( {rowComponent ? React.createElement(rowComponent, { row }) : null} )} )) ) : ( No results. )} {actionBar ? React.createElement(actionBar, { table }) : null}
{paginationComponent ? React.createElement(paginationComponent, { table }) : null}
); }