import { useState } from 'react'; import { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, type Column, type ColumnDef, type ColumnFiltersState, type SortingState, type VisibilityState, } from '@tanstack/react-table'; import { ArrowDown, ArrowUp, ArrowUpDown, ChevronLeft, ChevronRight, SlidersHorizontal } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Input } from '@/components/ui'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; interface DataTableProps { columns: ColumnDef[]; data: TData[]; emptyMessage?: string; filterColumn?: string; filterPlaceholder?: string; initialColumnVisibility?: VisibilityState; } export function DataTable({ columns, data, emptyMessage = 'No results.', filterColumn, filterPlaceholder = 'Filter results', initialColumnVisibility = {}, }: DataTableProps) { const [sorting, setSorting] = useState([]); const [columnFilters, setColumnFilters] = useState([]); const [columnVisibility, setColumnVisibility] = useState( initialColumnVisibility, ); const table = useReactTable({ data, columns, state: { sorting, columnFilters, columnVisibility }, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onColumnVisibilityChange: setColumnVisibility, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), }); const activeFilter = filterColumn ? table.getColumn(filterColumn) : undefined; const hideableColumns = table.getAllColumns().filter((column) => column.getCanHide()); return (
{activeFilter ? ( activeFilter.setFilterValue(event.target.value)} placeholder={filterPlaceholder} aria-label={filterPlaceholder} className="sm:max-w-xs" /> ) : ( )} Visible columns {hideableColumns.map((column) => ( column.toggleVisibility(Boolean(visible))} > {columnLabel(column.id)} ))}
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {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())} ))} )) ) : ( {emptyMessage} )}

{table.getFilteredRowModel().rows.length} result {table.getFilteredRowModel().rows.length === 1 ? '' : 's'} ยท Page{' '} {table.getState().pagination.pageIndex + 1} of {Math.max(table.getPageCount(), 1)}

); } export function DataTableColumnHeader({ column, title, }: { column: Column; title: string; }) { if (!column.getCanSort()) return {title}; const direction = column.getIsSorted(); const SortIcon = direction === 'asc' ? ArrowUp : direction === 'desc' ? ArrowDown : ArrowUpDown; return ( ); } function columnLabel(value: string): string { return value .replace(/([a-z])([A-Z])/g, '$1 $2') .replace(/_/g, ' ') .replace(/^./, (character) => character.toUpperCase()); }