11import {
2+ useInfiniteQuery ,
23 useQuery ,
34 useQueryClient ,
45 useSuspenseQuery ,
@@ -10,10 +11,12 @@ import { createProductQueryKeys } from "./query-keys"
1011import { resolvePagination } from "./pagination"
1112import type {
1213 ProductDetailInputBase ,
14+ ProductInfiniteInputBase ,
1315 ProductListInputBase ,
1416 ProductQueryKeys ,
1517 ProductService ,
1618 RegionInfo ,
19+ UseInfiniteProductsResult ,
1720 UseProductsResult ,
1821 UseSuspenseProductsResult ,
1922} from "./types"
@@ -168,6 +171,92 @@ export function createProductHooks<
168171 }
169172 }
170173
174+ function useInfiniteProducts (
175+ input : TListInput & ProductInfiniteInputBase
176+ ) : UseInfiniteProductsResult < TProduct > {
177+ const region = resolveRegion ? resolveRegion ( ) : null
178+ const baseInput = { ...input } as TListInput & { enabled ?: boolean }
179+ delete baseInput . enabled
180+ const resolvedInput = applyRegion ( baseInput , region ?? undefined )
181+ const enabled =
182+ input . enabled ?? ( ! requireRegion || Boolean ( resolvedInput . region_id ) )
183+
184+ const limitFromInput = ( resolvedInput as { limit ?: number } ) . limit
185+ const resolvedLimit =
186+ typeof limitFromInput === "number" && limitFromInput > 0
187+ ? limitFromInput
188+ : defaultPageSize
189+ const offsetFromInput = ( resolvedInput as { offset ?: number } ) . offset
190+ const pageFromInput = resolvedInput . page ?? 1
191+ const baseOffset =
192+ typeof offsetFromInput === "number"
193+ ? offsetFromInput
194+ : ( pageFromInput - 1 ) * resolvedLimit
195+
196+ const baseListParams = buildList ( resolvedInput )
197+ const baseQueryKey = resolvedQueryKeys . infinite
198+ ? resolvedQueryKeys . infinite ( baseListParams )
199+ : resolvedQueryKeys . list ( baseListParams )
200+ const queryKey =
201+ resolvedQueryKeys . infinite ||
202+ baseQueryKey [ baseQueryKey . length - 1 ] === "__infinite"
203+ ? baseQueryKey
204+ : [ ...baseQueryKey , "__infinite" ]
205+
206+ const {
207+ data,
208+ isLoading,
209+ isFetching,
210+ isFetchingNextPage,
211+ hasNextPage,
212+ fetchNextPage,
213+ refetch,
214+ error,
215+ } = useInfiniteQuery ( {
216+ queryKey,
217+ queryFn : ( { pageParam = baseOffset , signal } ) => {
218+ const offset =
219+ typeof pageParam === "number" ? pageParam : baseOffset
220+ const page =
221+ resolvedLimit > 0 ? Math . floor ( offset / resolvedLimit ) + 1 : 1
222+ const pageInput = {
223+ ...resolvedInput ,
224+ page,
225+ limit : resolvedLimit ,
226+ offset,
227+ } as TListInput & { offset ?: number }
228+ const listParams = buildList ( pageInput )
229+ return service . getProducts ( listParams , signal )
230+ } ,
231+ initialPageParam : baseOffset ,
232+ getNextPageParam : ( lastPage ) => {
233+ const limit = lastPage . limit ?? resolvedLimit
234+ const offset = lastPage . offset ?? 0
235+ const moreItemsExist = lastPage . count > offset + limit
236+ return moreItemsExist ? offset + limit : undefined
237+ } ,
238+ enabled,
239+ ...resolvedCacheConfig . semiStatic ,
240+ } )
241+
242+ return {
243+ products : data ?. pages . flatMap ( ( page ) => page . products ) ?? [ ] ,
244+ isLoading,
245+ isFetching,
246+ isFetchingNextPage,
247+ hasNextPage : Boolean ( hasNextPage ) ,
248+ error :
249+ error instanceof Error ? error . message : error ? String ( error ) : null ,
250+ totalCount : data ?. pages [ 0 ] ?. count ?? 0 ,
251+ fetchNextPage : ( ) => {
252+ void fetchNextPage ( )
253+ } ,
254+ refetch : ( ) => {
255+ void refetch ( )
256+ } ,
257+ }
258+ }
259+
171260 function useSuspenseProducts (
172261 input : TListInput
173262 ) : UseSuspenseProductsResult < TProduct > {
@@ -590,6 +679,7 @@ export function createProductHooks<
590679
591680 return {
592681 useProducts,
682+ useInfiniteProducts,
593683 useSuspenseProducts,
594684 useProduct,
595685 useSuspenseProduct,
0 commit comments