@shopify/hydrogen-react
Version:
React components, hooks, and utilities for creating custom Shopify storefronts
1 lines • 7.22 kB
Source Map (JSON)
{"version":3,"file":"ShopPayButton.mjs","sources":["../../src/ShopPayButton.tsx"],"sourcesContent":["import {defaultShopifyContext, useShop} from './ShopifyProvider.js';\nimport {useLoadScript} from './load-script.js';\nimport {parseGid} from './analytics-utils.js';\n\n// By using 'never' in the \"or\" cases below, it makes these props \"exclusive\" and means that you cannot pass both of them; you must pass either one OR the other.\ntype ShopPayButtonProps = ShopPayButtonStyleProps &\n ShopPayDomainProps &\n ShopPayChannelAttribution &\n (ShopPayVariantIds | ShopPayVariantAndQuantities);\n\ntype ShopPayButtonStyleProps = {\n /** A string of classes to apply to the `div` that wraps the Shop Pay button. */\n className?: string;\n /** A string that's applied to the [CSS custom property (variable)](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) `--shop-pay-button-width` for the [Buy with Shop Pay component](https://shopify.dev/custom-storefronts/tools/web-components#buy-with-shop-pay-component). */\n width?: string;\n};\n\ntype ShopPayDomainProps = {\n /** The domain of your Shopify storefront URL (eg: `your-store.myshopify.com`). */\n storeDomain?: string;\n};\n\ntype ShopPayVariantIds = {\n /** An array of IDs of the variants to purchase with Shop Pay. This will only ever have a quantity of 1 for each variant. If you want to use other quantities, then use `variantIdsAndQuantities`. */\n variantIds: string[];\n /** An array of variant IDs and quantities to purchase with Shop Pay. */\n variantIdsAndQuantities?: never;\n};\n\ntype ShopPayVariantAndQuantities = {\n /** An array of IDs of the variants to purchase with Shop Pay. This will only ever have a quantity of 1 for each variant. If you want to use other quantities, then use `variantIdsAndQuantities`. */\n variantIds?: never;\n /** An array of variant IDs and quantities to purchase with Shop Pay. */\n variantIdsAndQuantities: Array<{\n id: string;\n quantity: number;\n }>;\n};\n\ntype ShopPayChannelAttribution = {\n /** A string that adds channel attribution to the order. Can be either `headless` or `hydrogen` */\n channel?: 'headless' | 'hydrogen';\n};\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace JSX {\n interface IntrinsicElements {\n 'shop-pay-button': {\n channel?: string;\n variants: string;\n 'store-url': string;\n };\n }\n }\n}\n\nconst SHOPJS_URL =\n 'https://cdn.shopify.com/shopifycloud/shop-js/v1.0/client.js';\n\nfunction isChannel(\n channel: string,\n): channel is Exclude<ShopPayChannelAttribution['channel'], undefined> {\n return channel === 'headless' || channel === 'hydrogen';\n}\n\n/**\n * The `ShopPayButton` component renders a button that redirects to the Shop Pay checkout.\n * It renders a [`<shop-pay-button>`](https://shopify.dev/custom-storefronts/tools/web-components) custom element, for which it will lazy-load the source code automatically.\n * It relies on the `<ShopProvider>` context provider.\n */\nexport function ShopPayButton({\n channel,\n variantIds,\n className,\n variantIdsAndQuantities,\n width,\n storeDomain: _storeDomain,\n}: ShopPayButtonProps): JSX.Element {\n const shop = useShop();\n const storeDomain = _storeDomain || shop?.storeDomain;\n const shopPayLoadedStatus = useLoadScript(SHOPJS_URL);\n\n let ids: string[] = [];\n let channelAttribution: string | undefined;\n\n if (!storeDomain || storeDomain === defaultShopifyContext.storeDomain) {\n throw new Error(MissingStoreDomainErrorMessage);\n }\n\n if (variantIds && variantIdsAndQuantities) {\n throw new Error(DoublePropsErrorMessage);\n }\n\n if (!variantIds && !variantIdsAndQuantities) {\n throw new Error(MissingPropsErrorMessage);\n }\n\n if (channel) {\n if (isChannel(channel)) {\n channelAttribution = channel;\n } else {\n throw new Error(InvalidChannelErrorMessage);\n }\n }\n\n if (variantIds) {\n ids = variantIds.reduce<string[]>((prev, curr) => {\n const bareId = parseGid(curr).id;\n if (bareId) {\n prev.push(bareId);\n }\n return prev;\n }, []);\n } else if (variantIdsAndQuantities) {\n ids = variantIdsAndQuantities.reduce<string[]>((prev, curr) => {\n const bareId = parseGid(curr?.id).id;\n if (bareId) {\n prev.push(`${bareId}:${curr?.quantity ?? 1}`);\n }\n return prev;\n }, []);\n } else {\n throw new Error(MissingPropsErrorMessage);\n }\n\n if (ids.length === 0) {\n throw new Error(InvalidPropsErrorMessage);\n }\n\n const style = width\n ? ({\n '--shop-pay-button-width': width,\n } as React.CSSProperties)\n : undefined;\n\n return (\n <div className={className} style={style}>\n {shopPayLoadedStatus === 'done' && (\n <shop-pay-button\n {...(channelAttribution ? {channel: channelAttribution} : {})}\n store-url={storeDomain}\n variants={ids.join(',')}\n />\n )}\n </div>\n );\n}\n\nexport const MissingStoreDomainErrorMessage =\n 'You must pass a \"storeDomain\" prop to the \"ShopPayButton\" component, or wrap it in a \"ShopifyProvider\" component.';\nexport const InvalidPropsErrorMessage = `You must pass in \"variantIds\" in the form of [\"gid://shopify/ProductVariant/1\"]`;\nexport const MissingPropsErrorMessage = `You must pass in either \"variantIds\" or \"variantIdsAndQuantities\" to ShopPayButton`;\nexport const DoublePropsErrorMessage = `You must provide either a variantIds or variantIdsAndQuantities prop, but not both in the ShopPayButton component`;\nexport const InvalidChannelErrorMessage = `Invalid channel attribution value. Must be either \"headless\" or \"hydrogen\"`;\n"],"names":[],"mappings":";;;;AAyDA,MAAM,aACJ;AAEF,SAAS,UACP,SACqE;AACrE,SAAO,YAAY,cAAc,YAAY;AAC/C;AAOO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAAoC;AAClC,QAAM,OAAO,QAAA;AACb,QAAM,cAAc,iBAAgB,6BAAM;AAC1C,QAAM,sBAAsB,cAAc,UAAU;AAEpD,MAAI,MAAgB,CAAA;AACpB,MAAI;AAEJ,MAAI,CAAC,eAAe,gBAAgB,sBAAsB,aAAa;AACrE,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAEA,MAAI,cAAc,yBAAyB;AACzC,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAEA,MAAI,CAAC,cAAc,CAAC,yBAAyB;AAC3C,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,MAAI,SAAS;AACX,QAAI,UAAU,OAAO,GAAG;AACtB,2BAAqB;AAAA,IACvB,OAAO;AACL,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAAA,EACF;AAEA,MAAI,YAAY;AACd,UAAM,WAAW,OAAiB,CAAC,MAAM,SAAS;AAChD,YAAM,SAAS,SAAS,IAAI,EAAE;AAC9B,UAAI,QAAQ;AACV,aAAK,KAAK,MAAM;AAAA,MAClB;AACA,aAAO;AAAA,IACT,GAAG,CAAA,CAAE;AAAA,EACP,WAAW,yBAAyB;AAClC,UAAM,wBAAwB,OAAiB,CAAC,MAAM,SAAS;AAC7D,YAAM,SAAS,SAAS,6BAAM,EAAE,EAAE;AAClC,UAAI,QAAQ;AACV,aAAK,KAAK,GAAG,MAAM,KAAI,6BAAM,aAAY,CAAC,EAAE;AAAA,MAC9C;AACA,aAAO;AAAA,IACT,GAAG,CAAA,CAAE;AAAA,EACP,OAAO;AACL,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,QAAM,QAAQ,QACT;AAAA,IACC,2BAA2B;AAAA,EAAA,IAE7B;AAEJ,SACE,oBAAC,OAAA,EAAI,WAAsB,OACxB,kCAAwB,UACvB;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAI,qBAAqB,EAAC,SAAS,mBAAA,IAAsB,CAAA;AAAA,MAC1D,aAAW;AAAA,MACX,UAAU,IAAI,KAAK,GAAG;AAAA,IAAA;AAAA,EAAA,GAG5B;AAEJ;AAEO,MAAM,iCACX;AACK,MAAM,2BAA2B;AACjC,MAAM,2BAA2B;AACjC,MAAM,0BAA0B;AAChC,MAAM,6BAA6B;"}