// ── Shared: Data Table Component ── // Generic data table powered by @tanstack/react-table. // Supports sorting, filtering, row selection, column visibility, faceted values, and pagination. // Renders loading skeletons (5 rows) while data is loading. "use client" import * as React from "react" import { ColumnDef, ColumnFiltersState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { DataTablePagination } from "./data-table-pagination" import { cn } from "@/lib/utils" interface DataTableProps { columns: ColumnDef[] data: TData[] toolbar?: React.ReactNode loading?: boolean emptyMessage?: string } /** * DataTable — fully featured generic table with TanStack Table. * Manages sorting, column filters, row selection, visibility, and pagination internally. * Shows skeleton placeholders when `loading` is true. */ export function DataTable({ columns, data, toolbar, loading, emptyMessage = "No results found.", }: DataTableProps) { const [rowSelection, setRowSelection] = React.useState({}) const [columnVisibility, setColumnVisibility] = React.useState({}) const [columnFilters, setColumnFilters] = React.useState([]) const [sorting, setSorting] = React.useState([]) const table = useReactTable({ data, columns, state: { sorting, columnVisibility, rowSelection, columnFilters, }, enableRowSelection: true, onRowSelectionChange: setRowSelection, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onColumnVisibilityChange: setColumnVisibility, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFacetedRowModel: getFacetedRowModel(), getFacetedUniqueValues: getFacetedUniqueValues(), }) return (
{toolbar &&
{toolbar}
}
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} ))} ))} {loading ? ( Array.from({ length: 5 }).map((_, i) => ( {columns.map((_, ci) => (
))} )) ) : table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : (

{emptyMessage}

)}
) }