"use client" import { useState } from "react" import { useQueryStates } from "nuqs" import { useQuery, useQueryClient, type UseQueryOptions } from "@tanstack/react-query" import type { DataViewChangeEvent, DataViewPaginationState, DataViewSorting } from "./types" import { dataTableSearchParams } from "./search-params" import { DEFAULT_PER_PAGE, type CrudListResponse } from "@garage/api" type DataTableClient = { list(query?: any): Promise } type DataTableParams = { page: number per_page: number sort_by: string | null sort_order: "asc" | "desc" | null } type UseDataTableQueryOptions = { queryKey: string[] client: C queryOptions?: Omit>, "queryKey" | "queryFn"> extraParams?: Record /** When true, pagination/sorting state lives in component state instead of URL params. Used for tables inside dialogs so they don't share state with the parent page. */ localState?: boolean } export function useDataTableQuery({ queryKey, client, queryOptions, extraParams, localState = false, }: UseDataTableQueryOptions) { const [urlParams, setUrlParams] = useQueryStates(dataTableSearchParams) const [localParams, setLocalParams] = useState({ page: 1, per_page: DEFAULT_PER_PAGE, sort_by: null, sort_order: null, }) const params: DataTableParams = localState ? localParams : urlParams const setParams = (next: Partial) => { if (localState) { setLocalParams((prev) => ({ ...prev, ...next })) } else { setUrlParams(next) } } const _queryKey = [...queryKey, params, ...(extraParams ? [extraParams] : [])] const query = useQuery>({ queryKey: _queryKey, queryFn: () => { const apiParams: Record = { page: params.page, per_page: params.per_page, ...extraParams, } if (params.sort_by) apiParams.sort_by = params.sort_by if (params.sort_order) apiParams.sort_order = params.sort_order return client.list(apiParams) as Promise> }, ...queryOptions, }) const pagination: DataViewPaginationState = { page: params.page, pageSize: params.per_page, pageCount: (query.data as any)?.meta?.last_page ?? 1, total: (query.data as any)?.meta?.total ?? 0, } const sorting: DataViewSorting = params.sort_by ? [{ id: params.sort_by, desc: params.sort_order === "desc" }] : [] const handleChange = (event: DataViewChangeEvent) => { switch (event.type) { case "pagination": setParams({ page: event.pagination.page, per_page: event.pagination.pageSize, }) break case "sorting": { const sort = event.sorting[0] setParams({ sort_by: sort?.id ?? null, sort_order: sort ? (sort.desc ? "desc" : "asc") : null, page: 1, }) break } } } const queryClient = useQueryClient(); const invalidateQuery = () => { // Prefix-match on the base route key so all paginated/sorted variants of // the list refetch — exact-matching the params object is flaky because // nuqs returns a fresh reference per render. queryClient.invalidateQueries({ queryKey, refetchType: "active" }) } return { ...query, pagination, sorting, params, setParams, handleChange, invalidateQuery, } }