4
0
forked from crowetic/commerce
Peter Mekhaeil 300d04c1ac
Shopify Provider (#186)
* Start of Shopify provider

* add missing comment to documentation

* add missing env vars to documentation

* update reference to types file
2021-02-12 11:14:16 -03:00

110 lines
2.6 KiB
TypeScript

import React, {
ReactNode,
createContext,
useContext,
useMemo,
useState,
useEffect,
} from 'react'
import Client from 'shopify-buy'
import { Shop, Cart, Client as ClientType } from './types'
import {
getCheckoutIdFromStorage,
setCheckoutIdInStorage,
} from './utils/storage'
import { getConfig } from '@framework/api'
const Commerce = createContext<CommerceContextValue | {}>({})
type CommerceProps = {
children?: ReactNode
locale: string
}
type CommerceContextValue = {
client: ClientType
shop: Shop
checkout: Cart
updateCheckout: (cart: Cart | undefined) => void
currencyCode: string
locale: string
sessionToken: string
}
export function CommerceProvider({
children,
locale = 'en-US',
}: CommerceProps) {
const sessionToken = 'nextjs-commerce-shopify-token'
const config = getConfig()
const client = Client.buildClient({
storefrontAccessToken: config.apiToken,
domain: config.commerceUrl,
language: locale,
}) as ClientType
const [shop, setShop] = useState<Shop>()
const [checkout, setCheckout] = useState<Cart>()
const fetchShopify = async () => {
const shopInfo: Shop = await client.shop.fetchInfo()
let checkoutResource: Cart
const checkoutOptions = {
presentmentCurrencyCode:
/*config.currencyCode ||*/ shopInfo?.currencyCode,
}
let checkoutId = getCheckoutIdFromStorage(sessionToken)
// we could have a cart id stored in session storage
// user could be refreshing or navigating back and forth
if (checkoutId) {
checkoutResource = await client.checkout.fetch(checkoutId)
// could be expired order - we will create a new order
if (checkoutResource.completedAt) {
checkoutResource = await client.checkout.create(checkoutOptions)
}
} else {
checkoutResource = await client.checkout.create(checkoutOptions)
}
setCheckoutIdInStorage(sessionToken, checkoutResource.id)
setShop(shopInfo)
setCheckout(checkoutResource)
}
useEffect(() => {
fetchShopify()
}, [])
const updateCheckout = (newCheckout: Cart) => {
setCheckout(newCheckout)
}
// Because the config is an object, if the parent re-renders this provider
// will re-render every consumer unless we memoize the config
const cfg = useMemo(
() => ({
client,
checkout,
shop,
updateCheckout: updateCheckout,
currencyCode: /*config.currencyCode ||*/ checkout?.currencyCode,
locale,
sessionToken,
}),
[client]
)
return <Commerce.Provider value={cfg}>{children}</Commerce.Provider>
}
export function useCommerce<T extends CommerceContextValue>() {
return useContext(Commerce) as T
}