Presupuestador_web/client/src/lib/hooks/useDataTable/useDataTable.tsx

218 lines
5.3 KiB
TypeScript
Raw Normal View History

2024-06-06 11:05:54 +00:00
import {
2024-08-25 18:18:07 +00:00
InitialTableState,
2024-06-06 11:05:54 +00:00
OnChangeFn,
PaginationState,
getCoreRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getSortedRowModel,
useReactTable,
type ColumnDef,
type SortingState,
type VisibilityState,
} from "@tanstack/react-table";
import { getDataTableSelectionColumn } from "@/components";
2024-06-13 11:09:26 +00:00
import React, { useCallback } from "react";
2024-06-11 16:48:09 +00:00
import { DataTableFilterField } from "./types";
import { useDataTableContext } from "./useDataTableContext";
2024-06-06 11:05:54 +00:00
//import { useDebounce } from "@/hooks/use-debounce";
interface UseDataTableProps<TData, TValue> {
/**
* The data for the table.
* @default []
* @type TData[]
*/
data: TData[];
/**
* The columns of the table.
* @default []
* @type ColumnDef<TData, TValue>[]
*/
columns: ColumnDef<TData, TValue>[];
/**
* The number of pages in the table.
* @type number
*/
pageCount: number;
/**
* Enable sorting columns.
* @default false
* @type boolean
*/
enableSorting?: boolean;
/**
* Enable hiding columns.
* @default false
* @type boolean
*/
enableHiding?: boolean;
/**
* Enable selection rows.
* @default false
* @type boolean
*/
enableRowSelection?: boolean;
2024-06-13 11:09:26 +00:00
/**
* The default number of rows per page.
* @default 10
* @type number | undefined
* @example 20
*/
defaultPerPage?: number;
/**
* The default sort order.
* @default undefined
* @type `${Extract<keyof TData, string | number>}.${"asc" | "desc"}` | undefined
* @example "createdAt.desc"
*/
defaultSort?: `${Extract<keyof TData, string | number>}.${"asc" | "desc"}`;
2024-06-06 11:05:54 +00:00
/**
* Defines filter fields for the table. Supports both dynamic faceted filters and search filters.
* - Faceted filters are rendered when `options` are provided for a filter field.
* - Otherwise, search filters are rendered.
*
* The indie filter field `value` represents the corresponding column name in the database table.
* @default []
* @type { label: string, value: keyof TData, placeholder?: string, options?: { label: string, value: string, icon?: React.ComponentType<{ className?: string }> }[] }[]
* @example
* ```ts
* // Render a search filter
* const filterFields = [
* { label: "Title", value: "title", placeholder: "Search titles" }
* ];
* // Render a faceted filter
* const filterFields = [
* {
* label: "Status",
* value: "status",
* options: [
* { label: "Todo", value: "todo" },
* { label: "In Progress", value: "in-progress" },
* { label: "Done", value: "done" },
* { label: "Canceled", value: "canceled" }
* ]
* }
* ];
* ```
*/
filterFields?: DataTableFilterField<TData>[];
/**
* Enable notion like column filters.
* Advanced filters and column filters cannot be used at the same time.
* @default false
* @type boolean
*/
enableAdvancedFilter?: boolean;
2024-08-20 15:16:41 +00:00
2024-08-25 18:22:37 +00:00
initialState?: InitialTableState;
2024-08-25 18:18:07 +00:00
2024-08-20 15:16:41 +00:00
onPaginationChange?: OnChangeFn<PaginationState>;
2024-06-06 11:05:54 +00:00
}
export function useDataTable<TData, TValue>({
data,
columns,
pageCount,
enableSorting = false,
enableHiding = false,
enableRowSelection = false,
2024-08-25 18:18:07 +00:00
initialState,
2024-08-20 15:16:41 +00:00
onPaginationChange,
2024-06-06 11:05:54 +00:00
}: UseDataTableProps<TData, TValue>) {
2024-06-14 12:07:20 +00:00
const { pagination, setPagination, sorting } = useDataTableContext();
2024-06-06 11:05:54 +00:00
// Table states
const [rowSelection, setRowSelection] = React.useState({});
2024-08-25 18:18:07 +00:00
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>(
initialState?.columnVisibility || {}
);
2024-06-06 11:05:54 +00:00
const paginationUpdater: OnChangeFn<PaginationState> = (updater) => {
if (typeof updater === "function") {
const newPagination = updater(pagination);
setPagination(newPagination);
}
2024-08-20 15:16:41 +00:00
if (onPaginationChange) {
onPaginationChange(updater);
}
2024-06-06 11:05:54 +00:00
};
const sortingUpdater: OnChangeFn<SortingState> = (updater) => {
if (typeof updater === "function") {
2024-06-13 11:09:26 +00:00
const newSorting = updater(sorting);
console.log(newSorting);
2024-06-14 12:07:20 +00:00
//setSorting(newSorting);
2024-06-06 11:05:54 +00:00
}
};
const getTableColumns = useCallback(() => {
const _columns = columns;
if (enableRowSelection) {
_columns.unshift(getDataTableSelectionColumn());
}
return _columns;
}, [columns, enableRowSelection]);
const table = useReactTable({
data,
2024-06-13 11:09:26 +00:00
columns: getTableColumns(),
2024-08-20 15:16:41 +00:00
//autoResetPageIndex: true,
2024-06-13 11:09:26 +00:00
pageCount: pageCount ?? -1,
2024-06-06 11:05:54 +00:00
getCoreRowModel: getCoreRowModel(),
2024-08-25 18:18:07 +00:00
initialState,
2024-06-06 11:05:54 +00:00
state: {
pagination,
sorting,
columnVisibility,
rowSelection,
},
enableRowSelection,
onRowSelectionChange: setRowSelection,
manualSorting: true,
enableSorting,
getSortedRowModel: getSortedRowModel(),
onSortingChange: sortingUpdater,
enableHiding,
onColumnVisibilityChange: setColumnVisibility,
manualPagination: true,
onPaginationChange: paginationUpdater,
manualFiltering: true,
2024-06-13 11:09:26 +00:00
getFilteredRowModel: getFilteredRowModel(),
2024-06-06 11:05:54 +00:00
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
2024-06-13 11:09:26 +00:00
2024-07-10 18:54:33 +00:00
debugTable: false,
debugHeaders: false,
debugColumns: false,
2024-07-11 11:08:53 +00:00
defaultColumn: {
2024-08-25 20:06:24 +00:00
minSize: 0, //starting column size
size: Number.MAX_SAFE_INTEGER, //enforced during column resizing
maxSize: Number.MAX_SAFE_INTEGER, //enforced during column resizing
2024-07-11 11:08:53 +00:00
},
2024-06-06 11:05:54 +00:00
});
return { table };
}