@vtex/faststore 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/catalog.json +67 -1
- package/dist/components.d.ts +4 -1
- package/dist/components.js +5 -2
- package/dist/content-types.json +73 -0
- package/dist/docs/account-access-gate.md +153 -0
- package/dist/docs/account-entry-point.md +1 -2
- package/dist/docs/account-menu.md +164 -0
- package/dist/docs/buy-button.md +1 -1
- package/dist/docs/cart.md +1 -1
- package/dist/docs/session.md +1 -1
- package/dist/docs/sign-in-redirect.md +1 -1
- package/dist/matter/account-access-gate/account-access-gate.d.ts +86 -0
- package/dist/matter/account-access-gate/account-access-gate.js +283 -0
- package/dist/matter/account-access-gate/account-access-gate.js.map +1 -0
- package/dist/matter/account-access-gate/sign-out-intent.d.ts +17 -0
- package/dist/matter/account-access-gate/sign-out-intent.js +62 -0
- package/dist/matter/account-access-gate/sign-out-intent.js.map +1 -0
- package/dist/matter/account-entry-point/account-entry-point.js +2 -2
- package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
- package/dist/matter/account-menu/account-menu.d.ts +88 -0
- package/dist/matter/account-menu/account-menu.js +246 -0
- package/dist/matter/account-menu/account-menu.js.map +1 -0
- package/dist/matter/cart/cart.d.ts +1 -1
- package/dist/matter/cart/cart.js +2 -2
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/delivery-options/delivery-options.js.map +1 -1
- package/dist/matter/my-account-profile/my-account-profile.js +1 -1
- package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
- package/dist/matter/shipping-address/shipping-address.js +1 -1
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/particles/footer-social/footer-social.js +1 -1
- package/dist/particles/incentives/incentives.js +1 -1
- package/dist/sdk/actions/cart-action-provider.d.ts +1 -1
- package/dist/sdk/actions/cart-action-provider.js +1 -1
- package/dist/sdk/actions/cart-action-provider.js.map +1 -1
- package/dist/sdk/actions/session-action-provider.d.ts +1 -1
- package/dist/sdk/actions/session-action-provider.js +1 -1
- package/dist/sdk/actions/session-action-provider.js.map +1 -1
- package/dist/sdk/actions/shipping-action-provider.d.ts +1 -1
- package/dist/sdk/actions/shipping-action-provider.js +1 -1
- package/dist/sdk/actions/shipping-action-provider.js.map +1 -1
- package/dist/sdk/cache/storefront-cache.js +1 -1
- package/dist/sdk/cache/storefront-cache.js.map +1 -1
- package/dist/sdk/cart/operations.d.ts +4 -4
- package/dist/sdk/cart/operations.js +1 -1
- package/dist/sdk/cart/operations.js.map +1 -1
- package/dist/sdk/cart/optimistic.js +1 -1
- package/dist/sdk/cart/optimistic.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.d.ts +1 -1
- package/dist/sdk/cart/use-cart-actions.js +3 -3
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js +1 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -1
- package/dist/sdk/cart/write-gate.js +1 -1
- package/dist/sdk/cart/write-gate.js.map +1 -1
- package/dist/sdk/data/page-reactive-data-root.d.ts +2 -2
- package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
- package/dist/sdk/data/reactive-data-provider.d.ts +1 -1
- package/dist/sdk/data/reactive-data-provider.js +1 -1
- package/dist/sdk/data/reactive-data-provider.js.map +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.d.ts +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.js +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -1
- package/dist/sdk/data/use-reactive-entity.js +1 -1
- package/dist/sdk/data/use-reactive-entity.js.map +1 -1
- package/dist/sdk/generated/gql.js +2 -1
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.js +85 -1
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/identity/operations.js.map +1 -1
- package/dist/sdk/identity/use-identity-actions.d.ts +1 -1
- package/dist/sdk/identity/use-identity-actions.js.map +1 -1
- package/dist/sdk/session/auth-operations.d.ts +1 -1
- package/dist/sdk/session/auth-operations.js.map +1 -1
- package/dist/sdk/session/use-session-actions.d.ts +1 -1
- package/dist/sdk/session/use-session-actions.js.map +1 -1
- package/dist/sdk/session/use-session-revalidation.js +65 -0
- package/dist/sdk/session/use-session-revalidation.js.map +1 -0
- package/dist/sdk/shipping/option-select-operations.d.ts +1 -1
- package/dist/sdk/shipping/option-select-operations.js.map +1 -1
- package/dist/sdk/shipping/request-timeout.js +1 -1
- package/dist/sdk/shipping/request-timeout.js.map +1 -1
- package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
- package/dist/sdk/shipping/shipping-operations.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-actions.d.ts +2 -2
- package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
- package/dist/sdk/state/cart.d.ts +3 -4
- package/dist/sdk/state/cart.js +6 -7
- package/dist/sdk/state/cart.js.map +1 -1
- package/dist/utils/safe-href.js +3 -3
- package/dist/utils/safe-href.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shipping-simulator.js","names":[],"sources":["../../../src/matter/shipping-simulator/shipping-simulator.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { FormattedMessage, type MessageId, useIntl } from '../../sdk/i18n/client.js';\nimport type { CartShippingSimulateInput } from '../../sdk/shipping/cart-operations.js';\nimport type { ShippingSimulateInput } from '../../sdk/shipping/operations.js';\nimport { useCartShippingSimulation } from '../../sdk/shipping/use-cart-shipping-simulation.js';\nimport { useShippingSimulation } from '../../sdk/shipping/use-shipping-simulation.js';\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ShippingSimulatorData on Query {\n productBySlug(slug: $slug) {\n variants(first: 1) {\n edges {\n node {\n id\n sellers {\n id\n isDefault\n }\n }\n }\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Raw data types (shape of the fragment result)\n// ---------------------------------------------------------------------------\n\ntype RawShippingSimulatorData = {\n variants: {\n edges: Array<{\n node: {\n id: string;\n sellers: Array<{\n id: string;\n isDefault: boolean;\n }>;\n };\n }>;\n };\n};\n\n// ---------------------------------------------------------------------------\n// Domain types (mirror the shippingSimulation GraphQL contract)\n// ---------------------------------------------------------------------------\n\ntype MoneyValue = { amount: number; currencyCode: string };\n\ntype DeliveryChannel = 'DELIVERY' | 'PICKUP' | 'UNKNOWN';\n\ntype ShippingEstimateUnit = 'BUSINESS_DAYS' | 'DAYS' | 'HOURS' | 'MINUTES';\n\ntype ShippingEstimate = { value: number; unit: ShippingEstimateUnit };\n\n// Exported alongside `ShippingSimulatorContextValue` so `DeliveryOptionsRoot`\n// (matter/delivery-options) can type against the exact shape the reused leaves expect, with no\n// structural duplication (specs/delivery-options-step.md Decision 2).\nexport type ShippingOption = {\n id: string;\n name: string;\n channel: DeliveryChannel;\n shippingEstimate: ShippingEstimate;\n price: MoneyValue;\n listPrice: MoneyValue;\n};\n\ntype ShippingSimulateErrorCode = 'INVALID_POSTAL_CODE' | 'UNKNOWN';\n\n// Exported with `ShippingSimulationPayload` so the `./client` entry can name the simulate callback's\n// whole contract — the SDK hooks return it and a store writing its own `onSimulate` has to name it.\nexport type ShippingSimulateError = {\n code: ShippingSimulateErrorCode;\n message: string;\n};\n\nexport type ShippingSimulationPayload = {\n shippingOptions: ShippingOption[] | null;\n userErrors: ShippingSimulateError[];\n};\n\ntype Status = 'idle' | 'loading' | 'success' | 'error';\n\nexport type ShippingSimulatorContextValue = {\n postalCode: string;\n setPostalCode: (value: string) => void;\n status: Status;\n shippingOptions: ShippingOption[] | null;\n userErrors: ShippingSimulateError[];\n submit: () => void;\n};\n\nconst SHIPPING_SIMULATOR_CONTEXT_UNSET = Symbol('ShippingSimulatorContextUnset');\n\nexport type ShippingSimulatorRootProps = ComponentPropsWithRef<'div'> & {\n country?: string;\n quantity?: number;\n variantId?: string;\n seller?: string;\n $data?: RawShippingSimulatorData | null;\n shippingOptions?: ShippingOption[];\n userErrors?: ShippingSimulateError[];\n onSimulate?: (input: ShippingSimulateInput) => Promise<ShippingSimulationPayload>;\n onResult?: (result: ShippingSimulationPayload) => void;\n};\n\nexport type CartShippingSimulatorRootProps = ComponentPropsWithRef<'div'> & {\n country?: string;\n shippingOptions?: ShippingOption[];\n userErrors?: ShippingSimulateError[];\n onSimulate?: (input: CartShippingSimulateInput) => Promise<ShippingSimulationPayload>;\n onResult?: (result: ShippingSimulationPayload) => void;\n};\n\nexport type ShippingSimulatorFormProps = ComponentPropsWithRef<'form'>;\n\nexport type ShippingSimulatorInputProps = Omit<ComponentPropsWithRef<'input'>, 'value' | 'onChange'> & {\n format?: boolean;\n};\n\nexport type ShippingSimulatorSubmitProps = ComponentPropsWithRef<'button'>;\n\nexport type ShippingSimulatorLoadingProps = ComponentPropsWithRef<'output'>;\n\nexport type ShippingSimulatorErrorProps = ComponentPropsWithRef<'div'>;\n\nexport type ShippingSimulatorOptionsProps = ComponentPropsWithRef<'ul'> & {\n sortBy?: 'price' | 'estimate';\n maxOptions?: number;\n};\n\nexport type ShippingSimulatorOptionProps = ComponentPropsWithRef<'li'>;\n\nexport type ShippingSimulatorOptionNameProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorOptionEstimateProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorOptionPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorOptionFreeBadgeProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorEmptyProps = ComponentPropsWithRef<'output'>;\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\n// Exported so `DeliveryOptionsRoot` can become a third provider by importing these same Context\n// objects directly (context matching is by identity, not shape). The two hooks below stay\n// module-private — providers need the objects, not the consumer API (Decision 2).\nexport const ShippingSimulatorContext = createContext<\n ShippingSimulatorContextValue | typeof SHIPPING_SIMULATOR_CONTEXT_UNSET\n>(SHIPPING_SIMULATOR_CONTEXT_UNSET);\n\nexport const OptionItemContext = createContext<ShippingOption | null>(null);\n\nfunction useShippingSimulator(): ShippingSimulatorContextValue {\n const ctx = useContext(ShippingSimulatorContext);\n if (ctx === SHIPPING_SIMULATOR_CONTEXT_UNSET) {\n throw new Error('ShippingSimulator components must be used inside ShippingSimulatorRoot.');\n }\n return ctx;\n}\n\nfunction useOptionItem(): ShippingOption {\n const ctx = useContext(OptionItemContext);\n if (!ctx) {\n throw new Error('ShippingSimulatorOption components must be used inside ShippingSimulatorOptions.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(value: number, locale: string, currency: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);\n}\n\n// Each unit's whole sentence, and the variable that sentence names.\n//\n// Whole sentence, not a unit fragment interpolated into a wrapper: interpolating a translated\n// fragment into a translated wrapper freezes \"preposition + noun\" order into every language, and\n// hands the translator `em {estimate}` with no way to agree preposition, article or case with a noun\n// they cannot see. The variable is named after what it counts (`{days}`, `{hours}`) rather than a\n// generic `{count}`, for the same reason.\n//\n// A `Record` and not a `switch` with a default: a fifth unit arriving in the GraphQL schema is a\n// type error here, not a silent fallback to the wrong sentence.\n//\n// `variable` is the union of the names those sentences read, never `string`: widened, a typo passes\n// typecheck, lint and every test, and the shopper gets the raw ICU pattern because `onIntlError` is\n// silent in production. The parity assertion in the test file closes the other half of the gap — that\n// the name written here is the one the catalog's message actually names.\nexport const ESTIMATE_MESSAGE: Record<ShippingEstimateUnit, { id: MessageId; variable: 'days' | 'hours' | 'minutes' }> =\n {\n BUSINESS_DAYS: { id: 'fs/shipping.estimate.in-business-days', variable: 'days' },\n DAYS: { id: 'fs/shipping.estimate.in-days', variable: 'days' },\n HOURS: { id: 'fs/shipping.estimate.in-hours', variable: 'hours' },\n MINUTES: { id: 'fs/shipping.estimate.in-minutes', variable: 'minutes' },\n };\n\n// Business days weigh the same as calendar days: exact wall-clock conversion is unknowable and\n// the ranking only needs a consistent order.\nconst ESTIMATE_UNIT_MINUTES: Record<ShippingEstimateUnit, number> = {\n MINUTES: 1,\n HOURS: 60,\n DAYS: 1440,\n BUSINESS_DAYS: 1440,\n};\n\nfunction sortShippingOptions(options: readonly ShippingOption[], sortBy: 'price' | 'estimate'): ShippingOption[] {\n const rank =\n sortBy === 'price'\n ? (option: ShippingOption) => Number(option.price.amount)\n : (option: ShippingOption) => option.shippingEstimate.value * ESTIMATE_UNIT_MINUTES[option.shippingEstimate.unit];\n return [...options].sort((a, b) => rank(a) - rank(b));\n}\n\nfunction normalizePostalCode(value: string): string {\n return value.replace(/\\D/g, '').slice(0, 8);\n}\n\nfunction formatPostalCode(value: string): string {\n const digits = normalizePostalCode(value);\n return digits.length > 5 ? `${digits.slice(0, 5)}-${digits.slice(5)}` : digits;\n}\n\nfunction extractProductFromData(data: RawShippingSimulatorData | null | undefined): {\n variantId: string | null;\n seller: string | null;\n} {\n if (!data) return { variantId: null, seller: null };\n const edge = data.variants?.edges?.[0];\n if (!edge) return { variantId: null, seller: null };\n const { id, sellers } = edge.node;\n const defaultSeller = sellers?.find((s) => s.isDefault) ?? sellers?.[0];\n return { variantId: id ?? null, seller: defaultSeller?.id ?? null };\n}\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ShippingSimulatorRootDefinition = defineComponent<ShippingSimulatorRootProps>({\n name: 'ShippingSimulatorRoot',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorRoot,\n fragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Shipping Simulator', category: 'commerce' },\n schema: {\n country: { type: 'string', default: 'BRA', label: 'Country (ISO-3)' },\n quantity: { type: 'number', default: 1, label: 'Quantity' },\n },\n providesContext: 'shipping-simulator',\n guideline:\n 'Root container for the PDP shipping simulator: a shopper types a postal code and sees a shipping preview for ONE product on a product detail page. Backed by shippingSimulation and a product fragment (productBySlug(slug: $slug)), so it must live on a page with a $slug variable. Use CartShippingSimulatorRoot instead for a whole-cart calculator in the cart/mini-cart. All other ShippingSimulator components must be descendants of this one.',\n});\n\nexport const CartShippingSimulatorRootDefinition = defineComponent<CartShippingSimulatorRootProps>({\n name: 'CartShippingSimulatorRoot',\n importPath: '@vtex/faststore/components',\n component: CartShippingSimulatorRoot,\n editor: { label: 'Cart Shipping Simulator', category: 'commerce' },\n schema: {\n country: { type: 'string', default: 'BRA', label: 'Country (ISO-3)' },\n },\n providesContext: 'shipping-simulator',\n guideline:\n 'Root container for the cart/mini-cart shipping calculator: the shopper types a postal code and sees the shipping options for the WHOLE cart. Backed by cartShippingSimulation (cart sourced server-side via x-order-form-id); needs no CartRoot ancestor and no product fragment. Use ShippingSimulatorRoot instead for a single-product shipping preview on a PDP. All other CartShippingSimulator components must be descendants of this one.',\n});\n\nexport const ShippingSimulatorFormDefinition = defineComponent<ShippingSimulatorFormProps>({\n name: 'ShippingSimulatorForm',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorForm,\n editor: { label: 'Shipping Simulator Form', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Form wrapper that holds ShippingSimulatorInput and ShippingSimulatorSubmit; must be a descendant of ShippingSimulatorRoot.',\n});\n\nexport const ShippingSimulatorInputDefinition = defineComponent<ShippingSimulatorInputProps>({\n name: 'ShippingSimulatorInput',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorInput,\n editor: { label: 'Shipping Simulator Input', category: 'action' },\n schema: {\n format: { type: 'boolean', default: false, label: 'Auto-format CEP (00000-000)' },\n },\n requiresContext: 'shipping-simulator',\n guideline:\n 'Postal-code text input; enable `format` to auto-hyphenate the CEP as the user types (e.g. 01310-100). The placeholder comes from the message catalog. Must be a descendant of ShippingSimulatorForm.',\n});\n\nexport const ShippingSimulatorSubmitDefinition = defineComponent<ShippingSimulatorSubmitProps>({\n name: 'ShippingSimulatorSubmit',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorSubmit,\n editor: { label: 'Shipping Simulator Submit', category: 'action' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline: 'Submit button for the postal-code form; must be a descendant of ShippingSimulatorForm.',\n});\n\nexport const ShippingSimulatorLoadingDefinition = defineComponent<ShippingSimulatorLoadingProps>({\n name: 'ShippingSimulatorLoading',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorLoading,\n editor: { label: 'Shipping Simulator Loading', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Loading indicator shown while a simulation is in progress; must be a descendant of ShippingSimulatorRoot.',\n});\n\nexport const ShippingSimulatorErrorDefinition = defineComponent<ShippingSimulatorErrorProps>({\n name: 'ShippingSimulatorError',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorError,\n editor: { label: 'Shipping Simulator Error', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Error banner shown when the simulation returns validation errors; must be a descendant of ShippingSimulatorRoot.',\n});\n\nexport const ShippingSimulatorOptionsDefinition = defineComponent<ShippingSimulatorOptionsProps>({\n name: 'ShippingSimulatorOptions',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptions,\n editor: { label: 'Shipping Simulator Options', category: 'commerce' },\n schema: {\n sortBy: { type: ['price', 'estimate'] as const, label: 'Sort by' },\n maxOptions: { type: 'number', label: 'Max options' },\n },\n requiresContext: 'shipping-simulator',\n providesContext: 'shipping-simulator-option',\n guideline:\n 'List that renders one ShippingSimulatorOption per available shipping option; must be a descendant of a shipping-simulator Root (PDP or cart). Renders every option in API order by default; set sortBy (\"price\" = cheapest first, \"estimate\" = fastest first) and maxOptions to cap the list — sortBy=\"price\" with maxOptions=1 shows only the cheapest option. See shipping-simulator.md.',\n});\n\nexport const ShippingSimulatorOptionDefinition = defineComponent<ShippingSimulatorOptionProps>({\n name: 'ShippingSimulatorOption',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOption,\n editor: { label: 'Shipping Simulator Option', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Container for a single shipping option row; holds ShippingSimulatorOptionName, ShippingSimulatorOptionEstimate, and ShippingSimulatorOptionPrice. Must be a descendant of ShippingSimulatorOptions.',\n});\n\nexport const ShippingSimulatorOptionNameDefinition = defineComponent<ShippingSimulatorOptionNameProps>({\n name: 'ShippingSimulatorOptionName',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionName,\n editor: { label: 'Option Name', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Displays the shipping option name (e.g. \"Entrega Normal\"); must be a descendant of ShippingSimulatorOption.',\n});\n\nexport const ShippingSimulatorOptionEstimateDefinition = defineComponent<ShippingSimulatorOptionEstimateProps>({\n name: 'ShippingSimulatorOptionEstimate',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionEstimate,\n editor: { label: 'Option Estimate', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Displays the delivery estimate in the active locale, one whole sentence per unit from the message catalog; a zero-value estimate (any unit) reads as an arrival-today message instead, since \"chega em 0 dias úteis\" reads wrong. Must be a descendant of ShippingSimulatorOption.',\n});\n\nexport const ShippingSimulatorOptionPriceDefinition = defineComponent<ShippingSimulatorOptionPriceProps>({\n name: 'ShippingSimulatorOptionPrice',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionPrice,\n editor: { label: 'Option Price', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Displays the shipping price, showing the free-shipping label from the message catalog when the amount is zero; must be a descendant of ShippingSimulatorOption.',\n});\n\nexport const ShippingSimulatorOptionFreeBadgeDefinition = defineComponent<ShippingSimulatorOptionFreeBadgeProps>({\n name: 'ShippingSimulatorOptionFreeBadge',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionFreeBadge,\n editor: { label: 'Option Free Badge', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Badge shown only when the current option price is zero (free shipping); renders nothing otherwise. Must be a descendant of ShippingSimulatorOption. Orthogonal to the free-price replacement text owned by ShippingSimulatorOptionPrice.',\n});\n\nexport const ShippingSimulatorEmptyDefinition = defineComponent<ShippingSimulatorEmptyProps>({\n name: 'ShippingSimulatorEmpty',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorEmpty,\n editor: { label: 'Shipping Simulator Empty', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Message shown when a simulation ran and returned no shipping options (e.g. no carrier common to the whole cart). Renders nothing before the first submit and nothing when options or an error are present. The copy comes from the message catalog; pass children to override. Must be a descendant of a shipping-simulator Root.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function ShippingSimulatorRoot({\n country = 'BRA',\n quantity = 1,\n variantId: variantIdProp,\n seller: sellerProp,\n $data: $dataProp,\n shippingOptions: shippingOptionsProp,\n userErrors: userErrorsProp,\n onSimulate: onSimulateProp,\n onResult,\n className,\n children,\n ...props\n}: ShippingSimulatorRootProps) {\n const defaultSimulate = useShippingSimulation();\n const onSimulate = onSimulateProp ?? defaultSimulate;\n const intl = useIntl();\n\n const $data = useDataOverride($dataProp);\n const extracted = extractProductFromData($data);\n const variantId = variantIdProp ?? extracted.variantId;\n const seller = sellerProp ?? extracted.seller;\n\n const [postalCode, setPostalCode] = useState('');\n const [status, setStatus] = useState<Status>(() => {\n if (userErrorsProp?.length) return 'error';\n if (shippingOptionsProp) return 'success';\n return 'idle';\n });\n const [shippingOptions, setShippingOptions] = useState<ShippingOption[] | null>(shippingOptionsProp ?? null);\n const [userErrors, setUserErrors] = useState<ShippingSimulateError[]>(userErrorsProp ?? []);\n\n const submissionToken = useRef(0);\n\n const submit = useCallback(() => {\n if (!onSimulate || !variantId || !seller) return;\n\n const normalizedCep = normalizePostalCode(postalCode);\n if (normalizedCep.length !== 8) return;\n\n const token = ++submissionToken.current;\n setStatus('loading');\n setShippingOptions(null);\n setUserErrors([]);\n\n onSimulate({ postalCode: normalizedCep, country, variantId, quantity, seller })\n .then((result) => {\n if (submissionToken.current !== token) return;\n setShippingOptions(result.shippingOptions);\n setUserErrors(result.userErrors);\n setStatus(result.userErrors.length > 0 ? 'error' : 'success');\n onResult?.(result);\n })\n .catch(() => {\n if (submissionToken.current !== token) return;\n // In a handler, not a render: the message goes into state, where only a string fits.\n const fallback: ShippingSimulateError = {\n code: 'UNKNOWN',\n message: intl.formatMessage({ id: 'fs/shipping.calculation-failed' }),\n };\n setShippingOptions(null);\n setUserErrors([fallback]);\n setStatus('error');\n onResult?.({ shippingOptions: null, userErrors: [fallback] });\n });\n }, [country, intl, onResult, onSimulate, postalCode, quantity, seller, variantId]);\n\n const contextValue = useMemo<ShippingSimulatorContextValue>(\n () => ({\n postalCode,\n setPostalCode,\n status,\n shippingOptions,\n userErrors,\n submit,\n }),\n [postalCode, status, shippingOptions, userErrors, submit],\n );\n\n return (\n <ShippingSimulatorContext value={contextValue}>\n <div {...props} className={className} data-fs-shipping-simulator=\"\">\n {children}\n </div>\n </ShippingSimulatorContext>\n );\n}\n\nexport function CartShippingSimulatorRoot({\n country = 'BRA',\n shippingOptions: shippingOptionsProp,\n userErrors: userErrorsProp,\n onSimulate: onSimulateProp,\n onResult,\n className,\n children,\n ...props\n}: CartShippingSimulatorRootProps) {\n const defaultSimulate = useCartShippingSimulation();\n const onSimulate = onSimulateProp ?? defaultSimulate;\n const intl = useIntl();\n\n const [postalCode, setPostalCode] = useState('');\n const [status, setStatus] = useState<Status>(() => {\n if (userErrorsProp?.length) return 'error';\n if (shippingOptionsProp) return 'success';\n return 'idle';\n });\n const [shippingOptions, setShippingOptions] = useState<ShippingOption[] | null>(shippingOptionsProp ?? null);\n const [userErrors, setUserErrors] = useState<ShippingSimulateError[]>(userErrorsProp ?? []);\n\n const submissionToken = useRef(0);\n\n const submit = useCallback(() => {\n const normalizedCep = normalizePostalCode(postalCode);\n if (normalizedCep.length !== 8) return;\n\n const token = ++submissionToken.current;\n setStatus('loading');\n setShippingOptions(null);\n setUserErrors([]);\n\n onSimulate({ postalCode: normalizedCep, country })\n .then((result) => {\n if (submissionToken.current !== token) return;\n setShippingOptions(result.shippingOptions);\n setUserErrors(result.userErrors);\n setStatus(result.userErrors.length > 0 ? 'error' : 'success');\n onResult?.(result);\n })\n .catch(() => {\n if (submissionToken.current !== token) return;\n // In a handler, not a render: the message goes into state, where only a string fits.\n const fallback: ShippingSimulateError = {\n code: 'UNKNOWN',\n message: intl.formatMessage({ id: 'fs/shipping.calculation-failed' }),\n };\n setShippingOptions(null);\n setUserErrors([fallback]);\n setStatus('error');\n onResult?.({ shippingOptions: null, userErrors: [fallback] });\n });\n }, [country, intl, onResult, onSimulate, postalCode]);\n\n const contextValue = useMemo<ShippingSimulatorContextValue>(\n () => ({\n postalCode,\n setPostalCode,\n status,\n shippingOptions,\n userErrors,\n submit,\n }),\n [postalCode, status, shippingOptions, userErrors, submit],\n );\n\n return (\n <ShippingSimulatorContext value={contextValue}>\n <div {...props} className={className} data-fs-shipping-simulator=\"\">\n {children}\n </div>\n </ShippingSimulatorContext>\n );\n}\n\nexport function ShippingSimulatorForm({ className, children, ...props }: ShippingSimulatorFormProps) {\n const { submit } = useShippingSimulator();\n\n return (\n <form\n {...props}\n className={className}\n data-fs-shipping-simulator-form=\"\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n {children}\n </form>\n );\n}\n\nexport function ShippingSimulatorInput({\n className,\n placeholder,\n 'aria-label': ariaLabel,\n format = false,\n ...props\n}: ShippingSimulatorInputProps) {\n const { postalCode, setPostalCode } = useShippingSimulator();\n const intl = useIntl();\n const displayValue = format ? formatPostalCode(postalCode) : postalCode;\n\n return (\n <input\n {...props}\n aria-label={ariaLabel ?? intl.formatMessage({ id: 'fs/shipping.postal-code.aria-label' })}\n className={className}\n data-fs-shipping-simulator-input=\"\"\n type=\"text\"\n value={displayValue}\n onChange={(event) => setPostalCode(normalizePostalCode(event.target.value))}\n placeholder={placeholder ?? intl.formatMessage({ id: 'fs/shipping.postal-code.placeholder' })}\n pattern=\"\\d{5}-?\\d{3}\"\n maxLength={9}\n inputMode=\"numeric\"\n required\n />\n );\n}\n\nexport function ShippingSimulatorSubmit({ className, children, disabled, ...props }: ShippingSimulatorSubmitProps) {\n const { status } = useShippingSimulator();\n const isLoading = status === 'loading';\n\n return (\n <button\n {...props}\n type=\"submit\"\n className={className}\n data-fs-shipping-simulator-submit=\"\"\n disabled={disabled || isLoading}\n aria-busy={isLoading}\n >\n {children}\n </button>\n );\n}\n\nexport function ShippingSimulatorLoading({ className, children, ...props }: ShippingSimulatorLoadingProps) {\n const { status } = useShippingSimulator();\n if (status !== 'loading') return null;\n\n return (\n <output {...props} aria-live=\"polite\" className={className} data-fs-shipping-simulator-loading=\"\">\n {children ?? <FormattedMessage id=\"fs/shipping.calculating\" />}\n </output>\n );\n}\n\nexport function ShippingSimulatorError({ className, children, ...props }: ShippingSimulatorErrorProps) {\n const { userErrors } = useShippingSimulator();\n const [firstError] = userErrors;\n if (!firstError) return null;\n\n return (\n <div {...props} role=\"alert\" className={className} data-fs-shipping-simulator-error=\"\">\n {children ?? firstError.message}\n </div>\n );\n}\n\nexport function ShippingSimulatorOptions({\n sortBy,\n maxOptions,\n className,\n children,\n ...props\n}: ShippingSimulatorOptionsProps) {\n const { shippingOptions } = useShippingSimulator();\n\n const visibleOptions = useMemo(() => {\n if (!shippingOptions) return null;\n const sorted = sortBy ? sortShippingOptions(shippingOptions, sortBy) : shippingOptions;\n return maxOptions && maxOptions > 0 ? sorted.slice(0, maxOptions) : sorted;\n }, [shippingOptions, sortBy, maxOptions]);\n\n if (!visibleOptions || visibleOptions.length === 0) return null;\n\n return (\n <ul {...props} className={className} data-fs-shipping-simulator-options=\"\">\n {visibleOptions.map((option) => (\n <OptionItemContext key={option.id} value={option}>\n {children}\n </OptionItemContext>\n ))}\n </ul>\n );\n}\n\nexport function ShippingSimulatorOption({ className, children, ...props }: ShippingSimulatorOptionProps) {\n const option = useOptionItem();\n\n return (\n <li\n {...props}\n className={className}\n data-fs-shipping-simulator-option=\"\"\n data-fs-shipping-simulator-option-channel={option.channel}\n >\n {children}\n </li>\n );\n}\n\nexport function ShippingSimulatorOptionName({ className, children, ...props }: ShippingSimulatorOptionNameProps) {\n const option = useOptionItem();\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-name=\"\">\n {children ?? option.name}\n </span>\n );\n}\n\nexport function ShippingSimulatorOptionEstimate({\n className,\n children,\n ...props\n}: ShippingSimulatorOptionEstimateProps) {\n const option = useOptionItem();\n const intl = useIntl();\n const { value, unit } = option.shippingEstimate;\n const { id, variable } = ESTIMATE_MESSAGE[unit];\n const text =\n value === 0\n ? intl.formatMessage({ id: 'fs/shipping.estimate.today' })\n : intl.formatMessage({ id }, { [variable]: value });\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-estimate=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function ShippingSimulatorOptionPrice({ className, children, ...props }: ShippingSimulatorOptionPriceProps) {\n const option = useOptionItem();\n const intl = useIntl();\n const { locale, currency } = useStorefrontContext();\n const text =\n option.price.amount === 0\n ? intl.formatMessage({ id: 'fs/shipping.free-price' })\n : formatPrice(option.price.amount, locale, currency);\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-price=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function ShippingSimulatorOptionFreeBadge({\n className,\n children,\n ...props\n}: ShippingSimulatorOptionFreeBadgeProps) {\n const option = useOptionItem();\n if (option.price.amount !== 0) return null;\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-free-badge=\"\">\n {children ?? <FormattedMessage id=\"fs/shipping.free-badge\" />}\n </span>\n );\n}\n\nexport function ShippingSimulatorEmpty({ className, children, ...props }: ShippingSimulatorEmptyProps) {\n const { shippingOptions, userErrors } = useShippingSimulator();\n // Idle (null) → nothing; error → nothing (Error owns it); options present → nothing.\n const simulatedEmpty = Array.isArray(shippingOptions) && shippingOptions.length === 0 && userErrors.length === 0;\n if (!simulatedEmpty) return null;\n\n return (\n <output {...props} aria-live=\"polite\" className={className} data-fs-shipping-simulator-empty=\"\">\n {children ?? <FormattedMessage id=\"fs/shipping.no-options\" />}\n </output>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Namespace export\n// ---------------------------------------------------------------------------\n\nexport const ShippingSimulator = {\n Root: ShippingSimulatorRoot,\n Form: ShippingSimulatorForm,\n Input: ShippingSimulatorInput,\n Submit: ShippingSimulatorSubmit,\n Loading: ShippingSimulatorLoading,\n Error: ShippingSimulatorError,\n Options: ShippingSimulatorOptions,\n Option: ShippingSimulatorOption,\n OptionName: ShippingSimulatorOptionName,\n OptionEstimate: ShippingSimulatorOptionEstimate,\n OptionPrice: ShippingSimulatorOptionPrice,\n OptionFreeBadge: ShippingSimulatorOptionFreeBadge,\n Empty: ShippingSimulatorEmpty,\n};\n\nexport const CartShippingSimulator = {\n Root: CartShippingSimulatorRoot,\n Form: ShippingSimulatorForm,\n Input: ShippingSimulatorInput,\n Submit: ShippingSimulatorSubmit,\n Loading: ShippingSimulatorLoading,\n Error: ShippingSimulatorError,\n Options: ShippingSimulatorOptions,\n Option: ShippingSimulatorOption,\n OptionName: ShippingSimulatorOptionName,\n OptionEstimate: ShippingSimulatorOptionEstimate,\n OptionPrice: ShippingSimulatorOptionPrice,\n OptionFreeBadge: ShippingSimulatorOptionFreeBadge,\n Empty: ShippingSimulatorEmpty,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shipping-simulator.js","names":[],"sources":["../../../src/matter/shipping-simulator/shipping-simulator.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { FormattedMessage, type MessageId, useIntl } from '../../sdk/i18n/client.js';\nimport type { CartShippingSimulateInput } from '../../sdk/shipping/cart-operations.js';\nimport type { ShippingSimulateInput } from '../../sdk/shipping/operations.js';\nimport { useCartShippingSimulation } from '../../sdk/shipping/use-cart-shipping-simulation.js';\nimport { useShippingSimulation } from '../../sdk/shipping/use-shipping-simulation.js';\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ShippingSimulatorData on Query {\n productBySlug(slug: $slug) {\n variants(first: 1) {\n edges {\n node {\n id\n sellers {\n id\n isDefault\n }\n }\n }\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Raw data types (shape of the fragment result)\n// ---------------------------------------------------------------------------\n\ntype RawShippingSimulatorData = {\n variants: {\n edges: Array<{\n node: {\n id: string;\n sellers: Array<{\n id: string;\n isDefault: boolean;\n }>;\n };\n }>;\n };\n};\n\n// ---------------------------------------------------------------------------\n// Domain types (mirror the shippingSimulation GraphQL contract)\n// ---------------------------------------------------------------------------\n\ntype MoneyValue = { amount: number; currencyCode: string };\n\ntype DeliveryChannel = 'DELIVERY' | 'PICKUP' | 'UNKNOWN';\n\ntype ShippingEstimateUnit = 'BUSINESS_DAYS' | 'DAYS' | 'HOURS' | 'MINUTES';\n\ntype ShippingEstimate = { value: number; unit: ShippingEstimateUnit };\n\n// Exported alongside `ShippingSimulatorContextValue` so `DeliveryOptionsRoot`\n// (matter/delivery-options) can type against the exact shape the reused leaves expect, with no\n// structural duplication (docs/storefront-core/reference-free-particle-model.md § Read side — state).\nexport type ShippingOption = {\n id: string;\n name: string;\n channel: DeliveryChannel;\n shippingEstimate: ShippingEstimate;\n price: MoneyValue;\n listPrice: MoneyValue;\n};\n\ntype ShippingSimulateErrorCode = 'INVALID_POSTAL_CODE' | 'UNKNOWN';\n\n// Exported with `ShippingSimulationPayload` so the `./client` entry can name the simulate callback's\n// whole contract — the SDK hooks return it and a store writing its own `onSimulate` has to name it.\nexport type ShippingSimulateError = {\n code: ShippingSimulateErrorCode;\n message: string;\n};\n\nexport type ShippingSimulationPayload = {\n shippingOptions: ShippingOption[] | null;\n userErrors: ShippingSimulateError[];\n};\n\ntype Status = 'idle' | 'loading' | 'success' | 'error';\n\nexport type ShippingSimulatorContextValue = {\n postalCode: string;\n setPostalCode: (value: string) => void;\n status: Status;\n shippingOptions: ShippingOption[] | null;\n userErrors: ShippingSimulateError[];\n submit: () => void;\n};\n\nconst SHIPPING_SIMULATOR_CONTEXT_UNSET = Symbol('ShippingSimulatorContextUnset');\n\nexport type ShippingSimulatorRootProps = ComponentPropsWithRef<'div'> & {\n country?: string;\n quantity?: number;\n variantId?: string;\n seller?: string;\n $data?: RawShippingSimulatorData | null;\n shippingOptions?: ShippingOption[];\n userErrors?: ShippingSimulateError[];\n onSimulate?: (input: ShippingSimulateInput) => Promise<ShippingSimulationPayload>;\n onResult?: (result: ShippingSimulationPayload) => void;\n};\n\nexport type CartShippingSimulatorRootProps = ComponentPropsWithRef<'div'> & {\n country?: string;\n shippingOptions?: ShippingOption[];\n userErrors?: ShippingSimulateError[];\n onSimulate?: (input: CartShippingSimulateInput) => Promise<ShippingSimulationPayload>;\n onResult?: (result: ShippingSimulationPayload) => void;\n};\n\nexport type ShippingSimulatorFormProps = ComponentPropsWithRef<'form'>;\n\nexport type ShippingSimulatorInputProps = Omit<ComponentPropsWithRef<'input'>, 'value' | 'onChange'> & {\n format?: boolean;\n};\n\nexport type ShippingSimulatorSubmitProps = ComponentPropsWithRef<'button'>;\n\nexport type ShippingSimulatorLoadingProps = ComponentPropsWithRef<'output'>;\n\nexport type ShippingSimulatorErrorProps = ComponentPropsWithRef<'div'>;\n\nexport type ShippingSimulatorOptionsProps = ComponentPropsWithRef<'ul'> & {\n sortBy?: 'price' | 'estimate';\n maxOptions?: number;\n};\n\nexport type ShippingSimulatorOptionProps = ComponentPropsWithRef<'li'>;\n\nexport type ShippingSimulatorOptionNameProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorOptionEstimateProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorOptionPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorOptionFreeBadgeProps = ComponentPropsWithRef<'span'>;\n\nexport type ShippingSimulatorEmptyProps = ComponentPropsWithRef<'output'>;\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\n// Exported so `DeliveryOptionsRoot` can become a third provider by importing these same Context\n// objects directly (context matching is by identity, not shape). The two hooks below stay\n// module-private — providers need the objects, not the consumer API (Decision 2).\nexport const ShippingSimulatorContext = createContext<\n ShippingSimulatorContextValue | typeof SHIPPING_SIMULATOR_CONTEXT_UNSET\n>(SHIPPING_SIMULATOR_CONTEXT_UNSET);\n\nexport const OptionItemContext = createContext<ShippingOption | null>(null);\n\nfunction useShippingSimulator(): ShippingSimulatorContextValue {\n const ctx = useContext(ShippingSimulatorContext);\n if (ctx === SHIPPING_SIMULATOR_CONTEXT_UNSET) {\n throw new Error('ShippingSimulator components must be used inside ShippingSimulatorRoot.');\n }\n return ctx;\n}\n\nfunction useOptionItem(): ShippingOption {\n const ctx = useContext(OptionItemContext);\n if (!ctx) {\n throw new Error('ShippingSimulatorOption components must be used inside ShippingSimulatorOptions.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(value: number, locale: string, currency: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);\n}\n\n// Each unit's whole sentence, and the variable that sentence names.\n//\n// Whole sentence, not a unit fragment interpolated into a wrapper: interpolating a translated\n// fragment into a translated wrapper freezes \"preposition + noun\" order into every language, and\n// hands the translator `em {estimate}` with no way to agree preposition, article or case with a noun\n// they cannot see. The variable is named after what it counts (`{days}`, `{hours}`) rather than a\n// generic `{count}`, for the same reason.\n//\n// A `Record` and not a `switch` with a default: a fifth unit arriving in the GraphQL schema is a\n// type error here, not a silent fallback to the wrong sentence.\n//\n// `variable` is the union of the names those sentences read, never `string`: widened, a typo passes\n// typecheck, lint and every test, and the shopper gets the raw ICU pattern because `onIntlError` is\n// silent in production. The parity assertion in the test file closes the other half of the gap — that\n// the name written here is the one the catalog's message actually names.\nexport const ESTIMATE_MESSAGE: Record<ShippingEstimateUnit, { id: MessageId; variable: 'days' | 'hours' | 'minutes' }> =\n {\n BUSINESS_DAYS: { id: 'fs/shipping.estimate.in-business-days', variable: 'days' },\n DAYS: { id: 'fs/shipping.estimate.in-days', variable: 'days' },\n HOURS: { id: 'fs/shipping.estimate.in-hours', variable: 'hours' },\n MINUTES: { id: 'fs/shipping.estimate.in-minutes', variable: 'minutes' },\n };\n\n// Business days weigh the same as calendar days: exact wall-clock conversion is unknowable and\n// the ranking only needs a consistent order.\nconst ESTIMATE_UNIT_MINUTES: Record<ShippingEstimateUnit, number> = {\n MINUTES: 1,\n HOURS: 60,\n DAYS: 1440,\n BUSINESS_DAYS: 1440,\n};\n\nfunction sortShippingOptions(options: readonly ShippingOption[], sortBy: 'price' | 'estimate'): ShippingOption[] {\n const rank =\n sortBy === 'price'\n ? (option: ShippingOption) => Number(option.price.amount)\n : (option: ShippingOption) => option.shippingEstimate.value * ESTIMATE_UNIT_MINUTES[option.shippingEstimate.unit];\n return [...options].sort((a, b) => rank(a) - rank(b));\n}\n\nfunction normalizePostalCode(value: string): string {\n return value.replace(/\\D/g, '').slice(0, 8);\n}\n\nfunction formatPostalCode(value: string): string {\n const digits = normalizePostalCode(value);\n return digits.length > 5 ? `${digits.slice(0, 5)}-${digits.slice(5)}` : digits;\n}\n\nfunction extractProductFromData(data: RawShippingSimulatorData | null | undefined): {\n variantId: string | null;\n seller: string | null;\n} {\n if (!data) return { variantId: null, seller: null };\n const edge = data.variants?.edges?.[0];\n if (!edge) return { variantId: null, seller: null };\n const { id, sellers } = edge.node;\n const defaultSeller = sellers?.find((s) => s.isDefault) ?? sellers?.[0];\n return { variantId: id ?? null, seller: defaultSeller?.id ?? null };\n}\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ShippingSimulatorRootDefinition = defineComponent<ShippingSimulatorRootProps>({\n name: 'ShippingSimulatorRoot',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorRoot,\n fragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Shipping Simulator', category: 'commerce' },\n schema: {\n country: { type: 'string', default: 'BRA', label: 'Country (ISO-3)' },\n quantity: { type: 'number', default: 1, label: 'Quantity' },\n },\n providesContext: 'shipping-simulator',\n guideline:\n 'Root container for the PDP shipping simulator: a shopper types a postal code and sees a shipping preview for ONE product on a product detail page. Backed by shippingSimulation and a product fragment (productBySlug(slug: $slug)), so it must live on a page with a $slug variable. Use CartShippingSimulatorRoot instead for a whole-cart calculator in the cart/mini-cart. All other ShippingSimulator components must be descendants of this one.',\n});\n\nexport const CartShippingSimulatorRootDefinition = defineComponent<CartShippingSimulatorRootProps>({\n name: 'CartShippingSimulatorRoot',\n importPath: '@vtex/faststore/components',\n component: CartShippingSimulatorRoot,\n editor: { label: 'Cart Shipping Simulator', category: 'commerce' },\n schema: {\n country: { type: 'string', default: 'BRA', label: 'Country (ISO-3)' },\n },\n providesContext: 'shipping-simulator',\n guideline:\n 'Root container for the cart/mini-cart shipping calculator: the shopper types a postal code and sees the shipping options for the WHOLE cart. Backed by cartShippingSimulation (cart sourced server-side via x-order-form-id); needs no CartRoot ancestor and no product fragment. Use ShippingSimulatorRoot instead for a single-product shipping preview on a PDP. All other CartShippingSimulator components must be descendants of this one.',\n});\n\nexport const ShippingSimulatorFormDefinition = defineComponent<ShippingSimulatorFormProps>({\n name: 'ShippingSimulatorForm',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorForm,\n editor: { label: 'Shipping Simulator Form', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Form wrapper that holds ShippingSimulatorInput and ShippingSimulatorSubmit; must be a descendant of ShippingSimulatorRoot.',\n});\n\nexport const ShippingSimulatorInputDefinition = defineComponent<ShippingSimulatorInputProps>({\n name: 'ShippingSimulatorInput',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorInput,\n editor: { label: 'Shipping Simulator Input', category: 'action' },\n schema: {\n format: { type: 'boolean', default: false, label: 'Auto-format CEP (00000-000)' },\n },\n requiresContext: 'shipping-simulator',\n guideline:\n 'Postal-code text input; enable `format` to auto-hyphenate the CEP as the user types (e.g. 01310-100). The placeholder comes from the message catalog. Must be a descendant of ShippingSimulatorForm.',\n});\n\nexport const ShippingSimulatorSubmitDefinition = defineComponent<ShippingSimulatorSubmitProps>({\n name: 'ShippingSimulatorSubmit',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorSubmit,\n editor: { label: 'Shipping Simulator Submit', category: 'action' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline: 'Submit button for the postal-code form; must be a descendant of ShippingSimulatorForm.',\n});\n\nexport const ShippingSimulatorLoadingDefinition = defineComponent<ShippingSimulatorLoadingProps>({\n name: 'ShippingSimulatorLoading',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorLoading,\n editor: { label: 'Shipping Simulator Loading', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Loading indicator shown while a simulation is in progress; must be a descendant of ShippingSimulatorRoot.',\n});\n\nexport const ShippingSimulatorErrorDefinition = defineComponent<ShippingSimulatorErrorProps>({\n name: 'ShippingSimulatorError',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorError,\n editor: { label: 'Shipping Simulator Error', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Error banner shown when the simulation returns validation errors; must be a descendant of ShippingSimulatorRoot.',\n});\n\nexport const ShippingSimulatorOptionsDefinition = defineComponent<ShippingSimulatorOptionsProps>({\n name: 'ShippingSimulatorOptions',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptions,\n editor: { label: 'Shipping Simulator Options', category: 'commerce' },\n schema: {\n sortBy: { type: ['price', 'estimate'] as const, label: 'Sort by' },\n maxOptions: { type: 'number', label: 'Max options' },\n },\n requiresContext: 'shipping-simulator',\n providesContext: 'shipping-simulator-option',\n guideline:\n 'List that renders one ShippingSimulatorOption per available shipping option; must be a descendant of a shipping-simulator Root (PDP or cart). Renders every option in API order by default; set sortBy (\"price\" = cheapest first, \"estimate\" = fastest first) and maxOptions to cap the list — sortBy=\"price\" with maxOptions=1 shows only the cheapest option. See shipping-simulator.md.',\n});\n\nexport const ShippingSimulatorOptionDefinition = defineComponent<ShippingSimulatorOptionProps>({\n name: 'ShippingSimulatorOption',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOption,\n editor: { label: 'Shipping Simulator Option', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Container for a single shipping option row; holds ShippingSimulatorOptionName, ShippingSimulatorOptionEstimate, and ShippingSimulatorOptionPrice. Must be a descendant of ShippingSimulatorOptions.',\n});\n\nexport const ShippingSimulatorOptionNameDefinition = defineComponent<ShippingSimulatorOptionNameProps>({\n name: 'ShippingSimulatorOptionName',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionName,\n editor: { label: 'Option Name', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Displays the shipping option name (e.g. \"Entrega Normal\"); must be a descendant of ShippingSimulatorOption.',\n});\n\nexport const ShippingSimulatorOptionEstimateDefinition = defineComponent<ShippingSimulatorOptionEstimateProps>({\n name: 'ShippingSimulatorOptionEstimate',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionEstimate,\n editor: { label: 'Option Estimate', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Displays the delivery estimate in the active locale, one whole sentence per unit from the message catalog; a zero-value estimate (any unit) reads as an arrival-today message instead, since \"chega em 0 dias úteis\" reads wrong. Must be a descendant of ShippingSimulatorOption.',\n});\n\nexport const ShippingSimulatorOptionPriceDefinition = defineComponent<ShippingSimulatorOptionPriceProps>({\n name: 'ShippingSimulatorOptionPrice',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionPrice,\n editor: { label: 'Option Price', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Displays the shipping price, showing the free-shipping label from the message catalog when the amount is zero; must be a descendant of ShippingSimulatorOption.',\n});\n\nexport const ShippingSimulatorOptionFreeBadgeDefinition = defineComponent<ShippingSimulatorOptionFreeBadgeProps>({\n name: 'ShippingSimulatorOptionFreeBadge',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorOptionFreeBadge,\n editor: { label: 'Option Free Badge', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator-option',\n guideline:\n 'Badge shown only when the current option price is zero (free shipping); renders nothing otherwise. Must be a descendant of ShippingSimulatorOption. Orthogonal to the free-price replacement text owned by ShippingSimulatorOptionPrice.',\n});\n\nexport const ShippingSimulatorEmptyDefinition = defineComponent<ShippingSimulatorEmptyProps>({\n name: 'ShippingSimulatorEmpty',\n importPath: '@vtex/faststore/components',\n component: ShippingSimulatorEmpty,\n editor: { label: 'Shipping Simulator Empty', category: 'commerce' },\n schema: {},\n requiresContext: 'shipping-simulator',\n guideline:\n 'Message shown when a simulation ran and returned no shipping options (e.g. no carrier common to the whole cart). Renders nothing before the first submit and nothing when options or an error are present. The copy comes from the message catalog; pass children to override. Must be a descendant of a shipping-simulator Root.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function ShippingSimulatorRoot({\n country = 'BRA',\n quantity = 1,\n variantId: variantIdProp,\n seller: sellerProp,\n $data: $dataProp,\n shippingOptions: shippingOptionsProp,\n userErrors: userErrorsProp,\n onSimulate: onSimulateProp,\n onResult,\n className,\n children,\n ...props\n}: ShippingSimulatorRootProps) {\n const defaultSimulate = useShippingSimulation();\n const onSimulate = onSimulateProp ?? defaultSimulate;\n const intl = useIntl();\n\n const $data = useDataOverride($dataProp);\n const extracted = extractProductFromData($data);\n const variantId = variantIdProp ?? extracted.variantId;\n const seller = sellerProp ?? extracted.seller;\n\n const [postalCode, setPostalCode] = useState('');\n const [status, setStatus] = useState<Status>(() => {\n if (userErrorsProp?.length) return 'error';\n if (shippingOptionsProp) return 'success';\n return 'idle';\n });\n const [shippingOptions, setShippingOptions] = useState<ShippingOption[] | null>(shippingOptionsProp ?? null);\n const [userErrors, setUserErrors] = useState<ShippingSimulateError[]>(userErrorsProp ?? []);\n\n const submissionToken = useRef(0);\n\n const submit = useCallback(() => {\n if (!onSimulate || !variantId || !seller) return;\n\n const normalizedCep = normalizePostalCode(postalCode);\n if (normalizedCep.length !== 8) return;\n\n const token = ++submissionToken.current;\n setStatus('loading');\n setShippingOptions(null);\n setUserErrors([]);\n\n onSimulate({ postalCode: normalizedCep, country, variantId, quantity, seller })\n .then((result) => {\n if (submissionToken.current !== token) return;\n setShippingOptions(result.shippingOptions);\n setUserErrors(result.userErrors);\n setStatus(result.userErrors.length > 0 ? 'error' : 'success');\n onResult?.(result);\n })\n .catch(() => {\n if (submissionToken.current !== token) return;\n // In a handler, not a render: the message goes into state, where only a string fits.\n const fallback: ShippingSimulateError = {\n code: 'UNKNOWN',\n message: intl.formatMessage({ id: 'fs/shipping.calculation-failed' }),\n };\n setShippingOptions(null);\n setUserErrors([fallback]);\n setStatus('error');\n onResult?.({ shippingOptions: null, userErrors: [fallback] });\n });\n }, [country, intl, onResult, onSimulate, postalCode, quantity, seller, variantId]);\n\n const contextValue = useMemo<ShippingSimulatorContextValue>(\n () => ({\n postalCode,\n setPostalCode,\n status,\n shippingOptions,\n userErrors,\n submit,\n }),\n [postalCode, status, shippingOptions, userErrors, submit],\n );\n\n return (\n <ShippingSimulatorContext value={contextValue}>\n <div {...props} className={className} data-fs-shipping-simulator=\"\">\n {children}\n </div>\n </ShippingSimulatorContext>\n );\n}\n\nexport function CartShippingSimulatorRoot({\n country = 'BRA',\n shippingOptions: shippingOptionsProp,\n userErrors: userErrorsProp,\n onSimulate: onSimulateProp,\n onResult,\n className,\n children,\n ...props\n}: CartShippingSimulatorRootProps) {\n const defaultSimulate = useCartShippingSimulation();\n const onSimulate = onSimulateProp ?? defaultSimulate;\n const intl = useIntl();\n\n const [postalCode, setPostalCode] = useState('');\n const [status, setStatus] = useState<Status>(() => {\n if (userErrorsProp?.length) return 'error';\n if (shippingOptionsProp) return 'success';\n return 'idle';\n });\n const [shippingOptions, setShippingOptions] = useState<ShippingOption[] | null>(shippingOptionsProp ?? null);\n const [userErrors, setUserErrors] = useState<ShippingSimulateError[]>(userErrorsProp ?? []);\n\n const submissionToken = useRef(0);\n\n const submit = useCallback(() => {\n const normalizedCep = normalizePostalCode(postalCode);\n if (normalizedCep.length !== 8) return;\n\n const token = ++submissionToken.current;\n setStatus('loading');\n setShippingOptions(null);\n setUserErrors([]);\n\n onSimulate({ postalCode: normalizedCep, country })\n .then((result) => {\n if (submissionToken.current !== token) return;\n setShippingOptions(result.shippingOptions);\n setUserErrors(result.userErrors);\n setStatus(result.userErrors.length > 0 ? 'error' : 'success');\n onResult?.(result);\n })\n .catch(() => {\n if (submissionToken.current !== token) return;\n // In a handler, not a render: the message goes into state, where only a string fits.\n const fallback: ShippingSimulateError = {\n code: 'UNKNOWN',\n message: intl.formatMessage({ id: 'fs/shipping.calculation-failed' }),\n };\n setShippingOptions(null);\n setUserErrors([fallback]);\n setStatus('error');\n onResult?.({ shippingOptions: null, userErrors: [fallback] });\n });\n }, [country, intl, onResult, onSimulate, postalCode]);\n\n const contextValue = useMemo<ShippingSimulatorContextValue>(\n () => ({\n postalCode,\n setPostalCode,\n status,\n shippingOptions,\n userErrors,\n submit,\n }),\n [postalCode, status, shippingOptions, userErrors, submit],\n );\n\n return (\n <ShippingSimulatorContext value={contextValue}>\n <div {...props} className={className} data-fs-shipping-simulator=\"\">\n {children}\n </div>\n </ShippingSimulatorContext>\n );\n}\n\nexport function ShippingSimulatorForm({ className, children, ...props }: ShippingSimulatorFormProps) {\n const { submit } = useShippingSimulator();\n\n return (\n <form\n {...props}\n className={className}\n data-fs-shipping-simulator-form=\"\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n {children}\n </form>\n );\n}\n\nexport function ShippingSimulatorInput({\n className,\n placeholder,\n 'aria-label': ariaLabel,\n format = false,\n ...props\n}: ShippingSimulatorInputProps) {\n const { postalCode, setPostalCode } = useShippingSimulator();\n const intl = useIntl();\n const displayValue = format ? formatPostalCode(postalCode) : postalCode;\n\n return (\n <input\n {...props}\n aria-label={ariaLabel ?? intl.formatMessage({ id: 'fs/shipping.postal-code.aria-label' })}\n className={className}\n data-fs-shipping-simulator-input=\"\"\n type=\"text\"\n value={displayValue}\n onChange={(event) => setPostalCode(normalizePostalCode(event.target.value))}\n placeholder={placeholder ?? intl.formatMessage({ id: 'fs/shipping.postal-code.placeholder' })}\n pattern=\"\\d{5}-?\\d{3}\"\n maxLength={9}\n inputMode=\"numeric\"\n required\n />\n );\n}\n\nexport function ShippingSimulatorSubmit({ className, children, disabled, ...props }: ShippingSimulatorSubmitProps) {\n const { status } = useShippingSimulator();\n const isLoading = status === 'loading';\n\n return (\n <button\n {...props}\n type=\"submit\"\n className={className}\n data-fs-shipping-simulator-submit=\"\"\n disabled={disabled || isLoading}\n aria-busy={isLoading}\n >\n {children}\n </button>\n );\n}\n\nexport function ShippingSimulatorLoading({ className, children, ...props }: ShippingSimulatorLoadingProps) {\n const { status } = useShippingSimulator();\n if (status !== 'loading') return null;\n\n return (\n <output {...props} aria-live=\"polite\" className={className} data-fs-shipping-simulator-loading=\"\">\n {children ?? <FormattedMessage id=\"fs/shipping.calculating\" />}\n </output>\n );\n}\n\nexport function ShippingSimulatorError({ className, children, ...props }: ShippingSimulatorErrorProps) {\n const { userErrors } = useShippingSimulator();\n const [firstError] = userErrors;\n if (!firstError) return null;\n\n return (\n <div {...props} role=\"alert\" className={className} data-fs-shipping-simulator-error=\"\">\n {children ?? firstError.message}\n </div>\n );\n}\n\nexport function ShippingSimulatorOptions({\n sortBy,\n maxOptions,\n className,\n children,\n ...props\n}: ShippingSimulatorOptionsProps) {\n const { shippingOptions } = useShippingSimulator();\n\n const visibleOptions = useMemo(() => {\n if (!shippingOptions) return null;\n const sorted = sortBy ? sortShippingOptions(shippingOptions, sortBy) : shippingOptions;\n return maxOptions && maxOptions > 0 ? sorted.slice(0, maxOptions) : sorted;\n }, [shippingOptions, sortBy, maxOptions]);\n\n if (!visibleOptions || visibleOptions.length === 0) return null;\n\n return (\n <ul {...props} className={className} data-fs-shipping-simulator-options=\"\">\n {visibleOptions.map((option) => (\n <OptionItemContext key={option.id} value={option}>\n {children}\n </OptionItemContext>\n ))}\n </ul>\n );\n}\n\nexport function ShippingSimulatorOption({ className, children, ...props }: ShippingSimulatorOptionProps) {\n const option = useOptionItem();\n\n return (\n <li\n {...props}\n className={className}\n data-fs-shipping-simulator-option=\"\"\n data-fs-shipping-simulator-option-channel={option.channel}\n >\n {children}\n </li>\n );\n}\n\nexport function ShippingSimulatorOptionName({ className, children, ...props }: ShippingSimulatorOptionNameProps) {\n const option = useOptionItem();\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-name=\"\">\n {children ?? option.name}\n </span>\n );\n}\n\nexport function ShippingSimulatorOptionEstimate({\n className,\n children,\n ...props\n}: ShippingSimulatorOptionEstimateProps) {\n const option = useOptionItem();\n const intl = useIntl();\n const { value, unit } = option.shippingEstimate;\n const { id, variable } = ESTIMATE_MESSAGE[unit];\n const text =\n value === 0\n ? intl.formatMessage({ id: 'fs/shipping.estimate.today' })\n : intl.formatMessage({ id }, { [variable]: value });\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-estimate=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function ShippingSimulatorOptionPrice({ className, children, ...props }: ShippingSimulatorOptionPriceProps) {\n const option = useOptionItem();\n const intl = useIntl();\n const { locale, currency } = useStorefrontContext();\n const text =\n option.price.amount === 0\n ? intl.formatMessage({ id: 'fs/shipping.free-price' })\n : formatPrice(option.price.amount, locale, currency);\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-price=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function ShippingSimulatorOptionFreeBadge({\n className,\n children,\n ...props\n}: ShippingSimulatorOptionFreeBadgeProps) {\n const option = useOptionItem();\n if (option.price.amount !== 0) return null;\n\n return (\n <span {...props} className={className} data-fs-shipping-simulator-option-free-badge=\"\">\n {children ?? <FormattedMessage id=\"fs/shipping.free-badge\" />}\n </span>\n );\n}\n\nexport function ShippingSimulatorEmpty({ className, children, ...props }: ShippingSimulatorEmptyProps) {\n const { shippingOptions, userErrors } = useShippingSimulator();\n // Idle (null) → nothing; error → nothing (Error owns it); options present → nothing.\n const simulatedEmpty = Array.isArray(shippingOptions) && shippingOptions.length === 0 && userErrors.length === 0;\n if (!simulatedEmpty) return null;\n\n return (\n <output {...props} aria-live=\"polite\" className={className} data-fs-shipping-simulator-empty=\"\">\n {children ?? <FormattedMessage id=\"fs/shipping.no-options\" />}\n </output>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Namespace export\n// ---------------------------------------------------------------------------\n\nexport const ShippingSimulator = {\n Root: ShippingSimulatorRoot,\n Form: ShippingSimulatorForm,\n Input: ShippingSimulatorInput,\n Submit: ShippingSimulatorSubmit,\n Loading: ShippingSimulatorLoading,\n Error: ShippingSimulatorError,\n Options: ShippingSimulatorOptions,\n Option: ShippingSimulatorOption,\n OptionName: ShippingSimulatorOptionName,\n OptionEstimate: ShippingSimulatorOptionEstimate,\n OptionPrice: ShippingSimulatorOptionPrice,\n OptionFreeBadge: ShippingSimulatorOptionFreeBadge,\n Empty: ShippingSimulatorEmpty,\n};\n\nexport const CartShippingSimulator = {\n Root: CartShippingSimulatorRoot,\n Form: ShippingSimulatorForm,\n Input: ShippingSimulatorInput,\n Submit: ShippingSimulatorSubmit,\n Loading: ShippingSimulatorLoading,\n Error: ShippingSimulatorError,\n Options: ShippingSimulatorOptions,\n Option: ShippingSimulatorOption,\n OptionName: ShippingSimulatorOptionName,\n OptionEstimate: ShippingSimulatorOptionEstimate,\n OptionPrice: ShippingSimulatorOptionPrice,\n OptionFreeBadge: ShippingSimulatorOptionFreeBadge,\n Empty: ShippingSimulatorEmpty,\n};\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defineComponent } from "../../core/dist/define-component.js";
|
|
2
2
|
import { defineContentType } from "../../core/dist/define-content-type.js";
|
|
3
3
|
import "../../core/dist/index.js";
|
|
4
|
-
import { Icon } from "../icon/icon.js";
|
|
5
4
|
import { resolveSafeHref } from "../../utils/safe-href.js";
|
|
6
5
|
import { NavigationLink } from "../navigation-link/navigation-link.js";
|
|
6
|
+
import { Icon } from "../icon/icon.js";
|
|
7
7
|
import { Image } from "../image/image.js";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/particles/footer-social/footer-social.tsx
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defineComponent } from "../../core/dist/define-component.js";
|
|
2
2
|
import { defineContentType } from "../../core/dist/define-content-type.js";
|
|
3
3
|
import "../../core/dist/index.js";
|
|
4
|
-
import { Icon } from "../icon/icon.js";
|
|
5
4
|
import { resolveSafeHref } from "../../utils/safe-href.js";
|
|
6
5
|
import { NavigationLink } from "../navigation-link/navigation-link.js";
|
|
6
|
+
import { Icon } from "../icon/icon.js";
|
|
7
7
|
import { Image } from "../image/image.js";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/particles/incentives/incentives.tsx
|
|
@@ -9,7 +9,7 @@ export type CartActionProviderProps = ActionProviderProps;
|
|
|
9
9
|
* once, narrows the surface to the declared `methods`, and publishes it through
|
|
10
10
|
* `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to
|
|
11
11
|
* read further down. A namespace a component does not declare is never wrapped, so its hook is never
|
|
12
|
-
* called (
|
|
12
|
+
* called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).
|
|
13
13
|
*
|
|
14
14
|
* It delivers `$actions` through context, not a `cloneElement` prop injection, matching `$data`
|
|
15
15
|
* (`DataOverrideContext`/`useDataOverride`) — see `useInjectActions`. A component with no provider
|
|
@@ -9,7 +9,7 @@ import { useInjectActions } from "./inject-actions.js";
|
|
|
9
9
|
* once, narrows the surface to the declared `methods`, and publishes it through
|
|
10
10
|
* `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to
|
|
11
11
|
* read further down. A namespace a component does not declare is never wrapped, so its hook is never
|
|
12
|
-
* called (
|
|
12
|
+
* called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).
|
|
13
13
|
*
|
|
14
14
|
* It delivers `$actions` through context, not a `cloneElement` prop injection, matching `$data`
|
|
15
15
|
* (`DataOverrideContext`/`useDataOverride`) — see `useInjectActions`. A component with no provider
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-action-provider.js","names":[],"sources":["../../../src/sdk/actions/cart-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { useCartActions } from '../cart/use-cart-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type CartActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `cart` action namespace — the write-side mirror of\n * `ReactiveDataProvider`. The compiler wraps every element whose definition declares\n * `actions: { cart: [...] }` with `<CartActionProvider methods={[...]}>`, calls `useCartActions`\n * once, narrows the surface to the declared `methods`, and publishes it through\n * `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to\n * read further down. A namespace a component does not declare is never wrapped, so its hook is never\n * called (
|
|
1
|
+
{"version":3,"file":"cart-action-provider.js","names":[],"sources":["../../../src/sdk/actions/cart-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { useCartActions } from '../cart/use-cart-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type CartActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `cart` action namespace — the write-side mirror of\n * `ReactiveDataProvider`. The compiler wraps every element whose definition declares\n * `actions: { cart: [...] }` with `<CartActionProvider methods={[...]}>`, calls `useCartActions`\n * once, narrows the surface to the declared `methods`, and publishes it through\n * `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to\n * read further down. A namespace a component does not declare is never wrapped, so its hook is never\n * called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).\n *\n * It delivers `$actions` through context, not a `cloneElement` prop injection, matching `$data`\n * (`DataOverrideContext`/`useDataOverride`) — see `useInjectActions`. A component with no provider\n * above it (`mockAction` in a test or story) still works: `useActionsOverride` falls back to\n * whatever `$actions` prop the component was directly given.\n */\nexport function CartActionProvider(props: CartActionProviderProps): ReactNode {\n return useInjectActions('cart', useCartActions(), props);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAsBA,SAAgB,mBAAmB,OAA2C;CAC5E,OAAO,iBAAiB,QAAQ,eAAe,GAAG,KAAK;AACzD"}
|
|
@@ -9,7 +9,7 @@ export type SessionActionProviderProps = ActionProviderProps;
|
|
|
9
9
|
* `useSessionActions` once, narrows the surface to the declared `methods`, and publishes it through
|
|
10
10
|
* `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to
|
|
11
11
|
* read further down. A namespace a component does not declare is never wrapped, so its hook is
|
|
12
|
-
* never called (
|
|
12
|
+
* never called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).
|
|
13
13
|
*/
|
|
14
14
|
export declare function SessionActionProvider(props: SessionActionProviderProps): ReactNode;
|
|
15
15
|
//#endregion
|
|
@@ -9,7 +9,7 @@ import { useSessionActions } from "../session/use-session-actions.js";
|
|
|
9
9
|
* `useSessionActions` once, narrows the surface to the declared `methods`, and publishes it through
|
|
10
10
|
* `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to
|
|
11
11
|
* read further down. A namespace a component does not declare is never wrapped, so its hook is
|
|
12
|
-
* never called (
|
|
12
|
+
* never called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).
|
|
13
13
|
*/
|
|
14
14
|
function SessionActionProvider(props) {
|
|
15
15
|
return useInjectActions("session", useSessionActions(), props);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-action-provider.js","names":[],"sources":["../../../src/sdk/actions/session-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { useSessionActions } from '../session/use-session-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type SessionActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `session` action namespace — a line-for-line mirror of\n * `CartActionProvider`. The compiler wraps every element whose definition declares\n * `actions: { session: [...] }` with `<SessionActionProvider methods={[...]}>`, calls\n * `useSessionActions` once, narrows the surface to the declared `methods`, and publishes it through\n * `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to\n * read further down. A namespace a component does not declare is never wrapped, so its hook is\n * never called (
|
|
1
|
+
{"version":3,"file":"session-action-provider.js","names":[],"sources":["../../../src/sdk/actions/session-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { useSessionActions } from '../session/use-session-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type SessionActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `session` action namespace — a line-for-line mirror of\n * `CartActionProvider`. The compiler wraps every element whose definition declares\n * `actions: { session: [...] }` with `<SessionActionProvider methods={[...]}>`, calls\n * `useSessionActions` once, narrows the surface to the declared `methods`, and publishes it through\n * `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to\n * read further down. A namespace a component does not declare is never wrapped, so its hook is\n * never called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).\n */\nexport function SessionActionProvider(props: SessionActionProviderProps): ReactNode {\n return useInjectActions('session', useSessionActions(), props);\n}\n"],"mappings":";;;;;;;;;;;;;AAiBA,SAAgB,sBAAsB,OAA8C;CAClF,OAAO,iBAAiB,WAAW,kBAAkB,GAAG,KAAK;AAC/D"}
|
|
@@ -9,7 +9,7 @@ export type ShippingActionProviderProps = ActionProviderProps;
|
|
|
9
9
|
* `useShippingActions` once, narrows the surface to the declared `methods`, and publishes it through
|
|
10
10
|
* `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to
|
|
11
11
|
* read further down. A namespace a component does not declare is never wrapped, so its hook is
|
|
12
|
-
* never called (
|
|
12
|
+
* never called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).
|
|
13
13
|
*/
|
|
14
14
|
export declare function ShippingActionProvider(props: ShippingActionProviderProps): ReactNode;
|
|
15
15
|
//#endregion
|
|
@@ -9,7 +9,7 @@ import { useShippingActions } from "../shipping/use-shipping-actions.js";
|
|
|
9
9
|
* `useShippingActions` once, narrows the surface to the declared `methods`, and publishes it through
|
|
10
10
|
* `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to
|
|
11
11
|
* read further down. A namespace a component does not declare is never wrapped, so its hook is
|
|
12
|
-
* never called (
|
|
12
|
+
* never called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).
|
|
13
13
|
*/
|
|
14
14
|
function ShippingActionProvider(props) {
|
|
15
15
|
return useInjectActions("shipping", useShippingActions(), props);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shipping-action-provider.js","names":[],"sources":["../../../src/sdk/actions/shipping-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { useShippingActions } from '../shipping/use-shipping-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type ShippingActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `shipping` action namespace — a line-for-line mirror of\n * `SessionActionProvider`. The compiler wraps every element whose definition declares\n * `actions: { shipping: [...] }` with `<ShippingActionProvider methods={[...]}>`, calls\n * `useShippingActions` once, narrows the surface to the declared `methods`, and publishes it through\n * `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to\n * read further down. A namespace a component does not declare is never wrapped, so its hook is\n * never called (
|
|
1
|
+
{"version":3,"file":"shipping-action-provider.js","names":[],"sources":["../../../src/sdk/actions/shipping-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { useShippingActions } from '../shipping/use-shipping-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type ShippingActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `shipping` action namespace — a line-for-line mirror of\n * `SessionActionProvider`. The compiler wraps every element whose definition declares\n * `actions: { shipping: [...] }` with `<ShippingActionProvider methods={[...]}>`, calls\n * `useShippingActions` once, narrows the surface to the declared `methods`, and publishes it through\n * `ActionsOverrideContext` (merging with any outer namespace provider) for `useActionsOverride` to\n * read further down. A namespace a component does not declare is never wrapped, so its hook is\n * never called (docs/storefront-core/reference-free-particle-model.md § Write side — actions).\n */\nexport function ShippingActionProvider(props: ShippingActionProviderProps): ReactNode {\n return useInjectActions('shipping', useShippingActions(), props);\n}\n"],"mappings":";;;;;;;;;;;;;AAiBA,SAAgB,uBAAuB,OAA+C;CACpF,OAAO,iBAAiB,YAAY,mBAAmB,GAAG,KAAK;AACjE"}
|
|
@@ -5,7 +5,7 @@ import { InMemoryCache } from "@apollo/client";
|
|
|
5
5
|
* Per-entity normalization and field-merge rules for the Storefront cache.
|
|
6
6
|
*
|
|
7
7
|
* Empty in T1. Domain entries (Product, Cart, OrderForm, …) arrive with the
|
|
8
|
-
* particles that need them — see
|
|
8
|
+
* particles that need them — see docs/storefront-core/reference-free-particle-model.md § Typed documents and the shared cache,
|
|
9
9
|
* "Out of Scope".
|
|
10
10
|
*/
|
|
11
11
|
const typePolicies = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storefront-cache.js","names":[],"sources":["../../../src/sdk/cache/storefront-cache.ts"],"sourcesContent":["import { InMemoryCache, type InMemoryCacheConfig, type TypePolicies } from '@apollo/client';\nimport { possibleTypes } from '../generated/fragment-types.js';\n\n/**\n * Per-entity normalization and field-merge rules for the Storefront cache.\n *\n * Empty in T1. Domain entries (Product, Cart, OrderForm, …) arrive with the\n * particles that need them — see
|
|
1
|
+
{"version":3,"file":"storefront-cache.js","names":[],"sources":["../../../src/sdk/cache/storefront-cache.ts"],"sourcesContent":["import { InMemoryCache, type InMemoryCacheConfig, type TypePolicies } from '@apollo/client';\nimport { possibleTypes } from '../generated/fragment-types.js';\n\n/**\n * Per-entity normalization and field-merge rules for the Storefront cache.\n *\n * Empty in T1. Domain entries (Product, Cart, OrderForm, …) arrive with the\n * particles that need them — see docs/storefront-core/reference-free-particle-model.md § Typed documents and the shared cache,\n * \"Out of Scope\".\n */\nexport const typePolicies: TypePolicies = {};\n\nexport { possibleTypes };\n\n/**\n * The single source of truth for InMemoryCache configuration. Both the\n * server-side `createClient` and the client-side `StorefrontProvider`\n * consume this so SSR and CSR normalize entities identically.\n */\nexport function getCacheConfig(): InMemoryCacheConfig {\n return {\n typePolicies,\n possibleTypes,\n };\n}\n\n/**\n * The only place an `InMemoryCache` is constructed on the server path.\n * The client-side provider builds its cache from `getCacheConfig()` so the\n * config is shared verbatim without coupling to a specific InMemoryCache\n * subclass (the Next.js integration ships its own SSR-aware variant).\n */\nexport function buildCache(): InMemoryCache {\n return new InMemoryCache(getCacheConfig());\n}\n"],"mappings":";;;;;;;;;;AAUA,MAAa,eAA6B,CAAC;;;;;;AAS3C,SAAgB,iBAAsC;CACpD,OAAO;EACL;EACA;CACF;AACF;;;;;;;AAQA,SAAgB,aAA4B;CAC1C,OAAO,IAAI,cAAc,eAAe,CAAC;AAC3C"}
|
|
@@ -3,18 +3,18 @@ import "./operations.js";
|
|
|
3
3
|
import { TypedDocumentNode } from "@apollo/client";
|
|
4
4
|
//#region src/sdk/cart/operations.d.ts
|
|
5
5
|
/**
|
|
6
|
-
* Cart-related GraphQL operations and shared fragments (T6 /
|
|
6
|
+
* Cart-related GraphQL operations and shared fragments (T6 / mutation-contract.md (archived at the specs-archive tag)).
|
|
7
7
|
*
|
|
8
8
|
* The `CartFragment` is the canonical Cart selection set: every mutation operation spreads it so
|
|
9
9
|
* the cache normalisation reaches every reactive subscriber (CartTotal, CartCount, CartItems, …)
|
|
10
10
|
* through a single response. The contract regression test (`contract.test.ts`) parses these
|
|
11
|
-
* documents and asserts the spread is present — see
|
|
11
|
+
* documents and asserts the spread is present — see mutation-contract.md (archived at the specs-archive tag).
|
|
12
12
|
*
|
|
13
|
-
* T7 ([
|
|
13
|
+
* T7 ([Typed documents and the shared cache][T7]) routes the domain types and the operation factory
|
|
14
14
|
* through @graphql-codegen. Public type names (`CartEntity`, `CartItemEntity`, `Money`, payload
|
|
15
15
|
* + input aliases) are preserved as re-exports / aliases so consumer call sites do not change.
|
|
16
16
|
*
|
|
17
|
-
* [T7]: ../../../../../
|
|
17
|
+
* [T7]: ../../../../../docs/storefront-core/reference-free-particle-model.md#typed-documents-and-the-shared-cache
|
|
18
18
|
*/
|
|
19
19
|
export type Money = MoneyFragmentFragment;
|
|
20
20
|
export type CartItemEntity = CartItemFragmentFragment;
|
|
@@ -189,7 +189,7 @@ const CART_COUPON_REMOVE = graphql(`
|
|
|
189
189
|
`);
|
|
190
190
|
/**
|
|
191
191
|
* Re-check the active cart against the platform and adopt corrected availability. Read-only upstream
|
|
192
|
-
* (
|
|
192
|
+
* (docs/storefront-api-core/CONTEXT.md § Language, Cart Validation): the payload is the cart with each line's
|
|
193
193
|
* `variant.availability` refreshed, shaped like every other cart mutation so the correction lands in
|
|
194
194
|
* the normalized cache. Takes no arguments — the cart resolves from the request context. Spreading
|
|
195
195
|
* `CartFragment` is what makes the guard, the per-line alert, and the badge re-render as subscribers,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations.js","names":[],"sources":["../../../src/sdk/cart/operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { graphql } from '../generated/gql.js';\nimport type {\n CartCouponApplyMutation,\n CartCouponApplyMutationVariables,\n CartCouponRemoveMutation,\n CartCouponRemoveMutationVariables,\n CartFragmentFragment,\n CartItemAddMutation,\n CartItemAddMutationVariables,\n CartItemFragmentFragment,\n CartItemQuantityDecreaseMutation,\n CartItemQuantityDecreaseMutationVariables,\n CartItemQuantityIncreaseMutation,\n CartItemQuantityIncreaseMutationVariables,\n CartItemRemoveMutation,\n CartItemRemoveMutationVariables,\n CartItemsRemoveMutation,\n CartItemsRemoveMutationVariables,\n CartValidateMutation,\n CartValidateMutationVariables,\n MoneyFragmentFragment,\n} from '../generated/graphql.js';\n\n/**\n * Cart-related GraphQL operations and shared fragments (T6 / specs/mutation-contract.md).\n *\n * The `CartFragment` is the canonical Cart selection set: every mutation operation spreads it so\n * the cache normalisation reaches every reactive subscriber (CartTotal, CartCount, CartItems, …)\n * through a single response. The contract regression test (`contract.test.ts`) parses these\n * documents and asserts the spread is present — see specs/mutation-contract.md AD-D3 / AD-8.\n *\n * T7 ([specs/graphql-codegen-pipeline.md][T7]) routes the domain types and the operation factory\n * through @graphql-codegen. Public type names (`CartEntity`, `CartItemEntity`, `Money`, payload\n * + input aliases) are preserved as re-exports / aliases so consumer call sites do not change.\n *\n * [T7]: ../../../../../specs/graphql-codegen-pipeline.md\n */\n\n// ---------------------------------------------------------------------------\n// Domain type aliases — re-exports from codegen artifacts (T7)\n// ---------------------------------------------------------------------------\n\nexport type Money = MoneyFragmentFragment;\nexport type CartItemEntity = CartItemFragmentFragment;\nexport type CartEntity = CartFragmentFragment;\nexport type CartTotalizer = CartFragmentFragment['totalizers'][number];\nexport type CartMessage = CartFragmentFragment['messages'][number];\nexport type AppliedCoupon = CartFragmentFragment['appliedCoupons'][number];\n\nexport type CartUserError = Readonly<{ code: string; message: string }>;\n\n// ---------------------------------------------------------------------------\n// Mutation input types — direct re-exports from codegen\n// ---------------------------------------------------------------------------\n\nexport type {\n CartCouponApplyInput,\n CartCouponRemoveInput,\n CartItemAddInput,\n CartItemQuantityDecreaseInput,\n CartItemQuantityIncreaseInput,\n CartItemRemoveInput,\n CartItemsRemoveInput,\n} from '../generated/graphql.js';\n\n// ---------------------------------------------------------------------------\n// Mutation payload types — derived from operation result types\n// ---------------------------------------------------------------------------\n\nexport type CartItemAddPayload = CartItemAddMutation['cartItemAdd'];\nexport type CartItemRemovePayload = CartItemRemoveMutation['cartItemRemove'];\nexport type CartItemsRemovePayload = CartItemsRemoveMutation['cartItemsRemove'];\nexport type CartItemQuantityIncreasePayload = CartItemQuantityIncreaseMutation['cartItemQuantityIncrease'];\nexport type CartItemQuantityDecreasePayload = CartItemQuantityDecreaseMutation['cartItemQuantityDecrease'];\nexport type CartCouponApplyPayload = CartCouponApplyMutation['cartCouponApply'];\nexport type CartCouponRemovePayload = CartCouponRemoveMutation['cartCouponRemove'];\nexport type CartValidatePayload = CartValidateMutation['cartValidate'];\n\n// ---------------------------------------------------------------------------\n// Shared fragments — authored via the codegen `graphql()` factory so codegen can scan and type\n// every operation that spreads them.\n// ---------------------------------------------------------------------------\n\nexport const MoneyFragment: TypedDocumentNode<MoneyFragmentFragment, never> = graphql(`\n fragment MoneyFragment on Money {\n __typename\n amount\n currencyCode\n }\n`);\n\nexport const CartItemFragment: TypedDocumentNode<CartItemFragmentFragment, never> = graphql(`\n fragment CartItemFragment on CartItem {\n __typename\n id\n quantity\n price {\n ...MoneyFragment\n }\n listPrice {\n ...MoneyFragment\n }\n sellingPrice {\n ...MoneyFragment\n }\n gift\n ownTotal {\n ...MoneyFragment\n }\n total {\n ...MoneyFragment\n }\n variant {\n __typename\n variantId\n sku\n name\n image {\n url\n altText\n }\n availability\n }\n product {\n __typename\n productId\n title\n detailUrl\n categories {\n categoryId\n name\n }\n brand {\n brandId\n name\n }\n }\n }\n`);\n\n/**\n * Canonical Cart selection set. Every cart mutation MUST spread this fragment so the cache\n * receives the entity slices that all subscribers depend on (id + items + totalizers + total +\n * messages). The regression test in contract.test.ts enforces this.\n */\nexport const CartFragment: TypedDocumentNode<CartFragmentFragment, never> = graphql(`\n fragment CartFragment on Cart {\n __typename\n id\n items {\n ...CartItemFragment\n }\n totalizers {\n __typename\n id\n name\n value {\n ...MoneyFragment\n }\n }\n total {\n ...MoneyFragment\n }\n messages {\n __typename\n code\n text\n status\n }\n appliedCoupons {\n code\n isUnmatchedCondition\n }\n }\n`);\n\n// ---------------------------------------------------------------------------\n// Mutation operations — authored via `graphql()`, typed via the codegen-derived\n// TypedDocumentNode generic so Apollo's `useMutation` infers TData / TVariables correctly.\n// ---------------------------------------------------------------------------\n\nexport const CART_ITEM_ADD: TypedDocumentNode<CartItemAddMutation, CartItemAddMutationVariables> = graphql(`\n mutation CartItemAdd($input: CartItemAddInput!) {\n cartItemAdd(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEM_REMOVE: TypedDocumentNode<CartItemRemoveMutation, CartItemRemoveMutationVariables> = graphql(`\n mutation CartItemRemove($input: CartItemRemoveInput!) {\n cartItemRemove(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEMS_REMOVE: TypedDocumentNode<CartItemsRemoveMutation, CartItemsRemoveMutationVariables> = graphql(`\n mutation CartItemsRemove($input: CartItemsRemoveInput!) {\n cartItemsRemove(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEM_QUANTITY_INCREASE: TypedDocumentNode<\n CartItemQuantityIncreaseMutation,\n CartItemQuantityIncreaseMutationVariables\n> = graphql(`\n mutation CartItemQuantityIncrease($input: CartItemQuantityIncreaseInput!) {\n cartItemQuantityIncrease(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEM_QUANTITY_DECREASE: TypedDocumentNode<\n CartItemQuantityDecreaseMutation,\n CartItemQuantityDecreaseMutationVariables\n> = graphql(`\n mutation CartItemQuantityDecrease($input: CartItemQuantityDecreaseInput!) {\n cartItemQuantityDecrease(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_COUPON_APPLY: TypedDocumentNode<CartCouponApplyMutation, CartCouponApplyMutationVariables> = graphql(`\n mutation CartCouponApply($input: CartCouponApplyInput!) {\n cartCouponApply(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_COUPON_REMOVE: TypedDocumentNode<CartCouponRemoveMutation, CartCouponRemoveMutationVariables> =\n graphql(`\n mutation CartCouponRemove($input: CartCouponRemoveInput!) {\n cartCouponRemove(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\n/**\n * Re-check the active cart against the platform and adopt corrected availability. Read-only upstream\n * (specs/mini-cart-validate-operation.md): the payload is the cart with each line's\n * `variant.availability` refreshed, shaped like every other cart mutation so the correction lands in\n * the normalized cache. Takes no arguments — the cart resolves from the request context. Spreading\n * `CartFragment` is what makes the guard, the per-line alert, and the badge re-render as subscribers,\n * so T13 needs no fragment or codegen change beyond registering this document.\n */\nexport const CART_VALIDATE: TypedDocumentNode<CartValidateMutation, CartValidateMutationVariables> = graphql(`\n mutation CartValidate {\n cartValidate {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\n/**\n * Canonical list of cart mutation documents. Used by the contract regression test to iterate\n * over every shipped operation without hard-coding names.\n */\nexport const CART_MUTATIONS = [\n { name: 'CartItemAdd', document: CART_ITEM_ADD },\n { name: 'CartItemRemove', document: CART_ITEM_REMOVE },\n { name: 'CartItemsRemove', document: CART_ITEMS_REMOVE },\n { name: 'CartItemQuantityIncrease', document: CART_ITEM_QUANTITY_INCREASE },\n { name: 'CartItemQuantityDecrease', document: CART_ITEM_QUANTITY_DECREASE },\n { name: 'CartCouponApply', document: CART_COUPON_APPLY },\n { name: 'CartCouponRemove', document: CART_COUPON_REMOVE },\n { name: 'CartValidate', document: CART_VALIDATE },\n] as const;\n"],"mappings":";AAoF8E,QAAQ;;;;;;CAMrF;AAEmF,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+C3F;;;;;;AAOD,MAAa,eAA+D,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BnF;AAOD,MAAa,gBAAsF,QAAQ;;;;;;;;;;;;;CAa1G;AAED,MAAa,mBAA+F,QAAQ;;;;;;;;;;;;;CAanH;AAED,MAAa,oBAAkG,QAAQ;;;;;;;;;;;;;CAatH;AAED,MAAa,8BAGT,QAAQ;;;;;;;;;;;;;CAaX;AAED,MAAa,8BAGT,QAAQ;;;;;;;;;;;;;CAaX;AAED,MAAa,oBAAkG,QAAQ;;;;;;;;;;;;;CAatH;AAED,MAAa,qBACX,QAAQ;;;;;;;;;;;;;CAaT;;;;;;;;;AAUD,MAAa,gBAAwF,QAAQ;;;;;;;;;;;;;CAa5G"}
|
|
1
|
+
{"version":3,"file":"operations.js","names":[],"sources":["../../../src/sdk/cart/operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { graphql } from '../generated/gql.js';\nimport type {\n CartCouponApplyMutation,\n CartCouponApplyMutationVariables,\n CartCouponRemoveMutation,\n CartCouponRemoveMutationVariables,\n CartFragmentFragment,\n CartItemAddMutation,\n CartItemAddMutationVariables,\n CartItemFragmentFragment,\n CartItemQuantityDecreaseMutation,\n CartItemQuantityDecreaseMutationVariables,\n CartItemQuantityIncreaseMutation,\n CartItemQuantityIncreaseMutationVariables,\n CartItemRemoveMutation,\n CartItemRemoveMutationVariables,\n CartItemsRemoveMutation,\n CartItemsRemoveMutationVariables,\n CartValidateMutation,\n CartValidateMutationVariables,\n MoneyFragmentFragment,\n} from '../generated/graphql.js';\n\n/**\n * Cart-related GraphQL operations and shared fragments (T6 / mutation-contract.md (archived at the specs-archive tag)).\n *\n * The `CartFragment` is the canonical Cart selection set: every mutation operation spreads it so\n * the cache normalisation reaches every reactive subscriber (CartTotal, CartCount, CartItems, …)\n * through a single response. The contract regression test (`contract.test.ts`) parses these\n * documents and asserts the spread is present — see mutation-contract.md (archived at the specs-archive tag).\n *\n * T7 ([Typed documents and the shared cache][T7]) routes the domain types and the operation factory\n * through @graphql-codegen. Public type names (`CartEntity`, `CartItemEntity`, `Money`, payload\n * + input aliases) are preserved as re-exports / aliases so consumer call sites do not change.\n *\n * [T7]: ../../../../../docs/storefront-core/reference-free-particle-model.md#typed-documents-and-the-shared-cache\n */\n\n// ---------------------------------------------------------------------------\n// Domain type aliases — re-exports from codegen artifacts (T7)\n// ---------------------------------------------------------------------------\n\nexport type Money = MoneyFragmentFragment;\nexport type CartItemEntity = CartItemFragmentFragment;\nexport type CartEntity = CartFragmentFragment;\nexport type CartTotalizer = CartFragmentFragment['totalizers'][number];\nexport type CartMessage = CartFragmentFragment['messages'][number];\nexport type AppliedCoupon = CartFragmentFragment['appliedCoupons'][number];\n\nexport type CartUserError = Readonly<{ code: string; message: string }>;\n\n// ---------------------------------------------------------------------------\n// Mutation input types — direct re-exports from codegen\n// ---------------------------------------------------------------------------\n\nexport type {\n CartCouponApplyInput,\n CartCouponRemoveInput,\n CartItemAddInput,\n CartItemQuantityDecreaseInput,\n CartItemQuantityIncreaseInput,\n CartItemRemoveInput,\n CartItemsRemoveInput,\n} from '../generated/graphql.js';\n\n// ---------------------------------------------------------------------------\n// Mutation payload types — derived from operation result types\n// ---------------------------------------------------------------------------\n\nexport type CartItemAddPayload = CartItemAddMutation['cartItemAdd'];\nexport type CartItemRemovePayload = CartItemRemoveMutation['cartItemRemove'];\nexport type CartItemsRemovePayload = CartItemsRemoveMutation['cartItemsRemove'];\nexport type CartItemQuantityIncreasePayload = CartItemQuantityIncreaseMutation['cartItemQuantityIncrease'];\nexport type CartItemQuantityDecreasePayload = CartItemQuantityDecreaseMutation['cartItemQuantityDecrease'];\nexport type CartCouponApplyPayload = CartCouponApplyMutation['cartCouponApply'];\nexport type CartCouponRemovePayload = CartCouponRemoveMutation['cartCouponRemove'];\nexport type CartValidatePayload = CartValidateMutation['cartValidate'];\n\n// ---------------------------------------------------------------------------\n// Shared fragments — authored via the codegen `graphql()` factory so codegen can scan and type\n// every operation that spreads them.\n// ---------------------------------------------------------------------------\n\nexport const MoneyFragment: TypedDocumentNode<MoneyFragmentFragment, never> = graphql(`\n fragment MoneyFragment on Money {\n __typename\n amount\n currencyCode\n }\n`);\n\nexport const CartItemFragment: TypedDocumentNode<CartItemFragmentFragment, never> = graphql(`\n fragment CartItemFragment on CartItem {\n __typename\n id\n quantity\n price {\n ...MoneyFragment\n }\n listPrice {\n ...MoneyFragment\n }\n sellingPrice {\n ...MoneyFragment\n }\n gift\n ownTotal {\n ...MoneyFragment\n }\n total {\n ...MoneyFragment\n }\n variant {\n __typename\n variantId\n sku\n name\n image {\n url\n altText\n }\n availability\n }\n product {\n __typename\n productId\n title\n detailUrl\n categories {\n categoryId\n name\n }\n brand {\n brandId\n name\n }\n }\n }\n`);\n\n/**\n * Canonical Cart selection set. Every cart mutation MUST spread this fragment so the cache\n * receives the entity slices that all subscribers depend on (id + items + totalizers + total +\n * messages). The regression test in contract.test.ts enforces this.\n */\nexport const CartFragment: TypedDocumentNode<CartFragmentFragment, never> = graphql(`\n fragment CartFragment on Cart {\n __typename\n id\n items {\n ...CartItemFragment\n }\n totalizers {\n __typename\n id\n name\n value {\n ...MoneyFragment\n }\n }\n total {\n ...MoneyFragment\n }\n messages {\n __typename\n code\n text\n status\n }\n appliedCoupons {\n code\n isUnmatchedCondition\n }\n }\n`);\n\n// ---------------------------------------------------------------------------\n// Mutation operations — authored via `graphql()`, typed via the codegen-derived\n// TypedDocumentNode generic so Apollo's `useMutation` infers TData / TVariables correctly.\n// ---------------------------------------------------------------------------\n\nexport const CART_ITEM_ADD: TypedDocumentNode<CartItemAddMutation, CartItemAddMutationVariables> = graphql(`\n mutation CartItemAdd($input: CartItemAddInput!) {\n cartItemAdd(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEM_REMOVE: TypedDocumentNode<CartItemRemoveMutation, CartItemRemoveMutationVariables> = graphql(`\n mutation CartItemRemove($input: CartItemRemoveInput!) {\n cartItemRemove(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEMS_REMOVE: TypedDocumentNode<CartItemsRemoveMutation, CartItemsRemoveMutationVariables> = graphql(`\n mutation CartItemsRemove($input: CartItemsRemoveInput!) {\n cartItemsRemove(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEM_QUANTITY_INCREASE: TypedDocumentNode<\n CartItemQuantityIncreaseMutation,\n CartItemQuantityIncreaseMutationVariables\n> = graphql(`\n mutation CartItemQuantityIncrease($input: CartItemQuantityIncreaseInput!) {\n cartItemQuantityIncrease(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_ITEM_QUANTITY_DECREASE: TypedDocumentNode<\n CartItemQuantityDecreaseMutation,\n CartItemQuantityDecreaseMutationVariables\n> = graphql(`\n mutation CartItemQuantityDecrease($input: CartItemQuantityDecreaseInput!) {\n cartItemQuantityDecrease(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_COUPON_APPLY: TypedDocumentNode<CartCouponApplyMutation, CartCouponApplyMutationVariables> = graphql(`\n mutation CartCouponApply($input: CartCouponApplyInput!) {\n cartCouponApply(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\nexport const CART_COUPON_REMOVE: TypedDocumentNode<CartCouponRemoveMutation, CartCouponRemoveMutationVariables> =\n graphql(`\n mutation CartCouponRemove($input: CartCouponRemoveInput!) {\n cartCouponRemove(input: $input) {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\n/**\n * Re-check the active cart against the platform and adopt corrected availability. Read-only upstream\n * (docs/storefront-api-core/CONTEXT.md § Language, Cart Validation): the payload is the cart with each line's\n * `variant.availability` refreshed, shaped like every other cart mutation so the correction lands in\n * the normalized cache. Takes no arguments — the cart resolves from the request context. Spreading\n * `CartFragment` is what makes the guard, the per-line alert, and the badge re-render as subscribers,\n * so T13 needs no fragment or codegen change beyond registering this document.\n */\nexport const CART_VALIDATE: TypedDocumentNode<CartValidateMutation, CartValidateMutationVariables> = graphql(`\n mutation CartValidate {\n cartValidate {\n __typename\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n`);\n\n/**\n * Canonical list of cart mutation documents. Used by the contract regression test to iterate\n * over every shipped operation without hard-coding names.\n */\nexport const CART_MUTATIONS = [\n { name: 'CartItemAdd', document: CART_ITEM_ADD },\n { name: 'CartItemRemove', document: CART_ITEM_REMOVE },\n { name: 'CartItemsRemove', document: CART_ITEMS_REMOVE },\n { name: 'CartItemQuantityIncrease', document: CART_ITEM_QUANTITY_INCREASE },\n { name: 'CartItemQuantityDecrease', document: CART_ITEM_QUANTITY_DECREASE },\n { name: 'CartCouponApply', document: CART_COUPON_APPLY },\n { name: 'CartCouponRemove', document: CART_COUPON_REMOVE },\n { name: 'CartValidate', document: CART_VALIDATE },\n] as const;\n"],"mappings":";AAoF8E,QAAQ;;;;;;CAMrF;AAEmF,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+C3F;;;;;;AAOD,MAAa,eAA+D,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BnF;AAOD,MAAa,gBAAsF,QAAQ;;;;;;;;;;;;;CAa1G;AAED,MAAa,mBAA+F,QAAQ;;;;;;;;;;;;;CAanH;AAED,MAAa,oBAAkG,QAAQ;;;;;;;;;;;;;CAatH;AAED,MAAa,8BAGT,QAAQ;;;;;;;;;;;;;CAaX;AAED,MAAa,8BAGT,QAAQ;;;;;;;;;;;;;CAaX;AAED,MAAa,oBAAkG,QAAQ;;;;;;;;;;;;;CAatH;AAED,MAAa,qBACX,QAAQ;;;;;;;;;;;;;CAaT;;;;;;;;;AAUD,MAAa,gBAAwF,QAAQ;;;;;;;;;;;;;CAa5G"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/sdk/cart/optimistic.ts
|
|
2
2
|
/**
|
|
3
3
|
* Pure optimistic-response builders for the three cache-propagating cart mutations
|
|
4
|
-
* (
|
|
4
|
+
* (mutation-contract.md (archived at the specs-archive tag)).
|
|
5
5
|
*
|
|
6
6
|
* Each builder takes the current `CartEntity` and the affected `CartItemEntity` and returns the
|
|
7
7
|
* predicted post-mutation `Cart` carrying every field the canonical `CartFragment` selects:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimistic.js","names":[],"sources":["../../../src/sdk/cart/optimistic.ts"],"sourcesContent":["import type {\n CartEntity,\n CartItemEntity,\n CartItemQuantityDecreasePayload,\n CartItemQuantityIncreasePayload,\n CartItemRemovePayload,\n CartItemsRemovePayload,\n CartTotalizer,\n Money,\n} from './operations.js';\n\n/**\n * Pure optimistic-response builders for the three cache-propagating cart mutations\n * (specs/mutation-contract.md AD-3 / AD-D6).\n *\n * Each builder takes the current `CartEntity` and the affected `CartItemEntity` and returns the\n * predicted post-mutation `Cart` carrying every field the canonical `CartFragment` selects:\n * `id`, `items`, `totalizers`, `total`. The shape MUST match Apollo's normalised cache slot for\n * the entity, so `__typename` and the same `id` are preserved.\n *\n * Lines are matched by their opaque `id` (Base64(\"CartItem:<orderFormId>:<uniqueId>\")).\n *\n * Recomputation rules (kept simple — server reconciles drift on response):\n * - `Items` totalizer (matched by `id === 'Items'`) is adjusted by `item.sellingPrice * delta`.\n * - `total` (the cart's grand total) is adjusted by the same delta.\n * - All other totalizers (Shipping, Discounts, …) stay as-is until the server response lands.\n */\n\nfunction moneyAdd(money: Money, delta: number): Money {\n // `Money.amount` is typed as `number` by codegen but arrives over the wire as a decimal *string*\n // (the server's `Decimal` scalar = `(cents / 100).toFixed(2)`). Without coercing, `string + number`\n // concatenates (e.g. \"49.99\" + 49.99 → \"49.9949.99\"), which formats to NaN during the optimistic\n // window until the server response replaces it. Number() restores numeric addition.\n return { __typename: 'Money', amount: Number(money.amount) + delta, currencyCode: money.currencyCode };\n}\n\nfunction adjustItemsTotalizer(totalizers: readonly CartTotalizer[], delta: number): CartTotalizer[] {\n return totalizers.map((t) => (t.id === 'Items' ? { ...t, value: moneyAdd(t.value, delta) } : t));\n}\n\nfunction emptyUserErrors<T>(): T[] {\n return [];\n}\n\n/**\n * Predicts the cart after `cartItemQuantityIncrease(input: { variantId, quantityToAdd })`.\n */\nexport function buildOptimisticIncrease(\n cart: CartEntity,\n item: CartItemEntity,\n by = 1,\n): { cartItemQuantityIncrease: CartItemQuantityIncreasePayload } {\n if (by <= 0) {\n return {\n cartItemQuantityIncrease: {\n __typename: 'CartItemQuantityIncreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const currentItem = cart.items.find((i) => i.id === item.id);\n if (!currentItem) {\n return {\n cartItemQuantityIncrease: {\n __typename: 'CartItemQuantityIncreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const newQuantity = currentItem.quantity + by;\n const delta = currentItem.sellingPrice.amount * by;\n\n const updatedItems = cart.items.map((i) => (i.id === item.id ? { ...i, quantity: newQuantity } : i));\n\n return {\n cartItemQuantityIncrease: {\n __typename: 'CartItemQuantityIncreasePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: updatedItems,\n totalizers: adjustItemsTotalizer(cart.totalizers, delta),\n total: moneyAdd(cart.total, delta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n\n/**\n * Predicts the cart after `cartItemQuantityDecrease(input: { variantId, quantityToRemove })`.\n *\n * If the resulting quantity would be `<= 0`, the line is removed entirely.\n */\nexport function buildOptimisticDecrease(\n cart: CartEntity,\n item: CartItemEntity,\n by = 1,\n): { cartItemQuantityDecrease: CartItemQuantityDecreasePayload } {\n if (by <= 0) {\n return {\n cartItemQuantityDecrease: {\n __typename: 'CartItemQuantityDecreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const currentItem = cart.items.find((i) => i.id === item.id);\n if (!currentItem) {\n return {\n cartItemQuantityDecrease: {\n __typename: 'CartItemQuantityDecreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const requestedQuantity = currentItem.quantity - by;\n const removed = requestedQuantity <= 0;\n const actualDelta = removed ? currentItem.quantity : by;\n const priceDelta = -currentItem.sellingPrice.amount * actualDelta;\n\n const updatedItems = removed\n ? cart.items.filter((i) => i.id !== item.id)\n : cart.items.map((i) => (i.id === item.id ? { ...i, quantity: requestedQuantity } : i));\n\n return {\n cartItemQuantityDecrease: {\n __typename: 'CartItemQuantityDecreasePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: updatedItems,\n totalizers: adjustItemsTotalizer(cart.totalizers, priceDelta),\n total: moneyAdd(cart.total, priceDelta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n\n/**\n * Predicts the cart after `cartItemRemove(input: { variantId })`.\n */\nexport function buildOptimisticRemove(\n cart: CartEntity,\n item: CartItemEntity,\n): { cartItemRemove: CartItemRemovePayload } {\n const currentItem = cart.items.find((i) => i.id === item.id);\n if (!currentItem) {\n return {\n cartItemRemove: {\n __typename: 'CartItemRemovePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const priceDelta = -currentItem.sellingPrice.amount * currentItem.quantity;\n\n return {\n cartItemRemove: {\n __typename: 'CartItemRemovePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: cart.items.filter((i) => i.id !== item.id),\n totalizers: adjustItemsTotalizer(cart.totalizers, priceDelta),\n total: moneyAdd(cart.total, priceDelta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n\n/**\n * Predicts the cart after `cartItemsRemove(input: { variantIds })` — the N-line generalisation of\n * `buildOptimisticRemove`. Lines absent from the cart are ignored; the summed price delta of the\n * matched lines adjusts the `Items` totalizer and the grand total.\n */\nexport function buildOptimisticRemoveItems(\n cart: CartEntity,\n items: readonly CartItemEntity[],\n): { cartItemsRemove: CartItemsRemovePayload } {\n const removedIds = new Set(items.map((item) => item.id));\n const removedLines = cart.items.filter((i) => removedIds.has(i.id));\n if (removedLines.length === 0) {\n return {\n cartItemsRemove: {\n __typename: 'CartItemsRemovePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const priceDelta = removedLines.reduce((sum, line) => sum - line.sellingPrice.amount * line.quantity, 0);\n\n return {\n cartItemsRemove: {\n __typename: 'CartItemsRemovePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: cart.items.filter((i) => !removedIds.has(i.id)),\n totalizers: adjustItemsTotalizer(cart.totalizers, priceDelta),\n total: moneyAdd(cart.total, priceDelta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA4BA,SAAS,SAAS,OAAc,OAAsB;CAKpD,OAAO;EAAE,YAAY;EAAS,QAAQ,OAAO,MAAM,MAAM,IAAI;EAAO,cAAc,MAAM;CAAa;AACvG;AAEA,SAAS,qBAAqB,YAAsC,OAAgC;CAClG,OAAO,WAAW,KAAK,MAAO,EAAE,OAAO,UAAU;EAAE,GAAG;EAAG,OAAO,SAAS,EAAE,OAAO,KAAK;CAAE,IAAI,CAAE;AACjG;AAEA,SAAS,kBAA0B;CACjC,OAAO,CAAC;AACV;;;;AAKA,SAAgB,wBACd,MACA,MACA,KAAK,GAC0D;CAC/D,IAAI,MAAM,GACR,OAAO,EACL,0BAA0B;EACxB,YAAY;EACZ;EACA,YAAY,gBAAgB;CAC9B,EACF;CAGF,MAAM,cAAc,KAAK,MAAM,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE;CAC3D,IAAI,CAAC,aACH,OAAO,EACL,0BAA0B;EACxB,YAAY;EACZ;EACA,YAAY,gBAAgB;CAC9B,EACF;CAGF,MAAM,cAAc,YAAY,WAAW;CAC3C,MAAM,QAAQ,YAAY,aAAa,SAAS;CAEhD,MAAM,eAAe,KAAK,MAAM,KAAK,MAAO,EAAE,OAAO,KAAK,KAAK;EAAE,GAAG;EAAG,UAAU;CAAY,IAAI,CAAE;CAEnG,OAAO,EACL,0BAA0B;EACxB,YAAY;EACZ,MAAM;GACJ,YAAY;GACZ,IAAI,KAAK;GACT,OAAO;GACP,YAAY,qBAAqB,KAAK,YAAY,KAAK;GACvD,OAAO,SAAS,KAAK,OAAO,KAAK;GACjC,UAAU,KAAK;GACf,gBAAgB,KAAK;EACvB;EACA,YAAY,gBAAgB;CAC9B,EACF;AACF;;;;;;AAOA,SAAgB,wBACd,MACA,MACA,KAAK,GAC0D;CAC/D,IAAI,MAAM,GACR,OAAO,EACL,0BAA0B;EACxB,YAAY;EACZ;EACA,YAAY,gBAAgB;CAC9B,EACF;CAGF,MAAM,cAAc,KAAK,MAAM,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE;CAC3D,IAAI,CAAC,aACH,OAAO,EACL,0BAA0B;EACxB,YAAY;EACZ;EACA,YAAY,gBAAgB;CAC9B,EACF;CAGF,MAAM,oBAAoB,YAAY,WAAW;CACjD,MAAM,UAAU,qBAAqB;CACrC,MAAM,cAAc,UAAU,YAAY,WAAW;CACrD,MAAM,aAAa,CAAC,YAAY,aAAa,SAAS;CAEtD,MAAM,eAAe,UACjB,KAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,KAAK,EAAE,IACzC,KAAK,MAAM,KAAK,MAAO,EAAE,OAAO,KAAK,KAAK;EAAE,GAAG;EAAG,UAAU;CAAkB,IAAI,CAAE;CAExF,OAAO,EACL,0BAA0B;EACxB,YAAY;EACZ,MAAM;GACJ,YAAY;GACZ,IAAI,KAAK;GACT,OAAO;GACP,YAAY,qBAAqB,KAAK,YAAY,UAAU;GAC5D,OAAO,SAAS,KAAK,OAAO,UAAU;GACtC,UAAU,KAAK;GACf,gBAAgB,KAAK;EACvB;EACA,YAAY,gBAAgB;CAC9B,EACF;AACF;;;;AAKA,SAAgB,sBACd,MACA,MAC2C;CAC3C,MAAM,cAAc,KAAK,MAAM,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE;CAC3D,IAAI,CAAC,aACH,OAAO,EACL,gBAAgB;EACd,YAAY;EACZ;EACA,YAAY,gBAAgB;CAC9B,EACF;CAGF,MAAM,aAAa,CAAC,YAAY,aAAa,SAAS,YAAY;CAElE,OAAO,EACL,gBAAgB;EACd,YAAY;EACZ,MAAM;GACJ,YAAY;GACZ,IAAI,KAAK;GACT,OAAO,KAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,KAAK,EAAE;GAChD,YAAY,qBAAqB,KAAK,YAAY,UAAU;GAC5D,OAAO,SAAS,KAAK,OAAO,UAAU;GACtC,UAAU,KAAK;GACf,gBAAgB,KAAK;EACvB;EACA,YAAY,gBAAgB;CAC9B,EACF;AACF;;;;;;AAOA,SAAgB,2BACd,MACA,OAC6C;CAC7C,MAAM,aAAa,IAAI,IAAI,MAAM,KAAK,SAAS,KAAK,EAAE,CAAC;CACvD,MAAM,eAAe,KAAK,MAAM,QAAQ,MAAM,WAAW,IAAI,EAAE,EAAE,CAAC;CAClE,IAAI,aAAa,WAAW,GAC1B,OAAO,EACL,iBAAiB;EACf,YAAY;EACZ;EACA,YAAY,gBAAgB;CAC9B,EACF;CAGF,MAAM,aAAa,aAAa,QAAQ,KAAK,SAAS,MAAM,KAAK,aAAa,SAAS,KAAK,UAAU,CAAC;CAEvG,OAAO,EACL,iBAAiB;EACf,YAAY;EACZ,MAAM;GACJ,YAAY;GACZ,IAAI,KAAK;GACT,OAAO,KAAK,MAAM,QAAQ,MAAM,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;GACrD,YAAY,qBAAqB,KAAK,YAAY,UAAU;GAC5D,OAAO,SAAS,KAAK,OAAO,UAAU;GACtC,UAAU,KAAK;GACf,gBAAgB,KAAK;EACvB;EACA,YAAY,gBAAgB;CAC9B,EACF;AACF"}
|
|
1
|
+
{"version":3,"file":"optimistic.js","names":[],"sources":["../../../src/sdk/cart/optimistic.ts"],"sourcesContent":["import type {\n CartEntity,\n CartItemEntity,\n CartItemQuantityDecreasePayload,\n CartItemQuantityIncreasePayload,\n CartItemRemovePayload,\n CartItemsRemovePayload,\n CartTotalizer,\n Money,\n} from './operations.js';\n\n/**\n * Pure optimistic-response builders for the three cache-propagating cart mutations\n * (mutation-contract.md (archived at the specs-archive tag)).\n *\n * Each builder takes the current `CartEntity` and the affected `CartItemEntity` and returns the\n * predicted post-mutation `Cart` carrying every field the canonical `CartFragment` selects:\n * `id`, `items`, `totalizers`, `total`. The shape MUST match Apollo's normalised cache slot for\n * the entity, so `__typename` and the same `id` are preserved.\n *\n * Lines are matched by their opaque `id` (Base64(\"CartItem:<orderFormId>:<uniqueId>\")).\n *\n * Recomputation rules (kept simple — server reconciles drift on response):\n * - `Items` totalizer (matched by `id === 'Items'`) is adjusted by `item.sellingPrice * delta`.\n * - `total` (the cart's grand total) is adjusted by the same delta.\n * - All other totalizers (Shipping, Discounts, …) stay as-is until the server response lands.\n */\n\nfunction moneyAdd(money: Money, delta: number): Money {\n // `Money.amount` is typed as `number` by codegen but arrives over the wire as a decimal *string*\n // (the server's `Decimal` scalar = `(cents / 100).toFixed(2)`). Without coercing, `string + number`\n // concatenates (e.g. \"49.99\" + 49.99 → \"49.9949.99\"), which formats to NaN during the optimistic\n // window until the server response replaces it. Number() restores numeric addition.\n return { __typename: 'Money', amount: Number(money.amount) + delta, currencyCode: money.currencyCode };\n}\n\nfunction adjustItemsTotalizer(totalizers: readonly CartTotalizer[], delta: number): CartTotalizer[] {\n return totalizers.map((t) => (t.id === 'Items' ? { ...t, value: moneyAdd(t.value, delta) } : t));\n}\n\nfunction emptyUserErrors<T>(): T[] {\n return [];\n}\n\n/**\n * Predicts the cart after `cartItemQuantityIncrease(input: { variantId, quantityToAdd })`.\n */\nexport function buildOptimisticIncrease(\n cart: CartEntity,\n item: CartItemEntity,\n by = 1,\n): { cartItemQuantityIncrease: CartItemQuantityIncreasePayload } {\n if (by <= 0) {\n return {\n cartItemQuantityIncrease: {\n __typename: 'CartItemQuantityIncreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const currentItem = cart.items.find((i) => i.id === item.id);\n if (!currentItem) {\n return {\n cartItemQuantityIncrease: {\n __typename: 'CartItemQuantityIncreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const newQuantity = currentItem.quantity + by;\n const delta = currentItem.sellingPrice.amount * by;\n\n const updatedItems = cart.items.map((i) => (i.id === item.id ? { ...i, quantity: newQuantity } : i));\n\n return {\n cartItemQuantityIncrease: {\n __typename: 'CartItemQuantityIncreasePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: updatedItems,\n totalizers: adjustItemsTotalizer(cart.totalizers, delta),\n total: moneyAdd(cart.total, delta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n\n/**\n * Predicts the cart after `cartItemQuantityDecrease(input: { variantId, quantityToRemove })`.\n *\n * If the resulting quantity would be `<= 0`, the line is removed entirely.\n */\nexport function buildOptimisticDecrease(\n cart: CartEntity,\n item: CartItemEntity,\n by = 1,\n): { cartItemQuantityDecrease: CartItemQuantityDecreasePayload } {\n if (by <= 0) {\n return {\n cartItemQuantityDecrease: {\n __typename: 'CartItemQuantityDecreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const currentItem = cart.items.find((i) => i.id === item.id);\n if (!currentItem) {\n return {\n cartItemQuantityDecrease: {\n __typename: 'CartItemQuantityDecreasePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const requestedQuantity = currentItem.quantity - by;\n const removed = requestedQuantity <= 0;\n const actualDelta = removed ? currentItem.quantity : by;\n const priceDelta = -currentItem.sellingPrice.amount * actualDelta;\n\n const updatedItems = removed\n ? cart.items.filter((i) => i.id !== item.id)\n : cart.items.map((i) => (i.id === item.id ? { ...i, quantity: requestedQuantity } : i));\n\n return {\n cartItemQuantityDecrease: {\n __typename: 'CartItemQuantityDecreasePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: updatedItems,\n totalizers: adjustItemsTotalizer(cart.totalizers, priceDelta),\n total: moneyAdd(cart.total, priceDelta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n\n/**\n * Predicts the cart after `cartItemRemove(input: { variantId })`.\n */\nexport function buildOptimisticRemove(\n cart: CartEntity,\n item: CartItemEntity,\n): { cartItemRemove: CartItemRemovePayload } {\n const currentItem = cart.items.find((i) => i.id === item.id);\n if (!currentItem) {\n return {\n cartItemRemove: {\n __typename: 'CartItemRemovePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const priceDelta = -currentItem.sellingPrice.amount * currentItem.quantity;\n\n return {\n cartItemRemove: {\n __typename: 'CartItemRemovePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: cart.items.filter((i) => i.id !== item.id),\n totalizers: adjustItemsTotalizer(cart.totalizers, priceDelta),\n total: moneyAdd(cart.total, priceDelta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n\n/**\n * Predicts the cart after `cartItemsRemove(input: { variantIds })` — the N-line generalisation of\n * `buildOptimisticRemove`. Lines absent from the cart are ignored; the summed price delta of the\n * matched lines adjusts the `Items` totalizer and the grand total.\n */\nexport function buildOptimisticRemoveItems(\n cart: CartEntity,\n items: readonly CartItemEntity[],\n): { cartItemsRemove: CartItemsRemovePayload } {\n const removedIds = new Set(items.map((item) => item.id));\n const removedLines = cart.items.filter((i) => removedIds.has(i.id));\n if (removedLines.length === 0) {\n return {\n cartItemsRemove: {\n __typename: 'CartItemsRemovePayload',\n cart,\n userErrors: emptyUserErrors(),\n },\n };\n }\n\n const priceDelta = removedLines.reduce((sum, line) => sum - line.sellingPrice.amount * line.quantity, 0);\n\n return {\n cartItemsRemove: {\n __typename: 'CartItemsRemovePayload',\n cart: {\n __typename: 'Cart',\n id: cart.id,\n items: cart.items.filter((i) => !removedIds.has(i.id)),\n totalizers: adjustItemsTotalizer(cart.totalizers, priceDelta),\n total: moneyAdd(cart.total, priceDelta),\n messages: cart.messages,\n appliedCoupons: cart.appliedCoupons,\n },\n userErrors: emptyUserErrors(),\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -27,7 +27,7 @@ export type CartCouponPayload = Readonly<{
|
|
|
27
27
|
/**
|
|
28
28
|
* The `cart` namespace surface. Item writes return the resulting `userErrors` (empty on success)
|
|
29
29
|
* and publish them to `cartUserErrorsVar`; coupon writes publish to the dedicated
|
|
30
|
-
* `cartCouponErrorsVar` (
|
|
30
|
+
* `cartCouponErrorsVar` (docs/storefront-core/reference-free-particle-model.md § The cart write contract).
|
|
31
31
|
*/
|
|
32
32
|
export type CartActions = Readonly<{
|
|
33
33
|
/** Add an item to the cart. Async (no optimistic response). Creates the cart on first add. */
|
|
@@ -10,7 +10,7 @@ import { useCallback, useMemo } from "react";
|
|
|
10
10
|
//#region src/sdk/cart/use-cart-actions.ts
|
|
11
11
|
/**
|
|
12
12
|
* The `cart` action namespace — the consolidated, context-free owner of every cart write
|
|
13
|
-
* (
|
|
13
|
+
* (docs/storefront-core/reference-free-particle-model.md § The cart write contract, docs/storefront-core/adr-0010-actions-own-the-write-side.md).
|
|
14
14
|
*
|
|
15
15
|
* It replaces `useCartMutations` + the mutation handlers `CartRoot` used to publish through
|
|
16
16
|
* `CartDataContext`. A handler reads the current cart from the normalized Apollo cache (keyed by
|
|
@@ -48,7 +48,7 @@ function publishCoupon(errors) {
|
|
|
48
48
|
/**
|
|
49
49
|
* Publish a write's outcome and, when it came back clean, stamp the availability freshness window —
|
|
50
50
|
* a clean write's payload carries the platform's recomputed cart, which is what lets the
|
|
51
|
-
* validate-on-open call skip (
|
|
51
|
+
* validate-on-open call skip (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Used only on paths
|
|
52
52
|
* where a mutation actually reached the server: a `userErrors` response carries `cart: null` and a
|
|
53
53
|
* no-op (unknown line) issues no request, so neither refreshes availability.
|
|
54
54
|
*/
|
|
@@ -75,7 +75,7 @@ function hydrateCartId(cartId) {
|
|
|
75
75
|
* null before the cart is minted/loaded. Module-level so it can be shared with the read-only callers
|
|
76
76
|
* that live outside this hook — the pre-checkout gate re-reads the corrected cart this way after
|
|
77
77
|
* `validate` resolves, because Apollo commits the mutation's cache write before the promise settles
|
|
78
|
-
* (
|
|
78
|
+
* (docs/storefront-core/reference-cart.md § Validation). The codegen `CartFragment` document embeds its
|
|
79
79
|
* nested fragments, so it is a self-contained read.
|
|
80
80
|
*/
|
|
81
81
|
function readCartFromCache(client) {
|