import { AnyUseSuspenseInfiniteQueryOptions, InfiniteData, useSuspenseInfiniteQuery, useSuspenseQuery, UseSuspenseQueryOptions, } from '@tanstack/react-query' import { ApiCollection, ApiResource, ResourceObject } from '../types' import { FailedResponse } from '../types/api_primitives' import { Log } from '../utils' import { GetRequest, RequestData } from '../utils/client' import { throwResponseError } from '../utils/response_error' import { getNextPageParamFromMeta } from './paginator_meta' import { App, useApiClient } from './use_api_client' interface SuspenseGetOptions extends GetRequest { app?: App reply_root_id?: string | null } export type SuspenseGetQueryOptions = Omit< UseSuspenseQueryOptions, FailedResponse>, 'queryKey' | 'queryFn' > export const useSuspenseGet = ( args: SuspenseGetOptions, options?: SuspenseGetQueryOptions ) => { type Resource = ApiResource const apiClient = useApiClient() const { data, ...query } = useSuspenseQuery({ queryKey: getRequestQueryKey(args), queryFn: ({ queryKey }) => { const [url, d, headers, app = 'chat'] = queryKey as RequestQueryKey return apiClient[app] .get({ url, data: d, headers }) .catch(throwResponseError) as Promise }, ...options, }) return { ...data, ...query } } export type SuspensePaginatorOptions = Omit< AnyUseSuspenseInfiniteQueryOptions, 'getNextPageParam' | 'initialPageParam' | 'queryFn' | 'queryKey' > & { initialPageParam?: Partial transformPage?( page: ApiCollection, pageParam: Partial | undefined ): ApiCollection } export const useSuspensePaginator = ( args: SuspenseGetOptions, { transformPage, ...opts }: SuspensePaginatorOptions = {} ) => { const apiClient = useApiClient() const query = useSuspenseInfiniteQuery< ApiCollection, Response, InfiniteData, Partial | undefined>, any, Partial | undefined >({ queryKey: getRequestQueryKey(args), queryFn: ({ pageParam }) => { Log.info('useSuspenseGet', { pageParam }) const pageParmWhere = pageParam?.where || {} const argsWhere = args.data.where || {} const where = { ...argsWhere, ...pageParmWhere } const app = args.app || 'chat' const offset = pageParam?.offset || args.data.offset const order = pageParam?.order || args.data.order const data = { ...args.data, where, offset, ...(order && { order }) } return apiClient[app] .get>({ url: args.url, data, }) .catch(throwResponseError) .then(page => (transformPage ? (transformPage(page, pageParam) as ApiCollection) : page)) }, initialPageParam: {} as Partial, getNextPageParam: lastPage => getNextPageParamFromMeta(lastPage.meta?.next), ...opts, }) const data: T[] = query.data?.pages.flatMap(page => page.data) || [] const totalCount = query.data?.pages[0]?.meta?.totalCount || data.length return { ...query, data, totalCount, infiniteData: query.data } } export type RequestQueryKey = [ SuspenseGetOptions['url'], SuspenseGetOptions['data'], SuspenseGetOptions['headers'], SuspenseGetOptions['app'], SuspenseGetOptions['reply_root_id'], ] export const getRequestQueryKey = (args: SuspenseGetOptions): RequestQueryKey => [ args.url, args.data, args.headers, args.app || 'chat', args.reply_root_id, ]