Skip to content

Commit

Permalink
Adds optional channel prop to ShopPayButton
Browse files Browse the repository at this point in the history
  • Loading branch information
QuintonC committed Oct 25, 2023
1 parent 11a38ef commit 307c553
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 9 deletions.
79 changes: 72 additions & 7 deletions packages/hydrogen-react/docs/generated/generated_docs_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@
"filePath": "/CartProvider.tsx",
"syntaxKind": "TypeAliasDeclaration",
"name": "CartProviderProps",
"value": "{\n /** Any `ReactNode` elements. */\n children: React.ReactNode;\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A callback that is invoked when the process to create a cart begins, but before the cart is created in the Storefront API. */\n onCreate?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart begins, but before the line item is added to the Storefront API. */\n onLineAdd?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart begins, but before the line item is removed from the Storefront API. */\n onLineRemove?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart begins, but before the line item is updated in the Storefront API. */\n onLineUpdate?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart begins, but before the note is added or updated in the Storefront API. */\n onNoteUpdate?: () => void;\n /** A callback that is invoked when the process to update the buyer identity begins, but before the buyer identity is updated in the Storefront API. */\n onBuyerIdentityUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart attributes begins, but before the attributes are updated in the Storefront API. */\n onAttributesUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes begins, but before the discount codes are updated in the Storefront API. */\n onDiscountCodesUpdate?: () => void;\n /** A callback that is invoked when the process to create a cart completes */\n onCreateComplete?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart completes */\n onLineAddComplete?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart completes */\n onLineRemoveComplete?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart completes */\n onLineUpdateComplete?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart completes */\n onNoteUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the buyer identity completes */\n onBuyerIdentityUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart attributes completes */\n onAttributesUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes completes */\n onDiscountCodesUpdateComplete?: () => void;\n /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/2023-07/objects/cart). */\n data?: PartialDeep<CartType, {recurseIntoArrays: true}>;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/2023-07/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment?: string;\n /** A customer access token that's accessible on the server if there's a customer login. */\n customerAccessToken?: CartBuyerIdentityInput['customerAccessToken'];\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n}",
"value": "{\n /** Any `ReactNode` elements. */\n children: React.ReactNode;\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A callback that is invoked when the process to create a cart begins, but before the cart is created in the Storefront API. */\n onCreate?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart begins, but before the line item is added to the Storefront API. */\n onLineAdd?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart begins, but before the line item is removed from the Storefront API. */\n onLineRemove?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart begins, but before the line item is updated in the Storefront API. */\n onLineUpdate?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart begins, but before the note is added or updated in the Storefront API. */\n onNoteUpdate?: () => void;\n /** A callback that is invoked when the process to update the buyer identity begins, but before the buyer identity is updated in the Storefront API. */\n onBuyerIdentityUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart attributes begins, but before the attributes are updated in the Storefront API. */\n onAttributesUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes begins, but before the discount codes are updated in the Storefront API. */\n onDiscountCodesUpdate?: () => void;\n /** A callback that is invoked when the process to create a cart completes */\n onCreateComplete?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart completes */\n onLineAddComplete?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart completes */\n onLineRemoveComplete?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart completes */\n onLineUpdateComplete?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart completes */\n onNoteUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the buyer identity completes */\n onBuyerIdentityUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart attributes completes */\n onAttributesUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes completes */\n onDiscountCodesUpdateComplete?: () => void;\n /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/2023-07/objects/cart). */\n data?: PartialDeep<CartType, {recurseIntoArrays: true}>;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/2023-07/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment?: string;\n /** A customer access token that's accessible on the server if there's a customer login. */\n customerAccessToken?: CartBuyerIdentityInput['customerAccessToken'];\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n /** The ISO luanguage code for i18n. */\n languageCode?: LanguageCode;\n}",
"description": "",
"members": [
{
Expand Down Expand Up @@ -817,6 +817,14 @@
"value": "CountryCode",
"description": "The ISO country code for i18n.",
"isOptional": true
},
{
"filePath": "/CartProvider.tsx",
"syntaxKind": "PropertySignature",
"name": "languageCode",
"value": "LanguageCode",
"description": "The ISO luanguage code for i18n.",
"isOptional": true
}
]
}
Expand Down Expand Up @@ -4477,12 +4485,12 @@
"tabs": [
{
"title": "JavaScript",
"code": "import {ShopPayButton} from '@shopify/hydrogen-react';\n\nexport function AddVariantQuantity1({variantId, storeDomain}) {\n return &lt;ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} /&gt;;\n}\n\nexport function AddVariantQuantityMultiple({variantId, quantity, storeDomain}) {\n return (\n &lt;ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n /&gt;\n );\n}\n",
"code": "import {ShopPayButton} from '@shopify/hydrogen-react';\n\nexport function AddVariantQuantity1({variantId, storeDomain}) {\n return &lt;ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} /&gt;;\n}\n\nexport function AddVariantQuantityMultiple({variantId, quantity, storeDomain}) {\n return (\n &lt;ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n /&gt;\n );\n}\n\nexport function ChannelAttribution({channel, variantId, storeDomain}) {\n return (\n &lt;ShopPayButton\n channel={channel}\n variantIds={[variantId]}\n storeDomain={storeDomain}\n /&gt;\n );\n}\n",
"language": "jsx"
},
{
"title": "TypeScript",
"code": "import {ShopPayButton} from '@shopify/hydrogen-react';\n\nexport function AddVariantQuantity1({\n variantId,\n storeDomain,\n}: {\n variantId: string;\n storeDomain: string;\n}) {\n return &lt;ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} /&gt;;\n}\n\nexport function AddVariantQuantityMultiple({\n variantId,\n quantity,\n storeDomain,\n}: {\n variantId: string;\n quantity: number;\n storeDomain: string;\n}) {\n return (\n &lt;ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n /&gt;\n );\n}\n",
"code": "import {ShopPayButton} from '@shopify/hydrogen-react';\n\nexport function AddVariantQuantity1({\n variantId,\n storeDomain,\n}: {\n variantId: string;\n storeDomain: string;\n}) {\n return &lt;ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} /&gt;;\n}\n\nexport function AddVariantQuantityMultiple({\n variantId,\n quantity,\n storeDomain,\n}: {\n variantId: string;\n quantity: number;\n storeDomain: string;\n}) {\n return (\n &lt;ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n /&gt;\n );\n}\n\nexport function ChannelAttribution({\n channel,\n variantId,\n storeDomain,\n}: {\n channel: 'headless' | 'hydrogen';\n variantId: string;\n storeDomain: string;\n}) {\n return (\n &lt;ShopPayButton\n channel={channel}\n variantIds={[variantId]}\n storeDomain={storeDomain}\n /&gt;\n );\n}\n",
"language": "tsx"
}
],
Expand Down Expand Up @@ -4522,7 +4530,7 @@
"filePath": "/ShopPayButton.tsx",
"syntaxKind": "TypeAliasDeclaration",
"name": "ShopPayButtonProps",
"value": "ShopPayButtonStyleProps & ShopPayDomainProps & (ShopPayVariantIds | ShopPayVariantAndQuantities)",
"value": "ShopPayButtonStyleProps & ShopPayDomainProps & ShopPayChannelAttribution & (ShopPayVariantIds | ShopPayVariantAndQuantities)",
"description": ""
},
"ShopPayButtonStyleProps": {
Expand Down Expand Up @@ -4567,6 +4575,30 @@
}
]
},
"ShopPayChannelAttribution": {
"filePath": "/ShopPayButton.tsx",
"syntaxKind": "TypeAliasDeclaration",
"name": "ShopPayChannelAttribution",
"value": "{\n /** A string that adds channel attribution to the order. Can be either `headless` or `hydrogen` */\n channel?: Channel;\n}",
"description": "",
"members": [
{
"filePath": "/ShopPayButton.tsx",
"syntaxKind": "PropertySignature",
"name": "channel",
"value": "Channel",
"description": "A string that adds channel attribution to the order. Can be either `headless` or `hydrogen`",
"isOptional": true
}
]
},
"Channel": {
"filePath": "/ShopPayButton.tsx",
"syntaxKind": "TypeAliasDeclaration",
"name": "Channel",
"value": "'headless' | 'hydrogen'",
"description": "The valid values for `channel` at checkout for custom storefront channel attribution can be one of either `custom-storefronts` or `headless-storefronts`.\n\nTo prevent from confusion, the values exposed on the `ShopPayButton` are simplified to match the channel display name rather than the registered channel identifier."
},
"ShopPayVariantIds": {
"filePath": "/ShopPayButton.tsx",
"syntaxKind": "TypeAliasDeclaration",
Expand Down Expand Up @@ -5999,14 +6031,14 @@
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "__@iterator@441",
"name": "__@iterator@414",
"value": "() => IterableIterator<unknown>",
"description": "Iterator"
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "__@unscopables@443",
"name": "__@unscopables@416",
"value": "() => { copyWithin: boolean; entries: boolean; fill: boolean; find: boolean; findIndex: boolean; keys: boolean; values: boolean; }",
"description": "Returns an object whose properties have the value 'true'\r\nwhen they will be absent when used in a 'with' statement."
},
Expand Down Expand Up @@ -6313,8 +6345,41 @@
"filePath": "/load-script.tsx",
"syntaxKind": "TypeAliasDeclaration",
"name": "LoadScriptParams",
"value": "[src: string, options?: { module?: boolean; in?: \"body\" | \"head\"; }]",
"value": "[src: string, options?: LoadScriptOptions]",
"description": ""
},
"LoadScriptOptions": {
"filePath": "/load-script.tsx",
"syntaxKind": "TypeAliasDeclaration",
"name": "LoadScriptOptions",
"value": "{\n module?: boolean;\n in?: 'head' | 'body';\n attributes?: Record<string, string>;\n}",
"description": "",
"members": [
{
"filePath": "/load-script.tsx",
"syntaxKind": "PropertySignature",
"name": "module",
"value": "boolean",
"description": "",
"isOptional": true
},
{
"filePath": "/load-script.tsx",
"syntaxKind": "PropertySignature",
"name": "in",
"value": "\"body\" | \"head\"",
"description": "",
"isOptional": true
},
{
"filePath": "/load-script.tsx",
"syntaxKind": "PropertySignature",
"name": "attributes",
"value": "Record<string, string>",
"description": "",
"isOptional": true
}
]
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions packages/hydrogen-react/src/ShopPayButton.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@ export function AddVariantQuantityMultiple({variantId, quantity, storeDomain}) {
/>
);
}

export function ChannelAttribution({channel, variantId, storeDomain}) {
return (
<ShopPayButton
channel={channel}
variantIds={[variantId]}
storeDomain={storeDomain}
/>
);
}
18 changes: 18 additions & 0 deletions packages/hydrogen-react/src/ShopPayButton.example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,21 @@ export function AddVariantQuantityMultiple({
/>
);
}

export function ChannelAttribution({
channel,
variantId,
storeDomain,
}: {
channel: 'headless' | 'hydrogen';
variantId: string;
storeDomain: string;
}) {
return (
<ShopPayButton
channel={channel}
variantIds={[variantId]}
storeDomain={storeDomain}
/>
);
}
11 changes: 11 additions & 0 deletions packages/hydrogen-react/src/ShopPayButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,14 @@ Quantities.args = {
className: '',
width: '',
};

export const ChannelAttribution = Template.bind({});
ChannelAttribution.args = {
channel: 'hydrogen',
variantIdsAndQuantities: [
{id: 'gid://shopify/ProductVariant/123', quantity: 2},
],
storeDomain: 'https://notashop.myshopify.io',
className: '',
width: '',
};
44 changes: 43 additions & 1 deletion packages/hydrogen-react/src/ShopPayButton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {vi, describe, expect, it} from 'vitest';

import {render} from '@testing-library/react';
import {render, screen} from '@testing-library/react';
import {ShopifyProvider} from './ShopifyProvider.js';
import {
ShopPayButton,
DoublePropsErrorMessage,
MissingPropsErrorMessage,
InvalidPropsErrorMessage,
InvalidChannelErrorMessage,
MissingStoreDomainErrorMessage,
} from './ShopPayButton.js';
import {getShopifyConfig} from './ShopifyProvider.test.js';
Expand Down Expand Up @@ -165,4 +166,45 @@ describe(`<ShopPayButton />`, () => {
'https://notashop.myshopify.com',
);
});

it(`throws an error if you pass an invalid channel value`, () => {
expect(() =>
render(
<ShopPayButton
// @ts-expect-error Purposely passing in invalid channel
channel="test"
variantIdsAndQuantities={[]}
/>,
{
wrapper: ({children}) => (
<ShopifyProvider {...getShopifyConfig()}>
{children}
</ShopifyProvider>
),
},
),
).toThrow(InvalidChannelErrorMessage);
});

it(`creates the correct attribute when using 'channel'`, () => {
const {container} = render(
<ShopPayButton
channel="hydrogen"
variantIds={['gid://shopify/ProductVariant/123']}
/>,
{
wrapper: ({children}) => (
<ShopifyProvider {...getShopifyConfig()}>{children}</ShopifyProvider>
),
},
);

const button = container.querySelector('shop-pay-button');

expect(button).toHaveAttribute(
'store-url',
'https://notashop.myshopify.io',
);
expect(button).toHaveAttribute('channel', 'custom-storefronts');
});
});
Loading

0 comments on commit 307c553

Please sign in to comment.