Skip to content

Commit

Permalink
Adds optional channel prop to ShopPayButton (#1447)
Browse files Browse the repository at this point in the history
  • Loading branch information
QuintonC committed Nov 6, 2023
1 parent ac3f49f commit e8cc49f
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/small-zoos-grab.md
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen-react': patch
---

This change adds an optional prop to the `ShopPayButton` that adds order attribution support for either the Headless or Hydrogen sales channel.
5 changes: 5 additions & 0 deletions .changeset/witty-lamps-fly.md
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Adds default channel value of "hydrogen" to the ShopPayButton component exported out of the @shopify/hydrogen package.
59 changes: 38 additions & 21 deletions packages/hydrogen-react/docs/generated/generated_docs_data.json
Expand Up @@ -2019,7 +2019,7 @@
"filePath": "/MediaFile.tsx",
"syntaxKind": "PropertySignature",
"name": "aria-current",
"value": "boolean | \"time\" | \"step\" | \"page\" | \"date\" | \"true\" | \"false\" | \"location\"",
"value": "boolean | \"time\" | \"step\" | \"date\" | \"true\" | \"false\" | \"page\" | \"location\"",
"description": "Indicates the element that represents the current item within a container or set of related elements.",
"isOptional": true
},
Expand Down Expand Up @@ -4367,12 +4367,12 @@
"tabs": [
{
"title": "JavaScript",
"code": "import {ShopPayButton} from '@shopify/hydrogen-react';\n\nexport function AddVariantQuantity1({variantId, storeDomain}) {\n return <ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} />;\n}\n\nexport function AddVariantQuantityMultiple({variantId, quantity, storeDomain}) {\n return (\n <ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n />\n );\n}\n",
"code": "import {ShopPayButton} from '@shopify/hydrogen-react';\n\nexport function AddVariantQuantity1({variantId, storeDomain}) {\n return <ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} />;\n}\n\nexport function AddVariantQuantityMultiple({variantId, quantity, storeDomain}) {\n return (\n <ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n />\n );\n}\n\nexport function ChannelAttribution({channel, variantId, storeDomain}) {\n return (\n <ShopPayButton\n channel={channel}\n variantIds={[variantId]}\n storeDomain={storeDomain}\n />\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 <ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} />;\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 <ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n />\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 <ShopPayButton variantIds={[variantId]} storeDomain={storeDomain} />;\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 <ShopPayButton\n variantIdsAndQuantities={[{id: variantId, quantity}]}\n storeDomain={storeDomain}\n />\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 <ShopPayButton\n channel={channel}\n variantIds={[variantId]}\n storeDomain={storeDomain}\n />\n );\n}\n",
"language": "tsx"
}
],
Expand Down Expand Up @@ -4412,7 +4412,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 @@ -4457,6 +4457,23 @@
}
]
},
"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?: 'headless' | 'hydrogen';\n}",
"description": "",
"members": [
{
"filePath": "/ShopPayButton.tsx",
"syntaxKind": "PropertySignature",
"name": "channel",
"value": "\"headless\" | \"hydrogen\"",
"description": "A string that adds channel attribution to the order. Can be either `headless` or `hydrogen`",
"isOptional": true
}
]
},
"ShopPayVariantIds": {
"filePath": "/ShopPayButton.tsx",
"syntaxKind": "TypeAliasDeclaration",
Expand Down Expand Up @@ -5688,7 +5705,7 @@
"syntaxKind": "MethodSignature",
"name": "pop",
"value": "() => unknown",
"description": "Removes the last element from an array and returns it. If the array is empty, undefined is returned and the array is not modified."
"description": "Removes the last element from an array and returns it.\r\nIf the array is empty, undefined is returned and the array is not modified."
},
{
"filePath": "/flatten-connection.ts",
Expand All @@ -5702,7 +5719,7 @@
"syntaxKind": "MethodSignature",
"name": "concat",
"value": "{ (...items: ConcatArray<unknown>[]): unknown[]; (...items: unknown[]): unknown[]; }",
"description": "Combines two or more arrays. This method returns a new array without modifying any existing arrays."
"description": "Combines two or more arrays.\r\nThis method returns a new array without modifying any existing arrays."
},
{
"filePath": "/flatten-connection.ts",
Expand All @@ -5716,28 +5733,28 @@
"syntaxKind": "MethodSignature",
"name": "reverse",
"value": "() => unknown[]",
"description": "Reverses the elements in an array in place. This method mutates the array and returns a reference to the same array."
"description": "Reverses the elements in an array in place.\r\nThis method mutates the array and returns a reference to the same array."
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "shift",
"value": "() => unknown",
"description": "Removes the first element from an array and returns it. If the array is empty, undefined is returned and the array is not modified."
"description": "Removes the first element from an array and returns it.\r\nIf the array is empty, undefined is returned and the array is not modified."
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "slice",
"value": "(start?: number, end?: number) => unknown[]",
"description": "Returns a copy of a section of an array. For both start and end, a negative index can be used to indicate an offset from the end of the array. For example, -2 refers to the second to last element of the array."
"description": "Returns a copy of a section of an array.\r\nFor both start and end, a negative index can be used to indicate an offset from the end of the array.\r\nFor example, -2 refers to the second to last element of the array."
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "sort",
"value": "(compareFn?: (a: unknown, b: unknown) => number) => FlattenConnectionReturnForDoc",
"description": "Sorts an array in place. This method mutates the array and returns a reference to the same array."
"description": "Sorts an array in place.\r\nThis method mutates the array and returns a reference to the same array."
},
{
"filePath": "/flatten-connection.ts",
Expand Down Expand Up @@ -5820,15 +5837,15 @@
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "find",
"value": "{ <S extends unknown>(predicate: (value: unknown, index: number, obj: unknown[]) => value is S, thisArg?: any): S; (predicate: (value: unknown, index: number, obj: unknown[]) => unknown, thisArg?: any): unknown; }",
"description": "Returns the value of the first element in the array where predicate is true, and undefined otherwise."
"value": "{ <S extends unknown>(predicate: (this: void, value: unknown, index: number, obj: unknown[]) => value is S, thisArg?: any): S; (predicate: (value: unknown, index: number, obj: unknown[]) => unknown, thisArg?: any): unknown; }",
"description": "Returns the value of the first element in the array where predicate is true, and undefined\r\notherwise."
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "findIndex",
"value": "(predicate: (value: unknown, index: number, obj: unknown[]) => unknown, thisArg?: any) => number",
"description": "Returns the index of the first element in the array where predicate is true, and -1 otherwise."
"description": "Returns the index of the first element in the array where predicate is true, and -1\r\notherwise."
},
{
"filePath": "/flatten-connection.ts",
Expand All @@ -5842,7 +5859,7 @@
"syntaxKind": "MethodSignature",
"name": "copyWithin",
"value": "(target: number, start: number, end?: number) => FlattenConnectionReturnForDoc",
"description": "Returns the this object after copying a section of the array identified by start and end to the same array starting at position target"
"description": "Returns the this object after copying a section of the array identified by start and end\r\nto the same array starting at position target"
},
{
"filePath": "/flatten-connection.ts",
Expand Down Expand Up @@ -5877,28 +5894,28 @@
"syntaxKind": "MethodSignature",
"name": "flatMap",
"value": "<U, This = undefined>(callback: (this: This, value: unknown, index: number, array: unknown[]) => U | readonly U[], thisArg?: This) => U[]",
"description": "Calls a defined callback function on each element of an array. Then, flattens the result into a new array. This is identical to a map followed by flat with depth 1."
"description": "Calls a defined callback function on each element of an array. Then, flattens the result into\r\na new array.\r\nThis is identical to a map followed by flat with depth 1."
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "flat",
"value": "<A, D extends number = 1>(this: A, depth?: D) => FlatArray<A, D>[]",
"description": "Returns a new array with all sub-array elements concatenated into it recursively up to the specified depth."
"description": "Returns a new array with all sub-array elements concatenated into it recursively up to the\r\nspecified depth."
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "MethodSignature",
"name": "__@iterator@448",
"name": "__@iterator@441",
"value": "() => IterableIterator<unknown>",
"description": "Iterator"
},
{
"filePath": "/flatten-connection.ts",
"syntaxKind": "PropertySignature",
"name": "__@unscopables@450",
"value": "{ [x: number]: boolean; length?: boolean; toString?: boolean; toLocaleString?: boolean; pop?: boolean; push?: boolean; concat?: boolean; join?: boolean; reverse?: boolean; shift?: boolean; slice?: boolean; sort?: boolean; splice?: boolean; unshift?: boolean; indexOf?: boolean; lastIndexOf?: boolean; every?: boolean; some?: boolean; forEach?: boolean; map?: boolean; filter?: boolean; reduce?: boolean; reduceRight?: boolean; find?: boolean; findIndex?: boolean; fill?: boolean; copyWithin?: boolean; entries?: boolean; keys?: boolean; values?: boolean; includes?: boolean; flatMap?: boolean; flat?: boolean; [Symbol.iterator]?: boolean; readonly [Symbol.unscopables]?: boolean; at?: boolean; }",
"description": "Is an object whose properties have the value 'true' when they will be absent when used in a 'with' statement."
"syntaxKind": "MethodSignature",
"name": "__@unscopables@443",
"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."
},
{
"filePath": "/flatten-connection.ts",
Expand Down
10 changes: 10 additions & 0 deletions packages/hydrogen-react/src/ShopPayButton.example.jsx
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
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
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: '',
};
43 changes: 43 additions & 0 deletions packages/hydrogen-react/src/ShopPayButton.test.tsx
Expand Up @@ -7,6 +7,7 @@ import {
DoublePropsErrorMessage,
MissingPropsErrorMessage,
InvalidPropsErrorMessage,
InvalidChannelErrorMessage,
MissingStoreDomainErrorMessage,
} from './ShopPayButton.js';
import {getShopifyConfig} from './ShopifyProvider.test.js';
Expand Down Expand Up @@ -165,4 +166,46 @@ 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 channel = 'hydrogen';
const {container} = render(
<ShopPayButton
channel={channel}
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', channel);
});
});

0 comments on commit e8cc49f

Please sign in to comment.