'use client' import * as React from 'react' import type { ColumnDef, ColumnFiltersState, RowData, SortingState } from '@tanstack/react-table' import { DataGrid, DataGridBody, DataGridCell, DataGridHead, DataGridHeader, DataGridRow } from '@admin/components/shared/data-table/data-grid' import { useTableUtils } from '@admin/hooks/use-table-utils' import { cn } from '@admin/utils/shared/cn' import { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table' import { GripVertical } from 'lucide-react' import { parseAsInteger, useQueryState } from 'nuqs' import { DataTablePagination } from './data-table-pagination' interface DataTableProps { columns: ColumnDef[] data: TData[] isPending?: boolean error?: Error | null emptyMessage?: string loadingMessage?: string selectedIds?: string[] onSelectedIdsChange?: (ids: string[]) => void meta?: Record getId?: (row: TData) => string } export function DataTable({ columns, data, isPending = false, error = null, emptyMessage = 'No results found.', loadingMessage = 'Loading…', selectedIds, onSelectedIdsChange, meta, getId }: DataTableProps) { const [sorting, setSorting] = React.useState([]) const [columnFilters, setColumnFilters] = React.useState([]) const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0)) const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(20)) const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize const { columnSizing, handleColumnSizingChange, handlePaginationChange, handleRowSelectionChange, hoveredColumnId, registerTable, resetColumnSizingToContainer, rowSelection, setHoveredColumnId, tableContainerRef } = useTableUtils({ data, getId, onSelectedIdsChange, pageIndex, pageSize: effectivePageSize, selectedIds, setPageIndex }) const table = useReactTable({ data, columns, columnResizeMode: 'onChange', defaultColumn: { minSize: 48, size: 220 }, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), onSortingChange: setSorting, getSortedRowModel: getSortedRowModel(), onColumnFiltersChange: setColumnFilters, getFilteredRowModel: getFilteredRowModel(), onColumnSizingChange: handleColumnSizingChange, onRowSelectionChange: selectedIds ? handleRowSelectionChange : undefined, onPaginationChange: handlePaginationChange, meta, state: { sorting, columnFilters, columnSizing, rowSelection, pagination: { pageIndex, pageSize: effectivePageSize } } }) registerTable(table) const gridTemplateColumns = table .getVisibleLeafColumns() .map((column) => `${column.getSize()}px`) .join(' ') return (
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header, headerIndex) => { const meta = header.column.columnDef.meta as Record | undefined const resizeLabel = typeof header.column.columnDef.header === 'string' ? header.column.columnDef.header : header.column.id const nextHeader = headerGroup.headers[headerIndex + 1] const canResizeColumn = header.column.getCanResize() && nextHeader?.column.getCanResize() === true return ( setHoveredColumnId(header.column.id)} onMouseLeave={() => setHoveredColumnId((current) => current === header.column.id ? null : current ) } > {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} {canResizeColumn ? ( ) : null} ) })} ))} {isPending ? (
{loadingMessage}
) : error ? (
Failed to load these results. Refresh to try again.
) : table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => { const meta = cell.column.columnDef.meta as Record | undefined return ( setHoveredColumnId(cell.column.id)} onMouseLeave={() => setHoveredColumnId((current) => current === cell.column.id ? null : current ) } > {flexRender(cell.column.columnDef.cell, cell.getContext())} ) })} )) ) : ( {emptyMessage} )}
) } export type { DataTableProps }