diff --git a/framework/shopify/provider.ts b/framework/shopify/provider.ts deleted file mode 100644 index 7c3a7a14e..000000000 --- a/framework/shopify/provider.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Fetcher, HookHandler } from '@commerce/utils/types' -import { - API_TOKEN, - API_URL, - SHOPIFY_CHECKOUT_ID_COOKIE, - STORE_DOMAIN, -} from './const' -import { normalizeCart } from './lib/normalize' -import { Cart } from './types' - -import handleFetchResponse from './utils/handle-fetch-response' -import { getCheckoutQuery } from './utils/queries' - -const useCart: HookHandler< - Cart | null, - [], - any, - any, - any, - { isEmpty?: boolean } -> = { - fetchOptions: { - query: getCheckoutQuery, - }, - swrOptions: { - revalidateOnFocus: false, - }, - normalizer: normalizeCart, - onResponse(response) { - return Object.create(response, { - isEmpty: { - get() { - return (response.data?.lineItems.length ?? 0) <= 0 - }, - enumerable: true, - }, - }) - }, -} - -const fetcher: Fetcher = async ({ method = 'POST', variables, query }) => { - return handleFetchResponse( - await fetch(API_URL, { - method, - body: JSON.stringify({ query, variables }), - headers: { - 'X-Shopify-Storefront-Access-Token': API_TOKEN!, - 'Content-Type': 'application/json', - }, - }) - ) -} - -export const shopifyProvider = { - locale: 'en-us', - cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, - storeDomain: STORE_DOMAIN, - fetcher, - cartNormalizer: normalizeCart, - cart: { useCart }, -} - -export type ShopifyProvider = typeof shopifyProvider diff --git a/framework/shopify/provider.tsx b/framework/shopify/provider.tsx new file mode 100644 index 000000000..e8770ac97 --- /dev/null +++ b/framework/shopify/provider.tsx @@ -0,0 +1,97 @@ +import { useMemo } from 'react' +import { Fetcher, HookFetcherFn, HookHandler } from '@commerce/utils/types' + +import { + API_TOKEN, + API_URL, + SHOPIFY_CHECKOUT_ID_COOKIE, + STORE_DOMAIN, +} from './const' + +import { Cart } from './types' +import { normalizeCart } from './lib/normalize' +import handleFetchResponse from './utils/handle-fetch-response' +import getCheckoutQuery from './utils/queries/get-checkout-query' +import { FetchCartInput, UseCartInput } from '@commerce/cart/use-cart' +import { checkoutCreate, checkoutToCart } from './cart/utils' + +const fetcher: Fetcher = async ({ method = 'POST', variables, query }) => { + return handleFetchResponse( + await fetch(API_URL, { + method, + body: JSON.stringify({ query, variables }), + headers: { + 'X-Shopify-Storefront-Access-Token': API_TOKEN!, + 'Content-Type': 'application/json', + }, + }) + ) +} + +export const cartFetcher: HookFetcherFn = async ({ + options, + input: { cartId }, + fetch, +}) => { + let checkout + + if (cartId) { + const data = await fetch({ + ...options, + variables: { + cartId, + }, + }) + checkout = data?.node + } + + if (checkout?.completedAt || !cartId) { + checkout = await checkoutCreate(fetch) + } + + return checkoutToCart({ checkout }) +} + +const useCart: HookHandler< + Cart | null, + {}, + any, + any, + any, + { isEmpty?: boolean } +> = { + fetchOptions: { + query: getCheckoutQuery, + }, + fetcher: cartFetcher, + normalizer: normalizeCart, + useHook({ input, useData }) { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input.swrOptions }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} + +export const shopifyProvider = { + locale: 'en-us', + cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, + storeDomain: STORE_DOMAIN, + fetcher, + cartNormalizer: normalizeCart, + cart: { useCart }, +} + +export type ShopifyProvider = typeof shopifyProvider