@techsio/storefront-data
Version:
Medusa-first storefront data layer built on TanStack Query.
191 lines (190 loc) • 7.48 kB
JavaScript
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 };