Skip to content

Instantly share code, notes, and snippets.

@isaac-martin
Last active May 6, 2020 20:56
Show Gist options
  • Save isaac-martin/999df3eb6afac0dc5c4ae6330e27c9b2 to your computer and use it in GitHub Desktop.
Save isaac-martin/999df3eb6afac0dc5c4ae6330e27c9b2 to your computer and use it in GitHub Desktop.
import React, { useState, useEffect, useContext } from "react";
import { Checkout } from "shopify-storefront-api-typings";
import Client from "shopify-buy";
const SHOPIFY_CHECKOUT_STORAGE_KEY = "shopify_checkout_id";
const storefrontAccessToken = process.env.GASTBY_SHOPIFY_ACCESS_TOKEN as string;
const client = Client.buildClient({
storefrontAccessToken,
domain: `${process.env.GATSBY_SHOP_NAME}.myshopify.com`
});
interface InitialStore {
client: ShopifyBuy.Client;
isAdding: boolean;
cartIsOpen: boolean;
navIsOpen: boolean;
checkout: Checkout;
}
const initialStoreState: InitialStore = {
client,
isAdding: false,
cartIsOpen: false,
navIsOpen: false,
checkout: {} as Checkout
};
const StoreContext = React.createContext({
store: initialStoreState,
setStore: () => null
});
const createNewCheckout = (store): Checkout => {
return store.client.checkout.create();
};
const fetchCheckout = (store, id): Checkout => store.client.checkout.fetch(id);
const setCheckoutInState = (checkout, setStore) => {
const isBrowser = typeof window !== "undefined";
if (isBrowser) {
localStorage.setItem(SHOPIFY_CHECKOUT_STORAGE_KEY, checkout.id);
}
setStore(prevState => {
return { ...prevState, checkout };
});
};
const StoreContextProvider: React.FC<> = ({ children }) => {
const [store, setStore] = useState<InitialStore>(initialStoreState);
const [initStore, setInitStore] = useState<Boolean>(false);
useEffect(() => {
if (!initStore) {
const initializeCheckout = async () => {
// Check for an existing cart.
const isBrowser = typeof window !== "undefined";
const existingCheckoutId = isBrowser
? localStorage.getItem(SHOPIFY_CHECKOUT_STORAGE_KEY)
: null;
if (existingCheckoutId) {
try {
const checkout = await fetchCheckout(store, existingCheckoutId);
// Make sure this cart hasn’t already been purchased.
console.log("sup checkout?", checkout);
if (!checkout.completedAt) {
setCheckoutInState(checkout, setStore);
return;
}
} catch (e) {
localStorage.setItem(SHOPIFY_CHECKOUT_STORAGE_KEY, "null");
}
}
const newCheckout = await createNewCheckout(store);
setCheckoutInState(newCheckout, setStore);
};
initializeCheckout();
setInitStore(true);
}
}, [store, setStore, store.client.checkout, initStore]);
return (
<StoreContext.Provider
value={{
store,
setStore
}}
>
{children}
</StoreContext.Provider>
);
};
const useStore = () => {
const { store } = useContext(StoreContext);
return store;
};
const useCartCount = (): Number => {
const {
store: { checkout }
} = useContext(StoreContext);
const count = checkout.lineItems.edges.reduce(
(runningTotal, item) => item.node.quantity + runningTotal,
0
);
return count;
};
const useCartTotals = () => {
const {
store: { checkout }
} = useContext(StoreContext);
const tax = checkout.totalTaxV2
? `$${Number(checkout.totalTaxV2.amount).toFixed(2)}`
: "-";
const total = checkout.totalPriceV2
? `$${Number(checkout.totalPriceV2.amount).toFixed(2)}`
: "-";
return {
tax,
total
};
};
const useCartItems = () => {
const {
store: { checkout }
} = useContext(StoreContext);
return checkout.lineItems;
};
const useAddItemToCart = () => {
const {
store: { checkout, client },
setStore
} = useContext(StoreContext);
async function addItemToCart(
variantId: string,
quantity: number,
attributes: []
) {
console.log(variantId, quantity);
if (variantId === "" || !quantity) {
console.error("Both a size and quantity are required.");
return;
}
setStore(prevState => {
return { ...prevState, isAdding: true };
});
const checkoutId = checkout.id;
const lineItemsToAdd = [
{ variantId, quantity, customAttributes: attributes }
];
const newCheckout = await client.checkout.addLineItems(
checkoutId,
lineItemsToAdd
);
setStore(prevState => {
return { ...prevState, checkout: newCheckout, isAdding: false };
});
}
return addItemToCart;
};
const useRemoveItemFromCart = () => {
const {
store: { client, checkout },
setStore
} = useContext(StoreContext);
async function removeItemFromCart(itemId) {
const newCheckout = await client.checkout.removeLineItems(checkout.id, [
itemId
]);
setStore(prevState => {
return { ...prevState, cart: newCheckout };
});
}
return removeItemFromCart;
};
const useCheckout = () => {
const {
store: { checkout }
} = useContext(StoreContext);
return () => {
window.open(checkout.webUrl);
};
};
const useToggleCart = () => {
const {
store: { cartIsOpen },
setStore
} = useContext(StoreContext);
async function toggleCart() {
setStore(prevState => {
return { ...prevState, cartIsOpen: !cartIsOpen };
});
}
return toggleCart;
};
export {
StoreContextProvider,
useAddItemToCart,
useStore,
useCartCount,
useCartItems,
useCartTotals,
useRemoveItemFromCart,
useCheckout,
useToggleCart
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment