UNPKG

@shopify/hydrogen-react

Version:

React components, hooks, and utilities for creating custom Shopify storefronts

486 lines (484 loc) • 15.7 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const require$$0 = require("react"); const useCartAPIStateMachine = require("./useCartAPIStateMachine.js"); const cartConstants = require("./cart-constants.js"); const jsxRuntime = require("react/jsx-runtime"); const CartContext = require$$0.createContext(null); function useCart() { const context = require$$0.useContext(CartContext); if (!context) { throw new Error("Expected a Cart Context, but no Cart Context was found"); } return context; } function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLineRemove, onLineUpdate, onNoteUpdate, onBuyerIdentityUpdate, onAttributesUpdate, onDiscountCodesUpdate, onCreateComplete, onLineAddComplete, onLineRemoveComplete, onLineUpdateComplete, onNoteUpdateComplete, onBuyerIdentityUpdateComplete, onAttributesUpdateComplete, onDiscountCodesUpdateComplete, data: cart, cartFragment = defaultCartFragment, customerAccessToken, countryCode = "US" }) { var _a, _b, _c, _d, _e, _f, _g; if (countryCode) countryCode = countryCode.toUpperCase(); const [prevCountryCode, setPrevCountryCode] = require$$0.useState(countryCode); const [prevCustomerAccessToken, setPrevCustomerAccessToken] = require$$0.useState(customerAccessToken); const customerOverridesCountryCode = require$$0.useRef(false); if (prevCountryCode !== countryCode || prevCustomerAccessToken !== customerAccessToken) { setPrevCountryCode(countryCode); setPrevCustomerAccessToken(customerAccessToken); customerOverridesCountryCode.current = false; } const [cartState, cartSend] = useCartAPIStateMachine.useCartAPIStateMachine({ numCartLines, data: cart, cartFragment, countryCode, onCartActionEntry(context, event) { try { switch (event.type) { case "CART_CREATE": return onCreate == null ? void 0 : onCreate(); case "CARTLINE_ADD": return onLineAdd == null ? void 0 : onLineAdd(); case "CARTLINE_REMOVE": return onLineRemove == null ? void 0 : onLineRemove(); case "CARTLINE_UPDATE": return onLineUpdate == null ? void 0 : onLineUpdate(); case "NOTE_UPDATE": return onNoteUpdate == null ? void 0 : onNoteUpdate(); case "BUYER_IDENTITY_UPDATE": return onBuyerIdentityUpdate == null ? void 0 : onBuyerIdentityUpdate(); case "CART_ATTRIBUTES_UPDATE": return onAttributesUpdate == null ? void 0 : onAttributesUpdate(); case "DISCOUNT_CODES_UPDATE": return onDiscountCodesUpdate == null ? void 0 : onDiscountCodesUpdate(); } } catch (error) { console.error("Cart entry action failed", error); } }, onCartActionOptimisticUI(context, event) { var _a2, _b2, _c2, _d2; if (!(context == null ? void 0 : context.cart)) return { cart: void 0 }; switch (event.type) { case "CARTLINE_REMOVE": return { ...context, lastValidCart: context.cart, cart: { ...context.cart, lines: (_b2 = (_a2 = context == null ? void 0 : context.cart) == null ? void 0 : _a2.lines) == null ? void 0 : _b2.filter((line) => (line == null ? void 0 : line.id) && !event.payload.lines.includes(line == null ? void 0 : line.id)) } }; case "CARTLINE_UPDATE": return { ...context, lastValidCart: context.cart, cart: { ...context.cart, lines: (_d2 = (_c2 = context == null ? void 0 : context.cart) == null ? void 0 : _c2.lines) == null ? void 0 : _d2.map((line) => { const updatedLine = event.payload.lines.find(({ id }) => id === (line == null ? void 0 : line.id)); if (updatedLine && updatedLine.quantity) { return { ...line, quantity: updatedLine.quantity }; } return line; }) } }; } return { cart: context.cart ? { ...context.cart } : void 0 }; }, onCartActionComplete(context, event) { const cartActionEvent = event.payload.cartActionEvent; try { switch (event.type) { case "RESOLVE": switch (cartActionEvent.type) { case "CART_CREATE": return onCreateComplete == null ? void 0 : onCreateComplete(); case "CARTLINE_ADD": return onLineAddComplete == null ? void 0 : onLineAddComplete(); case "CARTLINE_REMOVE": return onLineRemoveComplete == null ? void 0 : onLineRemoveComplete(); case "CARTLINE_UPDATE": return onLineUpdateComplete == null ? void 0 : onLineUpdateComplete(); case "NOTE_UPDATE": return onNoteUpdateComplete == null ? void 0 : onNoteUpdateComplete(); case "BUYER_IDENTITY_UPDATE": if (countryCodeNotUpdated(context, cartActionEvent)) { customerOverridesCountryCode.current = true; } return onBuyerIdentityUpdateComplete == null ? void 0 : onBuyerIdentityUpdateComplete(); case "CART_ATTRIBUTES_UPDATE": return onAttributesUpdateComplete == null ? void 0 : onAttributesUpdateComplete(); case "DISCOUNT_CODES_UPDATE": return onDiscountCodesUpdateComplete == null ? void 0 : onDiscountCodesUpdateComplete(); } } } catch (error) { console.error("onCartActionComplete failed", error); } } }); const cartReady = require$$0.useRef(false); const cartCompleted = cartState.matches("cartCompleted"); const countryChanged = (cartState.value === "idle" || cartState.value === "error" || cartState.value === "cartCompleted") && countryCode !== ((_c = (_b = (_a = cartState == null ? void 0 : cartState.context) == null ? void 0 : _a.cart) == null ? void 0 : _b.buyerIdentity) == null ? void 0 : _c.countryCode) && !cartState.context.errors; const fetchingFromStorage = require$$0.useRef(false); require$$0.useEffect(() => { if (!cartReady.current && !fetchingFromStorage.current) { if (!cart && storageAvailable("localStorage")) { fetchingFromStorage.current = true; try { const cartId = window.localStorage.getItem(cartConstants.CART_ID_STORAGE_KEY); if (cartId) { cartSend({ type: "CART_FETCH", payload: { cartId } }); } } catch (error) { console.warn("error fetching cartId"); console.warn(error); } } cartReady.current = true; } }, [cart, cartReady, cartSend]); require$$0.useEffect(() => { if (!countryChanged || customerOverridesCountryCode.current) return; cartSend({ type: "BUYER_IDENTITY_UPDATE", payload: { buyerIdentity: { countryCode, customerAccessToken } } }); }, [countryCode, customerAccessToken, countryChanged, customerOverridesCountryCode, cartSend]); const onCartReadySend = require$$0.useCallback((cartEvent) => { if (!cartReady.current) { return console.warn("Cart isn't ready yet"); } cartSend(cartEvent); }, [cartSend]); require$$0.useEffect(() => { var _a2, _b2, _c2; if (((_b2 = (_a2 = cartState == null ? void 0 : cartState.context) == null ? void 0 : _a2.cart) == null ? void 0 : _b2.id) && storageAvailable("localStorage")) { try { window.localStorage.setItem(cartConstants.CART_ID_STORAGE_KEY, (_c2 = cartState.context.cart) == null ? void 0 : _c2.id); } catch (error) { console.warn("Failed to save cartId to localStorage", error); } } }, [(_e = (_d = cartState == null ? void 0 : cartState.context) == null ? void 0 : _d.cart) == null ? void 0 : _e.id]); require$$0.useEffect(() => { if (cartCompleted && storageAvailable("localStorage")) { try { window.localStorage.removeItem(cartConstants.CART_ID_STORAGE_KEY); } catch (error) { console.warn("Failed to delete cartId from localStorage", error); } } }, [cartCompleted]); const cartCreate = require$$0.useCallback((cartInput) => { var _a2, _b2; if (countryCode && !((_a2 = cartInput.buyerIdentity) == null ? void 0 : _a2.countryCode)) { if (cartInput.buyerIdentity == null) { cartInput.buyerIdentity = {}; } cartInput.buyerIdentity.countryCode = countryCode; } if (customerAccessToken && !((_b2 = cartInput.buyerIdentity) == null ? void 0 : _b2.customerAccessToken)) { if (cartInput.buyerIdentity == null) { cartInput.buyerIdentity = {}; } cartInput.buyerIdentity.customerAccessToken = customerAccessToken; } onCartReadySend({ type: "CART_CREATE", payload: cartInput }); }, [countryCode, customerAccessToken, onCartReadySend]); const cartDisplayState = useDelayedStateUntilHydration(cartState); const cartContextValue = require$$0.useMemo(() => { var _a2, _b2, _c2, _d2, _e2, _f2; return { ...(_b2 = (_a2 = cartDisplayState == null ? void 0 : cartDisplayState.context) == null ? void 0 : _a2.cart) != null ? _b2 : { lines: [], attributes: [] }, status: transposeStatus(cartDisplayState.value), error: (_c2 = cartDisplayState == null ? void 0 : cartDisplayState.context) == null ? void 0 : _c2.errors, totalQuantity: (_f2 = (_e2 = (_d2 = cartDisplayState == null ? void 0 : cartDisplayState.context) == null ? void 0 : _d2.cart) == null ? void 0 : _e2.totalQuantity) != null ? _f2 : 0, cartCreate, linesAdd(lines) { var _a3, _b3; if ((_b3 = (_a3 = cartDisplayState == null ? void 0 : cartDisplayState.context) == null ? void 0 : _a3.cart) == null ? void 0 : _b3.id) { onCartReadySend({ type: "CARTLINE_ADD", payload: { lines } }); } else { cartCreate({ lines }); } }, linesRemove(lines) { onCartReadySend({ type: "CARTLINE_REMOVE", payload: { lines } }); }, linesUpdate(lines) { onCartReadySend({ type: "CARTLINE_UPDATE", payload: { lines } }); }, noteUpdate(note) { onCartReadySend({ type: "NOTE_UPDATE", payload: { note } }); }, buyerIdentityUpdate(buyerIdentity) { onCartReadySend({ type: "BUYER_IDENTITY_UPDATE", payload: { buyerIdentity } }); }, cartAttributesUpdate(attributes) { onCartReadySend({ type: "CART_ATTRIBUTES_UPDATE", payload: { attributes } }); }, discountCodesUpdate(discountCodes) { onCartReadySend({ type: "DISCOUNT_CODES_UPDATE", payload: { discountCodes } }); }, cartFragment }; }, [cartCreate, (_f = cartDisplayState == null ? void 0 : cartDisplayState.context) == null ? void 0 : _f.cart, (_g = cartDisplayState == null ? void 0 : cartDisplayState.context) == null ? void 0 : _g.errors, cartDisplayState.value, cartFragment, onCartReadySend]); return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value: cartContextValue, children }); } function transposeStatus(status) { switch (status) { case "uninitialized": case "initializationError": return "uninitialized"; case "idle": case "cartCompleted": case "error": return "idle"; case "cartFetching": return "fetching"; case "cartCreating": return "creating"; case "cartLineAdding": case "cartLineRemoving": case "cartLineUpdating": case "noteUpdating": case "buyerIdentityUpdating": case "cartAttributesUpdating": case "discountCodesUpdating": return "updating"; } } function useDelayedStateUntilHydration(state) { const [isPending, startTransition] = require$$0.useTransition(); const [delayedState, setDelayedState] = require$$0.useState(state); const firstTimePending = require$$0.useRef(false); if (isPending) { firstTimePending.current = true; } const firstTimePendingFinished = require$$0.useRef(false); if (!isPending && firstTimePending.current) { firstTimePendingFinished.current = true; } require$$0.useEffect(() => { startTransition(() => { if (!firstTimePendingFinished.current) { setDelayedState(state); } }); }, [state]); const displayState = firstTimePendingFinished.current ? state : delayedState; return displayState; } function storageAvailable(type) { let storage; try { storage = window[type]; const x = "__storage_test__"; storage.setItem(x, x); storage.removeItem(x); return true; } catch (e) { return e instanceof DOMException && (e.code === 22 || e.code === 1014 || e.name === "QuotaExceededError" || e.name === "NS_ERROR_DOM_QUOTA_REACHED") && storage && storage.length !== 0; } } function countryCodeNotUpdated(context, event) { var _a, _b; return event.payload.buyerIdentity.countryCode && ((_b = (_a = context.cart) == null ? void 0 : _a.buyerIdentity) == null ? void 0 : _b.countryCode) !== event.payload.buyerIdentity.countryCode; } const defaultCartFragment = ` fragment CartFragment on Cart { id checkoutUrl totalQuantity buyerIdentity { countryCode customer { id email firstName lastName displayName } email phone } lines(first: $numCartLines) { edges { node { id quantity attributes { key value } cost { totalAmount { amount currencyCode } compareAtAmountPerQuantity { amount currencyCode } } merchandise { ... on ProductVariant { id availableForSale compareAtPriceV2 { ...MoneyFragment } priceV2 { ...MoneyFragment } requiresShipping title image { ...ImageFragment } product { handle title } selectedOptions { name value } } } } } } cost { subtotalAmount { ...MoneyFragment } totalAmount { ...MoneyFragment } totalDutyAmount { ...MoneyFragment } totalTaxAmount { ...MoneyFragment } } note attributes { key value } discountCodes { code } } fragment MoneyFragment on MoneyV2 { currencyCode amount } fragment ImageFragment on Image { id url altText width height } `; exports.CartContext = CartContext; exports.CartProvider = CartProvider; exports.defaultCartFragment = defaultCartFragment; exports.storageAvailable = storageAvailable; exports.useCart = useCart; //# sourceMappingURL=CartProvider.js.map