UNPKG

@techsio/storefront-data

Version:

Medusa-first storefront data layer built on TanStack Query.

191 lines (190 loc) • 7.48 kB
import { useQuery, useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; import { getPrefetchCacheOptions } from "./cache-config.js"; import { toErrorMessage } from "./error-utils.js"; import { resolvePagination } from "./pagination.js"; import { shouldSkipPrefetch } from "./prefetch.js"; import { useDelayedPrefetchController } from "./use-delayed-prefetch-controller.js"; const stripEnabled = (input)=>{ const { enabled: _inputEnabled, ...rest } = input; return rest; }; const resolveListPagination = (input, listParams, defaultPageSize)=>{ const limitFromParams = listParams.limit; const offsetFromParams = listParams.offset; return resolvePagination({ page: input.page, limit: limitFromParams ?? input.limit, offset: offsetFromParams }, defaultPageSize); }; function createSimpleListDetailHooks({ buildList, buildDetail, getListItems, getList, getDetail, getListQueryOptions, getDetailQueryOptions, resolvedCacheConfig, resolvedQueryKeys, defaultPageSize, defaultCacheStrategy }) { function useList(input, options) { const { enabled: inputEnabled } = input; const listParams = buildList(stripEnabled(input)); const enabled = inputEnabled ?? true; const query = useQuery({ ...getListQueryOptions(input, { queryOptions: options?.queryOptions }), enabled }); const { data, isLoading, isFetching, isSuccess, error } = query; const pagination = resolveListPagination(input, listParams, defaultPageSize); const totalCount = data?.count ?? 0; const totalPages = pagination.limit ? Math.ceil(totalCount / pagination.limit) : 0; return { items: getListItems(data), isLoading, isFetching, isSuccess, error: toErrorMessage(error), totalCount, currentPage: pagination.page, totalPages, hasNextPage: pagination.page < totalPages, hasPrevPage: pagination.page > 1, query }; } function useSuspenseList(input, options) { const listParams = buildList(stripEnabled(input)); const query = useSuspenseQuery({ ...getListQueryOptions(input, { queryOptions: options?.queryOptions }) }); const { data, isFetching } = query; const pagination = resolveListPagination(input, listParams, defaultPageSize); const totalCount = data?.count ?? 0; const totalPages = pagination.limit ? Math.ceil(totalCount / pagination.limit) : 0; return { items: getListItems(data), isLoading: false, isFetching, isSuccess: true, error: null, totalCount, currentPage: pagination.page, totalPages, hasNextPage: pagination.page < totalPages, hasPrevPage: pagination.page > 1, query }; } function useDetail(input, options) { const enabled = input.enabled ?? Boolean(input.id); const query = useQuery({ ...getDetailQueryOptions(input, { queryOptions: options?.queryOptions }), enabled }); const { data, isLoading, isFetching, isSuccess, error } = query; return { item: data ?? null, isLoading, isFetching, isSuccess, error: toErrorMessage(error), query }; } function useSuspenseDetail(input, options) { const query = useSuspenseQuery({ ...getDetailQueryOptions(input, { queryOptions: options?.queryOptions }) }); const { data, isFetching } = query; return { item: data ?? null, isLoading: false, isFetching, isSuccess: true, error: null, query }; } function usePrefetchList(options) { const queryClient = useQueryClient(); const { schedulePrefetch, cancelPrefetch } = useDelayedPrefetchController(); const cacheStrategy = options?.cacheStrategy ?? defaultCacheStrategy; const defaultDelay = options?.defaultDelay ?? 800; const skipIfCached = options?.skipIfCached ?? true; const skipMode = options?.skipMode ?? "fresh"; const prefetchCacheOptions = getPrefetchCacheOptions(resolvedCacheConfig, cacheStrategy); const prefetchList = async (input)=>{ const listParams = buildList(stripEnabled(input)); const queryKey = resolvedQueryKeys.list(listParams); if (shouldSkipPrefetch({ queryClient, queryKey, cacheOptions: prefetchCacheOptions, skipIfCached, skipMode })) return; await queryClient.prefetchQuery({ queryKey, queryFn: ({ signal })=>getList(listParams, signal), ...prefetchCacheOptions }); }; const delayedPrefetch = (input, delay = defaultDelay, prefetchId)=>{ const listParams = buildList(stripEnabled(input)); const queryKey = resolvedQueryKeys.list(listParams); const id = prefetchId ?? JSON.stringify(queryKey); return schedulePrefetch(()=>prefetchList(input), id, delay); }; return { prefetchList, delayedPrefetch, cancelPrefetch }; } function usePrefetchDetail(options) { const queryClient = useQueryClient(); const { schedulePrefetch, cancelPrefetch } = useDelayedPrefetchController(); const cacheStrategy = options?.cacheStrategy ?? defaultCacheStrategy; const defaultDelay = options?.defaultDelay ?? 400; const skipIfCached = options?.skipIfCached ?? true; const skipMode = options?.skipMode ?? "fresh"; const prefetchCacheOptions = getPrefetchCacheOptions(resolvedCacheConfig, cacheStrategy); const prefetchDetail = async (input)=>{ if (!input.id) return; const detailParams = buildDetail(stripEnabled(input)); const queryKey = resolvedQueryKeys.detail(detailParams); if (shouldSkipPrefetch({ queryClient, queryKey, cacheOptions: prefetchCacheOptions, skipIfCached, skipMode })) return; await queryClient.prefetchQuery({ queryKey, queryFn: ({ signal })=>getDetail(detailParams, signal), ...prefetchCacheOptions }); }; const delayedPrefetch = (input, delay = defaultDelay, prefetchId)=>{ const detailParams = buildDetail(stripEnabled(input)); const queryKey = resolvedQueryKeys.detail(detailParams); const id = prefetchId ?? JSON.stringify(queryKey); return schedulePrefetch(()=>prefetchDetail(input), id, delay); }; return { prefetchDetail, delayedPrefetch, cancelPrefetch }; } return { useList, useSuspenseList, useDetail, useSuspenseDetail, usePrefetchList, usePrefetchDetail }; } export { createSimpleListDetailHooks };