Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/customer-account-exaf-addresses.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/ui-extensions': minor
---

Add structured extended address fields to Customer Account order address APIs.
114 changes: 109 additions & 5 deletions packages/ui-extensions/docs/surfaces/customer-account/build-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,100 @@ const cleanupTempFiles = async (tempFiles) => {
);
};

const customerAccountMailingAddressFields = [
{
filePath: 'src/surfaces/customer-account/api/shared.ts',
syntaxKind: 'PropertySignature',
name: 'extendedFields',
value: 'AddressExtendedFields',
description:
'Structured address components for countries and regions that collect them. ' +
"The value is `undefined` when structured address data isn't available " +
'for the order address. Individual fields are `null` when Shopify has ' +
"a structured address record but a specific component wasn't provided.",
isOptional: true,
},
{
filePath: 'src/surfaces/customer-account/api/shared.ts',
syntaxKind: 'PropertySignature',
name: 'addressCode',
value: 'string | null',
description:
'A country-specific address code, such as a short code or postal ' +
"delivery code. The value is `null` when the order address doesn't " +
'have an address code.',
isOptional: true,
examples: [
{
title: 'Example',
description: '',
tabs: [{code: "'01001-000'", title: 'Example'}],
},
],
},
];

const customerAccountMailingAddressValue = ` /**
* Structured address components for countries and regions that collect them.
* The value is \`undefined\` when structured address data isn't available for
* the order address. Individual fields are \`null\` when Shopify has a
* structured address record but a specific component wasn't provided.
*/
extendedFields?: AddressExtendedFields;

/**
* A country-specific address code, such as a short code or postal delivery
* code. The value is \`null\` when the order address doesn't have an address
* code.
*
* @example '01001-000'
*/
addressCode?: string | null;

`;

const addCustomerAccountMailingAddressDocs = async (generatedDocsV2Path) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should need to make any changes to this script just for this API. It feels like we are solving the problem at the wrong layer here.

Still investigating the best way to avoid this, but I think we need a different approach here

const content = await fs.readFile(generatedDocsV2Path, 'utf8');
const generatedDocs = JSON.parse(content);
const mailingAddressDocs = generatedDocs.MailingAddress;

if (!mailingAddressDocs) return;

const [sourcePath] = Object.keys(mailingAddressDocs);
const docs = mailingAddressDocs[sourcePath];

if (!docs?.members || !docs?.value) return;

const existingMemberNames = new Set(
docs.members.map((member) => member.name),
);

const missingFields = customerAccountMailingAddressFields.filter(
(field) => !existingMemberNames.has(field.name),
);

if (missingFields.length > 0) {
const address2Index = docs.members.findIndex(
(member) => member.name === 'address2',
);
const insertIndex =
address2Index === -1 ? docs.members.length : address2Index + 1;
docs.members.splice(insertIndex, 0, ...missingFields);
}

if (!docs.value.includes('extendedFields?: AddressExtendedFields;')) {
docs.value = docs.value.replace(
' /**\n * The city, town, or village of the address.',
`${customerAccountMailingAddressValue} /**\n * The city, town, or village of the address.`,
);
}

await fs.writeFile(
generatedDocsV2Path,
`${JSON.stringify(generatedDocs, null, 2)}\n`,
);
};

const generateExtensionsDocs = async () => {
console.log(
`Building Customer Account UI Extensions docs for ${EXTENSIONS_API_VERSION} version`,
Expand Down Expand Up @@ -98,12 +192,16 @@ const generateExtensionsDocs = async () => {
replaceValue: '',
});

const generatedDocsV2Path = path.join(outputDir, generatedDocsDataV2File);

// Replace 'unstable' with the exact API version in relative doc links
await replaceFileContent({
filePaths: path.join(outputDir, generatedDocsDataV2File),
filePaths: generatedDocsV2Path,
searchValue: '/docs/api//unstable/',
replaceValue: `/docs/api/customer-account-ui-extensions/${EXTENSIONS_API_VERSION}`,
});

await addCustomerAccountMailingAddressDocs(generatedDocsV2Path);
};

let checkoutTempFiles = [];
Expand All @@ -126,10 +224,16 @@ try {
// Generate targets.json
console.log('Generating targets.json...');
try {
execSync(`node ${path.join(docsPath, 'build-docs-targets-json.mjs')} ${EXTENSIONS_API_VERSION}`, {
stdio: 'inherit',
cwd: rootPath,
});
execSync(
`node ${path.join(
docsPath,
'build-docs-targets-json.mjs',
)} ${EXTENSIONS_API_VERSION}`,
{
stdio: 'inherit',
cwd: rootPath,
},
);
console.log('✅ Generated targets.json');
} catch (targetsError) {
console.warn(
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export type {
GraphQLError,
SellingPlan,
StorefrontApiVersion,
AddressExtendedFields,
MailingAddress,
ApiVersion,
Capability,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,17 +341,21 @@ export interface OrderStatusApi<Target extends ExtensionTarget> {
* are delivered. The value is `undefined` if the order contains only digital products or
* if a shipping address wasn't required.
*
* Reflects the state at the time the order was placed. Doesn't update if the
* customer changes their account address afterward.
* Includes structured address fields, such as `addressCode` and `extendedFields`,
* when they're available for the order address. Reflects the state at the time
* the order was placed. Doesn't update if the customer changes their account
* address afterward.
*/
shippingAddress?: SubscribableSignalLike<MailingAddress | undefined>;

/**
* The billing address associated with the buyer's payment method for the order. The value
* is `undefined` if the order doesn't have a billing address on file.
*
* Reflects the state at the time the order was placed. Doesn't update if the
* customer changes their account address afterward.
* Includes structured address fields, such as `addressCode` and `extendedFields`,
* when they're available for the order address. Reflects the state at the time
* the order was placed. Doesn't update if the customer changes their account
* address afterward.
*/
billingAddress?: SubscribableSignalLike<MailingAddress | undefined>;

Expand Down
62 changes: 62 additions & 0 deletions packages/ui-extensions/src/surfaces/customer-account/api/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,51 @@ export interface Attribute {
value: string;
}

/**
* Structured extended address fields for countries and regions that collect
* address components separately from the flat address lines. These fields are
* available on order shipping and billing addresses when the order was placed
* with structured address data.
*
* @publicDocs
*/
export interface AddressExtendedFields {
/**
* The street name without the building or street number.
*
* @example 'Avenida Paulista'
*/
streetName?: string | null;

/**
* The building or street number.
*
* @example '123'
*/
streetNumber?: string | null;

/**
* Additional address information, such as a block, floor, or unit.
*
* @example '10th floor'
*/
line2?: string | null;

/**
* The district or neighborhood.
*
* @example 'Bela Vista'
*/
district?: string | null;

/**
* The subdistrict or smaller locality.
*
* @example 'Centro'
*/
subdistrict?: string | null;
}

/**
* A mailing address associated with the order, such as a shipping or billing address.
*
Expand Down Expand Up @@ -300,6 +345,23 @@ export interface MailingAddress {
*/
address2?: string;

/**
* Structured address components for countries and regions that collect them.
* The value is `undefined` when structured address data isn't available for
* the order address. Individual fields are `null` when Shopify has a
* structured address record but a specific component wasn't provided.
*/
extendedFields?: AddressExtendedFields;

/**
* A country-specific address code, such as a short code or postal delivery
* code. The value is `null` when the order address doesn't have an address
* code.
*
* @example '01001-000'
*/
addressCode?: string | null;

/**
* The city, town, or village of the address.
*
Expand Down
Loading