"use client"; import { activeFiltersParser, columnSizingParser, columnVisibilityParser, DEFAULT_PAGE_SIZE, pageIndexParser, pageSizeParser, searchTermParser, segmentIdParser, sortingParser, } from "@calcom/features/data-table/lib/parsers"; import type { ActiveFilters, SegmentIdentifier } from "@calcom/features/data-table/lib/types"; import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils"; import { useElementByClassName } from "@calcom/lib/hooks/useElementByClassName"; import type { ColumnSizingState, OnChangeFn, SortingState, VisibilityState } from "@tanstack/react-table"; import { useQueryState } from "nuqs"; import { createContext, useContext, useMemo, useRef } from "react"; export type ActiveFiltersValidator = (filters: ActiveFilters) => ActiveFilters; export type ActiveFiltersValidatorState = ActiveFiltersValidator | "loading" | undefined; export type DataTableStateContextType = { tableIdentifier: string; ctaContainerRef: React.RefObject; filterToOpen: React.MutableRefObject; pageIndex: number; setPageIndex: (pageIndex: number | null) => void; pageSize: number; setPageSize: (pageSize: number | null) => void; searchTerm: string; setSearchTerm: (searchTerm: string | null) => void; activeFilters: ActiveFilters; setActiveFilters: ReturnType>[1]; sorting: SortingState; setSorting: OnChangeFn; columnVisibility: VisibilityState; setColumnVisibility: OnChangeFn; columnSizing: ColumnSizingState; setColumnSizing: OnChangeFn; segmentIdRaw: string | null; setSegmentIdRaw: (segmentId: string | null) => void; defaultPageSize: number; timeZone?: string; validateActiveFilters?: ActiveFiltersValidatorState; }; export const DataTableStateContext = createContext(null); export function useDataTableState() { const context = useContext(DataTableStateContext); if (!context) { throw new Error("useDataTableState must be used within a DataTableStateProvider"); } return context; } interface DataTableStateProviderProps { tableIdentifier: string; children: React.ReactNode; defaultPageSize?: number; ctaContainerClassName?: string; timeZone?: string; preferredSegmentId?: SegmentIdentifier | null; validateActiveFilters?: ActiveFiltersValidatorState; } export function DataTableStateProvider({ tableIdentifier, children, defaultPageSize = DEFAULT_PAGE_SIZE, ctaContainerClassName = CTA_CONTAINER_CLASS_NAME, timeZone, preferredSegmentId, validateActiveFilters, }: DataTableStateProviderProps) { if (!tableIdentifier.trim()) { throw new Error("tableIdentifier is required and cannot be empty"); } const filterToOpen = useRef(undefined); const [pageIndex, setPageIndex] = useQueryState("page", pageIndexParser); const [pageSize, setPageSize] = useQueryState("size", pageSizeParser); const [searchTerm, setSearchTerm] = useQueryState("q", searchTermParser); const [activeFilters, setActiveFilters] = useQueryState("activeFilters", activeFiltersParser); const [sorting, setSorting] = useQueryState("sorting", sortingParser); const [columnVisibility, setColumnVisibility] = useQueryState( "cols", columnVisibilityParser ); const [columnSizing, setColumnSizing] = useQueryState("widths", columnSizingParser); const initialSegmentId = useMemo( () => (preferredSegmentId ? String(preferredSegmentId.id) : null), [preferredSegmentId] ); const [segmentIdRaw, setSegmentIdRaw] = useQueryState( "segment", initialSegmentId ? segmentIdParser.withDefault(initialSegmentId) : segmentIdParser ); const ctaContainerRef = useElementByClassName(ctaContainerClassName); const value = useMemo( () => ({ tableIdentifier, ctaContainerRef, filterToOpen, pageIndex, setPageIndex, pageSize, setPageSize, searchTerm, setSearchTerm, activeFilters, setActiveFilters, sorting, setSorting, columnVisibility, setColumnVisibility, columnSizing, setColumnSizing, segmentIdRaw, setSegmentIdRaw, defaultPageSize, timeZone, validateActiveFilters, }), [ tableIdentifier, ctaContainerRef, pageIndex, setPageIndex, pageSize, setPageSize, searchTerm, setSearchTerm, activeFilters, setActiveFilters, sorting, setSorting, columnVisibility, setColumnVisibility, columnSizing, setColumnSizing, segmentIdRaw, setSegmentIdRaw, defaultPageSize, timeZone, validateActiveFilters, ] ); return {children}; }