diff --git a/framework/shopify/api/checkout/index.ts b/framework/shopify/api/checkout/index.ts index 638dc20ee..344be62d6 100644 --- a/framework/shopify/api/checkout/index.ts +++ b/framework/shopify/api/checkout/index.ts @@ -7,7 +7,7 @@ import { SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_URL_COOKIE, SHOPIFY_CUSTOMER_TOKEN_COOKIE, -} from '@framework/const' +} from '@framework/config' import { getConfig } from '..' import associateCustomerWithCheckoutMutation from '@framework/utils/mutations/associate-customer-with-checkout' diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts index 273c43c8b..d246829ff 100644 --- a/framework/shopify/api/index.ts +++ b/framework/shopify/api/index.ts @@ -1,27 +1,16 @@ import type { CommerceAPIConfig } from '@commerce/api' + import { + API_URL, + API_TOKEN, SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CUSTOMER_TOKEN_COOKIE, -} from '@framework/const' -import fetchGraphqlApi from '../utils/fetch-graphql-api' +} from '@framework/config' + +import fetchGraphqlApi from './utils/fetch-graphql-api' export interface ShopifyConfig extends CommerceAPIConfig {} -const API_URL = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN -const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN - -if (!API_URL) { - throw new Error( - `The environment variable NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN is missing and it's required to access your store` - ) -} - -if (!API_TOKEN) { - throw new Error( - `The environment variable NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN is missing and it's required to access your store` - ) -} - export class Config { private config: ShopifyConfig @@ -41,13 +30,11 @@ export class Config { } } -const ONE_DAY = 60 * 60 * 24 - const config = new Config({ commerceUrl: API_URL, - apiToken: API_TOKEN, + apiToken: API_TOKEN!, cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, - cartCookieMaxAge: ONE_DAY * 30, + cartCookieMaxAge: 60 * 60 * 24 * 30, fetch: fetchGraphqlApi, customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE, }) diff --git a/framework/shopify/utils/fetch-graphql-api.ts b/framework/shopify/api/utils/fetch-graphql-api.ts similarity index 69% rename from framework/shopify/utils/fetch-graphql-api.ts rename to framework/shopify/api/utils/fetch-graphql-api.ts index b552a7f18..8ff4b27b7 100644 --- a/framework/shopify/utils/fetch-graphql-api.ts +++ b/framework/shopify/api/utils/fetch-graphql-api.ts @@ -1,10 +1,10 @@ import type { GraphQLFetcher } from '@commerce/api' -import { FetcherError } from '@commerce/utils/errors' import fetch from './fetch' -import { STORE_DOMAIN, API_URL, API_TOKEN } from '../config' +import { API_URL, API_TOKEN } from '../../config' +import { getError } from '@framework/utils/handle-fetch-response' -if (!STORE_DOMAIN) { +if (!API_URL) { throw new Error( `The environment variable NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN is missing and it's required to access your store` ) @@ -35,15 +35,12 @@ const fetchGraphqlApi: GraphQLFetcher = async ( }), }) - const json = await res.json() + const { data, errors, status } = await res.json() - if (json.errors) { - throw new FetcherError({ - errors: json.errors ?? [{ message: 'Failed to fetch Shopify API' }], - status: res.status, - }) + if (errors) { + throw getError(errors, status) } - return { data: json.data, res } + return { data: data, res } } export default fetchGraphqlApi diff --git a/framework/shopify/utils/fetch.ts b/framework/shopify/api/utils/fetch.ts similarity index 98% rename from framework/shopify/utils/fetch.ts rename to framework/shopify/api/utils/fetch.ts index 9d9fff3ed..0b8367102 100644 --- a/framework/shopify/utils/fetch.ts +++ b/framework/shopify/api/utils/fetch.ts @@ -1,3 +1,2 @@ import zeitFetch from '@vercel/fetch' - export default zeitFetch() diff --git a/framework/shopify/cart/use-add-item.tsx b/framework/shopify/cart/use-add-item.tsx index 313bffde7..b5b34adc3 100644 --- a/framework/shopify/cart/use-add-item.tsx +++ b/framework/shopify/cart/use-add-item.tsx @@ -1,5 +1,4 @@ import { useCallback } from 'react' -import { CommerceError } from '@commerce/utils/errors' import useCart from './use-cart' import useCartAddItem, { AddItemInput as UseAddItemInput, @@ -47,7 +46,7 @@ export function extendHook(customFetcher: typeof fetcher) { quantity: input.quantity ?? 1, }, ], - checkoutId: getCheckoutId(cart?.id), + checkoutId: getCheckoutId(cart?.id)!, }) await mutate(data, false) return data diff --git a/framework/shopify/cart/use-cart.tsx b/framework/shopify/cart/use-cart.tsx index a4b92786f..a04c30def 100644 --- a/framework/shopify/cart/use-cart.tsx +++ b/framework/shopify/cart/use-cart.tsx @@ -44,7 +44,7 @@ export function extendHook( ) { const useCart = () => { const response = useCommerceCart(defaultOpts, [], customFetcher, { - revalidateOnFocus: false, + revalidateOnFocus: true, ...swrOptions, }) const res = useResponse(response, { diff --git a/framework/shopify/cart/utils/checkout-create.ts b/framework/shopify/cart/utils/checkout-create.ts index 24d080551..17377e7f5 100644 --- a/framework/shopify/cart/utils/checkout-create.ts +++ b/framework/shopify/cart/utils/checkout-create.ts @@ -1,7 +1,7 @@ import { SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_URL_COOKIE, -} from '@framework/const' +} from '@framework/config' import checkoutCreateMutation from '@framework/utils/mutations/checkout-create' import Cookies from 'js-cookie' diff --git a/framework/shopify/cart/utils/checkout-to-cart.ts b/framework/shopify/cart/utils/checkout-to-cart.ts index b38738e2f..4c64d23e6 100644 --- a/framework/shopify/cart/utils/checkout-to-cart.ts +++ b/framework/shopify/cart/utils/checkout-to-cart.ts @@ -7,13 +7,8 @@ const checkoutToCart = (checkoutResponse?: { checkout: Checkout userErrors?: UserError[] }): Maybe => { - if (!checkoutResponse) { - throw new CommerceError({ - message: 'Missing checkout details from response cart Response', - }) - } - - const { checkout, userErrors } = checkoutResponse + const checkout = checkoutResponse?.checkout + const userErrors = checkoutResponse?.userErrors if (userErrors && userErrors.length) { throw new ValidationError({ @@ -22,7 +17,7 @@ const checkoutToCart = (checkoutResponse?: { } if (!checkout) { - throw new ValidationError({ + throw new CommerceError({ message: 'Missing checkout details from response cart Response', }) } diff --git a/framework/shopify/config.ts b/framework/shopify/config.ts index 66f2b4bc8..2444f6033 100644 --- a/framework/shopify/config.ts +++ b/framework/shopify/config.ts @@ -1,6 +1,17 @@ -import { CommerceError, FetcherError } from '@commerce/utils/errors' -import { SHOPIFY_CHECKOUT_ID_COOKIE } from './const' import type { CommerceConfig } from '@commerce' +import handleFetchResponse from './utils/handle-fetch-response' + +export const SHOPIFY_CHECKOUT_ID_COOKIE = 'shopify_checkoutId' + +export const SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl' + +export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken' + +export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN + +export const API_URL = `https://${STORE_DOMAIN}/api/2021-01/graphql.json` + +export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN export type ShopifyConfig = { locale: string @@ -8,52 +19,21 @@ export type ShopifyConfig = { storeDomain: string | undefined } & CommerceConfig -export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN -export const API_URL = `https://${STORE_DOMAIN}/api/2021-01/graphql.json` -export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN - -async function getText(res: Response) { - try { - return (await res.text()) || res.statusText - } catch (error) { - return res.statusText - } -} - -async function getError(res: Response) { - if (res.headers.get('Content-Type')?.includes('application/json')) { - const data = await res.json() - return new FetcherError({ errors: data.errors, status: res.status }) - } - return new FetcherError({ message: await getText(res), status: res.status }) -} - const shopifyConfig: ShopifyConfig = { locale: 'en-us', cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, storeDomain: STORE_DOMAIN, async fetcher({ method = 'POST', query, variables }) { - const res = await fetch(API_URL, { - method, - body: JSON.stringify({ query, variables }), - headers: { - 'X-Shopify-Storefront-Access-Token': API_TOKEN!, - 'Content-Type': 'application/json', - }, - }) - - if (res.ok) { - const { data, errors } = await res.json() - - if (errors && errors.length) { - throw new CommerceError({ - message: errors[0].message, - }) - } - return data - } - - throw await getError(res) + return handleFetchResponse( + await fetch(API_URL, { + method, + body: JSON.stringify({ query, variables }), + headers: { + 'X-Shopify-Storefront-Access-Token': API_TOKEN!, + 'Content-Type': 'application/json', + }, + }) + ) }, } diff --git a/framework/shopify/const.ts b/framework/shopify/const.ts deleted file mode 100644 index aa8291c02..000000000 --- a/framework/shopify/const.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const SHOPIFY_CHECKOUT_ID_COOKIE = 'shopify_checkoutId' -export const SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl' -export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken' diff --git a/framework/shopify/index.tsx b/framework/shopify/index.tsx index ad54ec6ab..0d6f9fca9 100644 --- a/framework/shopify/index.tsx +++ b/framework/shopify/index.tsx @@ -1,5 +1,5 @@ -import { ReactNode } from 'react' import * as React from 'react' +import { ReactNode } from 'react' import { CommerceProvider as CoreCommerceProvider, @@ -7,7 +7,6 @@ import { } from '@commerce' import shopifyConfig, { ShopifyConfig } from './config' - export type ShopifyProps = { children?: ReactNode locale: string diff --git a/framework/shopify/utils/customer-token.ts b/framework/shopify/utils/customer-token.ts index c78a07c44..119f465b5 100644 --- a/framework/shopify/utils/customer-token.ts +++ b/framework/shopify/utils/customer-token.ts @@ -1,5 +1,5 @@ import Cookies from 'js-cookie' -import { SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '@framework/const' +import { SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '@framework/config' export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE) diff --git a/framework/shopify/utils/get-checkout-id.ts b/framework/shopify/utils/get-checkout-id.ts index 11e3802d9..623cf9577 100644 --- a/framework/shopify/utils/get-checkout-id.ts +++ b/framework/shopify/utils/get-checkout-id.ts @@ -1,5 +1,5 @@ import Cookies from 'js-cookie' -import { SHOPIFY_CHECKOUT_ID_COOKIE } from '../const' +import { SHOPIFY_CHECKOUT_ID_COOKIE } from '../config' const getCheckoutId = (id?: string) => { return id ?? Cookies.get(SHOPIFY_CHECKOUT_ID_COOKIE) diff --git a/framework/shopify/utils/handle-fetch-response.ts b/framework/shopify/utils/handle-fetch-response.ts new file mode 100644 index 000000000..8d7427d91 --- /dev/null +++ b/framework/shopify/utils/handle-fetch-response.ts @@ -0,0 +1,27 @@ +import { FetcherError } from '@commerce/utils/errors' + +export function getError(errors: any[], status: number) { + errors = errors ?? [{ message: 'Failed to fetch Shopify API' }] + return new FetcherError({ errors, status }) +} + +export async function getAsyncError(res: Response) { + const data = await res.json() + return getError(data.errors, res.status) +} + +const handleFetchResponse = async (res: Response) => { + if (res.ok) { + const { data, errors } = await res.json() + + if (errors && errors.length) { + throw getError(errors, res.status) + } + + return data + } + + throw await getAsyncError(res) +} + +export default handleFetchResponse