import { keepPreviousData, useQuery, UseQueryOptions, } from '@tanstack/react-query'; import {PaginatedBackendResponse} from '../../http/backend-response/pagination-response'; import {apiClient} from '../../http/query-client'; export interface GetDatatableDataParams { orderBy?: string; orderDir?: 'asc' | 'desc'; filters?: string | null; query?: string; with?: string; perPage?: number | string | null; page?: number | string; paginate?: 'simple' | 'lengthAware' | 'cursor'; [key: string]: string | number | boolean | undefined | null; } export const DatatableDataQueryKey = ( endpoint: string, params?: GetDatatableDataParams | Record, ) => { // split endpoint by slash, so we can clear cache from the root later, // for example, 'link-group' will clear 'link-group/1/links' endpoint const key: (string | GetDatatableDataParams)[] = endpoint.split('/'); if (params) { key.push(params); } return key; }; export function useDatatableData( endpoint: string, params: GetDatatableDataParams, options?: Omit< UseQueryOptions< PaginatedBackendResponse, unknown, PaginatedBackendResponse, any[] >, 'queryKey' | 'queryFn' >, onLoad?: (data: PaginatedBackendResponse) => void, ) { if (!params.paginate) { params.paginate = 'simple'; } return useQuery({ queryKey: DatatableDataQueryKey(endpoint, params), queryFn: ({signal}) => paginate(endpoint, params, onLoad, signal), placeholderData: keepPreviousData, ...options, }); } async function paginate( endpoint: string, params: GetDatatableDataParams, onLoad?: (data: PaginatedBackendResponse) => void, signal?: AbortSignal, ): Promise> { if (params.query) { await new Promise(resolve => setTimeout(resolve, 300)); } const response = await apiClient .get(endpoint, {params, signal: params.query ? signal : undefined}) .then(response => response.data); onLoad?.(response); return response; }