Skip to content

Commit

Permalink
Merge pull request #2118 from Shopify/checkout-unstable-release
Browse files Browse the repository at this point in the history
Unstable Release (checkout)
  • Loading branch information
thomas-marcucci committed Jun 20, 2024
2 parents 9526da4 + 0016e7e commit 887e104
Show file tree
Hide file tree
Showing 16 changed files with 101 additions and 67 deletions.
8 changes: 8 additions & 0 deletions .changeset/violet-flowers-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@shopify/ui-extensions-react': minor
'@shopify/ui-extensions': minor
---

- Adds `oneTimeUse` to `ShippingAddress` to denote whether the address can be saved in checkout.
- Adds `sku` to `ProductVariant` in checkout.
- Adds `bullet` icon in checkout.
4 changes: 2 additions & 2 deletions packages/ui-extensions-react/src/surfaces/checkout/context.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {createContext} from 'react';
import type {
ApiForRenderExtension,
ApiForExtension,
RenderExtensionTarget,
} from '@shopify/ui-extensions/checkout';

export const ExtensionApiContext =
createContext<ApiForRenderExtension<RenderExtensionTarget> | null>(null);
createContext<ApiForExtension<RenderExtensionTarget> | null>(null);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useContext} from 'react';
import type {
RenderExtensionTarget,
ApiForRenderExtension,
ApiForExtension,
} from '@shopify/ui-extensions/checkout';

import {CheckoutUIExtensionError} from '../errors';
Expand All @@ -19,16 +19,15 @@ import {ExtensionApiContext} from '../context';
*/
export function useApi<
Target extends RenderExtensionTarget = RenderExtensionTarget,
>(_target?: Target): ApiForRenderExtension<Target> {
>(_target?: Target): ApiForExtension<Target> {
const api = useContext(ExtensionApiContext);

if (api == null) {
throw new CheckoutUIExtensionError(
'You can only call this hook when running as a checkout UI extension.',
);
}

return api as ApiForRenderExtension<Target>;
return api as ApiForExtension<Target>;
}

/**
Expand All @@ -47,6 +46,6 @@ export function useApi<
*/
export function useExtensionApi<
Target extends RenderExtensionTarget = RenderExtensionTarget,
>(): ApiForRenderExtension<Target> {
>(): ApiForExtension<Target> {
return useApi();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {
MailingAddress,
ShippingAddress,
RenderExtensionTarget,
ShippingAddressChange,
ShippingAddressChangeResult,
Expand All @@ -15,7 +15,7 @@ import {useSubscription} from './subscription';
*/
export function useShippingAddress<
Target extends RenderExtensionTarget = RenderExtensionTarget,
>(): MailingAddress | undefined {
>(): ShippingAddress | undefined {
const shippingAddress = useApi<Target>().shippingAddress;

if (!shippingAddress) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import {createRender} from '@quilted/react-testing';
import type {
ApiForRenderExtension,
ApiForExtension,
RenderExtensionTarget,
} from '@shopify/ui-extensions/checkout';
import type {StatefulRemoteSubscribable} from '@remote-ui/async-subscription';
Expand All @@ -27,7 +27,7 @@ type DeepPartial<T> = {
};

export type PartialExtensionApi = DeepPartial<
ApiForRenderExtension<RenderExtensionTarget>
ApiForExtension<RenderExtensionTarget>
>;

interface Options {
Expand Down
8 changes: 4 additions & 4 deletions packages/ui-extensions-react/src/surfaces/checkout/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {extension} from '@shopify/ui-extensions/checkout';
import type {
ExtensionTargets,
RenderExtensionTarget,
ApiForRenderExtension,
ApiForExtension,
} from '@shopify/ui-extensions/checkout';

import {ExtensionApiContext} from './context';
Expand All @@ -29,7 +29,7 @@ import {ExtensionApiContext} from './context';
export function reactExtension<Target extends RenderExtensionTarget>(
target: Target,
render: (
api: ApiForRenderExtension<Target>,
api: ApiForExtension<Target>,
) => ReactElement<any> | Promise<ReactElement<any>>,
): ExtensionTargets[Target] {
// TypeScript can’t infer the type of the callback because it’s a big union
Expand All @@ -39,7 +39,7 @@ export function reactExtension<Target extends RenderExtensionTarget>(
return extension<'purchase.checkout.block.render'>(
target as any,
async (root, api) => {
const element = await render(api as ApiForRenderExtension<Target>);
const element = await render(api as ApiForExtension<Target>);

await new Promise<void>((resolve, reject) => {
try {
Expand Down Expand Up @@ -84,7 +84,7 @@ export function reactExtension<Target extends RenderExtensionTarget>(
export function render<Target extends RenderExtensionTarget>(
target: Target,

render: (api: ApiForRenderExtension<Target>) => ReactElement<any>,
render: (api: ApiForExtension<Target>) => ReactElement<any>,
): ExtensionTargets[Target] {
return reactExtension(target, render);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
reactExtension,
Banner,
useApi,
useSubscription,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
Expand All @@ -11,13 +12,13 @@ export default reactExtension(

function Extension() {
const {orderConfirmation} = useApi();
const {id} = useSubscription(orderConfirmation);

if (orderConfirmation) {
if (id) {
return (
<Banner>
Please include your order confirmation ID
({orderConfirmation.id}) in support
requests
({id}) in support requests
</Banner>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,50 @@ import {
TextBlock,
} from '@shopify/ui-extensions/checkout';

export default extension('purchase.checkout.block.render', (root) => {
const label = 'Queue process';
export default extension(
'purchase.checkout.block.render',
(root) => {
const label = 'Queue process';

const progress = root.createComponent(BlockStack, null, [
root.createComponent(
Grid,
{
columns: ['fill', 'auto'],
},
const progress = root.createComponent(
BlockStack,
null,
[
root.createComponent(Text, null, label),
root.createComponent(
Text,
Grid,
{
columns: ['fill', 'auto'],
},
[
root.createComponent(
Text,
null,
label,
),
root.createComponent(
Text,
{
appearance: 'subdued',
},
'45% completed',
),
],
),
root.createComponent(Progress, {
value: 45,
max: 100,
accessibilityLabel: label,
}),
root.createComponent(
TextBlock,
{
appearance: 'subdued',
},
'45% completed',
'Estimated wait time: 4 minutes',
),
],
),
root.createComponent(Progress, {
value: 45,
max: 100,
accessibilityLabel: label,
}),
root.createComponent(
TextBlock,
{
appearance: 'subdued',
},
'Estimated wait time: 4 minutes',
),
]);
);

root.appendChild(progress);
});
root.appendChild(progress);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,29 @@ import {
TextBlock,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension('purchase.checkout.footer.render-after', () => (
<Extension />
));
export default reactExtension(
'purchase.checkout.footer.render-after',
() => <Extension />,
);

function Extension() {
const label = 'Queue process';
return (
<BlockStack>
<Grid columns={['fill', 'auto']}>
<Text>{label}</Text>
<Text appearance="subdued">45% completed</Text>
<Text appearance="subdued">
45% completed
</Text>
</Grid>
<Progress value={45} max={100} accessibilityLabel={label} />
<TextBlock appearance="subdued">Estimated wait time: 4 minutes</TextBlock>
<Progress
value={45}
max={100}
accessibilityLabel={label}
/>
<TextBlock appearance="subdued">
Estimated wait time: 4 minutes
</TextBlock>
</BlockStack>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ Review [all **Order status** page extensions targets](/docs/api/checkout-ui-exte
type: 'Generic',
anchorLink: 'block-extension-targets',
title: 'Block extension targets',
sectionContent: `Block extension targets render between core checkout features. Merchants can use the [checkout and accounts editor](/apps/checkout/test-ui-extensions#test-the-extension-in-the-checkout-editor) to place the extension in the [checkout](/docs/api/checkout-ui-extensions/extension-targets-overview#supported-locations), [Thank you](/docs/api/checkout-ui-extensions/extension-targets-overview#supported-typ-locations), or [Order status](/docs/api/checkout-ui-extensions/extension-targets-overview#supported-osp-locations) pages.\n\nBlock extensions are always rendered, regardless of what other elements of the checkout are present. For example, an extension placed above the shipping address will still render even for digital products which do not require a shipping address. Choose block extension targets when your content and functionality works independently of a core checkout feature. This is useful for custom content, like a field to capture order notes from the customer.\n\nBlock extension targets always support multiple placements. Each placement has an associated placement reference that represents its location on the page. For example, the block extension target \`purchase.checkout.block.render\` supports fourteen placements. The placement references include \`INFORMATION1\`, \`DELIVERY1\`, \`PAYMENT1\`, and more.\n\nYou can use placement references as URL parameters to [test block extensions](/docs/apps/build/checkout/test-checkout-ui-extensions#block-targets) in all supported placements on a page. You can also use placement references to [define the default placement](/docs/apps/build/app-extensions/configure-app-extensions#checkout-ui-extensions) of an extension for merchants.`,
sectionContent: `Block extension targets render between core checkout features. Merchants can use the [checkout editor](/apps/checkout/test-ui-extensions#test-the-extension-in-the-checkout-editor) to place the extension in the [checkout](/docs/api/checkout-ui-extensions/extension-targets-overview#supported-locations), [**Thank you**](/docs/api/checkout-ui-extensions/extension-targets-overview#supported-typ-locations), or [**Order status**](/docs/api/checkout-ui-extensions/extension-targets-overview#supported-osp-locations) pages.
\n\nBlock extensions are always rendered, regardless of what other elements of the checkout are present. For example, an extension placed above the shipping address will still render even for digital products which do not require a shipping address.\n\nChoose block extension targets when your content and functionality works independently of a core checkout feature. This is useful for custom content, like a field to capture order notes from the customer.`,
image: 'block-extension-targets.png',
sectionCard: [
{
Expand All @@ -194,12 +195,6 @@ Review [all **Order status** page extensions targets](/docs/api/checkout-ui-exte
url: '/docs/api/checkout-ui-extensions/targets',
type: 'blocks',
},
{
name: 'Placement references',
subtitle: 'Learn more',
url: '/docs/apps/build/checkout/test-checkout-ui-extensions#placement-references',
type: 'resource',
},
],
},
],
Expand Down
1 change: 1 addition & 0 deletions packages/ui-extensions/src/surfaces/checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export type {
SellingPlan,
ValidationError,
MailingAddress,
ShippingAddress,
} from './checkout/api/shared';

export type {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type {Attribute, SellingPlan, MailingAddress} from '../shared';
import type {
Attribute,
SellingPlan,
MailingAddress,
ShippingAddress,
} from '../shared';

/**
* Removes a note
Expand Down Expand Up @@ -452,7 +457,7 @@ export interface ShippingAddressUpdateChange {
* values for the fields you want to update — any fields you do not list
* will keep their current values.
*/
address: Partial<MailingAddress>;
address: Partial<ShippingAddress>;
}

export type ShippingAddressChange = ShippingAddressUpdateChange;
Expand Down
4 changes: 4 additions & 0 deletions packages/ui-extensions/src/surfaces/checkout/api/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,7 @@ export interface MailingAddress {
*/
phone?: string;
}

export interface ShippingAddress extends MailingAddress {
oneTimeUse?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
SellingPlan,
Attribute,
MailingAddress,
ShippingAddress,
} from '../shared';
import type {ExtensionTarget} from '../../targets';
import type {
Expand Down Expand Up @@ -664,7 +665,7 @@ export interface StandardApi<Target extends ExtensionTarget = ExtensionTarget> {
*
* {% include /apps/checkout/privacy-icon.md %} Requires access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).
*/
shippingAddress?: StatefulRemoteSubscribable<MailingAddress | undefined>;
shippingAddress?: StatefulRemoteSubscribable<ShippingAddress | undefined>;

/**
* The proposed customer billing address. The address updates when the field is
Expand Down Expand Up @@ -1047,6 +1048,11 @@ export interface ProductVariant extends BaseMerchandise {
* The selling plan associated with the merchandise.
*/
sellingPlan?: SellingPlan;

/**
* The product variant's sku.
*/
sku?: string;
}

export interface Product {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type IconSource =
| 'arrowUpRight'
| 'arrowDown'
| 'bag'
| 'bullet'
| 'calendar'
| 'camera'
| 'caretDown'
Expand Down
6 changes: 0 additions & 6 deletions packages/ui-extensions/src/surfaces/checkout/targets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -780,12 +780,6 @@ export type ArgumentsForExtension<Target extends keyof ExtensionTargets> =
/**
* For a given extension target, returns the type of the API that the
* extension will receive at runtime.
*
* For RenderExtensionTargets, this API type is the second argument to
* the callback for that extension target.
*
* For RunnableExtensionTargets, this API type is the only argument to
* the callback for that extension target.
*/
export type ApiForExtension<Target extends ExtensionTarget> =
ExtractedApiFromExtensionDefinition<ExtensionTargets[Target]>;
Expand Down

0 comments on commit 887e104

Please sign in to comment.