'use client' import { flexRender, getCoreRowModel, useReactTable, type ColumnDef, type ColumnSort, type RowSelectionState, type SortingState, type Table, type VisibilityState } from '@tanstack/react-table' import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from 'react' import { useSearchParams } from 'react-router' import { Card, CardContent } from '@repo/ui/components/ui/card' import { Table as Table_, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@repo/ui/components/ui/table' import { cn } from '@repo/ui/lib/utils' import { DataTablePagination } from './pagination' interface DataTableProps { children?: ReactNode columns: ColumnDef[] data: TData[] setSelectedRows?: (selectedRows: TData[]) => void pageIndex: number sort: SortingState pageSize: number rowCount: number columnInvisibilityInit?: string[] } interface TableContextProps { table: Table } const TableContext = createContext | null>(null) export function useDataTable() { const ctx = useContext(TableContext) if (!ctx) { throw new Error('TableContext is null') } return ctx as { table: Table } } export function DataTable({ data, children, columns, sort, pageIndex, pageSize, rowCount, setSelectedRows, columnInvisibilityInit = [] }: DataTableProps) { const [dataTable, setDataTable] = useState(data) const columnInvisibility = useMemo( () => Object.fromEntries( columnInvisibilityInit.map((column) => [column, false]) ), [columnInvisibilityInit] ) const [searchParams, setSearchParams] = useSearchParams() const [columnVisibility, setColumnVisibility] = useState(columnInvisibility) const [rowSelection, setRowSelection] = useState({}) const sorting = useMemo(() => { const sortParam = searchParams.get('sort') if (!sortParam) { return sort } return sortParam.split(',').map((s) => { const [id, dir] = s.split(':') return { id, desc: dir === 'desc' } }) }, [searchParams, sort]) const setPagination = useCallback( (updater: any) => { const newState = typeof updater === 'function' ? updater({ pageIndex, pageSize }) : updater setRowSelection({}) setSearchParams((prev) => { prev.set('p', newState?.pageIndex.toString()) prev.set('perPage', newState?.pageSize.toString()) return prev }) }, [pageIndex, pageSize, setSearchParams] ) const setSorting = useCallback( (updater: any) => { const newSorting = typeof updater === 'function' ? updater(sorting) : updater setSearchParams((prev) => { if (newSorting.length) { const sort = newSorting .map((s: ColumnSort) => `${s.id}:${s.desc ? 'desc' : 'asc'}`) .join(',') prev.set('sort', sort) } else { prev.delete('sort') } return prev }) }, [sorting, setSearchParams] ) useEffect(() => { setDataTable(data) }, [data]) const tableConfig = useMemo( () => ({ data: dataTable, columns, rowCount, state: { sorting, rowSelection, columnVisibility, pagination: { pageIndex, pageSize } }, manualSorting: true, manualPagination: true, enableRowSelection: true, getRowId: (row: any) => row.id, getCoreRowModel: getCoreRowModel(), onRowSelectionChange: setRowSelection, onSortingChange: setSorting, onColumnVisibilityChange: setColumnVisibility, onPaginationChange: setPagination, meta: { removeRow: (rowId: string) => { setDataTable((rows) => rows.filter((row: any) => row?.id !== rowId)) } } }), [ dataTable, columns, rowCount, sorting, rowSelection, columnVisibility, setColumnVisibility, pageIndex, pageSize, setSorting, setPagination ] ) const table = useReactTable(tableConfig) useEffect(() => { if (!setSelectedRows) return const selected = table.getSelectedRowModel().flatRows.map((r) => r.original) setSelectedRows(selected) }, [rowSelection, setSelectedRows, table]) return (
{children} {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) => ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext() )} ))} )) ) : ( Nenhum resultado. )}
) }