import type { ColumnDef, PaginationState, SortingState, VisibilityState, } from "@tanstack/react-table"; import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table"; import { useMemo, useState } from "react"; import type { EntityColumn } from "../components/entity-list"; import { entityListRange } from "../lib/entity-list"; export function useEntityTable({ items, columns, search, onSearchChange, filterKey, }: { items: readonly T[]; columns: readonly EntityColumn[]; search: string | undefined; onSearchChange: ((value: string) => void) | undefined; filterKey: string; }) { const [localSearch, setLocalSearch] = useState(""); const currentSearch = search ?? localSearch; const [sorting, setSorting] = useState([]); const [visibility, setVisibility] = useState({}); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); const resetKey = `${currentSearch}\0${filterKey}`; const [previousKey, setPreviousKey] = useState(resetKey); if (previousKey !== resetKey) { setPreviousKey(resetKey); setPagination((previous) => ({ ...previous, pageIndex: 0 })); } const definitions = useMemo[]>( () => columns.map((column) => ({ id: column.id, header: column.label, accessorFn: column.value ?? (() => ""), enableSorting: column.id !== "actions" && !!column.value, enableGlobalFilter: column.id !== "actions" && !!column.value, enableHiding: column.id !== "actions" && column.hideable !== false, })), [columns] ); const table = useReactTable({ data: [...items], columns: definitions, getRowId: (item) => item.id, state: { sorting, columnVisibility: visibility, columnPinning: { right: columns.filter((column) => column.id === "actions").map((column) => column.id), }, pagination, globalFilter: onSearchChange ? "" : currentSearch.trim(), }, onSortingChange: setSorting, onColumnVisibilityChange: setVisibility, onPaginationChange: setPagination, autoResetPageIndex: false, globalFilterFn: "includesString", getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), }); const total = table.getFilteredRowModel().rows.length; const range = entityListRange(total, pagination.pageIndex, pagination.pageSize); // Una actualización puede reducir el conjunto sin cambiar los filtros. if (pagination.pageIndex !== range.page) { setPagination({ ...pagination, pageIndex: range.page }); } return { table, total, range, pagination, setPagination, sorting, setSorting, currentSearch, setLocalSearch, }; }