4
0
forked from crowetic/commerce
This commit is contained in:
cond0r 2021-02-08 09:15:20 +02:00
parent 1384a88440
commit 0dad4ddedb
14 changed files with 75 additions and 95 deletions

View File

@ -7,7 +7,7 @@ import {
SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE, SHOPIFY_CHECKOUT_URL_COOKIE,
SHOPIFY_CUSTOMER_TOKEN_COOKIE, SHOPIFY_CUSTOMER_TOKEN_COOKIE,
} from '@framework/const' } from '@framework/config'
import { getConfig } from '..' import { getConfig } from '..'
import associateCustomerWithCheckoutMutation from '@framework/utils/mutations/associate-customer-with-checkout' import associateCustomerWithCheckoutMutation from '@framework/utils/mutations/associate-customer-with-checkout'

View File

@ -1,27 +1,16 @@
import type { CommerceAPIConfig } from '@commerce/api' import type { CommerceAPIConfig } from '@commerce/api'
import { import {
API_URL,
API_TOKEN,
SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CUSTOMER_TOKEN_COOKIE, SHOPIFY_CUSTOMER_TOKEN_COOKIE,
} from '@framework/const' } from '@framework/config'
import fetchGraphqlApi from '../utils/fetch-graphql-api'
import fetchGraphqlApi from './utils/fetch-graphql-api'
export interface ShopifyConfig extends CommerceAPIConfig {} 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 { export class Config {
private config: ShopifyConfig private config: ShopifyConfig
@ -41,13 +30,11 @@ export class Config {
} }
} }
const ONE_DAY = 60 * 60 * 24
const config = new Config({ const config = new Config({
commerceUrl: API_URL, commerceUrl: API_URL,
apiToken: API_TOKEN, apiToken: API_TOKEN!,
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
cartCookieMaxAge: ONE_DAY * 30, cartCookieMaxAge: 60 * 60 * 24 * 30,
fetch: fetchGraphqlApi, fetch: fetchGraphqlApi,
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE, customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
}) })

View File

@ -1,10 +1,10 @@
import type { GraphQLFetcher } from '@commerce/api' import type { GraphQLFetcher } from '@commerce/api'
import { FetcherError } from '@commerce/utils/errors'
import fetch from './fetch' 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( throw new Error(
`The environment variable NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN is missing and it's required to access your store` `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) { if (errors) {
throw new FetcherError({ throw getError(errors, status)
errors: json.errors ?? [{ message: 'Failed to fetch Shopify API' }],
status: res.status,
})
} }
return { data: json.data, res } return { data: data, res }
} }
export default fetchGraphqlApi export default fetchGraphqlApi

View File

@ -1,3 +1,2 @@
import zeitFetch from '@vercel/fetch' import zeitFetch from '@vercel/fetch'
export default zeitFetch() export default zeitFetch()

View File

@ -1,5 +1,4 @@
import { useCallback } from 'react' import { useCallback } from 'react'
import { CommerceError } from '@commerce/utils/errors'
import useCart from './use-cart' import useCart from './use-cart'
import useCartAddItem, { import useCartAddItem, {
AddItemInput as UseAddItemInput, AddItemInput as UseAddItemInput,
@ -47,7 +46,7 @@ export function extendHook(customFetcher: typeof fetcher) {
quantity: input.quantity ?? 1, quantity: input.quantity ?? 1,
}, },
], ],
checkoutId: getCheckoutId(cart?.id), checkoutId: getCheckoutId(cart?.id)!,
}) })
await mutate(data, false) await mutate(data, false)
return data return data

View File

@ -44,7 +44,7 @@ export function extendHook(
) { ) {
const useCart = () => { const useCart = () => {
const response = useCommerceCart(defaultOpts, [], customFetcher, { const response = useCommerceCart(defaultOpts, [], customFetcher, {
revalidateOnFocus: false, revalidateOnFocus: true,
...swrOptions, ...swrOptions,
}) })
const res = useResponse(response, { const res = useResponse(response, {

View File

@ -1,7 +1,7 @@
import { import {
SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE, SHOPIFY_CHECKOUT_URL_COOKIE,
} from '@framework/const' } from '@framework/config'
import checkoutCreateMutation from '@framework/utils/mutations/checkout-create' import checkoutCreateMutation from '@framework/utils/mutations/checkout-create'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'

View File

@ -7,13 +7,8 @@ const checkoutToCart = (checkoutResponse?: {
checkout: Checkout checkout: Checkout
userErrors?: UserError[] userErrors?: UserError[]
}): Maybe<Cart> => { }): Maybe<Cart> => {
if (!checkoutResponse) { const checkout = checkoutResponse?.checkout
throw new CommerceError({ const userErrors = checkoutResponse?.userErrors
message: 'Missing checkout details from response cart Response',
})
}
const { checkout, userErrors } = checkoutResponse
if (userErrors && userErrors.length) { if (userErrors && userErrors.length) {
throw new ValidationError({ throw new ValidationError({
@ -22,7 +17,7 @@ const checkoutToCart = (checkoutResponse?: {
} }
if (!checkout) { if (!checkout) {
throw new ValidationError({ throw new CommerceError({
message: 'Missing checkout details from response cart Response', message: 'Missing checkout details from response cart Response',
}) })
} }

View File

@ -1,6 +1,17 @@
import { CommerceError, FetcherError } from '@commerce/utils/errors'
import { SHOPIFY_CHECKOUT_ID_COOKIE } from './const'
import type { CommerceConfig } from '@commerce' 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 = { export type ShopifyConfig = {
locale: string locale: string
@ -8,52 +19,21 @@ export type ShopifyConfig = {
storeDomain: string | undefined storeDomain: string | undefined
} & CommerceConfig } & 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 = { const shopifyConfig: ShopifyConfig = {
locale: 'en-us', locale: 'en-us',
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
storeDomain: STORE_DOMAIN, storeDomain: STORE_DOMAIN,
async fetcher({ method = 'POST', query, variables }) { async fetcher({ method = 'POST', query, variables }) {
const res = await fetch(API_URL, { return handleFetchResponse(
method, await fetch(API_URL, {
body: JSON.stringify({ query, variables }), method,
headers: { body: JSON.stringify({ query, variables }),
'X-Shopify-Storefront-Access-Token': API_TOKEN!, headers: {
'Content-Type': 'application/json', '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)
}, },
} }

View File

@ -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'

View File

@ -1,5 +1,5 @@
import { ReactNode } from 'react'
import * as React from 'react' import * as React from 'react'
import { ReactNode } from 'react'
import { import {
CommerceProvider as CoreCommerceProvider, CommerceProvider as CoreCommerceProvider,
@ -7,7 +7,6 @@ import {
} from '@commerce' } from '@commerce'
import shopifyConfig, { ShopifyConfig } from './config' import shopifyConfig, { ShopifyConfig } from './config'
export type ShopifyProps = { export type ShopifyProps = {
children?: ReactNode children?: ReactNode
locale: string locale: string

View File

@ -1,5 +1,5 @@
import Cookies from 'js-cookie' 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) export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE)

View File

@ -1,5 +1,5 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { SHOPIFY_CHECKOUT_ID_COOKIE } from '../const' import { SHOPIFY_CHECKOUT_ID_COOKIE } from '../config'
const getCheckoutId = (id?: string) => { const getCheckoutId = (id?: string) => {
return id ?? Cookies.get(SHOPIFY_CHECKOUT_ID_COOKIE) return id ?? Cookies.get(SHOPIFY_CHECKOUT_ID_COOKIE)

View File

@ -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