DataTableProvider.tsx85 lines · main
| 1 | import type { |
| 2 | ColumnDef, |
| 3 | ColumnFiltersState, |
| 4 | PaginationState, |
| 5 | RowSelectionState, |
| 6 | SortingState, |
| 7 | Table, |
| 8 | VisibilityState, |
| 9 | } from '@tanstack/react-table' |
| 10 | import { createContext, ReactNode, useContext, useMemo } from 'react' |
| 11 | |
| 12 | import { DataTableFilterField } from '../DataTable.types' |
| 13 | import { QuerySearchParamsType } from '@/components/interfaces/UnifiedLogs/UnifiedLogs.types' |
| 14 | import { ResponseError } from '@/types' |
| 15 | |
| 16 | // REMINDER: read about how to move controlled state out of the useReactTable hook |
| 17 | // https://github.com/TanStack/table/discussions/4005#discussioncomment-7303569 |
| 18 | |
| 19 | interface DataTableStateContextType { |
| 20 | columnFilters: ColumnFiltersState |
| 21 | sorting: SortingState |
| 22 | rowSelection: RowSelectionState |
| 23 | columnOrder: string[] |
| 24 | columnVisibility: VisibilityState |
| 25 | pagination: PaginationState |
| 26 | enableColumnOrdering: boolean |
| 27 | searchParameters: QuerySearchParamsType |
| 28 | openRowId: string | undefined |
| 29 | setOpenRowId: (id: string | undefined) => void |
| 30 | } |
| 31 | |
| 32 | interface DataTableBaseContextType<TData = unknown, TValue = unknown> { |
| 33 | table: Table<TData> |
| 34 | error: ResponseError | null |
| 35 | filterFields: DataTableFilterField<TData>[] |
| 36 | columns: ColumnDef<TData, TValue>[] |
| 37 | isFetching: boolean |
| 38 | isError: boolean |
| 39 | isLoading: boolean |
| 40 | isLoadingCounts: boolean |
| 41 | getFacetedUniqueValues?: (table: Table<TData>, columnId: string) => Map<string, number> |
| 42 | getFacetedMinMaxValues?: (table: Table<TData>, columnId: string) => undefined | [number, number] |
| 43 | } |
| 44 | |
| 45 | interface DataTableContextType<TData = unknown, TValue = unknown> |
| 46 | extends DataTableStateContextType, DataTableBaseContextType<TData, TValue> {} |
| 47 | |
| 48 | export const DataTableContext = createContext<DataTableContextType<any, any> | null>(null) |
| 49 | |
| 50 | export function DataTableProvider<TData, TValue>({ |
| 51 | children, |
| 52 | ...props |
| 53 | }: Partial<DataTableStateContextType> & |
| 54 | DataTableBaseContextType<TData, TValue> & { |
| 55 | children: ReactNode |
| 56 | }) { |
| 57 | const value = useMemo( |
| 58 | () => ({ |
| 59 | ...props, |
| 60 | columnFilters: props.columnFilters ?? [], |
| 61 | sorting: props.sorting ?? [], |
| 62 | rowSelection: props.rowSelection ?? {}, |
| 63 | columnOrder: props.columnOrder ?? [], |
| 64 | columnVisibility: props.columnVisibility ?? {}, |
| 65 | pagination: props.pagination ?? { pageIndex: 0, pageSize: 10 }, |
| 66 | enableColumnOrdering: props.enableColumnOrdering ?? false, |
| 67 | searchParameters: props.searchParameters ?? ({} as any), |
| 68 | openRowId: props.openRowId, |
| 69 | setOpenRowId: props.setOpenRowId ?? (() => {}), |
| 70 | }), |
| 71 | [props] |
| 72 | ) |
| 73 | |
| 74 | return <DataTableContext.Provider value={value}>{children}</DataTableContext.Provider> |
| 75 | } |
| 76 | |
| 77 | export function useDataTable<TData, TValue>() { |
| 78 | const context = useContext(DataTableContext) |
| 79 | |
| 80 | if (!context) { |
| 81 | throw new Error('useDataTable must be used within a DataTableProvider') |
| 82 | } |
| 83 | |
| 84 | return context as DataTableContextType<TData, TValue> |
| 85 | } |