diff --git a/lib/context.js b/lib/context.js index 69fa8c5..5f30e32 100644 --- a/lib/context.js +++ b/lib/context.js @@ -1,68 +1,68 @@ -import { Base64 } from 'base64-string'; -import { createContext, useContext, useState } from 'react'; +import { Base64 } from 'base64-string' +import { createContext, useContext, useState } from 'react' // get our API clients (shopify + sanity) -import { getSanityClient } from '@lib/sanity'; -import shopify from '@lib/shopify'; +import { getSanityClient } from '@lib/sanity' +import shopify from '@lib/shopify' // get our global image GROQ -import { queries } from '@data'; +import { queries } from '@data' // Set our initial context states const initialContext = { - isPageTransition: false, - meganav: { - isOpen: false, - activeID: null, - }, - productCounts: [], - shopifyClient: shopify, - isLoading: true, - isAdding: false, - isUpdating: false, - isCartOpen: false, - checkout: { - id: null, - lineItems: [], - }, - cart: {}, -}; + isPageTransition: false, + meganav: { + isOpen: false, + activeID: null, + }, + productCounts: [], + shopifyClient: shopify, + isLoading: true, + isAdding: false, + isUpdating: false, + isCartOpen: false, + checkout: { + id: null, + lineItems: [], + }, + cart: {}, +} // Set context const SiteContext = createContext({ - context: initialContext, - setContext: () => null, -}); + context: initialContext, + setContext: () => null, +}) // set Shopify variables -const shopifyCartID = 'shopify_checkout_id'; -const shopifyVariantGID = 'gid://shopify/ProductVariant/'; +const shopifyCartID = 'shopify_checkout_id' +const shopifyVariantGID = 'gid://shopify/ProductVariant/' // Set ShopifyGraphQL as a function so we can reuse it async function shopifyGraphQL(query, variables) { - try { - const res = await fetch( - `https://${process.env.NEXT_PUBLIC_SHOPIFY_STORE_ID}.myshopify.com/api/2023-10/graphql.json`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Shopify-Storefront-Access-Token': - process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_API_TOKEN, - }, - body: JSON.stringify({ - query: query, - variables: variables ?? null, - }), - }, - ); - - const data = await res.json(); - return data; - } catch (error) { - console.error(error); - return ''; - } + try { + const res = await fetch( + `https://${process.env.NEXT_PUBLIC_SHOPIFY_STORE_ID}.myshopify.com/api/2023-10/graphql.json`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Shopify-Storefront-Access-Token': + process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_API_TOKEN, + }, + body: JSON.stringify({ + query: query, + variables: variables ?? null, + }), + } + ) + + const data = await res.json() + return data + } catch (error) { + console.error(error) + return '' + } } // defining what the query returns for the product so that we can easily reuse it const product = `product { @@ -77,12 +77,12 @@ const product = `product { } } } - }`; + }` // Build a new checkout const createNewCart = async (context) => { - // GraphQL query to create a cart - const query = `mutation { + // GraphQL query to create a cart + const query = `mutation { cartCreate(input: {lines: []}) { cart { id @@ -94,20 +94,20 @@ const createNewCart = async (context) => { } } } -}`; - const queryResponse = await shopifyGraphQL(query); - const cart = queryResponse.data.cartCreate; +}` + const queryResponse = await shopifyGraphQL(query) + const cart = queryResponse.data.cartCreate - // Update our global store states - setCartState(cart); + // Update our global store states + setCartState(cart) - return; -}; + return +} // Get Shopify checkout cart const fetchCart = async (context, id) => { - // GraphQL query to fetch a cart - const query = `{ + // GraphQL query to fetch a cart + const query = `{ cart(id: "${id}") { id checkoutUrl @@ -131,18 +131,18 @@ const fetchCart = async (context, id) => { } } } -}`; - const queryResponse = await shopifyGraphQL(query); - const cart = queryResponse.data; - // Update our global store states - setCartState(cart); - return; -}; +}` + const queryResponse = await shopifyGraphQL(query) + const cart = queryResponse.data + // Update our global store states + setCartState(cart) + return +} // get associated variant from Sanity const fetchVariant = async (id) => { - const variant = await getSanityClient().fetch( - ` + const variant = await getSanityClient().fetch( + ` *[_type == "productVariant" && variantID == ${id}][0]{ "product": *[_type == "product" && productID == ^.productID][0]{ title, @@ -165,71 +165,71 @@ const fetchVariant = async (id) => { value } } - `, - ); + ` + ) - return variant; -}; + return variant +} // set our checkout states const setCartState = async (cart, checkout, setContext, openCart) => { - if (!checkout && !cart) return null; - - if (typeof window !== `undefined`) { - localStorage.setItem(shopifyCartID, cart.id); - } - - // get real lineItems data from Sanity - const lineItems = cart?.lines - ? await Promise.all( - cart.lines.edges.map(async (edge) => { - const variantID = edge.node.merchandise.id.replace( - shopifyVariantGID, - '', - ); - const variant = await fetchVariant(variantID); - - return { - ...variant, - quantity: edge.node.quantity, - lineID: edge.node.id, - }; - }), - ) - : []; - - // update state - setContext((prevState) => { - return { - ...prevState, - isAdding: false, - isLoading: false, - isUpdating: false, - isCartOpen: openCart ? true : prevState.isCartOpen, - checkout: { - id: checkout.id, - webUrl: checkout.webUrl, - }, - cart: cart, - }; - }); -}; + if (!checkout && !cart) return null + + if (typeof window !== `undefined`) { + localStorage.setItem(shopifyCartID, cart.id) + } + + // get real lineItems data from Sanity + const lineItems = cart?.lines + ? await Promise.all( + cart.lines.edges.map(async (edge) => { + const variantID = edge.node.merchandise.id.replace( + shopifyVariantGID, + '' + ) + const variant = await fetchVariant(variantID) + + return { + ...variant, + quantity: edge.node.quantity, + lineID: edge.node.id, + } + }) + ) + : [] + + // update state + setContext((prevState) => { + return { + ...prevState, + isAdding: false, + isLoading: false, + isUpdating: false, + isCartOpen: openCart ? true : prevState.isCartOpen, + checkout: { + id: checkout.id, + webUrl: checkout.webUrl, + }, + cart: cart, + } + }) +} /* ------------------------------ */ /* Our Context Wrapper /* ------------------------------ */ const SiteContextProvider = ({ data, children }) => { - const { productCounts } = data; + const { productCounts } = data - const [context, setContext] = useState({ - ...initialContext, - ...{ productCounts }, - }); + const [context, setContext] = useState({ + ...initialContext, + ...{ productCounts }, + }) - const [initContext, setInitContext] = useState(false); + const [initContext, setInitContext] = useState(false) - /* Is the error here? + /* Is the error here? useEffect(() => { // Shopify checkout not build yet if (initContext === false) { @@ -277,58 +277,58 @@ const SiteContextProvider = ({ data, children }) => { }, [initContext, context, setContext, context.shopifyClient?.checkout]); // Needs reviewing */ - return ( - - {children} - - ); -}; + return ( + + {children} + + ) +} // Access our global store states function useSiteContext() { - const { context } = useContext(SiteContext); - return context; + const { context } = useContext(SiteContext) + return context } // Toggle page transition state function useTogglePageTransition() { - const { - context: { isPageTransition }, - setContext, - } = useContext(SiteContext); - - async function togglePageTransition(state) { - setContext((prevState) => { - return { ...prevState, isPageTransition: state }; - }); - } - return togglePageTransition; + const { + context: { isPageTransition }, + setContext, + } = useContext(SiteContext) + + async function togglePageTransition(state) { + setContext((prevState) => { + return { ...prevState, isPageTransition: state } + }) + } + return togglePageTransition } // Toggle Mega Navigation states function useToggleMegaNav() { - const { - context: { meganav }, - setContext, - } = useContext(SiteContext); - - async function toggleMegaNav(state, id = null) { - setContext((prevState) => { - return { - ...prevState, - meganav: { - isOpen: state === 'toggle' ? !meganav.isOpen : state, - activeID: state === 'toggle' && meganav.isOpen ? null : id, - }, - }; - }); - } - return toggleMegaNav; + const { + context: { meganav }, + setContext, + } = useContext(SiteContext) + + async function toggleMegaNav(state, id = null) { + setContext((prevState) => { + return { + ...prevState, + meganav: { + isOpen: state === 'toggle' ? !meganav.isOpen : state, + activeID: state === 'toggle' && meganav.isOpen ? null : id, + }, + } + }) + } + return toggleMegaNav } /* ------------------------------ */ @@ -337,74 +337,74 @@ function useToggleMegaNav() { // Access our cart item count function useCartCount() { - const { - context: { cart }, - } = useContext(SiteContext); + const { + context: { cart }, + } = useContext(SiteContext) - let count = 0; + let count = 0 - if (cart.lines) { - count = cart.lines.edges.forEach((edge) => { - count += edge.node.quantity; - }); - } + if (cart.lines) { + count = cart.lines.edges.forEach((edge) => { + count += edge.node.quantity + }) + } - return count; + return count } // Access our cart totals function useCartTotals() { - const { - context: { cart }, - } = useContext(SiteContext); + const { + context: { cart }, + } = useContext(SiteContext) - // Our GraphQL queries always return this property: - /* + // Our GraphQL queries always return this property: + /* The estimated amount, before taxes and discounts, for the customer to pay at checkout. The checkout charge amount doesn't include any deferred payments that'll be paid at a later date. If the cart has no deferred payments, then the checkout charge amount is equivalent to subtotalAmount. */ - // We might want to use a different key in order to get discount included - // https://shopify.dev/docs/api/storefront/2023-10/objects/CartCost - const subTotal = cart?.cost?.checkoutChargeAmount?.amount - ? cart.cost.checkoutChargeAmount.amount - : false; - return { - subTotal, - }; + // We might want to use a different key in order to get discount included + // https://shopify.dev/docs/api/storefront/2023-10/objects/CartCost + const subTotal = cart?.cost?.checkoutChargeAmount?.amount + ? cart.cost.checkoutChargeAmount.amount + : false + return { + subTotal, + } } // Access our cart items function useCartItems() { - const { - context: { cart }, - } = useContext(SiteContext); + const { + context: { cart }, + } = useContext(SiteContext) - return cart?.lines?.edges; + return cart?.lines?.edges } // Add an item to the checkout cart function useAddItem() { - const { - context: { cart }, - setContext, - } = useContext(SiteContext); - - async function addItem(variantID, quantity, attributes) { - // Bail if no ID or quantity given - if (!variantID || !quantity) return; - - // Otherwise, start adding the product - setContext((prevState) => { - return { ...prevState, isAdding: true, isUpdating: true }; - }); - - // build encoded variantID - const enc = new Base64(); - const variant = enc.urlEncode(`${shopifyVariantGID}${variantID}`); - - // GraphQL query to add items to the cart - const query = `mutation { + const { + context: { cart }, + setContext, + } = useContext(SiteContext) + + async function addItem(variantID, quantity, attributes) { + // Bail if no ID or quantity given + if (!variantID || !quantity) return + + // Otherwise, start adding the product + setContext((prevState) => { + return { ...prevState, isAdding: true, isUpdating: true } + }) + + // build encoded variantID + const enc = new Base64() + const variant = enc.urlEncode(`${shopifyVariantGID}${variantID}`) + + // GraphQL query to add items to the cart + const query = `mutation { cartLinesAdd( cartId: "${cart.id}" lines: [ @@ -442,37 +442,37 @@ function useAddItem() { message } } -}`; - const queryResponse = await shopifyGraphQL(query); - const newCart = queryResponse.data.cartLinesAdd; - console.log(newCart); - const newCheckout = { webUrl: newCart.checkoutUrl }; - - // Update our global store states - setCartState(newCart, newCheckout, setContext, true); - } +}` + const queryResponse = await shopifyGraphQL(query) + const newCart = queryResponse.data.cartLinesAdd + console.log(newCart) + const newCheckout = { webUrl: newCart.checkoutUrl } + + // Update our global store states + setCartState(newCart, newCheckout, setContext, true) + } - return addItem; + return addItem } // Update item in cart function useUpdateItem() { - const { - context: { cart }, - setContext, - } = useContext(SiteContext); - - async function updateItem(itemID, quantity) { - // Bail if no ID or quantity given - if (!itemID || !quantity) return; - - // Otherwise, start adding the product - setContext((prevState) => { - return { ...prevState, isUpdating: true }; - }); - - // GraphQL query to update items in the cart - const query = `mutation { + const { + context: { cart }, + setContext, + } = useContext(SiteContext) + + async function updateItem(itemID, quantity) { + // Bail if no ID or quantity given + if (!itemID || !quantity) return + + // Otherwise, start adding the product + setContext((prevState) => { + return { ...prevState, isUpdating: true } + }) + + // GraphQL query to update items in the cart + const query = `mutation { cartLinesUpdate( cartId: "${cart.id}" lines: [ @@ -510,36 +510,36 @@ function useUpdateItem() { message } } -}`; - const queryResponse = await shopifyGraphQL(query); - const newCart = queryResponse.data.cartLinesUpdate; - console.log(newCart); - const newCheckout = { webUrl: newCart.checkoutUrl }; - - // Update our global store states - setCartState(newCart, newCheckout, setContext, true); - } - return updateItem; +}` + const queryResponse = await shopifyGraphQL(query) + const newCart = queryResponse.data.cartLinesUpdate + console.log(newCart) + const newCheckout = { webUrl: newCart.checkoutUrl } + + // Update our global store states + setCartState(newCart, newCheckout, setContext, true) + } + return updateItem } // Remove item from cart function useRemoveItem() { - const { - context: { cart }, - setContext, - } = useContext(SiteContext); - - async function removeItem(itemID) { - // Bail if no ID given - if (!itemID) return; - - // Otherwise, start removing the product - setContext((prevState) => { - return { ...prevState, isUpdating: true }; - }); - - // GraphQL query to remove items from the cart - const query = `mutation { + const { + context: { cart }, + setContext, + } = useContext(SiteContext) + + async function removeItem(itemID) { + // Bail if no ID given + if (!itemID) return + + // Otherwise, start removing the product + setContext((prevState) => { + return { ...prevState, isUpdating: true } + }) + + // GraphQL query to remove items from the cart + const query = `mutation { cartLinesRemove( cartId: "${cart.id}" lineIds: [ @@ -574,53 +574,53 @@ function useRemoveItem() { message } } -}`; - const queryResponse = await shopifyGraphQL(query); - const newCart = queryResponse.data.cartLinesRemove; - console.log(newCart); - const newCheckout = { webUrl: newCart.checkoutUrl }; - - setCartState(newCart, newCheckout, setContext); - } - return removeItem; +}` + const queryResponse = await shopifyGraphQL(query) + const newCart = queryResponse.data.cartLinesRemove + console.log(newCart) + const newCheckout = { webUrl: newCart.checkoutUrl } + + setCartState(newCart, newCheckout, setContext) + } + return removeItem } // Build our Checkout URL function useCheckout() { - const { - context: { checkout }, - } = useContext(SiteContext); + const { + context: { checkout }, + } = useContext(SiteContext) - return checkout.webUrl; + return checkout.webUrl } // Toggle cart state function useToggleCart() { - const { - context: { isCartOpen }, - setContext, - } = useContext(SiteContext); - - async function toggleCart() { - setContext((prevState) => { - return { ...prevState, isCartOpen: !isCartOpen }; - }); - } - return toggleCart; + const { + context: { isCartOpen }, + setContext, + } = useContext(SiteContext) + + async function toggleCart() { + setContext((prevState) => { + return { ...prevState, isCartOpen: !isCartOpen } + }) + } + return toggleCart } // Reference a collection product count function useProductCount() { - const { - context: { productCounts }, - } = useContext(SiteContext); + const { + context: { productCounts }, + } = useContext(SiteContext) - function productCount(collection) { - const collectionItem = productCounts.find((c) => c.slug === collection); - return collectionItem.count; - } + function productCount(collection) { + const collectionItem = productCounts.find((c) => c.slug === collection) + return collectionItem.count + } - return productCount; + return productCount } export { @@ -637,5 +637,5 @@ export { useToggleMegaNav, useTogglePageTransition, useUpdateItem -}; +}