"use client"; import * as React from "react"; import { type ColumnDef, type SortingState, type VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table"; import { ChevronLeft, ChevronRight, CheckCircle, Download, Trash2, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { cn } from "@/lib/utils"; import type { ResponseCard } from "./columns"; type DataTableProps = { data: TData[]; columns: ColumnDef[]; totalCount: number; page: number; limit: number; onPageChange?: (page: number) => void; onLimitChange?: (limit: number) => void; onBulkMarkReviewed?: (ids: string[]) => void; onBulkMarkExported?: (ids: string[]) => void; onBulkDelete?: (ids: string[]) => void; columnVisibility?: VisibilityState; onColumnVisibilityChange?: (visibility: VisibilityState) => void; sortBy?: string; sortOrder?: "asc" | "desc"; onSortChange?: (sortBy: string, sortOrder: "asc" | "desc") => void; }; const PAGE_SIZES = [10, 20, 50, 100]; export function DataTable({ data, columns, totalCount, page, limit, onPageChange, onLimitChange, onBulkMarkReviewed, onBulkMarkExported, onBulkDelete, columnVisibility: controlledVisibility, onColumnVisibilityChange, sortBy: controlledSortBy, sortOrder: controlledSortOrder, onSortChange, }: DataTableProps) { const sorting: SortingState = controlledSortBy && controlledSortOrder ? [{ id: controlledSortBy, desc: controlledSortOrder === "desc" }] : []; const setSorting = React.useCallback( (updater: React.SetStateAction) => { const next = typeof updater === "function" ? updater(sorting) : updater; const first = next[0]; if (first && onSortChange) { onSortChange(first.id, first.desc ? "desc" : "asc"); } }, [sorting, onSortChange] ); const [rowSelection, setRowSelection] = React.useState({}); const [internalVisibility, setInternalVisibility] = React.useState({}); const visibility = controlledVisibility !== undefined ? controlledVisibility : internalVisibility; const setVisibility = onColumnVisibilityChange ?? setInternalVisibility; const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onSortingChange: setSorting, onRowSelectionChange: setRowSelection, onColumnVisibilityChange: (updater) => { const next = typeof updater === "function" ? updater(visibility) : updater; setVisibility(next); }, state: { sorting, rowSelection, columnVisibility: visibility, pagination: { pageIndex: page - 1, pageSize: limit, }, }, manualPagination: true, manualSorting: !!onSortChange, pageCount: Math.ceil(totalCount / limit) || 1, }); const selectedRows = table.getFilteredSelectedRowModel().rows; const selectedCount = selectedRows.length; const selectedIds = selectedRows.map((r) => r.original.id); const totalPages = Math.ceil(totalCount / limit); const canPrev = page > 1; const canNext = page < totalPages; const start = (page - 1) * limit + 1; const end = Math.min(page * limit, totalCount); return (
{selectedCount > 0 && (
{selectedCount} row{selectedCount !== 1 ? "s" : ""} selected
{onBulkMarkReviewed && ( )} {onBulkMarkExported && ( )} {onBulkDelete && ( )}
)}
{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() )} ))} )) ) : ( No results. )}
{totalCount === 0 ? "0 results" : `${start}–${end} of ${totalCount}`}
Rows per page
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => { let p: number; if (totalPages <= 5) { p = i + 1; } else if (page <= 3) { p = i + 1; } else if (page >= totalPages - 2) { p = totalPages - 4 + i; } else { p = page - 2 + i; } return ( ); })}
); }