Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 16 additions & 0 deletions locale/defaultMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,10 @@
"6Y1YDn": {
"string": "Updated extension permissions"
},
"6ZnMfQ": {
"context": "card header and checkbox label",
"string": "Use legacy shipping zone stock availability"
},
"6ZubLQ": {
"string": "Manage available refunds reasons"
},
Expand Down Expand Up @@ -10023,6 +10027,14 @@
"context": "error message",
"string": "Promo code already exists"
},
"stockAvailabilityDesc": {
"context": "section description",
"string": "When enabled, stock availability is filtered by shipping zones and the destination address (legacy behavior). When disabled, it is determined only by the direct warehouse-channel link."
},
"stockAvailabilityWebhooks": {
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

defaultMessages.json adds entries under keys stockAvailabilityDesc and stockAvailabilityWebhooks, but the corresponding defineMessages IDs are 6LdQvx and wmybDi. This will prevent those strings from being picked up/translated correctly (and leaves two unused keys in the messages catalog). Update the JSON keys to match the message IDs (or update the message IDs to match), keeping the catalog consistent with the rest of the file.

Suggested change
"stockAvailabilityDesc": {
"context": "section description",
"string": "When enabled, stock availability is filtered by shipping zones and the destination address (legacy behavior). When disabled, it is determined only by the direct warehouse-channel link."
},
"stockAvailabilityWebhooks": {
"6LdQvx": {
"context": "section description",
"string": "When enabled, stock availability is filtered by shipping zones and the destination address (legacy behavior). When disabled, it is determined only by the direct warehouse-channel link."
},
"wmybDi": {

Copilot uses AI. Check for mistakes.
"context": "intro to webhook list",
"string": "When disabled, the following channel-scoped stock webhooks become available:"
},
"suAexp": {
"context": "aria label for list view button",
"string": "List view"
Expand Down Expand Up @@ -10430,6 +10442,10 @@
"v3WWK+": {
"string": "Status is invalid"
},
"v5yLSE": {
"context": "section title",
"string": "Stock availability"
},
"v8UngX": {
"string": "Search warehouses..."
},
Expand Down
1 change: 1 addition & 0 deletions src/fragments/shop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const shopFragment = gql`
limitQuantityPerCheckout
enableAccountConfirmationByEmail
useLegacyUpdateWebhookEmission
useLegacyShippingZoneStockAvailability
preserveAllAddressFields
passwordLoginMode
}
Expand Down
1 change: 1 addition & 0 deletions src/graphql/hooks.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3386,6 +3386,7 @@ export const ShopFragmentDoc = gql`
limitQuantityPerCheckout
enableAccountConfirmationByEmail
useLegacyUpdateWebhookEmission
useLegacyShippingZoneStockAvailability
preserveAllAddressFields
passwordLoginMode
}
Expand Down
6 changes: 3 additions & 3 deletions src/graphql/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11787,7 +11787,7 @@ export type LimitInfoFragment = { __typename: 'Limits', channels?: number | null

export type ShopLimitFragment = { __typename: 'Shop', limits: { __typename: 'LimitInfo', currentUsage: { __typename: 'Limits', channels?: number | null, orders?: number | null, productVariants?: number | null, staffUsers?: number | null, warehouses?: number | null }, allowedUsage: { __typename: 'Limits', channels?: number | null, orders?: number | null, productVariants?: number | null, staffUsers?: number | null, warehouses?: number | null } } };

export type ShopFragment = { __typename: 'Shop', customerSetPasswordUrl: string | null, defaultMailSenderAddress: string | null, defaultMailSenderName: string | null, description: string | null, name: string, reserveStockDurationAnonymousUser: number | null, reserveStockDurationAuthenticatedUser: number | null, limitQuantityPerCheckout: number | null, enableAccountConfirmationByEmail: boolean | null, useLegacyUpdateWebhookEmission: boolean | null, preserveAllAddressFields: boolean, passwordLoginMode: PasswordLoginModeEnum, companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null, countries: Array<{ __typename: 'CountryDisplay', code: string, country: string }>, domain: { __typename: 'Domain', host: string } };
export type ShopFragment = { __typename: 'Shop', customerSetPasswordUrl: string | null, defaultMailSenderAddress: string | null, defaultMailSenderName: string | null, description: string | null, name: string, reserveStockDurationAnonymousUser: number | null, reserveStockDurationAuthenticatedUser: number | null, limitQuantityPerCheckout: number | null, enableAccountConfirmationByEmail: boolean | null, useLegacyUpdateWebhookEmission: boolean | null, useLegacyShippingZoneStockAvailability: boolean, preserveAllAddressFields: boolean, passwordLoginMode: PasswordLoginModeEnum, companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null, countries: Array<{ __typename: 'CountryDisplay', code: string, country: string }>, domain: { __typename: 'Domain', host: string } };

export type StaffMemberFragment = { __typename: 'User', id: string, email: string, firstName: string, isActive: boolean, lastName: string };

Expand Down Expand Up @@ -13430,7 +13430,7 @@ export type ShopSettingsUpdateMutationVariables = Exact<{
}>;


export type ShopSettingsUpdateMutation = { __typename: 'Mutation', shopSettingsUpdate: { __typename: 'ShopSettingsUpdate', errors: Array<{ __typename: 'ShopError', code: ShopErrorCode, field: string | null, message: string | null }>, shop: { __typename: 'Shop', customerSetPasswordUrl: string | null, defaultMailSenderAddress: string | null, defaultMailSenderName: string | null, description: string | null, name: string, reserveStockDurationAnonymousUser: number | null, reserveStockDurationAuthenticatedUser: number | null, limitQuantityPerCheckout: number | null, enableAccountConfirmationByEmail: boolean | null, useLegacyUpdateWebhookEmission: boolean | null, preserveAllAddressFields: boolean, passwordLoginMode: PasswordLoginModeEnum, companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null, countries: Array<{ __typename: 'CountryDisplay', code: string, country: string }>, domain: { __typename: 'Domain', host: string } } | null } | null, shopAddressUpdate: { __typename: 'ShopAddressUpdate', errors: Array<{ __typename: 'ShopError', code: ShopErrorCode, field: string | null, message: string | null }>, shop: { __typename: 'Shop', companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null } | null } | null };
export type ShopSettingsUpdateMutation = { __typename: 'Mutation', shopSettingsUpdate: { __typename: 'ShopSettingsUpdate', errors: Array<{ __typename: 'ShopError', code: ShopErrorCode, field: string | null, message: string | null }>, shop: { __typename: 'Shop', customerSetPasswordUrl: string | null, defaultMailSenderAddress: string | null, defaultMailSenderName: string | null, description: string | null, name: string, reserveStockDurationAnonymousUser: number | null, reserveStockDurationAuthenticatedUser: number | null, limitQuantityPerCheckout: number | null, enableAccountConfirmationByEmail: boolean | null, useLegacyUpdateWebhookEmission: boolean | null, useLegacyShippingZoneStockAvailability: boolean, preserveAllAddressFields: boolean, passwordLoginMode: PasswordLoginModeEnum, companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null, countries: Array<{ __typename: 'CountryDisplay', code: string, country: string }>, domain: { __typename: 'Domain', host: string } } | null } | null, shopAddressUpdate: { __typename: 'ShopAddressUpdate', errors: Array<{ __typename: 'ShopError', code: ShopErrorCode, field: string | null, message: string | null }>, shop: { __typename: 'Shop', companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null } | null } | null };

export type RefundSettingsUpdateMutationVariables = Exact<{
refundSettingsInput: RefundSettingsUpdateInput;
Expand All @@ -13447,7 +13447,7 @@ export type RefundReasonReferenceClearMutation = { __typename: 'Mutation', refun
export type SiteSettingsQueryVariables = Exact<{ [key: string]: never; }>;


export type SiteSettingsQuery = { __typename: 'Query', shop: { __typename: 'Shop', customerSetPasswordUrl: string | null, defaultMailSenderAddress: string | null, defaultMailSenderName: string | null, description: string | null, name: string, reserveStockDurationAnonymousUser: number | null, reserveStockDurationAuthenticatedUser: number | null, limitQuantityPerCheckout: number | null, enableAccountConfirmationByEmail: boolean | null, useLegacyUpdateWebhookEmission: boolean | null, preserveAllAddressFields: boolean, passwordLoginMode: PasswordLoginModeEnum, companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null, countries: Array<{ __typename: 'CountryDisplay', code: string, country: string }>, domain: { __typename: 'Domain', host: string } } };
export type SiteSettingsQuery = { __typename: 'Query', shop: { __typename: 'Shop', customerSetPasswordUrl: string | null, defaultMailSenderAddress: string | null, defaultMailSenderName: string | null, description: string | null, name: string, reserveStockDurationAnonymousUser: number | null, reserveStockDurationAuthenticatedUser: number | null, limitQuantityPerCheckout: number | null, enableAccountConfirmationByEmail: boolean | null, useLegacyUpdateWebhookEmission: boolean | null, useLegacyShippingZoneStockAvailability: boolean, preserveAllAddressFields: boolean, passwordLoginMode: PasswordLoginModeEnum, companyAddress: { __typename: 'Address', city: string, cityArea: string, companyName: string, countryArea: string, firstName: string, id: string, lastName: string, phone: string | null, postalCode: string, streetAddress1: string, streetAddress2: string, country: { __typename: 'CountryDisplay', code: string, country: string } } | null, countries: Array<{ __typename: 'CountryDisplay', code: string, country: string }>, domain: { __typename: 'Domain', host: string } } };

export type StaffMemberAddMutationVariables = Exact<{
input: StaffCreateInput;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
type PasswordLoginModeEnum,
type ShopErrorFragment,
type SiteSettingsQuery,
WebhookEventTypeAsyncEnum,
} from "@dashboard/graphql";
import useAddressValidation from "@dashboard/hooks/useAddressValidation";
import { type SubmitPromise } from "@dashboard/hooks/useForm";
Expand All @@ -28,6 +29,13 @@ import SiteCheckoutSettingsCard from "../SiteCheckoutSettingsCard";
import { SitePasswordLoginCard } from "../SitePasswordLoginCard/SitePasswordLoginCard";
import { messages } from "./messages";

const stockAvailabilityWebhooks = [
WebhookEventTypeAsyncEnum.PRODUCT_VARIANT_OUT_OF_STOCK_IN_CHANNEL,
WebhookEventTypeAsyncEnum.PRODUCT_VARIANT_BACK_IN_STOCK_IN_CHANNEL,
WebhookEventTypeAsyncEnum.PRODUCT_VARIANT_OUT_OF_STOCK_FOR_CLICK_AND_COLLECT,
WebhookEventTypeAsyncEnum.PRODUCT_VARIANT_BACK_IN_STOCK_FOR_CLICK_AND_COLLECT,
];

interface SiteSettingsPageAddressFormData {
city: string;
companyName: string;
Expand All @@ -46,6 +54,7 @@ export interface SiteSettingsPageFormData extends SiteSettingsPageAddressFormDat
limitQuantityPerCheckout: number;
emailConfirmation: boolean;
useLegacyUpdateWebhookEmission: boolean;
useLegacyShippingZoneStockAvailability: boolean;
preserveAllAddressFields: boolean;
passwordLoginMode: PasswordLoginModeEnum;
}
Expand Down Expand Up @@ -101,6 +110,7 @@ const SiteSettingsPage = (props: SiteSettingsPageProps) => {
limitQuantityPerCheckout: shop?.limitQuantityPerCheckout ?? 0,
emailConfirmation: shop?.enableAccountConfirmationByEmail ?? false,
useLegacyUpdateWebhookEmission: shop?.useLegacyUpdateWebhookEmission ?? true,
useLegacyShippingZoneStockAvailability: shop?.useLegacyShippingZoneStockAvailability ?? true,
preserveAllAddressFields: shop?.preserveAllAddressFields ?? false,
passwordLoginMode: shop?.passwordLoginMode,
};
Expand Down Expand Up @@ -133,6 +143,9 @@ const SiteSettingsPage = (props: SiteSettingsPageProps) => {
const handlePreserveAddressFieldsChange = isEnabled => {
change({ target: { name: "preserveAllAddressFields", value: isEnabled } });
};
const handleLegacyStockAvailabilityChange = isEnabled => {
change({ target: { name: "useLegacyShippingZoneStockAvailability", value: isEnabled } });
};

return (
<DetailPageLayout gridTemplateColumns={1}>
Expand Down Expand Up @@ -251,6 +264,48 @@ const SiteSettingsPage = (props: SiteSettingsPageProps) => {
</DashboardCard>
</Box>
<Divider />
<Box
display="grid"
__gridTemplateColumns="1fr 3fr"
paddingLeft={6}
paddingBottom={8}
>
<PageSectionHeader
title={intl.formatMessage(messages.sectionStockAvailabilityTitle)}
description={intl.formatMessage(messages.sectionStockAvailabilityDescription)}
/>
<DashboardCard>
<DashboardCard.Header>
<DashboardCard.Title>
{intl.formatMessage(messages.sectionStockAvailabilityHeader)}
</DashboardCard.Title>
</DashboardCard.Header>
<DashboardCard.Content>
<Box display="flex" flexDirection="column" gap={3}>
<Checkbox
data-test-id="legacy-shipping-zone-stock-availability-checkbox"
checked={data.useLegacyShippingZoneStockAvailability}
onCheckedChange={handleLegacyStockAvailabilityChange}
>
<Text>{intl.formatMessage(messages.sectionStockAvailabilityHeader)}</Text>
</Checkbox>
<Box display="flex" flexDirection="column" gap={1}>
<Text size={2} color="default2">
{intl.formatMessage(messages.sectionStockAvailabilityWebhooksIntro)}
</Text>
<Box as="ul" margin={0} paddingLeft={5}>
{stockAvailabilityWebhooks.map(name => (
<Box as="li" key={name}>
<Text size={2}>{name}</Text>
</Box>
))}
Comment on lines +316 to +320
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The webhook event types are rendered directly from WebhookEventTypeAsyncEnum (e.g. PRODUCT_VARIANT_OUT_OF_STOCK_IN_CHANNEL), which will show up as all-caps with underscores in the UI. Consider formatting these values into a human-readable label (replace _ with spaces, lowercase + capitalize) or reusing the formatting approach used in the webhook events UI so this section is readable for non-technical users.

Copilot uses AI. Check for mistakes.
</Box>
</Box>
Comment on lines +311 to +322
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The copy says these webhooks become available when the setting is disabled, but the intro + list are always rendered regardless of useLegacyShippingZoneStockAvailability. This is misleading in the enabled state; consider rendering the intro/list only when !data.useLegacyShippingZoneStockAvailability (or adjust the copy so it matches the always-visible behavior).

Suggested change
<Box display="flex" flexDirection="column" gap={1}>
<Text size={2} color="default2">
{intl.formatMessage(messages.sectionStockAvailabilityWebhooksIntro)}
</Text>
<Box as="ul" margin={0} paddingLeft={5}>
{stockAvailabilityWebhooks.map(name => (
<Box as="li" key={name}>
<Text size={2}>{name}</Text>
</Box>
))}
</Box>
</Box>
{!data.useLegacyShippingZoneStockAvailability && (
<Box display="flex" flexDirection="column" gap={1}>
<Text size={2} color="default2">
{intl.formatMessage(messages.sectionStockAvailabilityWebhooksIntro)}
</Text>
<Box as="ul" margin={0} paddingLeft={5}>
{stockAvailabilityWebhooks.map(name => (
<Box as="li" key={name}>
<Text size={2}>{name}</Text>
</Box>
))}
</Box>
</Box>
)}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't like the propose changes. Current approach just adds extra info that extra webhooks will be available when the flag is disabled.

</Box>
</DashboardCard.Content>
</DashboardCard>
</Box>
<Divider />
<Box
display="grid"
__gridTemplateColumns="1fr 3fr"
Expand Down
21 changes: 21 additions & 0 deletions src/siteSettings/components/SiteSettingsPage/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,25 @@ export const messages = defineMessages({
"Controls whether users can authenticate using password-based login. You can allow it for everyone, restrict it to customers only, or disable it entirely.",
description: "section description",
},
sectionStockAvailabilityTitle: {
id: "v5yLSE",
defaultMessage: "Stock availability",
description: "section title",
},
sectionStockAvailabilityDescription: {
id: "6LdQvx",
defaultMessage:
"When enabled, stock availability is filtered by shipping zones and the destination address (legacy behavior). When disabled, it is determined only by the direct warehouse-channel link.",
description: "section description",
},
sectionStockAvailabilityHeader: {
id: "6ZnMfQ",
defaultMessage: "Use legacy shipping zone stock availability",
description: "card header and checkbox label",
},
sectionStockAvailabilityWebhooksIntro: {
id: "wmybDi",
defaultMessage: "When disabled, the following channel-scoped stock webhooks become available:",
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

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

The intro copy says these webhooks “become available” when the setting is disabled, but the Dashboard already lists all async webhook event types unconditionally (e.g. WebhookDetailsPage builds its event list from Object.keys(WebhookEventTypeAsyncEnum)). This makes “available” misleading; consider rewording to reflect that the events are only triggered/fired when the setting is disabled (as described in the GraphQL schema docs), rather than implying they cannot be selected/used otherwise.

Suggested change
defaultMessage: "When disabled, the following channel-scoped stock webhooks become available:",
defaultMessage: "When disabled, the following channel-scoped stock webhooks are triggered:",

Copilot uses AI. Check for mistakes.
description: "intro to webhook list",
},
});
1 change: 1 addition & 0 deletions src/siteSettings/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const shop: SiteSettingsQuery["shop"] = {
limitQuantityPerCheckout: 50,
enableAccountConfirmationByEmail: true,
useLegacyUpdateWebhookEmission: true,
useLegacyShippingZoneStockAvailability: true,
preserveAllAddressFields: false,
passwordLoginMode: PasswordLoginModeEnum.ENABLED,
};
1 change: 1 addition & 0 deletions src/siteSettings/views/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const SiteSettings = () => {
enableAccountConfirmationByEmail: data.emailConfirmation,
limitQuantityPerCheckout: data.limitQuantityPerCheckout || null,
useLegacyUpdateWebhookEmission: data.useLegacyUpdateWebhookEmission,
useLegacyShippingZoneStockAvailability: data.useLegacyShippingZoneStockAvailability,
preserveAllAddressFields: data.preserveAllAddressFields,
passwordLoginMode: data.passwordLoginMode,
};
Expand Down
Loading