@vtex/faststore 0.0.8 → 0.0.10

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.
Files changed (151) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/actions.json +42 -0
  3. package/dist/catalog.json +731 -16
  4. package/dist/cli/index.js +1 -1
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/components.d.ts +9 -4
  7. package/dist/components.js +11 -6
  8. package/dist/content-types.json +300 -0
  9. package/dist/core/dist/define-component.d.ts +6 -1
  10. package/dist/docs/account-entry-point.md +4 -4
  11. package/dist/docs/account-menu.md +2 -2
  12. package/dist/docs/account-saved-cards.md +301 -0
  13. package/dist/docs/binding-switcher.md +154 -0
  14. package/dist/docs/card-entry.md +3 -3
  15. package/dist/docs/card-summary.md +175 -0
  16. package/dist/docs/cart-destination.md +238 -0
  17. package/dist/docs/cart-item.md +21 -3
  18. package/dist/docs/cart-totalizer.md +1 -1
  19. package/dist/docs/cart.md +118 -11
  20. package/dist/docs/footer-social.md +1 -1
  21. package/dist/docs/free-shipping-progress.md +13 -9
  22. package/dist/docs/incentives.md +2 -2
  23. package/dist/docs/logo.md +1 -1
  24. package/dist/docs/payment-method-badges.md +2 -2
  25. package/dist/docs/payment-methods.md +1 -1
  26. package/dist/docs/product-information.md +2 -2
  27. package/dist/docs/product-shelf.md +7 -0
  28. package/dist/docs/select.md +3 -4
  29. package/dist/docs/sign-in-redirect.md +1 -1
  30. package/dist/docs/toast.md +30 -12
  31. package/dist/index.d.ts +2 -1
  32. package/dist/internal/client.d.ts +4 -1
  33. package/dist/internal/client.js +4 -1
  34. package/dist/internal/server.d.ts +4 -2
  35. package/dist/internal/server.js +4 -2
  36. package/dist/matter/account-saved-cards/account-saved-cards.d.ts +383 -0
  37. package/dist/matter/account-saved-cards/account-saved-cards.js +956 -0
  38. package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
  39. package/dist/matter/billing-address/billing-address.js.map +1 -1
  40. package/dist/matter/cart/cart-namespace.d.ts +5 -1
  41. package/dist/matter/cart/cart-namespace.js +5 -1
  42. package/dist/matter/cart/cart-namespace.js.map +1 -1
  43. package/dist/matter/cart/cart.d.ts +34 -4
  44. package/dist/matter/cart/cart.js +238 -28
  45. package/dist/matter/cart/cart.js.map +1 -1
  46. package/dist/matter/cart-destination/cart-destination.d.ts +222 -0
  47. package/dist/matter/cart-destination/cart-destination.js +613 -0
  48. package/dist/matter/cart-destination/cart-destination.js.map +1 -0
  49. package/dist/matter/cart-item/cart-item.d.ts +4 -2
  50. package/dist/matter/cart-item/cart-item.js +75 -16
  51. package/dist/matter/cart-item/cart-item.js.map +1 -1
  52. package/dist/matter/cart-totalizer/cart-totalizer.js +3 -2
  53. package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
  54. package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +6 -3
  55. package/dist/matter/free-shipping-progress/free-shipping-progress.js +76 -33
  56. package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
  57. package/dist/matter/pricing/pricing.js.map +1 -1
  58. package/dist/matter/product-shelf/product-shelf.d.ts +7 -0
  59. package/dist/matter/product-shelf/product-shelf.js +115 -1
  60. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  61. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  62. package/dist/matter/shipping-simulator/shipping-simulator.d.ts +1 -1
  63. package/dist/matter/shipping-simulator/shipping-simulator.js +6 -2
  64. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  65. package/dist/particles/binding-switcher/binding-switcher.d.ts +38 -0
  66. package/dist/particles/binding-switcher/binding-switcher.js +183 -0
  67. package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
  68. package/dist/particles/card-summary/card-network.d.ts +17 -0
  69. package/dist/particles/card-summary/card-network.js +25 -0
  70. package/dist/particles/card-summary/card-network.js.map +1 -0
  71. package/dist/particles/card-summary/card-summary.d.ts +83 -0
  72. package/dist/particles/card-summary/card-summary.js +188 -0
  73. package/dist/particles/card-summary/card-summary.js.map +1 -0
  74. package/dist/particles/footer-social/footer-social.d.ts +1 -1
  75. package/dist/particles/footer-social/footer-social.js +1 -1
  76. package/dist/particles/footer-social/footer-social.js.map +1 -1
  77. package/dist/particles/incentives/incentives.d.ts +1 -1
  78. package/dist/particles/incentives/incentives.js +1 -1
  79. package/dist/particles/incentives/incentives.js.map +1 -1
  80. package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
  81. package/dist/particles/payment-methods/payment-methods.js +1 -1
  82. package/dist/particles/payment-methods/payment-methods.js.map +1 -1
  83. package/dist/particles/toast/toast.d.ts +20 -6
  84. package/dist/particles/toast/toast.js +49 -7
  85. package/dist/particles/toast/toast.js.map +1 -1
  86. package/dist/schema.graphql +298 -34
  87. package/dist/sdk/actions/index.d.ts +3 -1
  88. package/dist/sdk/actions/index.js +3 -1
  89. package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
  90. package/dist/sdk/actions/locale-action-provider.js +20 -0
  91. package/dist/sdk/actions/locale-action-provider.js.map +1 -0
  92. package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
  93. package/dist/sdk/actions/saved-card-action-provider.js +16 -0
  94. package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
  95. package/dist/sdk/actions/types.d.ts +6 -2
  96. package/dist/sdk/cache/storefront-cache.js +2 -1
  97. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  98. package/dist/sdk/cart/operations.d.ts +2 -1
  99. package/dist/sdk/cart/operations.js +55 -1
  100. package/dist/sdk/cart/operations.js.map +1 -1
  101. package/dist/sdk/cart/optimistic.d.ts +30 -7
  102. package/dist/sdk/cart/optimistic.js +78 -41
  103. package/dist/sdk/cart/optimistic.js.map +1 -1
  104. package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
  105. package/dist/sdk/cart/use-cart-actions.js +61 -15
  106. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  107. package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
  108. package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
  109. package/dist/sdk/generated/gql.js +15 -11
  110. package/dist/sdk/generated/gql.js.map +1 -1
  111. package/dist/sdk/generated/graphql.d.ts +177 -46
  112. package/dist/sdk/generated/graphql.js +2314 -93
  113. package/dist/sdk/generated/graphql.js.map +1 -1
  114. package/dist/sdk/i18n/messages/en-US.js +19 -0
  115. package/dist/sdk/i18n/messages/en-US.json +19 -0
  116. package/dist/sdk/i18n/messages/en-US.json.d.ts +19 -0
  117. package/dist/sdk/i18n/messages/es-ES.js +19 -0
  118. package/dist/sdk/i18n/messages/es-ES.json +19 -0
  119. package/dist/sdk/i18n/messages/pt-BR.js +19 -0
  120. package/dist/sdk/i18n/messages/pt-BR.json +19 -0
  121. package/dist/sdk/i18n/provider.js +1 -1
  122. package/dist/sdk/i18n/provider.js.map +1 -1
  123. package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
  124. package/dist/sdk/locale/binding-switch-provider.js +20 -0
  125. package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
  126. package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
  127. package/dist/sdk/locale/use-locale-actions.js +70 -0
  128. package/dist/sdk/locale/use-locale-actions.js.map +1 -0
  129. package/dist/sdk/navigation/binding-switch.d.ts +39 -0
  130. package/dist/sdk/navigation/binding-switch.js +129 -0
  131. package/dist/sdk/navigation/binding-switch.js.map +1 -0
  132. package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
  133. package/dist/sdk/navigation/decode-route-params.js +32 -0
  134. package/dist/sdk/navigation/decode-route-params.js.map +1 -0
  135. package/dist/sdk/saved-cards/operations.d.ts +16 -0
  136. package/dist/sdk/saved-cards/operations.js +41 -0
  137. package/dist/sdk/saved-cards/operations.js.map +1 -0
  138. package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
  139. package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
  140. package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
  141. package/dist/sdk/seo/page-alternates.d.ts +5 -3
  142. package/dist/sdk/seo/page-alternates.js +7 -12
  143. package/dist/sdk/seo/page-alternates.js.map +1 -1
  144. package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
  145. package/dist/sdk/shipping/shipping-operations.js +13 -0
  146. package/dist/sdk/shipping/shipping-operations.js.map +1 -1
  147. package/dist/sdk/state/cart.d.ts +9 -2
  148. package/dist/sdk/state/cart.js +9 -2
  149. package/dist/sdk/state/cart.js.map +1 -1
  150. package/package.json +2 -2
  151. package/src/styles/tailwind.css +1 -2
@@ -1 +1 @@
1
- {"version":3,"file":"cart-totalizer.js","names":[],"sources":["../../../src/matter/cart-totalizer/cart-totalizer.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport { type ComponentPropsWithRef, createContext, useContext, useMemo } from 'react';\nimport type { Money, CartTotalizer as Totalizer } from '../../sdk/cart/operations.js';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { graphql } from '../../sdk/generated/gql.js';\nimport { CartTotalValueContext, formatPrice } from '../cart/cart.js';\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — narrow cart slice (totalizers + total)\n// ---------------------------------------------------------------------------\n\nconst fragment = graphql(`\n fragment CartTotalizerData on Query {\n cart {\n __typename\n id\n totalizers {\n __typename\n id\n name\n value {\n ...MoneyFragment\n }\n }\n total {\n ...MoneyFragment\n }\n }\n }\n`);\n\n// ---------------------------------------------------------------------------\n// Context — totalizers list, provided by CartTotalizerRoot for CartTotalizerLine\n// ---------------------------------------------------------------------------\n\ntype CartTotalizerContextValue = Readonly<{\n totalizers: readonly Totalizer[];\n}>;\n\nconst CART_TOTALIZER_UNSET = Symbol('CartTotalizerContextUnset');\n\nconst CartTotalizerContextInternal = createContext<CartTotalizerContextValue | typeof CART_TOTALIZER_UNSET>(\n CART_TOTALIZER_UNSET,\n);\n\nexport function useCartTotalizers(): CartTotalizerContextValue {\n const ctx = useContext(CartTotalizerContextInternal);\n if (ctx === CART_TOTALIZER_UNSET) {\n throw new Error('useCartTotalizers() must be used inside a <CartTotalizerRoot> subtree.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type CartTotalizerRootProps = ComponentPropsWithRef<'div'> & {\n /**\n * Cart totalizer slice forwarded by the reactive runtime (`ReactiveDataProvider`) — it is the\n * value of the `cart` top-level field on `CartTotalizerData on Query`, not the wrapping\n * `{ cart: … }` shape. Receives `null` when the cart has not yet resolved.\n */\n $data?: { totalizers: readonly Totalizer[]; total: Money } | null;\n};\n\nexport type CartTotalizerLineProps = ComponentPropsWithRef<'div'> & {\n /** Which `cart.totalizers` entry to render, selected by `id` (e.g. \"Items\", \"Shipping\", \"Discounts\"). */\n totalizerId: string;\n /** Optional label override; defaults to the totalizer's `name`. */\n label?: string;\n /** Styling hook → `data-fs-cart-totalizer-line-variant`. The F9 discounts line uses `'discount'`. */\n variant?: 'default' | 'discount';\n /** Text rendered in place of the value when the amount is exactly zero (e.g. \"Free\" for shipping — Decision 5). */\n zeroLabel?: string;\n};\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const CartTotalizerRootDefinition = defineComponent<CartTotalizerRootProps>({\n name: 'CartTotalizerRoot',\n importPath: '@vtex/faststore/components',\n component: CartTotalizerRoot,\n fragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Cart Totalizer Root', category: 'commerce' },\n schema: {},\n guideline:\n 'Focused reactive provider for cart totalizers + total (narrower than CartRoot); merges with CartRoot into one cart query when both are present on the page (e.g. CartRoot wrapping the mini-cart drawer, CartTotalizerRoot composing its footer). Use it to compose an order summary — in a mini-cart drawer footer or a checkout summary panel: wrap a CartTotalizerLine totalizerId=\"Items\" (subtotal), a CartTotalizerLine totalizerId=\"Discounts\" variant=\"discount\" (auto-hides at zero), a CartTotalizerLine totalizerId=\"Shipping\" zeroLabel=\"Grátis\", and a CartTotal for the grand total (set CartTotal label for a labeled total row). CartTotal is root-agnostic and reads the total from this root — there is no CartTotalizerTotal.',\n});\n\nexport const CartTotalizerLineDefinition = defineComponent<CartTotalizerLineProps>({\n name: 'CartTotalizerLine',\n importPath: '@vtex/faststore/components',\n component: CartTotalizerLine,\n editor: { label: 'Cart Totalizer Line', category: 'commerce' },\n schema: {\n totalizerId: { type: 'string', label: 'Totalizer Id' },\n label: { type: 'string', label: 'Label' },\n variant: { type: ['default', 'discount'] as const, default: 'default', label: 'Variant' },\n zeroLabel: { type: 'string', label: 'Zero Label' },\n },\n guideline:\n 'Renders one cart totalizer row (label + value) selected by totalizerId. The canonical order-summary lines are totalizerId=\"Items\" (the subtotal), totalizerId=\"Discounts\" (the discount), and totalizerId=\"Shipping\" (the shipping cost). For the discounts line set variant=\"discount\" — it hides itself when the value is zero (no active discount). The Core API returns a negative amount for discounts; the formatted value displays as-is (e.g. \"-R$ 40,00\"). Set zeroLabel=\"Grátis\" for the shipping line so a zero amount renders the label instead of R$ 0,00. A line whose totalizerId is absent from the cart renders nothing (no empty row). Must be inside CartTotalizerRoot.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function CartTotalizerRoot({ $data: $dataProp, className, children, ...props }: CartTotalizerRootProps) {\n const $data = useDataOverride($dataProp);\n\n const totalizerValue: CartTotalizerContextValue = useMemo(\n () => ({ totalizers: $data?.totalizers ?? [] }),\n [$data?.totalizers],\n );\n\n return (\n <CartTotalValueContext value={$data?.total ?? null}>\n <CartTotalizerContextInternal value={totalizerValue}>\n <div {...props} className={className} data-fs-cart-totalizer-root=\"\">\n {children}\n </div>\n </CartTotalizerContextInternal>\n </CartTotalValueContext>\n );\n}\n\nexport function CartTotalizerLine({\n totalizerId,\n label,\n variant = 'default',\n zeroLabel,\n className,\n children,\n ...props\n}: CartTotalizerLineProps) {\n const { totalizers } = useCartTotalizers();\n const { locale, currency } = useStorefrontContext();\n const totalizer = totalizers.find((t) => t.id === totalizerId);\n\n if (!totalizer) return null;\n\n const amount = totalizer.value.amount;\n\n if (variant === 'discount' && amount === 0) return null;\n\n const valueContent = amount === 0 && zeroLabel != null ? zeroLabel : formatPrice(amount, locale, currency);\n\n return (\n <div {...props} className={className} data-fs-cart-totalizer-line=\"\" data-fs-cart-totalizer-line-variant={variant}>\n <span>{label ?? totalizer.name}</span>\n <span>{children ?? valueContent}</span>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CartDiscountLine — itemized discount breakdown (F11)\n// ---------------------------------------------------------------------------\n\n// Owns its own `Cart.discounts` slice (ADR-0011 data ownership): the field is fetched only when this\n// leaf is placed and merges with any CartTotalizerRoot / CartRoot cart selection into one query. The\n// entries are the itemized companion to the aggregate \"Discounts\" totalizer and sum to it, so a store\n// composes this OR CartTotalizerLine totalizerId=\"Discounts\", never both.\nconst cartDiscountLinesFragment = graphql(`\n fragment CartDiscountLinesData on Query {\n cart {\n __typename\n id\n discounts {\n name\n value {\n ...MoneyFragment\n }\n kind\n }\n }\n }\n`);\n\nexport type CartDiscountKind = 'PROMOTION' | 'COUPON' | 'OTHER';\n\n/**\n * One cart-level discount line from `Cart.discounts`. `value` is the absolute amount discounted\n * (a positive `Money`); the negative sign is applied on render by the locale's currency format.\n * `amount` is typed `number` but is a string at runtime, so it is `Number()`-coerced before formatting.\n * `name` is null for the OTHER residual and for an unnamed promotion — the `otherLabel` prop names those.\n */\nexport type CartDiscountEntry = {\n name: string | null;\n value: { amount: number; currencyCode: string };\n kind: CartDiscountKind;\n};\n\n/** Cart slice forwarded by the reactive runtime — the value of the top-level `cart` field. */\ntype CartDiscountLinesSlice = { discounts: CartDiscountEntry[] };\n\nexport type CartDiscountLineProps = ComponentPropsWithRef<'div'> & {\n /** Label for lines the API cannot name: the OTHER residual and an unnamed featured promotion. */\n otherLabel?: string;\n /** Cart discount slice forwarded by the reactive runtime; injected/overridden by the runtime or in tests. */\n $data?: CartDiscountLinesSlice | null;\n};\n\nexport const CartDiscountLineDefinition = defineComponent<CartDiscountLineProps>({\n name: 'CartDiscountLine',\n importPath: '@vtex/faststore/components',\n component: CartDiscountLine,\n fragment: cartDiscountLinesFragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Cart Discount Line', category: 'commerce' },\n schema: {\n otherLabel: { type: 'string', default: 'Other discounts', label: 'Unnamed discount label' },\n },\n guideline:\n 'Itemized order-summary discounts: renders one line per entry in cart.discounts (one per promotion ' +\n 'and per coupon, plus a residual \"other\" line), each as label + negative amount. Renders nothing ' +\n 'when the cart has no discounts. This is the itemized alternative to CartTotalizerLine ' +\n 'totalizerId=\"Discounts\": the entries sum to that same aggregate, so compose this OR that line, ' +\n 'never both (both would double-count the same money). Place it in the order summary, typically ' +\n 'inside CartTotalizerRoot. Set otherLabel for the residual and any unnamed promotion. See cart-totalizer.md.',\n});\n\nexport function CartDiscountLine({\n otherLabel = 'Other discounts',\n className,\n $data: $dataProp,\n ...props\n}: CartDiscountLineProps) {\n const slice = useDataOverride<CartDiscountLinesSlice | null | undefined>($dataProp);\n const { locale, currency } = useStorefrontContext();\n const discounts = slice?.discounts;\n\n if (!discounts || discounts.length === 0) {\n return null;\n }\n\n return (\n <div {...props} className={className} data-fs-cart-discount-lines=\"\">\n {discounts.map((discount, index) => {\n const amount = Number(discount.value.amount);\n const label = discount.name ?? otherLabel;\n\n return (\n <div\n key={`${discount.kind}-${discount.name}-${index}`}\n data-fs-cart-discount-line=\"\"\n data-fs-cart-discount-line-kind={discount.kind.toLowerCase()}\n data-fs-text=\"\"\n >\n <span data-fs-cart-discount-line-label=\"\">{label}</span>\n {/* Negate the positive magnitude and let the currency format sign it — no hardcoded glyph. */}\n <span data-fs-cart-discount-line-value=\"\">{formatPrice(-amount, locale, currency)}</span>\n </div>\n );\n })}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CartMarkdownLine — aggregate item-level catalog markdown (F11 scenario 1)\n// ---------------------------------------------------------------------------\n\n// Renders Cart.itemMarkdownTotal — Σ(listPrice − price) × qty across non-gift lines, computed\n// server-side — as one negative summary line, self-hiding when zero. This is the catalog \"de/por\"\n// markdown that sits ABOVE the Items subtotal, so it is DISTINCT money from the cart-level promotions\n// on the Discounts totalizer / CartDiscountLine (price − sellingPrice): the two coexist in a summary,\n// they do not substitute. Owns its own slice (ADR-0011): the field is fetched only when this leaf is\n// placed and merges with any CartTotalizerRoot / CartRoot cart selection into one query.\nconst cartMarkdownFragment = graphql(`\n fragment CartMarkdownData on Query {\n cart {\n __typename\n id\n itemMarkdownTotal {\n ...MoneyFragment\n }\n }\n }\n`);\n\n/** Cart slice forwarded by the reactive runtime — the value of the top-level `cart` field. */\ntype CartMarkdownSlice = { itemMarkdownTotal: { amount: number; currencyCode: string } };\n\nexport type CartMarkdownLineProps = ComponentPropsWithRef<'div'> & {\n /** Row label for the aggregate item-level markdown. Interim operational default until the i18n catalog lands. */\n label?: string;\n /** Cart markdown slice forwarded by the reactive runtime; injected/overridden by the runtime or in tests. */\n $data?: CartMarkdownSlice | null;\n};\n\nexport const CartMarkdownLineDefinition = defineComponent<CartMarkdownLineProps>({\n name: 'CartMarkdownLine',\n importPath: '@vtex/faststore/components',\n component: CartMarkdownLine,\n fragment: cartMarkdownFragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Cart Markdown Line', category: 'commerce' },\n schema: {\n label: { type: 'string', default: 'Item discounts', label: 'Markdown label' },\n },\n guideline:\n 'Aggregate item-level catalog markdown: renders Cart.itemMarkdownTotal (the sum of listPrice − price ' +\n 'across the cart, the \"de/por\" catalog savings) as a single negative line. Renders nothing when the ' +\n 'cart has no markdown. This is DISTINCT money from CartDiscountLine and CartTotalizerLine ' +\n 'totalizerId=\"Discounts\" (those are cart-level promotions/coupons, price − sellingPrice) — it may be ' +\n 'shown ALONGSIDE them, not instead of them, and does not double-count. Place it in the order summary, ' +\n 'typically inside CartTotalizerRoot. Set label to word the row. See cart-totalizer.md.',\n});\n\nexport function CartMarkdownLine({\n label = 'Item discounts',\n className,\n $data: $dataProp,\n ...props\n}: CartMarkdownLineProps) {\n const slice = useDataOverride<CartMarkdownSlice | null | undefined>($dataProp);\n const { locale, currency } = useStorefrontContext();\n // `amount` is a string at runtime; coerce before checking/formatting. A zero markdown self-hides.\n const amount = Number(slice?.itemMarkdownTotal?.amount ?? 0);\n\n if (!amount) {\n return null;\n }\n\n return (\n <div {...props} className={className} data-fs-cart-markdown-line=\"\" data-fs-text=\"\">\n <span data-fs-cart-markdown-line-label=\"\">{label}</span>\n {/* Negate the positive magnitude and let the currency format sign it — no hardcoded glyph. */}\n <span data-fs-cart-markdown-line-value=\"\">{formatPrice(-amount, locale, currency)}</span>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAcA,MAAM,WAAW,QAAQ;;;;;;;;;;;;;;;;;;CAkBxB;AAUD,MAAM,uBAAuB,OAAO,2BAA2B;AAE/D,MAAM,+BAA+B,cACnC,oBACF;AAEA,SAAgB,oBAA+C;CAC7D,MAAM,MAAM,WAAW,4BAA4B;CACnD,IAAI,QAAQ,sBACV,MAAM,IAAI,MAAM,wEAAwE;CAE1F,OAAO;AACT;AA8BA,MAAa,8BAA8B,gBAAwC;CACjF,MAAM;CACN,YAAY;CACZ,WAAW;CACX;CACA,eAAe;CACf,QAAQ;EAAE,OAAO;EAAuB,UAAU;CAAW;CAC7D,QAAQ,CAAC;CACT,WACE;AACJ,CAAC;AAED,MAAa,8BAA8B,gBAAwC;CACjF,MAAM;CACN,YAAY;CACZ,WAAW;CACX,QAAQ;EAAE,OAAO;EAAuB,UAAU;CAAW;CAC7D,QAAQ;EACN,aAAa;GAAE,MAAM;GAAU,OAAO;EAAe;EACrD,OAAO;GAAE,MAAM;GAAU,OAAO;EAAQ;EACxC,SAAS;GAAE,MAAM,CAAC,WAAW,UAAU;GAAY,SAAS;GAAW,OAAO;EAAU;EACxF,WAAW;GAAE,MAAM;GAAU,OAAO;EAAa;CACnD;CACA,WACE;AACJ,CAAC;AAMD,SAAgB,kBAAkB,EAAE,OAAO,WAAW,WAAW,UAAU,GAAG,SAAiC;CAC7G,MAAM,QAAQ,gBAAgB,SAAS;CAEvC,MAAM,iBAA4C,eACzC,EAAE,YAAY,OAAO,cAAc,CAAC,EAAE,IAC7C,CAAC,OAAO,UAAU,CACpB;CAEA,OACE,oBAAC,uBAAD;EAAuB,OAAO,OAAO,SAAS;EAC5C,UAAA,oBAAC,8BAAD;GAA8B,OAAO;GACnC,UAAA,oBAAC,OAAD;IAAK,GAAI;IAAkB;IAAW,+BAA4B;IAC/D;GACE,CAAA;EACuB,CAAA;CACT,CAAA;AAE3B;AAEA,SAAgB,kBAAkB,EAChC,aACA,OACA,UAAU,WACV,WACA,WACA,UACA,GAAG,SACsB;CACzB,MAAM,EAAE,eAAe,kBAAkB;CACzC,MAAM,EAAE,QAAQ,aAAa,qBAAqB;CAClD,MAAM,YAAY,WAAW,MAAM,MAAM,EAAE,OAAO,WAAW;CAE7D,IAAI,CAAC,WAAW,OAAO;CAEvB,MAAM,SAAS,UAAU,MAAM;CAE/B,IAAI,YAAY,cAAc,WAAW,GAAG,OAAO;CAEnD,MAAM,eAAe,WAAW,KAAK,aAAa,OAAO,YAAY,YAAY,QAAQ,QAAQ,QAAQ;CAEzG,OACE,qBAAC,OAAD;EAAK,GAAI;EAAkB;EAAW,+BAA4B;EAAG,uCAAqC;EAA1G,UAAA,CACE,oBAAC,QAAD,EAAA,UAAO,SAAS,UAAU,KAAW,CAAA,GACrC,oBAAC,QAAD,EAAA,UAAO,YAAY,aAAmB,CAAA,CACnC;;AAET;AAUA,MAAM,4BAA4B,QAAQ;;;;;;;;;;;;;;CAczC;AA0BD,MAAa,6BAA6B,gBAAuC;CAC/E,MAAM;CACN,YAAY;CACZ,WAAW;CACX,UAAU;CACV,eAAe;CACf,QAAQ;EAAE,OAAO;EAAsB,UAAU;CAAW;CAC5D,QAAQ,EACN,YAAY;EAAE,MAAM;EAAU,SAAS;EAAmB,OAAO;CAAyB,EAC5F;CACA,WACE;AAMJ,CAAC;AAED,SAAgB,iBAAiB,EAC/B,aAAa,mBACb,WACA,OAAO,WACP,GAAG,SACqB;CACxB,MAAM,QAAQ,gBAA2D,SAAS;CAClF,MAAM,EAAE,QAAQ,aAAa,qBAAqB;CAClD,MAAM,YAAY,OAAO;CAEzB,IAAI,CAAC,aAAa,UAAU,WAAW,GACrC,OAAO;CAGT,OACE,oBAAC,OAAD;EAAK,GAAI;EAAkB;EAAW,+BAA4B;EAC/D,UAAA,UAAU,KAAK,UAAU,UAAU;GAClC,MAAM,SAAS,OAAO,SAAS,MAAM,MAAM;GAC3C,MAAM,QAAQ,SAAS,QAAQ;GAE/B,OACE,qBAAC,OAAD;IAEE,8BAA2B;IAC3B,mCAAiC,SAAS,KAAK,YAAY;IAC3D,gBAAa;IAJf,UAAA,CAME,oBAAC,QAAD;KAAM,oCAAiC;KAAI,UAAA;IAAY,CAAA,GAEvD,oBAAC,QAAD;KAAM,oCAAiC;KAAI,UAAA,YAAY,CAAC,QAAQ,QAAQ,QAAQ;IAAQ,CAAA,CACrF;GARE,GAAA,GAAG,SAAS,KAAK,GAAG,SAAS,KAAK,GAAG,OAQvC;EAET,CAAC;CACE,CAAA;AAET;AAYA,MAAM,uBAAuB,QAAQ;;;;;;;;;;CAUpC;AAYD,MAAa,6BAA6B,gBAAuC;CAC/E,MAAM;CACN,YAAY;CACZ,WAAW;CACX,UAAU;CACV,eAAe;CACf,QAAQ;EAAE,OAAO;EAAsB,UAAU;CAAW;CAC5D,QAAQ,EACN,OAAO;EAAE,MAAM;EAAU,SAAS;EAAkB,OAAO;CAAiB,EAC9E;CACA,WACE;AAMJ,CAAC;AAED,SAAgB,iBAAiB,EAC/B,QAAQ,kBACR,WACA,OAAO,WACP,GAAG,SACqB;CACxB,MAAM,QAAQ,gBAAsD,SAAS;CAC7E,MAAM,EAAE,QAAQ,aAAa,qBAAqB;CAElD,MAAM,SAAS,OAAO,OAAO,mBAAmB,UAAU,CAAC;CAE3D,IAAI,CAAC,QACH,OAAO;CAGT,OACE,qBAAC,OAAD;EAAK,GAAI;EAAkB;EAAW,8BAA2B;EAAG,gBAAa;EAAjF,UAAA,CACE,oBAAC,QAAD;GAAM,oCAAiC;GAAI,UAAA;EAAY,CAAA,GAEvD,oBAAC,QAAD;GAAM,oCAAiC;GAAI,UAAA,YAAY,CAAC,QAAQ,QAAQ,QAAQ;EAAQ,CAAA,CACrF;;AAET"}
1
+ {"version":3,"file":"cart-totalizer.js","names":[],"sources":["../../../src/matter/cart-totalizer/cart-totalizer.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport { type ComponentPropsWithRef, createContext, useContext, useMemo } from 'react';\nimport type { Money, CartTotalizer as Totalizer } from '../../sdk/cart/operations.js';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { graphql } from '../../sdk/generated/gql.js';\nimport { CartTotalValueContext, formatPrice, isFiniteAmount } from '../cart/cart.js';\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — narrow cart slice (totalizers + total)\n// ---------------------------------------------------------------------------\n\nconst fragment = graphql(`\n fragment CartTotalizerData on Query {\n cart {\n __typename\n id\n totalizers {\n __typename\n id\n name\n value {\n ...MoneyFragment\n }\n }\n total {\n ...MoneyFragment\n }\n }\n }\n`);\n\n// ---------------------------------------------------------------------------\n// Context — totalizers list, provided by CartTotalizerRoot for CartTotalizerLine\n// ---------------------------------------------------------------------------\n\ntype CartTotalizerContextValue = Readonly<{\n totalizers: readonly Totalizer[];\n}>;\n\nconst CART_TOTALIZER_UNSET = Symbol('CartTotalizerContextUnset');\n\nconst CartTotalizerContextInternal = createContext<CartTotalizerContextValue | typeof CART_TOTALIZER_UNSET>(\n CART_TOTALIZER_UNSET,\n);\n\nexport function useCartTotalizers(): CartTotalizerContextValue {\n const ctx = useContext(CartTotalizerContextInternal);\n if (ctx === CART_TOTALIZER_UNSET) {\n throw new Error('useCartTotalizers() must be used inside a <CartTotalizerRoot> subtree.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type CartTotalizerRootProps = ComponentPropsWithRef<'div'> & {\n /**\n * Cart totalizer slice forwarded by the reactive runtime (`ReactiveDataProvider`) — it is the\n * value of the `cart` top-level field on `CartTotalizerData on Query`, not the wrapping\n * `{ cart: … }` shape. Receives `null` when the cart has not yet resolved.\n */\n $data?: { totalizers: readonly Totalizer[]; total: Money } | null;\n};\n\nexport type CartTotalizerLineProps = ComponentPropsWithRef<'div'> & {\n /** Which `cart.totalizers` entry to render, selected by `id` (e.g. \"Items\", \"Shipping\", \"Discounts\"). */\n totalizerId: string;\n /** Optional label override; defaults to the totalizer's `name`. */\n label?: string;\n /** Styling hook → `data-fs-cart-totalizer-line-variant`. The F9 discounts line uses `'discount'`. */\n variant?: 'default' | 'discount';\n /** Text rendered in place of the value when the amount is exactly zero (e.g. \"Free\" for shipping — Decision 5). */\n zeroLabel?: string;\n};\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const CartTotalizerRootDefinition = defineComponent<CartTotalizerRootProps>({\n name: 'CartTotalizerRoot',\n importPath: '@vtex/faststore/components',\n component: CartTotalizerRoot,\n fragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Cart Totalizer Root', category: 'commerce' },\n schema: {},\n guideline:\n 'Focused reactive provider for cart totalizers + total (narrower than CartRoot); merges with CartRoot into one cart query when both are present on the page (e.g. CartRoot wrapping the mini-cart drawer, CartTotalizerRoot composing its footer). Use it to compose an order summary — in a mini-cart drawer footer or a checkout summary panel: wrap a CartTotalizerLine totalizerId=\"Items\" (subtotal), a CartTotalizerLine totalizerId=\"Discounts\" variant=\"discount\" (auto-hides at zero), a CartTotalizerLine totalizerId=\"Shipping\" zeroLabel=\"Grátis\", and a CartTotal for the grand total (set CartTotal label for a labeled total row). CartTotal is root-agnostic and reads the total from this root — there is no CartTotalizerTotal.',\n});\n\nexport const CartTotalizerLineDefinition = defineComponent<CartTotalizerLineProps>({\n name: 'CartTotalizerLine',\n importPath: '@vtex/faststore/components',\n component: CartTotalizerLine,\n editor: { label: 'Cart Totalizer Line', category: 'commerce' },\n schema: {\n totalizerId: { type: 'string', label: 'Totalizer Id' },\n label: { type: 'string', label: 'Label' },\n variant: { type: ['default', 'discount'] as const, default: 'default', label: 'Variant' },\n zeroLabel: { type: 'string', label: 'Zero Label' },\n },\n guideline:\n 'Renders one cart totalizer row (label + value) selected by totalizerId. The canonical order-summary lines are totalizerId=\"Items\" (the subtotal), totalizerId=\"Discounts\" (the discount), and totalizerId=\"Shipping\" (the shipping cost). For the discounts line set variant=\"discount\" — it hides itself when the value is zero (no active discount). The Core API returns a negative amount for discounts; the formatted value displays as-is (e.g. \"-R$ 40,00\"). Set zeroLabel=\"Grátis\" for the shipping line so a zero amount renders the label instead of R$ 0,00. A line whose totalizerId is absent from the cart renders nothing (no empty row). Must be inside CartTotalizerRoot.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function CartTotalizerRoot({ $data: $dataProp, className, children, ...props }: CartTotalizerRootProps) {\n const $data = useDataOverride($dataProp);\n\n const totalizerValue: CartTotalizerContextValue = useMemo(\n () => ({ totalizers: $data?.totalizers ?? [] }),\n [$data?.totalizers],\n );\n\n return (\n <CartTotalValueContext value={$data?.total ?? null}>\n <CartTotalizerContextInternal value={totalizerValue}>\n <div {...props} className={className} data-fs-cart-totalizer-root=\"\">\n {children}\n </div>\n </CartTotalizerContextInternal>\n </CartTotalValueContext>\n );\n}\n\nexport function CartTotalizerLine({\n totalizerId,\n label,\n variant = 'default',\n zeroLabel,\n className,\n children,\n ...props\n}: CartTotalizerLineProps) {\n const { totalizers } = useCartTotalizers();\n const { locale, currency } = useStorefrontContext();\n const totalizer = totalizers.find((t) => t.id === totalizerId);\n\n if (!totalizer) return null;\n\n if (!isFiniteAmount(totalizer.value.amount)) return null;\n\n const amount = Number(totalizer.value.amount);\n\n if (variant === 'discount' && amount === 0) return null;\n\n const valueContent = amount === 0 && zeroLabel != null ? zeroLabel : formatPrice(amount, locale, currency);\n\n return (\n <div {...props} className={className} data-fs-cart-totalizer-line=\"\" data-fs-cart-totalizer-line-variant={variant}>\n <span>{label ?? totalizer.name}</span>\n <span>{children ?? valueContent}</span>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CartDiscountLine — itemized discount breakdown (F11)\n// ---------------------------------------------------------------------------\n\n// Owns its own `Cart.discounts` slice (ADR-0011 data ownership): the field is fetched only when this\n// leaf is placed and merges with any CartTotalizerRoot / CartRoot cart selection into one query. The\n// entries are the itemized companion to the aggregate \"Discounts\" totalizer and sum to it, so a store\n// composes this OR CartTotalizerLine totalizerId=\"Discounts\", never both.\nconst cartDiscountLinesFragment = graphql(`\n fragment CartDiscountLinesData on Query {\n cart {\n __typename\n id\n discounts {\n name\n value {\n ...MoneyFragment\n }\n kind\n }\n }\n }\n`);\n\nexport type CartDiscountKind = 'PROMOTION' | 'COUPON' | 'OTHER';\n\n/**\n * One cart-level discount line from `Cart.discounts`. `value` is the absolute amount discounted\n * (a positive `Money`); the negative sign is applied on render by the locale's currency format.\n * `amount` is typed `number` but is a string at runtime, so it is `Number()`-coerced before formatting.\n * `name` is null for the OTHER residual and for an unnamed promotion — the `otherLabel` prop names those.\n */\nexport type CartDiscountEntry = {\n name: string | null;\n value: { amount: number; currencyCode: string };\n kind: CartDiscountKind;\n};\n\n/** Cart slice forwarded by the reactive runtime — the value of the top-level `cart` field. */\ntype CartDiscountLinesSlice = { discounts: CartDiscountEntry[] };\n\nexport type CartDiscountLineProps = ComponentPropsWithRef<'div'> & {\n /** Label for lines the API cannot name: the OTHER residual and an unnamed featured promotion. */\n otherLabel?: string;\n /** Cart discount slice forwarded by the reactive runtime; injected/overridden by the runtime or in tests. */\n $data?: CartDiscountLinesSlice | null;\n};\n\nexport const CartDiscountLineDefinition = defineComponent<CartDiscountLineProps>({\n name: 'CartDiscountLine',\n importPath: '@vtex/faststore/components',\n component: CartDiscountLine,\n fragment: cartDiscountLinesFragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Cart Discount Line', category: 'commerce' },\n schema: {\n otherLabel: { type: 'string', default: 'Other discounts', label: 'Unnamed discount label' },\n },\n guideline:\n 'Itemized order-summary discounts: renders one line per entry in cart.discounts (one per promotion ' +\n 'and per coupon, plus a residual \"other\" line), each as label + negative amount. Renders nothing ' +\n 'when the cart has no discounts. This is the itemized alternative to CartTotalizerLine ' +\n 'totalizerId=\"Discounts\": the entries sum to that same aggregate, so compose this OR that line, ' +\n 'never both (both would double-count the same money). Place it in the order summary, typically ' +\n 'inside CartTotalizerRoot. Set otherLabel for the residual and any unnamed promotion. See cart-totalizer.md.',\n});\n\nexport function CartDiscountLine({\n otherLabel = 'Other discounts',\n className,\n $data: $dataProp,\n ...props\n}: CartDiscountLineProps) {\n const slice = useDataOverride<CartDiscountLinesSlice | null | undefined>($dataProp);\n const { locale, currency } = useStorefrontContext();\n const discounts = slice?.discounts;\n\n if (!discounts || discounts.length === 0) {\n return null;\n }\n\n return (\n <div {...props} className={className} data-fs-cart-discount-lines=\"\">\n {discounts.map((discount, index) => {\n const amount = Number(discount.value.amount);\n const label = discount.name ?? otherLabel;\n\n return (\n <div\n key={`${discount.kind}-${discount.name}-${index}`}\n data-fs-cart-discount-line=\"\"\n data-fs-cart-discount-line-kind={discount.kind.toLowerCase()}\n data-fs-text=\"\"\n >\n <span data-fs-cart-discount-line-label=\"\">{label}</span>\n {/* Negate the positive magnitude and let the currency format sign it — no hardcoded glyph. */}\n <span data-fs-cart-discount-line-value=\"\">{formatPrice(-amount, locale, currency)}</span>\n </div>\n );\n })}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CartMarkdownLine — aggregate item-level catalog markdown (F11 scenario 1)\n// ---------------------------------------------------------------------------\n\n// Renders Cart.itemMarkdownTotal — Σ(listPrice − price) × qty across non-gift lines, computed\n// server-side — as one negative summary line, self-hiding when zero. This is the catalog \"de/por\"\n// markdown that sits ABOVE the Items subtotal, so it is DISTINCT money from the cart-level promotions\n// on the Discounts totalizer / CartDiscountLine (price − sellingPrice): the two coexist in a summary,\n// they do not substitute. Owns its own slice (ADR-0011): the field is fetched only when this leaf is\n// placed and merges with any CartTotalizerRoot / CartRoot cart selection into one query.\nconst cartMarkdownFragment = graphql(`\n fragment CartMarkdownData on Query {\n cart {\n __typename\n id\n itemMarkdownTotal {\n ...MoneyFragment\n }\n }\n }\n`);\n\n/** Cart slice forwarded by the reactive runtime — the value of the top-level `cart` field. */\ntype CartMarkdownSlice = { itemMarkdownTotal: { amount: number; currencyCode: string } };\n\nexport type CartMarkdownLineProps = ComponentPropsWithRef<'div'> & {\n /** Row label for the aggregate item-level markdown. Interim operational default until the i18n catalog lands. */\n label?: string;\n /** Cart markdown slice forwarded by the reactive runtime; injected/overridden by the runtime or in tests. */\n $data?: CartMarkdownSlice | null;\n};\n\nexport const CartMarkdownLineDefinition = defineComponent<CartMarkdownLineProps>({\n name: 'CartMarkdownLine',\n importPath: '@vtex/faststore/components',\n component: CartMarkdownLine,\n fragment: cartMarkdownFragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Cart Markdown Line', category: 'commerce' },\n schema: {\n label: { type: 'string', default: 'Item discounts', label: 'Markdown label' },\n },\n guideline:\n 'Aggregate item-level catalog markdown: renders Cart.itemMarkdownTotal (the sum of listPrice − price ' +\n 'across the cart, the \"de/por\" catalog savings) as a single negative line. Renders nothing when the ' +\n 'cart has no markdown. This is DISTINCT money from CartDiscountLine and CartTotalizerLine ' +\n 'totalizerId=\"Discounts\" (those are cart-level promotions/coupons, price − sellingPrice) — it may be ' +\n 'shown ALONGSIDE them, not instead of them, and does not double-count. Place it in the order summary, ' +\n 'typically inside CartTotalizerRoot. Set label to word the row. See cart-totalizer.md.',\n});\n\nexport function CartMarkdownLine({\n label = 'Item discounts',\n className,\n $data: $dataProp,\n ...props\n}: CartMarkdownLineProps) {\n const slice = useDataOverride<CartMarkdownSlice | null | undefined>($dataProp);\n const { locale, currency } = useStorefrontContext();\n // `amount` is a string at runtime; coerce before checking/formatting. A zero markdown self-hides.\n const amount = Number(slice?.itemMarkdownTotal?.amount ?? 0);\n\n if (!amount) {\n return null;\n }\n\n return (\n <div {...props} className={className} data-fs-cart-markdown-line=\"\" data-fs-text=\"\">\n <span data-fs-cart-markdown-line-label=\"\">{label}</span>\n {/* Negate the positive magnitude and let the currency format sign it — no hardcoded glyph. */}\n <span data-fs-cart-markdown-line-value=\"\">{formatPrice(-amount, locale, currency)}</span>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -9,7 +9,10 @@ type MoneyValue = {
9
9
  type FreeShippingProgressData = {
10
10
  cart?: {
11
11
  id: string;
12
- total?: MoneyValue | null;
12
+ totalizers?: {
13
+ id: string;
14
+ value: MoneyValue;
15
+ }[] | null;
13
16
  freeShippingProgress?: {
14
17
  threshold: MoneyValue | null;
15
18
  remaining: MoneyValue;
@@ -21,7 +24,7 @@ export type FreeShippingProgressRootProps = ComponentPropsWithRef<'div'> & {
21
24
  threshold?: number;
22
25
  remaining?: number;
23
26
  qualified?: boolean;
24
- cartTotal?: number;
27
+ itemsTotal?: number;
25
28
  $data?: FreeShippingProgressData['cart'] | null;
26
29
  };
27
30
  export type FreeShippingProgressBarProps = ComponentPropsWithRef<'div'>;
@@ -32,7 +35,7 @@ export type FreeShippingProgressMessageProps = ComponentPropsWithRef<'div'> & {
32
35
  export declare const FreeShippingProgressRootDefinition: ComponentDefinition<FreeShippingProgressRootProps>;
33
36
  export declare const FreeShippingProgressBarDefinition: ComponentDefinition<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>>;
34
37
  export declare const FreeShippingProgressMessageDefinition: ComponentDefinition<FreeShippingProgressMessageProps>;
35
- export declare function FreeShippingProgressRoot({ threshold, remaining, qualified, cartTotal, $data: $dataProp, className, children, ...props }: FreeShippingProgressRootProps): import("react/jsx-runtime").JSX.Element | null;
38
+ export declare function FreeShippingProgressRoot({ threshold, remaining, qualified, itemsTotal, $data: $dataProp, className, children, ...props }: FreeShippingProgressRootProps): import("react/jsx-runtime").JSX.Element | null;
36
39
  export declare function FreeShippingProgressBar({ className, ...props }: FreeShippingProgressBarProps): import("react/jsx-runtime").JSX.Element;
37
40
  export declare function FreeShippingProgressMessage({ label, qualifiedLabel, className, children, ...props }: FreeShippingProgressMessageProps): import("react/jsx-runtime").JSX.Element;
38
41
  export declare const FreeShippingProgress: {
@@ -3,6 +3,7 @@ import { defineComponent } from "../../core/dist/define-component.js";
3
3
  import "../../core/dist/index.js";
4
4
  import { useStorefrontContext } from "../../sdk/context/storefront-context.js";
5
5
  import { useDataOverride } from "../../sdk/data/data-override-context.js";
6
+ import { isFiniteAmount } from "../cart/cart.js";
6
7
  import { Meter } from "../../particles/meter/meter.js";
7
8
  import { createContext, useContext } from "react";
8
9
  import { jsx } from "react/jsx-runtime";
@@ -11,9 +12,12 @@ const fragment = `
11
12
  fragment FreeShippingProgressData on Query {
12
13
  cart {
13
14
  id
14
- total {
15
- amount
16
- currencyCode
15
+ totalizers {
16
+ id
17
+ value {
18
+ amount
19
+ currencyCode
20
+ }
17
21
  }
18
22
  freeShippingProgress {
19
23
  threshold {
@@ -45,6 +49,62 @@ function formatCurrency(value, locale, currency) {
45
49
  function clamp01(value) {
46
50
  return Math.min(Math.max(value, 0), 1);
47
51
  }
52
+ function previewCart({ threshold, remaining, qualified, itemsTotal }, currency) {
53
+ if (qualified === void 0 && threshold === void 0 && remaining === void 0 && itemsTotal === void 0) return null;
54
+ return {
55
+ id: "preview",
56
+ totalizers: itemsTotal === void 0 ? [] : [{
57
+ id: "Items",
58
+ value: {
59
+ amount: itemsTotal,
60
+ currencyCode: currency
61
+ }
62
+ }],
63
+ freeShippingProgress: {
64
+ threshold: threshold == null ? null : {
65
+ amount: threshold,
66
+ currencyCode: currency
67
+ },
68
+ remaining: {
69
+ amount: remaining ?? threshold ?? 0,
70
+ currencyCode: currency
71
+ },
72
+ qualified: qualified ?? false
73
+ }
74
+ };
75
+ }
76
+ function itemsSubtotal(cart) {
77
+ const itemsAmount = cart.totalizers?.find((totalizer) => totalizer.id === "Items")?.value.amount;
78
+ return isFiniteAmount(itemsAmount) ? Number(itemsAmount) : null;
79
+ }
80
+ function usableThreshold(threshold) {
81
+ if (threshold == null) return null;
82
+ const parsed = Number(threshold.amount);
83
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
84
+ }
85
+ function fillRatio(isQualified, thresholdAmount, covered) {
86
+ if (isQualified) return 1;
87
+ if (thresholdAmount === null) return 0;
88
+ return clamp01(covered / thresholdAmount);
89
+ }
90
+ function computeProgress(fsp, items, thresholdAmount) {
91
+ if (items === null) {
92
+ const isQualified = fsp.qualified;
93
+ const liveRemaining = !isQualified && isFiniteAmount(fsp.remaining.amount) ? Math.max(Number(fsp.remaining.amount), 0) : 0;
94
+ return {
95
+ isQualified,
96
+ fill: fillRatio(isQualified, thresholdAmount, (thresholdAmount ?? 0) - liveRemaining),
97
+ liveRemaining
98
+ };
99
+ }
100
+ const isQualified = fsp.qualified || thresholdAmount !== null && items >= thresholdAmount;
101
+ const liveRemaining = isQualified || thresholdAmount === null ? 0 : Math.max(thresholdAmount - items, 0);
102
+ return {
103
+ isQualified,
104
+ fill: fillRatio(isQualified, thresholdAmount, items),
105
+ liveRemaining
106
+ };
107
+ }
48
108
  const FreeShippingProgressRootDefinition = defineComponent({
49
109
  name: "FreeShippingProgressRoot",
50
110
  importPath: "@vtex/faststore/components",
@@ -91,40 +151,23 @@ const FreeShippingProgressMessageDefinition = defineComponent({
91
151
  },
92
152
  guideline: "Below-threshold vs earned copy, front-formatted from the active storefront context. Must be inside FreeShippingProgressRoot. See free-shipping-progress.md."
93
153
  });
94
- function FreeShippingProgressRoot({ threshold, remaining, qualified, cartTotal, $data: $dataProp, className, children, ...props }) {
154
+ function FreeShippingProgressRoot({ threshold, remaining, qualified, itemsTotal, $data: $dataProp, className, children, ...props }) {
95
155
  const { currency } = useStorefrontContext();
96
- const cart = useDataOverride($dataProp) ?? (qualified !== void 0 || threshold !== void 0 || remaining !== void 0 || cartTotal !== void 0 ? {
97
- id: "preview",
98
- total: {
99
- amount: cartTotal ?? 0,
100
- currencyCode: currency
101
- },
102
- freeShippingProgress: {
103
- threshold: threshold != null ? {
104
- amount: threshold,
105
- currencyCode: currency
106
- } : null,
107
- remaining: {
108
- amount: remaining ?? 0,
109
- currencyCode: currency
110
- },
111
- qualified: qualified ?? false
112
- }
113
- } : null);
156
+ const cart = useDataOverride($dataProp) ?? previewCart({
157
+ threshold,
158
+ remaining,
159
+ qualified,
160
+ itemsTotal
161
+ }, currency);
114
162
  const fsp = cart?.freeShippingProgress;
115
163
  if (!cart || fsp == null) return null;
116
- const parsedThreshold = fsp.threshold != null ? Number(fsp.threshold.amount) : null;
117
- const cartTotalAmount = Number(cart.total?.amount ?? 0);
118
- const thresholdAmount = parsedThreshold != null && Number.isFinite(parsedThreshold) && parsedThreshold > 0 ? parsedThreshold : null;
119
- const isQualified = fsp.qualified || thresholdAmount != null && cartTotalAmount >= thresholdAmount;
120
- const liveRemaining = isQualified || thresholdAmount == null ? 0 : Math.max(thresholdAmount - cartTotalAmount, 0);
121
- const value = {
122
- isQualified,
123
- fill: isQualified ? 1 : thresholdAmount != null ? clamp01(cartTotalAmount / thresholdAmount) : 0,
124
- liveRemaining
125
- };
164
+ const { isQualified, fill, liveRemaining } = computeProgress(fsp, itemsSubtotal(cart), usableThreshold(fsp.threshold));
126
165
  return /* @__PURE__ */ jsx(FreeShippingProgressContext, {
127
- value,
166
+ value: {
167
+ isQualified,
168
+ fill,
169
+ liveRemaining
170
+ },
128
171
  children: /* @__PURE__ */ jsx("div", {
129
172
  ...props,
130
173
  className,
@@ -1 +1 @@
1
- {"version":3,"file":"free-shipping-progress.js","names":[],"sources":["../../../src/matter/free-shipping-progress/free-shipping-progress.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport { type ComponentPropsWithRef, createContext, useContext } from 'react';\nimport { Meter } from '../../particles/meter/meter.js';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype MoneyValue = { amount: number | string; currencyCode: string };\n\ntype FreeShippingProgressData = {\n cart?: {\n id: string;\n total?: MoneyValue | null;\n freeShippingProgress?: {\n threshold: MoneyValue | null;\n remaining: MoneyValue;\n qualified: boolean;\n } | null;\n } | null;\n};\n\ntype FreeShippingProgressContextValue = {\n isQualified: boolean;\n fill: number;\n liveRemaining: number;\n};\n\nexport type FreeShippingProgressRootProps = ComponentPropsWithRef<'div'> & {\n threshold?: number;\n remaining?: number;\n qualified?: boolean;\n cartTotal?: number;\n $data?: FreeShippingProgressData['cart'] | null;\n};\n\nexport type FreeShippingProgressBarProps = ComponentPropsWithRef<'div'>;\nexport type FreeShippingProgressMessageProps = ComponentPropsWithRef<'div'> & {\n label?: string;\n qualifiedLabel?: string;\n};\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — narrow cart slice (total + freeShippingProgress)\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment FreeShippingProgressData on Query {\n cart {\n id\n total {\n amount\n currencyCode\n }\n freeShippingProgress {\n threshold {\n amount\n currencyCode\n }\n remaining {\n amount\n currencyCode\n }\n qualified\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst FSP_CONTEXT_UNSET = Symbol('FreeShippingProgressContextUnset');\n\nconst FreeShippingProgressContext = createContext<FreeShippingProgressContextValue | typeof FSP_CONTEXT_UNSET>(\n FSP_CONTEXT_UNSET,\n);\n\nfunction useFreeShippingProgress(): FreeShippingProgressContextValue {\n const ctx = useContext(FreeShippingProgressContext);\n if (ctx === FSP_CONTEXT_UNSET) {\n throw new Error('useFreeShippingProgress() must be used inside a <FreeShippingProgressRoot> subtree.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatCurrency(value: number, locale: string, currency: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);\n}\n\nfunction clamp01(value: number): number {\n return Math.min(Math.max(value, 0), 1);\n}\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const FreeShippingProgressRootDefinition = defineComponent<FreeShippingProgressRootProps>({\n name: 'FreeShippingProgressRoot',\n importPath: '@vtex/faststore/components',\n component: FreeShippingProgressRoot,\n fragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Free Shipping Progress', category: 'commerce' },\n schema: {},\n guideline:\n 'Free-shipping progress bar for the top of a cart/mini-cart drawer: shows how much more to spend for free shipping and flips to an earned state when met. Renders nothing until a destination and an eligible promotion exist (self-hides on null). See free-shipping-progress.md.',\n});\n\nexport const FreeShippingProgressBarDefinition = defineComponent<FreeShippingProgressBarProps>({\n name: 'FreeShippingProgressBar',\n importPath: '@vtex/faststore/components',\n component: FreeShippingProgressBar,\n editor: { label: 'Free Shipping Progress Bar', category: 'commerce' },\n schema: {},\n guideline:\n 'Meter bar that fills toward the free-shipping goal, full when earned. Must be inside FreeShippingProgressRoot. See free-shipping-progress.md.',\n});\n\nexport const FreeShippingProgressMessageDefinition = defineComponent<FreeShippingProgressMessageProps>({\n name: 'FreeShippingProgressMessage',\n importPath: '@vtex/faststore/components',\n component: FreeShippingProgressMessage,\n editor: { label: 'Free Shipping Progress Message', category: 'commerce' },\n schema: {\n label: { type: 'string', default: 'faltam {value} para frete grátis', label: 'Below-threshold Label' },\n qualifiedLabel: { type: 'string', default: 'você ganhou frete grátis!', label: 'Qualified Label' },\n },\n guideline:\n 'Below-threshold vs earned copy, front-formatted from the active storefront context. Must be inside FreeShippingProgressRoot. See free-shipping-progress.md.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function FreeShippingProgressRoot({\n threshold,\n remaining,\n qualified,\n cartTotal,\n $data: $dataProp,\n className,\n children,\n ...props\n}: FreeShippingProgressRootProps) {\n // Only the synthesized preview cart below needs it; the leaves read the context where they format.\n const { currency } = useStorefrontContext();\n const $data = useDataOverride($dataProp);\n\n // Story / presentational overrides synthesize the field when no live cart is present.\n const cart =\n $data ??\n (qualified !== undefined || threshold !== undefined || remaining !== undefined || cartTotal !== undefined\n ? {\n id: 'preview',\n total: { amount: cartTotal ?? 0, currencyCode: currency },\n freeShippingProgress: {\n threshold: threshold != null ? { amount: threshold, currencyCode: currency } : null,\n remaining: { amount: remaining ?? 0, currencyCode: currency },\n qualified: qualified ?? false,\n },\n }\n : null);\n\n const fsp = cart?.freeShippingProgress;\n if (!cart || fsp == null) return null;\n\n const parsedThreshold = fsp.threshold != null ? Number(fsp.threshold.amount) : null;\n const cartTotalAmount = Number(cart.total?.amount ?? 0);\n // Usable threshold: present, finite, positive. Null/NaN/zero → no fill, no remaining.\n const thresholdAmount =\n parsedThreshold != null && Number.isFinite(parsedThreshold) && parsedThreshold > 0 ? parsedThreshold : null;\n\n const isQualified = fsp.qualified || (thresholdAmount != null && cartTotalAmount >= thresholdAmount);\n const liveRemaining = isQualified || thresholdAmount == null ? 0 : Math.max(thresholdAmount - cartTotalAmount, 0);\n const fill = isQualified ? 1 : thresholdAmount != null ? clamp01(cartTotalAmount / thresholdAmount) : 0;\n\n const value: FreeShippingProgressContextValue = { isQualified, fill, liveRemaining };\n\n return (\n <FreeShippingProgressContext value={value}>\n <div {...props} className={className} data-fs-free-shipping-progress-root=\"\">\n {children}\n </div>\n </FreeShippingProgressContext>\n );\n}\n\nexport function FreeShippingProgressBar({ className, ...props }: FreeShippingProgressBarProps) {\n const { fill, isQualified, liveRemaining } = useFreeShippingProgress();\n const { locale, currency } = useStorefrontContext();\n const ariaValueText = isQualified\n ? 'frete grátis conquistado'\n : `${formatCurrency(liveRemaining, locale, currency)} restantes para frete grátis`;\n\n return (\n <Meter.Root\n {...props}\n value={Math.round(fill * 100)}\n min={0}\n max={100}\n getAriaValueText={() => ariaValueText}\n className={className}\n data-fs-free-shipping-progress-bar=\"\"\n >\n <Meter.Track>\n <Meter.Indicator />\n </Meter.Track>\n </Meter.Root>\n );\n}\n\nexport function FreeShippingProgressMessage({\n label = 'faltam {value} para frete grátis',\n qualifiedLabel = 'você ganhou frete grátis!',\n className,\n children,\n ...props\n}: FreeShippingProgressMessageProps) {\n const { isQualified, liveRemaining } = useFreeShippingProgress();\n const { locale, currency } = useStorefrontContext();\n const text = isQualified ? qualifiedLabel : label.replace('{value}', formatCurrency(liveRemaining, locale, currency));\n\n return (\n <div {...props} className={className} data-fs-free-shipping-progress-message=\"\">\n {children ?? text}\n </div>\n );\n}\n\nexport const FreeShippingProgress = {\n Root: FreeShippingProgressRoot,\n Bar: FreeShippingProgressBar,\n Message: FreeShippingProgressMessage,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"free-shipping-progress.js","names":[],"sources":["../../../src/matter/free-shipping-progress/free-shipping-progress.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport { type ComponentPropsWithRef, createContext, useContext } from 'react';\nimport { Meter } from '../../particles/meter/meter.js';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { isFiniteAmount } from '../cart/cart.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype MoneyValue = { amount: number | string; currencyCode: string };\n\ntype FreeShippingProgressData = {\n cart?: {\n id: string;\n totalizers?: { id: string; value: MoneyValue }[] | null;\n freeShippingProgress?: {\n threshold: MoneyValue | null;\n remaining: MoneyValue;\n qualified: boolean;\n } | null;\n } | null;\n};\n\ntype FreeShippingProgressContextValue = {\n isQualified: boolean;\n fill: number;\n liveRemaining: number;\n};\n\nexport type FreeShippingProgressRootProps = ComponentPropsWithRef<'div'> & {\n threshold?: number;\n remaining?: number;\n qualified?: boolean;\n itemsTotal?: number;\n $data?: FreeShippingProgressData['cart'] | null;\n};\n\nexport type FreeShippingProgressBarProps = ComponentPropsWithRef<'div'>;\nexport type FreeShippingProgressMessageProps = ComponentPropsWithRef<'div'> & {\n label?: string;\n qualifiedLabel?: string;\n};\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — narrow cart slice (Items totalizer + freeShippingProgress)\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment FreeShippingProgressData on Query {\n cart {\n id\n totalizers {\n id\n value {\n amount\n currencyCode\n }\n }\n freeShippingProgress {\n threshold {\n amount\n currencyCode\n }\n remaining {\n amount\n currencyCode\n }\n qualified\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst FSP_CONTEXT_UNSET = Symbol('FreeShippingProgressContextUnset');\n\nconst FreeShippingProgressContext = createContext<FreeShippingProgressContextValue | typeof FSP_CONTEXT_UNSET>(\n FSP_CONTEXT_UNSET,\n);\n\nfunction useFreeShippingProgress(): FreeShippingProgressContextValue {\n const ctx = useContext(FreeShippingProgressContext);\n if (ctx === FSP_CONTEXT_UNSET) {\n throw new Error('useFreeShippingProgress() must be used inside a <FreeShippingProgressRoot> subtree.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatCurrency(value: number, locale: string, currency: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);\n}\n\nfunction clamp01(value: number): number {\n return Math.min(Math.max(value, 0), 1);\n}\n\ntype FreeShippingProgressCart = NonNullable<FreeShippingProgressData['cart']>;\ntype FreeShippingProgressState = NonNullable<FreeShippingProgressCart['freeShippingProgress']>;\n\nfunction previewCart(\n {\n threshold,\n remaining,\n qualified,\n itemsTotal,\n }: Pick<FreeShippingProgressRootProps, 'threshold' | 'remaining' | 'qualified' | 'itemsTotal'>,\n currency: string,\n): FreeShippingProgressCart | null {\n if (qualified === undefined && threshold === undefined && remaining === undefined && itemsTotal === undefined) {\n return null;\n }\n return {\n id: 'preview',\n totalizers:\n itemsTotal === undefined ? [] : [{ id: 'Items', value: { amount: itemsTotal, currencyCode: currency } }],\n freeShippingProgress: {\n threshold: threshold == null ? null : { amount: threshold, currencyCode: currency },\n remaining: { amount: remaining ?? threshold ?? 0, currencyCode: currency },\n qualified: qualified ?? false,\n },\n };\n}\n\n// The server measures the Items totalizer, never the grand total (shipping and discounts do not count).\nfunction itemsSubtotal(cart: FreeShippingProgressCart): number | null {\n const itemsAmount = cart.totalizers?.find((totalizer) => totalizer.id === 'Items')?.value.amount;\n return isFiniteAmount(itemsAmount) ? Number(itemsAmount) : null;\n}\n\n// Usable threshold: present, finite, positive. Null/NaN/zero → no fill, no remaining.\nfunction usableThreshold(threshold: MoneyValue | null): number | null {\n if (threshold == null) return null;\n const parsed = Number(threshold.amount);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\n\nfunction fillRatio(isQualified: boolean, thresholdAmount: number | null, covered: number): number {\n if (isQualified) return 1;\n if (thresholdAmount === null) return 0;\n return clamp01(covered / thresholdAmount);\n}\n\nfunction computeProgress(\n fsp: FreeShippingProgressState,\n items: number | null,\n thresholdAmount: number | null,\n): FreeShippingProgressContextValue {\n if (items === null) {\n // No usable Items amount: show the server's own answer rather than guess.\n const isQualified = fsp.qualified;\n const liveRemaining =\n !isQualified && isFiniteAmount(fsp.remaining.amount) ? Math.max(Number(fsp.remaining.amount), 0) : 0;\n const fill = fillRatio(isQualified, thresholdAmount, (thresholdAmount ?? 0) - liveRemaining);\n return { isQualified, fill, liveRemaining };\n }\n\n const isQualified = fsp.qualified || (thresholdAmount !== null && items >= thresholdAmount);\n const liveRemaining = isQualified || thresholdAmount === null ? 0 : Math.max(thresholdAmount - items, 0);\n return { isQualified, fill: fillRatio(isQualified, thresholdAmount, items), liveRemaining };\n}\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const FreeShippingProgressRootDefinition = defineComponent<FreeShippingProgressRootProps>({\n name: 'FreeShippingProgressRoot',\n importPath: '@vtex/faststore/components',\n component: FreeShippingProgressRoot,\n fragment,\n fetchStrategy: 'reactive',\n editor: { label: 'Free Shipping Progress', category: 'commerce' },\n schema: {},\n guideline:\n 'Free-shipping progress bar for the top of a cart/mini-cart drawer: shows how much more to spend for free shipping and flips to an earned state when met. Renders nothing until a destination and an eligible promotion exist (self-hides on null). See free-shipping-progress.md.',\n});\n\nexport const FreeShippingProgressBarDefinition = defineComponent<FreeShippingProgressBarProps>({\n name: 'FreeShippingProgressBar',\n importPath: '@vtex/faststore/components',\n component: FreeShippingProgressBar,\n editor: { label: 'Free Shipping Progress Bar', category: 'commerce' },\n schema: {},\n guideline:\n 'Meter bar that fills toward the free-shipping goal, full when earned. Must be inside FreeShippingProgressRoot. See free-shipping-progress.md.',\n});\n\nexport const FreeShippingProgressMessageDefinition = defineComponent<FreeShippingProgressMessageProps>({\n name: 'FreeShippingProgressMessage',\n importPath: '@vtex/faststore/components',\n component: FreeShippingProgressMessage,\n editor: { label: 'Free Shipping Progress Message', category: 'commerce' },\n schema: {\n label: { type: 'string', default: 'faltam {value} para frete grátis', label: 'Below-threshold Label' },\n qualifiedLabel: { type: 'string', default: 'você ganhou frete grátis!', label: 'Qualified Label' },\n },\n guideline:\n 'Below-threshold vs earned copy, front-formatted from the active storefront context. Must be inside FreeShippingProgressRoot. See free-shipping-progress.md.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function FreeShippingProgressRoot({\n threshold,\n remaining,\n qualified,\n itemsTotal,\n $data: $dataProp,\n className,\n children,\n ...props\n}: FreeShippingProgressRootProps) {\n // Only the synthesized preview cart below needs it; the leaves read the context where they format.\n const { currency } = useStorefrontContext();\n const $data = useDataOverride($dataProp);\n\n // Story / presentational overrides synthesize the field when no live cart is present.\n const cart = $data ?? previewCart({ threshold, remaining, qualified, itemsTotal }, currency);\n\n const fsp = cart?.freeShippingProgress;\n if (!cart || fsp == null) return null;\n\n const { isQualified, fill, liveRemaining } = computeProgress(\n fsp,\n itemsSubtotal(cart),\n usableThreshold(fsp.threshold),\n );\n\n const value: FreeShippingProgressContextValue = { isQualified, fill, liveRemaining };\n\n return (\n <FreeShippingProgressContext value={value}>\n <div {...props} className={className} data-fs-free-shipping-progress-root=\"\">\n {children}\n </div>\n </FreeShippingProgressContext>\n );\n}\n\nexport function FreeShippingProgressBar({ className, ...props }: FreeShippingProgressBarProps) {\n const { fill, isQualified, liveRemaining } = useFreeShippingProgress();\n const { locale, currency } = useStorefrontContext();\n const ariaValueText = isQualified\n ? 'frete grátis conquistado'\n : `${formatCurrency(liveRemaining, locale, currency)} restantes para frete grátis`;\n\n return (\n <Meter.Root\n {...props}\n value={Math.round(fill * 100)}\n min={0}\n max={100}\n getAriaValueText={() => ariaValueText}\n className={className}\n data-fs-free-shipping-progress-bar=\"\"\n >\n <Meter.Track>\n <Meter.Indicator />\n </Meter.Track>\n </Meter.Root>\n );\n}\n\nexport function FreeShippingProgressMessage({\n label = 'faltam {value} para frete grátis',\n qualifiedLabel = 'você ganhou frete grátis!',\n className,\n children,\n ...props\n}: FreeShippingProgressMessageProps) {\n const { isQualified, liveRemaining } = useFreeShippingProgress();\n const { locale, currency } = useStorefrontContext();\n const text = isQualified ? qualifiedLabel : label.replace('{value}', formatCurrency(liveRemaining, locale, currency));\n\n return (\n <div {...props} className={className} data-fs-free-shipping-progress-message=\"\">\n {children ?? text}\n </div>\n );\n}\n\nexport const FreeShippingProgress = {\n Root: FreeShippingProgressRoot,\n Bar: FreeShippingProgressBar,\n Message: FreeShippingProgressMessage,\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.js","names":[],"sources":["../../../src/matter/pricing/pricing.tsx"],"sourcesContent":["'use client';\n\nimport { useReactiveVar } from '@apollo/client/react';\nimport { defineComponent } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { createContext, Suspense, useContext } from 'react';\nimport { PopoverTrigger } from '../../particles/popover/popover.js';\nimport { TabsPanel, TabsTab } from '../../particles/tabs/tabs.js';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { HotDataProvider } from '../../sdk/data/hot-data-provider.js';\nimport { graphql } from '../../sdk/generated/gql.js';\nimport type { VariantPricingDataFragment } from '../../sdk/generated/graphql.js';\nimport { resolveDefaultSeller } from '../../sdk/seller.js';\nimport { publishedVariantIdFor, selectedVariantVar } from '../../sdk/state/variant-selector.js';\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment PricingData on Query {\n productBySlug(slug: $slug) {\n __typename\n id\n variants(first: 1) {\n edges {\n node {\n sellers {\n isDefault\n offer {\n price { amount currencyCode }\n listPrice { amount currencyCode }\n spotPrice { amount currencyCode }\n installmentPlans {\n paymentMethod\n paymentType\n installments {\n count\n value { amount currencyCode }\n totalAmount { amount currencyCode }\n interestRate\n interestFree\n }\n }\n discountHighlights\n promotions {\n name\n }\n }\n }\n }\n }\n }\n }\n }\n`;\n\n// The variant offer slice, authored via graphql() so HotDataProvider gets a TypedDocumentNode.\n// Declared so codegen scans the source and emits VariantPricingDataFragment; the fragment is spread\n// into variantQuery at the GraphQL layer, so the variable is unused at runtime.\nconst _variantFragment = graphql(`\n fragment VariantPricingData on Variant {\n __typename\n id\n sellers {\n isDefault\n offer {\n price { amount currencyCode }\n listPrice { amount currencyCode }\n spotPrice { amount currencyCode }\n installmentPlans {\n paymentMethod\n paymentType\n installments {\n count\n value { amount currencyCode }\n totalAmount { amount currencyCode }\n interestRate\n interestFree\n }\n }\n discountHighlights\n promotions {\n name\n }\n }\n }\n }\n`);\n\nconst variantQuery = graphql(`\n query VariantPricingQuery($id: ID!) {\n node(id: $id) {\n __typename\n ... on Variant {\n ...VariantPricingData\n }\n }\n }\n`);\n\n// ---------------------------------------------------------------------------\n// Raw data types (shape of the fragment result)\n// ---------------------------------------------------------------------------\n\ntype MoneyValue = {\n amount: number;\n currencyCode: string;\n};\n\ntype RawPromotion = {\n name: string;\n};\n\ntype RawOffer = {\n price: MoneyValue;\n listPrice: MoneyValue;\n spotPrice: MoneyValue;\n installmentPlans: Array<{\n paymentMethod: string;\n paymentType: string;\n installments: Array<{\n count: number;\n value: MoneyValue;\n totalAmount: MoneyValue;\n interestRate: number;\n interestFree: boolean;\n }>;\n }>;\n discountHighlights: string[];\n promotions: RawPromotion[];\n};\n\ntype RawPricingData = {\n // __typename/id are optional so existing fixtures (which omit them) still typecheck; the real\n // page query always supplies id, which scopes the published variant selection to this product.\n __typename?: string;\n id?: string;\n variants: {\n edges: Array<{\n node: {\n sellers: Array<{\n isDefault: boolean;\n offer: RawOffer | null;\n }>;\n };\n }>;\n };\n};\n\ntype VariantSlice = VariantPricingDataFragment;\n\ntype NormalizedPricingOffer = {\n price: number;\n listPrice: number;\n spotPrice: number;\n currency: string;\n installmentPlans: InstallmentPlanData[];\n discountHighlights: string[];\n promotions: PromotionData[];\n};\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype InstallmentData = {\n count: number;\n value: number;\n totalAmount: number;\n interestRate: number;\n interestFree: boolean;\n};\n\ntype InstallmentPlanData = {\n paymentMethod: string;\n paymentType: string;\n installments: InstallmentData[];\n};\n\ntype PromotionData = {\n name: string;\n};\n\ntype PricingContextData = {\n price: number;\n listPrice: number;\n spotPrice: number;\n currency: string;\n /** Undefined only for a directly-rendered view: `Intl` reads it as the platform default. */\n locale: string | undefined;\n installmentPlans: InstallmentPlanData[];\n discountHighlights: string[];\n promotions: PromotionData[];\n hasDiscount: boolean;\n hasSpotDiscount: boolean;\n discountPercentage: number;\n spotDiscountPercentage: number;\n bestInstallment: InstallmentData | null;\n};\n\ntype PricingContextValue = PricingContextData | null;\n\ntype InstallmentPlanItemContextData = {\n paymentMethod: string;\n paymentType: string;\n installments: InstallmentData[];\n bestInstallment: InstallmentData | null;\n};\n\nconst PRICING_CONTEXT_UNSET = Symbol('PricingContextUnset');\n\nexport type PricingRootProps = ComponentPropsWithRef<'div'> & {\n $data?: RawPricingData | null;\n /** Page-supplied viewed SKU; pre-selects the offer on first paint. A published swatch selection\n * wins over it once the shopper interacts. */\n selectedVariantId?: string;\n};\n\nexport type PricingSellingPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingListPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingSpotPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingInstallmentsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingInstallmentPlansProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingInstallmentPlanProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingInstallmentsForPlanProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodsTriggerProps = ComponentPropsWithRef<'button'>;\n\nexport type PricingPaymentMethodsListProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodsTabListProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodsTabPanelsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodNameProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingInstallmentProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n interestFreeLabel?: string;\n};\n\nexport type PricingDiscountProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n format?: 'percentage' | 'absolute';\n};\n\nexport type PricingHighlightsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingHighlightProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingPromotionsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPromotionProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n};\n\nexport type PricingSpotDiscountProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n};\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst PricingContext = createContext<PricingContextValue | typeof PRICING_CONTEXT_UNSET>(PRICING_CONTEXT_UNSET);\n\nconst InstallmentItemContext = createContext<InstallmentData | null>(null);\n\nconst InstallmentPlanItemContext = createContext<InstallmentPlanItemContextData | null>(null);\n\nconst HighlightItemContext = createContext<string | null>(null);\n\nconst PromotionItemContext = createContext<PromotionData | null>(null);\n\nfunction usePricing(): PricingContextValue {\n const ctx = useContext(PricingContext);\n if (ctx === PRICING_CONTEXT_UNSET) {\n throw new Error('Pricing components must be used inside PricingRoot.');\n }\n return ctx;\n}\n\nfunction useInstallmentItem(): InstallmentData {\n const ctx = useContext(InstallmentItemContext);\n if (!ctx) {\n throw new Error('PricingInstallment must be used inside PricingInstallments.');\n }\n return ctx;\n}\n\nexport function useInstallmentPlanItem(\n caller = 'PricingInstallmentPlan',\n parent = 'PricingInstallmentPlans',\n): InstallmentPlanItemContextData {\n const ctx = useContext(InstallmentPlanItemContext);\n if (!ctx) {\n throw new Error(`${caller} must be used inside ${parent}.`);\n }\n return ctx;\n}\n\nfunction useHighlightItem(): string {\n const ctx = useContext(HighlightItemContext);\n if (ctx === null) {\n throw new Error('PricingHighlight must be used inside PricingHighlights.');\n }\n return ctx;\n}\n\nfunction usePromotionItem(): PromotionData {\n const ctx = useContext(PromotionItemContext);\n if (!ctx) {\n throw new Error('PricingPromotion must be used inside PricingPromotions.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(value: number, locale: string | undefined, currency: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);\n}\n\nfunction findBestInstallment(plans: InstallmentPlanData[]): InstallmentData | null {\n const allInstallments = plans.flatMap((plan) => plan.installments);\n if (allInstallments.length === 0) return null;\n\n const interestFree = allInstallments.filter((i) => i.interestFree);\n if (interestFree.length > 0) {\n return interestFree.reduce((best, current) => (current.count > best.count ? current : best));\n }\n\n return allInstallments.reduce((best, current) => (current.count > best.count ? current : best));\n}\n\n// ---------------------------------------------------------------------------\n// Transform\n// ---------------------------------------------------------------------------\n\n// The GraphQL `Decimal` scalar is serialized as a string over the wire; convert it here so every\n// later comparison and subtraction works on numbers.\nfunction normalizeOffer(offer: RawOffer): NormalizedPricingOffer {\n return {\n price: Number(offer.price.amount),\n listPrice: Number(offer.listPrice.amount),\n spotPrice: Number(offer.spotPrice.amount),\n currency: offer.price.currencyCode,\n installmentPlans: offer.installmentPlans.map((plan) => ({\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments.map((inst) => ({\n count: inst.count,\n value: Number(inst.value.amount),\n totalAmount: Number(inst.totalAmount.amount),\n interestRate: inst.interestRate,\n interestFree: inst.interestFree,\n })),\n })),\n discountHighlights: offer.discountHighlights,\n promotions: offer.promotions.map((promotion) => ({ name: promotion.name })),\n };\n}\n\n// Resolves a variant's default seller and normalizes its offer, or null when that seller has no\n// offer. Shared by the product-level and selected-variant transforms so the default-seller + offer\n// gate lives in one place.\nfunction pricingOfferFromVariant(variant: {\n sellers: readonly { isDefault: boolean; offer: RawOffer | null }[];\n}): NormalizedPricingOffer | null {\n const seller = resolveDefaultSeller(variant.sellers);\n const offer = seller?.offer;\n if (!offer) return null;\n\n return normalizeOffer(offer);\n}\n\nfunction transformPricingData(data: RawPricingData): NormalizedPricingOffer | null {\n const edge = data.variants.edges[0];\n if (!edge) return null;\n\n return pricingOfferFromVariant(edge.node);\n}\n\nexport function transformVariantPricingData(variant: VariantSlice): NormalizedPricingOffer | null {\n return pricingOfferFromVariant(variant);\n}\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const PricingRootDefinition = defineComponent<PricingRootProps>({\n name: 'PricingRoot',\n importPath: '@vtex/faststore/components',\n component: PricingRoot,\n fragment,\n fetchStrategy: 'lazy',\n skeleton: PricingSkeleton,\n editor: { label: 'Pricing', category: 'commerce' },\n schema: {\n selectedVariantId: { type: 'string', label: 'Selected Variant ID' },\n },\n guideline:\n 'Root container for the PDP pricing block; all other Pricing sub-components must be descendants of it. Automatically recomputes the offer when a shopper picks a VariantSelector swatch (it reads the published variant selection); the selectedVariantId prop is an optional pre-selection fallback. Falls back silently to the product-level offer on variant fetch error. See pricing.md.',\n});\n\nexport const PricingSellingPriceDefinition = defineComponent<PricingSellingPriceProps>({\n name: 'PricingSellingPrice',\n importPath: '@vtex/faststore/components',\n component: PricingSellingPrice,\n editor: { label: 'Selling Price', category: 'commerce' },\n schema: {},\n guideline: 'Displays the current selling price; must be a descendant of PricingRoot.',\n});\n\nexport const PricingListPriceDefinition = defineComponent<PricingListPriceProps>({\n name: 'PricingListPrice',\n importPath: '@vtex/faststore/components',\n component: PricingListPrice,\n editor: { label: 'List Price', category: 'commerce' },\n schema: {},\n guideline:\n 'Displays the original (strikethrough) list price; only renders when a discount exists. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingSpotPriceDefinition = defineComponent<PricingSpotPriceProps>({\n name: 'PricingSpotPrice',\n importPath: '@vtex/faststore/components',\n component: PricingSpotPrice,\n editor: { label: 'Spot Price', category: 'commerce' },\n schema: {},\n guideline:\n 'Displays the best cash/instant-payment price (e.g. Pix); only renders when spotPrice is lower than the selling price. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingInstallmentsDefinition = defineComponent<PricingInstallmentsProps>({\n name: 'PricingInstallments',\n importPath: '@vtex/faststore/components',\n component: PricingInstallments,\n editor: { label: 'Installments', category: 'commerce' },\n schema: {},\n guideline:\n 'Shortcut container that exposes the single best installment across all plans; use PricingInstallmentPlans instead when a per-payment-method breakdown is needed. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingInstallmentPlansDefinition = defineComponent<PricingInstallmentPlansProps>({\n name: 'PricingInstallmentPlans',\n importPath: '@vtex/faststore/components',\n component: PricingInstallmentPlans,\n editor: { label: 'Installment Plans', category: 'commerce' },\n schema: {},\n guideline:\n 'Renders one row per payment method; use PricingInstallments instead when only the single best plan is needed. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingInstallmentPlanDefinition = defineComponent<PricingInstallmentPlanProps>({\n name: 'PricingInstallmentPlan',\n importPath: '@vtex/faststore/components',\n component: PricingInstallmentPlan,\n editor: { label: 'Installment Plan', category: 'commerce' },\n schema: {},\n guideline:\n 'Renders a single plan row inside PricingInstallmentPlans; nest PricingInstallmentsForPlan inside it to list every installment tier instead of just the best one. Must be a descendant of PricingInstallmentPlans.',\n});\n\nexport const PricingInstallmentsForPlanDefinition = defineComponent<PricingInstallmentsForPlanProps>({\n name: 'PricingInstallmentsForPlan',\n importPath: '@vtex/faststore/components',\n component: PricingInstallmentsForPlan,\n editor: { label: 'Installments For Plan', category: 'commerce' },\n schema: {},\n guideline:\n 'Iterates every installment tier (1x, 2x, … Nx) of the enclosing plan; must be a descendant of PricingInstallmentPlan.',\n});\n\nexport const PricingPaymentMethodsTriggerDefinition = defineComponent<PricingPaymentMethodsTriggerProps>({\n name: 'PricingPaymentMethodsTrigger',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsTrigger,\n editor: { label: 'Payment Methods Trigger', category: 'action' },\n schema: {},\n guideline: 'Button that opens the payment-methods disclosure panel; must be a descendant of PopoverRoot.',\n});\n\nexport const PricingPaymentMethodsListDefinition = defineComponent<PricingPaymentMethodsListProps>({\n name: 'PricingPaymentMethodsList',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsList,\n editor: { label: 'Payment Methods List', category: 'commerce' },\n schema: {},\n guideline:\n 'Flat disclosure panel content listing every payment plan; place inside PopoverPopup, DialogPopup, or DrawerPopup. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingPaymentMethodsTabListDefinition = defineComponent<PricingPaymentMethodsTabListProps>({\n name: 'PricingPaymentMethodsTabList',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsTabList,\n editor: { label: 'Payment Methods Tab List', category: 'commerce' },\n schema: {},\n guideline:\n 'Emits one tab per payment plan for the tab-grouped disclosure pattern; must be a descendant of TabsList (which is inside TabsRoot). Pair with PricingPaymentMethodsTabPanels.',\n});\n\nexport const PricingPaymentMethodsTabPanelsDefinition = defineComponent<PricingPaymentMethodsTabPanelsProps>({\n name: 'PricingPaymentMethodsTabPanels',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsTabPanels,\n editor: { label: 'Payment Methods Tab Panels', category: 'commerce' },\n schema: {},\n guideline:\n 'Emits one panel per payment plan for the tab-grouped disclosure pattern; must be a sibling of TabsList under TabsRoot (not nested inside TabsList). Pair with PricingPaymentMethodsTabList.',\n});\n\nexport const PricingPaymentMethodNameDefinition = defineComponent<PricingPaymentMethodNameProps>({\n name: 'PricingPaymentMethodName',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodName,\n editor: { label: 'Payment Method Name', category: 'commerce' },\n schema: {},\n guideline:\n 'Renders the enclosing plan\\'s payment method name (e.g. \"Visa\", \"Pix\"); must be inside a plan context — PricingInstallmentPlan, PricingPaymentMethodsTabList, or PricingPaymentMethodsTabPanels.',\n});\n\nexport const PricingInstallmentDefinition = defineComponent<PricingInstallmentProps>({\n name: 'PricingInstallment',\n importPath: '@vtex/faststore/components',\n component: PricingInstallment,\n editor: { label: 'Installment', category: 'commerce' },\n schema: {\n template: { type: 'string', default: '{count}x de {value}', label: 'Template' },\n interestFreeLabel: { type: 'string', default: 'sem juros', label: 'Interest-free label' },\n },\n guideline:\n 'Renders a single installment line using {count} and {value} template placeholders; must be a descendant of PricingInstallments, PricingInstallmentPlan, or PricingInstallmentsForPlan.',\n});\n\nexport const PricingDiscountDefinition = defineComponent<PricingDiscountProps>({\n name: 'PricingDiscount',\n importPath: '@vtex/faststore/components',\n component: PricingDiscount,\n editor: { label: 'Discount Badge', category: 'commerce' },\n schema: {\n format: { type: ['percentage', 'absolute'] as const, default: 'percentage', label: 'Discount Format' },\n template: { type: 'string', label: 'Template' },\n },\n guideline:\n 'Discount badge for the listPrice-vs-price markdown; use PricingSpotDiscount instead for the spotPrice-vs-price (Pix/cash) percentage. The format prop switches between a percentage (-25%, default) and an absolute amount (-R$ 10,00); the template supports {percentage} and {amount} placeholders and defaults to the format-appropriate one. Recomputes automatically on swatch change. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingSpotDiscountDefinition = defineComponent<PricingSpotDiscountProps>({\n name: 'PricingSpotDiscount',\n importPath: '@vtex/faststore/components',\n component: PricingSpotDiscount,\n editor: { label: 'Spot Discount Badge', category: 'commerce' },\n schema: {\n template: { type: 'string', default: '-{percentage}%', label: 'Template' },\n },\n guideline:\n 'Discount badge for the spotPrice-vs-price (cash/Pix) percentage; use PricingDiscount instead for the listPrice-vs-price percentage. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingHighlightsDefinition = defineComponent<PricingHighlightsProps>({\n name: 'PricingHighlights',\n importPath: '@vtex/faststore/components',\n component: PricingHighlights,\n editor: { label: 'Highlights', category: 'commerce' },\n schema: {},\n guideline:\n 'Iterates the offer\\'s discount highlight labels (e.g. \"Black Friday\", \"Exclusivo\"); place PricingHighlight as a child. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingHighlightDefinition = defineComponent<PricingHighlightProps>({\n name: 'PricingHighlight',\n importPath: '@vtex/faststore/components',\n component: PricingHighlight,\n editor: { label: 'Highlight', category: 'commerce' },\n schema: {},\n guideline: 'Renders a single highlight label as a span; must be a descendant of PricingHighlights.',\n});\n\nexport const PricingPromotionsDefinition = defineComponent<PricingPromotionsProps>({\n name: 'PricingPromotions',\n importPath: '@vtex/faststore/components',\n component: PricingPromotions,\n editor: { label: 'Promotions', category: 'commerce' },\n schema: {},\n guideline:\n 'Iterates the offer\\'s structured promotions (e.g. \"Compre 3 leve 2\"); place PricingPromotion as a child. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingPromotionDefinition = defineComponent<PricingPromotionProps>({\n name: 'PricingPromotion',\n importPath: '@vtex/faststore/components',\n component: PricingPromotion,\n editor: { label: 'Promotion', category: 'commerce' },\n schema: {\n template: { type: 'string', default: '{name}', label: 'Template' },\n },\n guideline:\n 'Renders a single promotion using the {name} template placeholder; must be a descendant of PricingPromotions.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function PricingRoot({ $data: $dataProp, selectedVariantId, children, ...props }: PricingRootProps) {\n const { locale, currency } = useStorefrontContext();\n const productSlice = useDataOverride($dataProp) ?? null;\n\n // The VariantSelector matter publishes the shopper's in-page selection here; reading it lets\n // pricing recompute when a swatch changes without a page navigation. Scope the published selection\n // to this product so a swatch picked on another PDP does not leak in after client-side navigation.\n // The explicit selectedVariantId prop is the pre-selection fallback; the live selection wins.\n const publishedSelection = useReactiveVar(selectedVariantVar);\n const publishedVariantId = publishedVariantIdFor(publishedSelection, productSlice?.id ?? null);\n const activeVariantId = publishedVariantId ?? selectedVariantId;\n\n if (activeVariantId) {\n return (\n <Suspense fallback={null}>\n <HotDataProvider\n query={variantQuery}\n variables={{ id: activeVariantId }}\n field=\"node\"\n fallbackData={productSlice}\n >\n <PricingProvider fallbackProductSlice={productSlice} currency={currency} locale={locale} {...props}>\n {children}\n </PricingProvider>\n </HotDataProvider>\n </Suspense>\n );\n }\n\n const transformed = productSlice ? transformPricingData(productSlice) : null;\n\n return (\n <PricingView transformed={transformed} currency={currency} locale={locale} {...props}>\n {children}\n </PricingView>\n );\n}\n\n/**\n * What `PricingRoot` hands its inner views: the container props plus the locale and currency it read\n * from the storefront context. They are internal parameters, not a public prop — `PricingRootProps`\n * no longer carries either.\n */\ntype PricingViewBaseProps = ComponentPropsWithRef<'div'> & {\n currency?: string;\n locale?: string;\n};\n\ntype PricingProviderProps = PricingViewBaseProps & {\n fallbackProductSlice: RawPricingData | null;\n};\n\n// Reads the override written by the nested HotDataProvider: a Variant node when the variant fetch\n// succeeds, or the product slice (fallbackData) on error/null. Dispatch on __typename and always\n// source the product path from the explicit fallback prop so a mis-passed Product node id can never\n// crash the variant transform.\nfunction PricingProvider({ fallbackProductSlice, ...viewProps }: PricingProviderProps) {\n const override = useDataOverride<unknown>(null);\n const overrideTypename = (override as { __typename?: string } | null)?.__typename;\n\n let transformed: NormalizedPricingOffer | null = null;\n if (overrideTypename === 'Variant') {\n transformed = transformVariantPricingData(override as VariantSlice);\n } else if (fallbackProductSlice) {\n transformed = transformPricingData(fallbackProductSlice);\n }\n\n return <PricingView transformed={transformed} {...viewProps} />;\n}\n\ntype PricingViewProps = PricingViewBaseProps & {\n transformed: NormalizedPricingOffer | null;\n};\n\nfunction PricingView({\n transformed,\n currency: currencyProp,\n locale: localeProp,\n className,\n children,\n ...props\n}: PricingViewProps) {\n let contextValue: PricingContextValue = null;\n\n if (transformed) {\n const { price, listPrice, spotPrice, installmentPlans, discountHighlights, promotions } = transformed;\n // `PricingRoot` always hands these down from the context; the offer's own currency is the same\n // channel's by construction, so it is a fallback only for a directly-rendered view.\n const currency = currencyProp ?? transformed.currency;\n // `PricingRoot` always supplies it from the context; a directly-rendered view falls back to the\n // platform default rather than a Brazilian one.\n const locale = localeProp;\n const hasDiscount = listPrice > price;\n const hasSpotDiscount = spotPrice < price;\n const discountPercentage = hasDiscount ? Math.round(((listPrice - price) / listPrice) * 100) : 0;\n const spotDiscountPercentage = hasSpotDiscount ? Math.round(((price - spotPrice) / price) * 100) : 0;\n const bestInstallment = findBestInstallment(installmentPlans);\n\n contextValue = {\n price,\n listPrice,\n spotPrice,\n currency,\n locale,\n installmentPlans,\n discountHighlights,\n promotions,\n hasDiscount,\n hasSpotDiscount,\n discountPercentage,\n spotDiscountPercentage,\n bestInstallment,\n };\n }\n\n return (\n <PricingContext value={contextValue}>\n <div {...props} className={className} data-fs-pricing=\"\">\n {children}\n </div>\n </PricingContext>\n );\n}\n\nexport function PricingSellingPrice({ className, children, ...props }: PricingSellingPriceProps) {\n const ctx = usePricing();\n if (!ctx) return null;\n\n const formatted = formatPrice(ctx.price, ctx.locale, ctx.currency);\n\n return (\n <span {...props} className={className} data-fs-pricing-selling-price=\"\">\n {children ?? formatted}\n </span>\n );\n}\n\nexport function PricingListPrice({ className, children, ...props }: PricingListPriceProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.hasDiscount) return null;\n\n const formatted = formatPrice(ctx.listPrice, ctx.locale, ctx.currency);\n\n return (\n <span {...props} className={className} data-fs-pricing-list-price=\"\">\n {children ?? formatted}\n </span>\n );\n}\n\nexport function PricingSpotPrice({ className, children, ...props }: PricingSpotPriceProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.hasSpotDiscount) return null;\n\n const formatted = formatPrice(ctx.spotPrice, ctx.locale, ctx.currency);\n\n return (\n <span {...props} className={className} data-fs-pricing-spot-price=\"\">\n {children ?? formatted}\n </span>\n );\n}\n\nexport function PricingInstallments({ className, children, ...props }: PricingInstallmentsProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.bestInstallment) return null;\n\n return (\n <InstallmentItemContext value={ctx.bestInstallment}>\n <div {...props} className={className} data-fs-pricing-installments=\"\">\n {children}\n </div>\n </InstallmentItemContext>\n );\n}\n\nexport function PricingInstallmentPlans({ className, children, ...props }: PricingInstallmentPlansProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n const sortedPlans = ctx.installmentPlans\n .map((plan) => ({ plan, bestInstallment: findBestInstallment([plan]) }))\n .sort((a, b) => {\n const aCount = a.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n const bCount = b.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n return aCount - bCount;\n });\n\n return (\n <div {...props} className={className} data-fs-pricing-installment-plans=\"\">\n {sortedPlans.map(({ plan, bestInstallment }, index) => (\n <InstallmentPlanItemContext\n key={`${plan.paymentType}-${plan.paymentMethod}-${index}`}\n value={{\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments,\n bestInstallment,\n }}\n >\n {children}\n </InstallmentPlanItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingInstallmentPlan({ className, children, ...props }: PricingInstallmentPlanProps) {\n const plan = useInstallmentPlanItem();\n if (!plan.bestInstallment) return null;\n\n return (\n <InstallmentItemContext value={plan.bestInstallment}>\n <div\n {...props}\n className={className}\n data-fs-pricing-installment-plan=\"\"\n data-fs-pricing-installment-plan-type={plan.paymentType}\n >\n {children}\n </div>\n </InstallmentItemContext>\n );\n}\n\nexport function PricingInstallmentsForPlan({ className, children, ...props }: PricingInstallmentsForPlanProps) {\n const plan = useInstallmentPlanItem('PricingInstallmentsForPlan', 'PricingInstallmentPlan');\n if (plan.installments.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-installments-for-plan=\"\">\n {plan.installments.map((installment, index) => (\n <InstallmentItemContext key={`${installment.count}-${index}`} value={installment}>\n {children}\n </InstallmentItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPaymentMethodsTrigger({ className, children, ...props }: PricingPaymentMethodsTriggerProps) {\n return (\n <PopoverTrigger {...props} className={className} data-fs-pricing-payment-methods-trigger=\"\">\n {children}\n </PopoverTrigger>\n );\n}\n\nexport function PricingPaymentMethodsList({ className, children, ...props }: PricingPaymentMethodsListProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-payment-methods-list=\"\">\n <PricingInstallmentPlans>{children}</PricingInstallmentPlans>\n </div>\n );\n}\n\nfunction sortPlansForTabs(plans: InstallmentPlanData[]) {\n return plans\n .map((plan) => ({\n plan,\n bestInstallment: findBestInstallment([plan]),\n tabValue: `${plan.paymentType}-${plan.paymentMethod}`,\n }))\n .sort((a, b) => {\n const aCount = a.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n const bCount = b.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n return aCount - bCount;\n });\n}\n\nexport function PricingPaymentMethodsTabList({ className, children, ...props }: PricingPaymentMethodsTabListProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-payment-methods-tab-list=\"\">\n {sortPlansForTabs(ctx.installmentPlans).map(({ plan, bestInstallment, tabValue }) => (\n <InstallmentPlanItemContext\n key={tabValue}\n value={{\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments,\n bestInstallment,\n }}\n >\n <TabsTab value={tabValue}>{children}</TabsTab>\n </InstallmentPlanItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPaymentMethodsTabPanels({ className, children, ...props }: PricingPaymentMethodsTabPanelsProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-payment-methods-tab-panels=\"\">\n {sortPlansForTabs(ctx.installmentPlans).map(({ plan, bestInstallment, tabValue }) => (\n <InstallmentPlanItemContext\n key={tabValue}\n value={{\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments,\n bestInstallment,\n }}\n >\n <TabsPanel value={tabValue}>{children}</TabsPanel>\n </InstallmentPlanItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPaymentMethodName({ className, children, ...props }: PricingPaymentMethodNameProps) {\n const plan = useInstallmentPlanItem();\n\n return (\n <span {...props} className={className} data-fs-pricing-payment-method-name=\"\">\n {children ?? plan.paymentMethod}\n </span>\n );\n}\n\nexport function PricingInstallment({\n template = '{count}x de {value}',\n interestFreeLabel = 'sem juros',\n className,\n children,\n ...props\n}: PricingInstallmentProps) {\n const installment = useInstallmentItem();\n const ctx = usePricing();\n if (!ctx) return null;\n\n const formattedValue = formatPrice(installment.value, ctx.locale, ctx.currency);\n const base = template.replace('{count}', String(installment.count)).replace('{value}', formattedValue);\n const text = installment.interestFree && interestFreeLabel ? `${base} ${interestFreeLabel}` : base;\n\n return (\n <span {...props} className={className} data-fs-pricing-installment=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function PricingDiscount({\n template,\n format = 'percentage',\n className,\n children,\n ...props\n}: PricingDiscountProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.hasDiscount) return null;\n\n const amount = ctx.listPrice - ctx.price;\n const formattedAmount = formatPrice(amount, ctx.locale, ctx.currency);\n const resolvedTemplate = template ?? (format === 'absolute' ? '-{amount}' : '-{percentage}%');\n const text = resolvedTemplate\n .replaceAll('{percentage}', String(ctx.discountPercentage))\n .replaceAll('{amount}', formattedAmount);\n\n return (\n <span {...props} className={className} data-fs-pricing-discount=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function PricingSpotDiscount({\n template = '-{percentage}%',\n className,\n children,\n ...props\n}: PricingSpotDiscountProps) {\n const ctx = usePricing();\n if (!ctx || ctx.spotDiscountPercentage <= 0) return null;\n\n const text = template.replace('{percentage}', String(ctx.spotDiscountPercentage));\n\n return (\n <span {...props} className={className} data-fs-pricing-spot-discount=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function PricingHighlights({ className, children, ...props }: PricingHighlightsProps) {\n const ctx = usePricing();\n if (!ctx || ctx.discountHighlights.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-highlights=\"\">\n {ctx.discountHighlights.map((highlight, index) => (\n <HighlightItemContext key={`${highlight}-${index}`} value={highlight}>\n {children}\n </HighlightItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingHighlight({ className, children, ...props }: PricingHighlightProps) {\n const highlight = useHighlightItem();\n\n return (\n <span {...props} className={className} data-fs-pricing-highlight=\"\">\n {children ?? highlight}\n </span>\n );\n}\n\nexport function PricingPromotions({ className, children, ...props }: PricingPromotionsProps) {\n const ctx = usePricing();\n if (!ctx || ctx.promotions.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-promotions=\"\">\n {ctx.promotions.map((promotion, index) => (\n <PromotionItemContext key={`${promotion.name}-${index}`} value={promotion}>\n {children}\n </PromotionItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPromotion({ template = '{name}', className, children, ...props }: PricingPromotionProps) {\n const promotion = usePromotionItem();\n const text = template.replace('{name}', promotion.name);\n\n return (\n <span {...props} className={className} data-fs-pricing-promotion=\"\">\n {children ?? text}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Skeleton\n// ---------------------------------------------------------------------------\n\nexport function PricingSkeleton({ className, ...props }: ComponentPropsWithRef<'div'>) {\n return (\n <div {...props} className={className} data-fs-pricing-skeleton=\"\" aria-hidden=\"true\">\n <span data-fs-pricing-skeleton-line=\"\" />\n <span data-fs-pricing-skeleton-line=\"\" />\n </div>\n );\n}\n\nPricingRoot.Skeleton = PricingSkeleton;\n\n// ---------------------------------------------------------------------------\n// Namespace export\n// ---------------------------------------------------------------------------\n\nexport const Pricing = {\n Root: PricingRoot,\n SellingPrice: PricingSellingPrice,\n ListPrice: PricingListPrice,\n SpotPrice: PricingSpotPrice,\n Installments: PricingInstallments,\n InstallmentPlans: PricingInstallmentPlans,\n InstallmentPlan: PricingInstallmentPlan,\n InstallmentsForPlan: PricingInstallmentsForPlan,\n Installment: PricingInstallment,\n PaymentMethodsTrigger: PricingPaymentMethodsTrigger,\n PaymentMethodsList: PricingPaymentMethodsList,\n PaymentMethodsTabList: PricingPaymentMethodsTabList,\n PaymentMethodsTabPanels: PricingPaymentMethodsTabPanels,\n PaymentMethodName: PricingPaymentMethodName,\n Discount: PricingDiscount,\n SpotDiscount: PricingSpotDiscount,\n Highlights: PricingHighlights,\n Highlight: PricingHighlight,\n Promotions: PricingPromotions,\n Promotion: PricingPromotion,\n Skeleton: PricingSkeleton,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"pricing.js","names":[],"sources":["../../../src/matter/pricing/pricing.tsx"],"sourcesContent":["'use client';\n\nimport { useReactiveVar } from '@apollo/client/react';\nimport { defineComponent } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { createContext, Suspense, useContext } from 'react';\nimport { PopoverTrigger } from '../../particles/popover/popover.js';\nimport { TabsPanel, TabsTab } from '../../particles/tabs/tabs.js';\nimport { useStorefrontContext } from '../../sdk/context/storefront-context.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { HotDataProvider } from '../../sdk/data/hot-data-provider.js';\nimport { graphql } from '../../sdk/generated/gql.js';\nimport type { VariantPricingDataFragment } from '../../sdk/generated/graphql.js';\nimport { resolveDefaultSeller } from '../../sdk/seller.js';\nimport { publishedVariantIdFor, selectedVariantVar } from '../../sdk/state/variant-selector.js';\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment PricingData on Query {\n productBySlug(slug: $slug) {\n __typename\n id\n variants(first: 1) {\n edges {\n node {\n sellers {\n isDefault\n offer {\n price { amount currencyCode }\n listPrice { amount currencyCode }\n spotPrice { amount currencyCode }\n installmentPlans {\n paymentMethod\n paymentType\n installments {\n count\n value { amount currencyCode }\n totalAmount { amount currencyCode }\n interestRate\n interestFree\n }\n }\n discountHighlights\n promotions {\n name\n }\n }\n }\n }\n }\n }\n }\n }\n`;\n\n// The variant offer slice, authored via graphql() so HotDataProvider gets a TypedDocumentNode.\n// Declared so codegen scans the source and emits VariantPricingDataFragment; the fragment is spread\n// into variantQuery at the GraphQL layer, so the variable is unused at runtime.\nconst _variantFragment = graphql(`\n fragment VariantPricingData on Variant {\n __typename\n id\n sellers {\n isDefault\n offer {\n price { amount currencyCode }\n listPrice { amount currencyCode }\n spotPrice { amount currencyCode }\n installmentPlans {\n paymentMethod\n paymentType\n installments {\n count\n value { amount currencyCode }\n totalAmount { amount currencyCode }\n interestRate\n interestFree\n }\n }\n discountHighlights\n promotions {\n name\n }\n }\n }\n }\n`);\n\nconst variantQuery = graphql(`\n query VariantPricingQuery($id: ID!) {\n node(id: $id) {\n __typename\n ... on Variant {\n ...VariantPricingData\n }\n }\n }\n`);\n\n// ---------------------------------------------------------------------------\n// Raw data types (shape of the fragment result)\n// ---------------------------------------------------------------------------\n\ntype MoneyValue = {\n amount: number;\n currencyCode: string;\n};\n\ntype RawPromotion = {\n name: string;\n};\n\ntype RawOffer = {\n price: MoneyValue;\n listPrice: MoneyValue;\n spotPrice: MoneyValue;\n installmentPlans: Array<{\n paymentMethod: string;\n paymentType: string;\n installments: Array<{\n count: number;\n value: MoneyValue;\n totalAmount: MoneyValue;\n interestRate: number;\n interestFree: boolean;\n }>;\n }>;\n discountHighlights: string[];\n promotions: RawPromotion[];\n};\n\ntype RawPricingData = {\n // __typename/id are optional so existing fixtures (which omit them) still typecheck; the real\n // page query always supplies id, which scopes the published variant selection to this product.\n __typename?: string;\n id?: string;\n variants: {\n edges: Array<{\n node: {\n sellers: Array<{\n isDefault: boolean;\n offer: RawOffer | null;\n }>;\n };\n }>;\n };\n};\n\ntype VariantSlice = VariantPricingDataFragment;\n\ntype NormalizedPricingOffer = {\n price: number;\n listPrice: number;\n spotPrice: number;\n currency: string;\n installmentPlans: InstallmentPlanData[];\n discountHighlights: string[];\n promotions: PromotionData[];\n};\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype InstallmentData = {\n count: number;\n value: number;\n totalAmount: number;\n interestRate: number;\n interestFree: boolean;\n};\n\ntype InstallmentPlanData = {\n paymentMethod: string;\n paymentType: string;\n installments: InstallmentData[];\n};\n\ntype PromotionData = {\n name: string;\n};\n\ntype PricingContextData = {\n price: number;\n listPrice: number;\n spotPrice: number;\n currency: string;\n /** Undefined only for a directly-rendered view: `Intl` reads it as the platform default. */\n locale: string | undefined;\n installmentPlans: InstallmentPlanData[];\n discountHighlights: string[];\n promotions: PromotionData[];\n hasDiscount: boolean;\n hasSpotDiscount: boolean;\n discountPercentage: number;\n spotDiscountPercentage: number;\n bestInstallment: InstallmentData | null;\n};\n\ntype PricingContextValue = PricingContextData | null;\n\ntype InstallmentPlanItemContextData = {\n paymentMethod: string;\n paymentType: string;\n installments: InstallmentData[];\n bestInstallment: InstallmentData | null;\n};\n\nconst PRICING_CONTEXT_UNSET = Symbol('PricingContextUnset');\n\nexport type PricingRootProps = ComponentPropsWithRef<'div'> & {\n $data?: RawPricingData | null;\n /** Page-supplied viewed SKU; pre-selects the offer on first paint. A published swatch selection\n * wins over it once the shopper interacts. */\n selectedVariantId?: string;\n};\n\nexport type PricingSellingPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingListPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingSpotPriceProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingInstallmentsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingInstallmentPlansProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingInstallmentPlanProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingInstallmentsForPlanProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodsTriggerProps = ComponentPropsWithRef<'button'>;\n\nexport type PricingPaymentMethodsListProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodsTabListProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodsTabPanelsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPaymentMethodNameProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingInstallmentProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n interestFreeLabel?: string;\n};\n\nexport type PricingDiscountProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n format?: 'percentage' | 'absolute';\n};\n\nexport type PricingHighlightsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingHighlightProps = ComponentPropsWithRef<'span'>;\n\nexport type PricingPromotionsProps = ComponentPropsWithRef<'div'>;\n\nexport type PricingPromotionProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n};\n\nexport type PricingSpotDiscountProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n};\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst PricingContext = createContext<PricingContextValue | typeof PRICING_CONTEXT_UNSET>(PRICING_CONTEXT_UNSET);\n\nconst InstallmentItemContext = createContext<InstallmentData | null>(null);\n\nconst InstallmentPlanItemContext = createContext<InstallmentPlanItemContextData | null>(null);\n\nconst HighlightItemContext = createContext<string | null>(null);\n\nconst PromotionItemContext = createContext<PromotionData | null>(null);\n\nfunction usePricing(): PricingContextValue {\n const ctx = useContext(PricingContext);\n if (ctx === PRICING_CONTEXT_UNSET) {\n throw new Error('Pricing components must be used inside PricingRoot.');\n }\n return ctx;\n}\n\nfunction useInstallmentItem(): InstallmentData {\n const ctx = useContext(InstallmentItemContext);\n if (!ctx) {\n throw new Error('PricingInstallment must be used inside PricingInstallments.');\n }\n return ctx;\n}\n\nexport function useInstallmentPlanItem(\n caller = 'PricingInstallmentPlan',\n parent = 'PricingInstallmentPlans',\n): InstallmentPlanItemContextData {\n const ctx = useContext(InstallmentPlanItemContext);\n if (!ctx) {\n throw new Error(`${caller} must be used inside ${parent}.`);\n }\n return ctx;\n}\n\nfunction useHighlightItem(): string {\n const ctx = useContext(HighlightItemContext);\n if (ctx === null) {\n throw new Error('PricingHighlight must be used inside PricingHighlights.');\n }\n return ctx;\n}\n\nfunction usePromotionItem(): PromotionData {\n const ctx = useContext(PromotionItemContext);\n if (!ctx) {\n throw new Error('PricingPromotion must be used inside PricingPromotions.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(value: number, locale: string | undefined, currency: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);\n}\n\nfunction findBestInstallment(plans: InstallmentPlanData[]): InstallmentData | null {\n const allInstallments = plans.flatMap((plan) => plan.installments);\n if (allInstallments.length === 0) return null;\n\n const interestFree = allInstallments.filter((i) => i.interestFree);\n if (interestFree.length > 0) {\n return interestFree.reduce((best, current) => (current.count > best.count ? current : best));\n }\n\n return allInstallments.reduce((best, current) => (current.count > best.count ? current : best));\n}\n\n// ---------------------------------------------------------------------------\n// Transform\n// ---------------------------------------------------------------------------\n\n// The GraphQL `Decimal` scalar is serialized as a string over the wire; convert it here so every\n// later comparison and subtraction works on numbers.\nfunction normalizeOffer(offer: RawOffer): NormalizedPricingOffer {\n return {\n price: Number(offer.price.amount),\n listPrice: Number(offer.listPrice.amount),\n spotPrice: Number(offer.spotPrice.amount),\n currency: offer.price.currencyCode,\n installmentPlans: offer.installmentPlans.map((plan) => ({\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments.map((inst) => ({\n count: inst.count,\n value: Number(inst.value.amount),\n totalAmount: Number(inst.totalAmount.amount),\n interestRate: inst.interestRate,\n interestFree: inst.interestFree,\n })),\n })),\n discountHighlights: offer.discountHighlights,\n promotions: offer.promotions.map((promotion) => ({ name: promotion.name })),\n };\n}\n\n// Resolves a variant's default seller and normalizes its offer, or null when that seller has no\n// offer. Shared by the product-level and selected-variant transforms so the default-seller + offer\n// gate lives in one place.\nfunction pricingOfferFromVariant(variant: {\n sellers: readonly { isDefault: boolean; offer: RawOffer | null }[];\n}): NormalizedPricingOffer | null {\n const seller = resolveDefaultSeller(variant.sellers);\n const offer = seller?.offer;\n if (!offer) return null;\n\n return normalizeOffer(offer);\n}\n\nfunction transformPricingData(data: RawPricingData): NormalizedPricingOffer | null {\n const edge = data.variants.edges[0];\n if (!edge) return null;\n\n return pricingOfferFromVariant(edge.node);\n}\n\nexport function transformVariantPricingData(variant: VariantSlice): NormalizedPricingOffer | null {\n // Generated amounts are strings (what the API sends); `RawOffer` still declares numbers. Typing only:\n // the product page comparisons stay as they are (see \"Cart data\" in docs/storefront-core/reference-cart.md).\n return pricingOfferFromVariant(variant as unknown as Parameters<typeof pricingOfferFromVariant>[0]);\n}\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const PricingRootDefinition = defineComponent<PricingRootProps>({\n name: 'PricingRoot',\n importPath: '@vtex/faststore/components',\n component: PricingRoot,\n fragment,\n fetchStrategy: 'lazy',\n skeleton: PricingSkeleton,\n editor: { label: 'Pricing', category: 'commerce' },\n schema: {\n selectedVariantId: { type: 'string', label: 'Selected Variant ID' },\n },\n guideline:\n 'Root container for the PDP pricing block; all other Pricing sub-components must be descendants of it. Automatically recomputes the offer when a shopper picks a VariantSelector swatch (it reads the published variant selection); the selectedVariantId prop is an optional pre-selection fallback. Falls back silently to the product-level offer on variant fetch error. See pricing.md.',\n});\n\nexport const PricingSellingPriceDefinition = defineComponent<PricingSellingPriceProps>({\n name: 'PricingSellingPrice',\n importPath: '@vtex/faststore/components',\n component: PricingSellingPrice,\n editor: { label: 'Selling Price', category: 'commerce' },\n schema: {},\n guideline: 'Displays the current selling price; must be a descendant of PricingRoot.',\n});\n\nexport const PricingListPriceDefinition = defineComponent<PricingListPriceProps>({\n name: 'PricingListPrice',\n importPath: '@vtex/faststore/components',\n component: PricingListPrice,\n editor: { label: 'List Price', category: 'commerce' },\n schema: {},\n guideline:\n 'Displays the original (strikethrough) list price; only renders when a discount exists. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingSpotPriceDefinition = defineComponent<PricingSpotPriceProps>({\n name: 'PricingSpotPrice',\n importPath: '@vtex/faststore/components',\n component: PricingSpotPrice,\n editor: { label: 'Spot Price', category: 'commerce' },\n schema: {},\n guideline:\n 'Displays the best cash/instant-payment price (e.g. Pix); only renders when spotPrice is lower than the selling price. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingInstallmentsDefinition = defineComponent<PricingInstallmentsProps>({\n name: 'PricingInstallments',\n importPath: '@vtex/faststore/components',\n component: PricingInstallments,\n editor: { label: 'Installments', category: 'commerce' },\n schema: {},\n guideline:\n 'Shortcut container that exposes the single best installment across all plans; use PricingInstallmentPlans instead when a per-payment-method breakdown is needed. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingInstallmentPlansDefinition = defineComponent<PricingInstallmentPlansProps>({\n name: 'PricingInstallmentPlans',\n importPath: '@vtex/faststore/components',\n component: PricingInstallmentPlans,\n editor: { label: 'Installment Plans', category: 'commerce' },\n schema: {},\n guideline:\n 'Renders one row per payment method; use PricingInstallments instead when only the single best plan is needed. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingInstallmentPlanDefinition = defineComponent<PricingInstallmentPlanProps>({\n name: 'PricingInstallmentPlan',\n importPath: '@vtex/faststore/components',\n component: PricingInstallmentPlan,\n editor: { label: 'Installment Plan', category: 'commerce' },\n schema: {},\n guideline:\n 'Renders a single plan row inside PricingInstallmentPlans; nest PricingInstallmentsForPlan inside it to list every installment tier instead of just the best one. Must be a descendant of PricingInstallmentPlans.',\n});\n\nexport const PricingInstallmentsForPlanDefinition = defineComponent<PricingInstallmentsForPlanProps>({\n name: 'PricingInstallmentsForPlan',\n importPath: '@vtex/faststore/components',\n component: PricingInstallmentsForPlan,\n editor: { label: 'Installments For Plan', category: 'commerce' },\n schema: {},\n guideline:\n 'Iterates every installment tier (1x, 2x, … Nx) of the enclosing plan; must be a descendant of PricingInstallmentPlan.',\n});\n\nexport const PricingPaymentMethodsTriggerDefinition = defineComponent<PricingPaymentMethodsTriggerProps>({\n name: 'PricingPaymentMethodsTrigger',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsTrigger,\n editor: { label: 'Payment Methods Trigger', category: 'action' },\n schema: {},\n guideline: 'Button that opens the payment-methods disclosure panel; must be a descendant of PopoverRoot.',\n});\n\nexport const PricingPaymentMethodsListDefinition = defineComponent<PricingPaymentMethodsListProps>({\n name: 'PricingPaymentMethodsList',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsList,\n editor: { label: 'Payment Methods List', category: 'commerce' },\n schema: {},\n guideline:\n 'Flat disclosure panel content listing every payment plan; place inside PopoverPopup, DialogPopup, or DrawerPopup. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingPaymentMethodsTabListDefinition = defineComponent<PricingPaymentMethodsTabListProps>({\n name: 'PricingPaymentMethodsTabList',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsTabList,\n editor: { label: 'Payment Methods Tab List', category: 'commerce' },\n schema: {},\n guideline:\n 'Emits one tab per payment plan for the tab-grouped disclosure pattern; must be a descendant of TabsList (which is inside TabsRoot). Pair with PricingPaymentMethodsTabPanels.',\n});\n\nexport const PricingPaymentMethodsTabPanelsDefinition = defineComponent<PricingPaymentMethodsTabPanelsProps>({\n name: 'PricingPaymentMethodsTabPanels',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodsTabPanels,\n editor: { label: 'Payment Methods Tab Panels', category: 'commerce' },\n schema: {},\n guideline:\n 'Emits one panel per payment plan for the tab-grouped disclosure pattern; must be a sibling of TabsList under TabsRoot (not nested inside TabsList). Pair with PricingPaymentMethodsTabList.',\n});\n\nexport const PricingPaymentMethodNameDefinition = defineComponent<PricingPaymentMethodNameProps>({\n name: 'PricingPaymentMethodName',\n importPath: '@vtex/faststore/components',\n component: PricingPaymentMethodName,\n editor: { label: 'Payment Method Name', category: 'commerce' },\n schema: {},\n guideline:\n 'Renders the enclosing plan\\'s payment method name (e.g. \"Visa\", \"Pix\"); must be inside a plan context — PricingInstallmentPlan, PricingPaymentMethodsTabList, or PricingPaymentMethodsTabPanels.',\n});\n\nexport const PricingInstallmentDefinition = defineComponent<PricingInstallmentProps>({\n name: 'PricingInstallment',\n importPath: '@vtex/faststore/components',\n component: PricingInstallment,\n editor: { label: 'Installment', category: 'commerce' },\n schema: {\n template: { type: 'string', default: '{count}x de {value}', label: 'Template' },\n interestFreeLabel: { type: 'string', default: 'sem juros', label: 'Interest-free label' },\n },\n guideline:\n 'Renders a single installment line using {count} and {value} template placeholders; must be a descendant of PricingInstallments, PricingInstallmentPlan, or PricingInstallmentsForPlan.',\n});\n\nexport const PricingDiscountDefinition = defineComponent<PricingDiscountProps>({\n name: 'PricingDiscount',\n importPath: '@vtex/faststore/components',\n component: PricingDiscount,\n editor: { label: 'Discount Badge', category: 'commerce' },\n schema: {\n format: { type: ['percentage', 'absolute'] as const, default: 'percentage', label: 'Discount Format' },\n template: { type: 'string', label: 'Template' },\n },\n guideline:\n 'Discount badge for the listPrice-vs-price markdown; use PricingSpotDiscount instead for the spotPrice-vs-price (Pix/cash) percentage. The format prop switches between a percentage (-25%, default) and an absolute amount (-R$ 10,00); the template supports {percentage} and {amount} placeholders and defaults to the format-appropriate one. Recomputes automatically on swatch change. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingSpotDiscountDefinition = defineComponent<PricingSpotDiscountProps>({\n name: 'PricingSpotDiscount',\n importPath: '@vtex/faststore/components',\n component: PricingSpotDiscount,\n editor: { label: 'Spot Discount Badge', category: 'commerce' },\n schema: {\n template: { type: 'string', default: '-{percentage}%', label: 'Template' },\n },\n guideline:\n 'Discount badge for the spotPrice-vs-price (cash/Pix) percentage; use PricingDiscount instead for the listPrice-vs-price percentage. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingHighlightsDefinition = defineComponent<PricingHighlightsProps>({\n name: 'PricingHighlights',\n importPath: '@vtex/faststore/components',\n component: PricingHighlights,\n editor: { label: 'Highlights', category: 'commerce' },\n schema: {},\n guideline:\n 'Iterates the offer\\'s discount highlight labels (e.g. \"Black Friday\", \"Exclusivo\"); place PricingHighlight as a child. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingHighlightDefinition = defineComponent<PricingHighlightProps>({\n name: 'PricingHighlight',\n importPath: '@vtex/faststore/components',\n component: PricingHighlight,\n editor: { label: 'Highlight', category: 'commerce' },\n schema: {},\n guideline: 'Renders a single highlight label as a span; must be a descendant of PricingHighlights.',\n});\n\nexport const PricingPromotionsDefinition = defineComponent<PricingPromotionsProps>({\n name: 'PricingPromotions',\n importPath: '@vtex/faststore/components',\n component: PricingPromotions,\n editor: { label: 'Promotions', category: 'commerce' },\n schema: {},\n guideline:\n 'Iterates the offer\\'s structured promotions (e.g. \"Compre 3 leve 2\"); place PricingPromotion as a child. Must be a descendant of PricingRoot.',\n});\n\nexport const PricingPromotionDefinition = defineComponent<PricingPromotionProps>({\n name: 'PricingPromotion',\n importPath: '@vtex/faststore/components',\n component: PricingPromotion,\n editor: { label: 'Promotion', category: 'commerce' },\n schema: {\n template: { type: 'string', default: '{name}', label: 'Template' },\n },\n guideline:\n 'Renders a single promotion using the {name} template placeholder; must be a descendant of PricingPromotions.',\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\nexport function PricingRoot({ $data: $dataProp, selectedVariantId, children, ...props }: PricingRootProps) {\n const { locale, currency } = useStorefrontContext();\n const productSlice = useDataOverride($dataProp) ?? null;\n\n // The VariantSelector matter publishes the shopper's in-page selection here; reading it lets\n // pricing recompute when a swatch changes without a page navigation. Scope the published selection\n // to this product so a swatch picked on another PDP does not leak in after client-side navigation.\n // The explicit selectedVariantId prop is the pre-selection fallback; the live selection wins.\n const publishedSelection = useReactiveVar(selectedVariantVar);\n const publishedVariantId = publishedVariantIdFor(publishedSelection, productSlice?.id ?? null);\n const activeVariantId = publishedVariantId ?? selectedVariantId;\n\n if (activeVariantId) {\n return (\n <Suspense fallback={null}>\n <HotDataProvider\n query={variantQuery}\n variables={{ id: activeVariantId }}\n field=\"node\"\n fallbackData={productSlice}\n >\n <PricingProvider fallbackProductSlice={productSlice} currency={currency} locale={locale} {...props}>\n {children}\n </PricingProvider>\n </HotDataProvider>\n </Suspense>\n );\n }\n\n const transformed = productSlice ? transformPricingData(productSlice) : null;\n\n return (\n <PricingView transformed={transformed} currency={currency} locale={locale} {...props}>\n {children}\n </PricingView>\n );\n}\n\n/**\n * What `PricingRoot` hands its inner views: the container props plus the locale and currency it read\n * from the storefront context. They are internal parameters, not a public prop — `PricingRootProps`\n * no longer carries either.\n */\ntype PricingViewBaseProps = ComponentPropsWithRef<'div'> & {\n currency?: string;\n locale?: string;\n};\n\ntype PricingProviderProps = PricingViewBaseProps & {\n fallbackProductSlice: RawPricingData | null;\n};\n\n// Reads the override written by the nested HotDataProvider: a Variant node when the variant fetch\n// succeeds, or the product slice (fallbackData) on error/null. Dispatch on __typename and always\n// source the product path from the explicit fallback prop so a mis-passed Product node id can never\n// crash the variant transform.\nfunction PricingProvider({ fallbackProductSlice, ...viewProps }: PricingProviderProps) {\n const override = useDataOverride<unknown>(null);\n const overrideTypename = (override as { __typename?: string } | null)?.__typename;\n\n let transformed: NormalizedPricingOffer | null = null;\n if (overrideTypename === 'Variant') {\n transformed = transformVariantPricingData(override as VariantSlice);\n } else if (fallbackProductSlice) {\n transformed = transformPricingData(fallbackProductSlice);\n }\n\n return <PricingView transformed={transformed} {...viewProps} />;\n}\n\ntype PricingViewProps = PricingViewBaseProps & {\n transformed: NormalizedPricingOffer | null;\n};\n\nfunction PricingView({\n transformed,\n currency: currencyProp,\n locale: localeProp,\n className,\n children,\n ...props\n}: PricingViewProps) {\n let contextValue: PricingContextValue = null;\n\n if (transformed) {\n const { price, listPrice, spotPrice, installmentPlans, discountHighlights, promotions } = transformed;\n // `PricingRoot` always hands these down from the context; the offer's own currency is the same\n // channel's by construction, so it is a fallback only for a directly-rendered view.\n const currency = currencyProp ?? transformed.currency;\n // `PricingRoot` always supplies it from the context; a directly-rendered view falls back to the\n // platform default rather than a Brazilian one.\n const locale = localeProp;\n const hasDiscount = listPrice > price;\n const hasSpotDiscount = spotPrice < price;\n const discountPercentage = hasDiscount ? Math.round(((listPrice - price) / listPrice) * 100) : 0;\n const spotDiscountPercentage = hasSpotDiscount ? Math.round(((price - spotPrice) / price) * 100) : 0;\n const bestInstallment = findBestInstallment(installmentPlans);\n\n contextValue = {\n price,\n listPrice,\n spotPrice,\n currency,\n locale,\n installmentPlans,\n discountHighlights,\n promotions,\n hasDiscount,\n hasSpotDiscount,\n discountPercentage,\n spotDiscountPercentage,\n bestInstallment,\n };\n }\n\n return (\n <PricingContext value={contextValue}>\n <div {...props} className={className} data-fs-pricing=\"\">\n {children}\n </div>\n </PricingContext>\n );\n}\n\nexport function PricingSellingPrice({ className, children, ...props }: PricingSellingPriceProps) {\n const ctx = usePricing();\n if (!ctx) return null;\n\n const formatted = formatPrice(ctx.price, ctx.locale, ctx.currency);\n\n return (\n <span {...props} className={className} data-fs-pricing-selling-price=\"\">\n {children ?? formatted}\n </span>\n );\n}\n\nexport function PricingListPrice({ className, children, ...props }: PricingListPriceProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.hasDiscount) return null;\n\n const formatted = formatPrice(ctx.listPrice, ctx.locale, ctx.currency);\n\n return (\n <span {...props} className={className} data-fs-pricing-list-price=\"\">\n {children ?? formatted}\n </span>\n );\n}\n\nexport function PricingSpotPrice({ className, children, ...props }: PricingSpotPriceProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.hasSpotDiscount) return null;\n\n const formatted = formatPrice(ctx.spotPrice, ctx.locale, ctx.currency);\n\n return (\n <span {...props} className={className} data-fs-pricing-spot-price=\"\">\n {children ?? formatted}\n </span>\n );\n}\n\nexport function PricingInstallments({ className, children, ...props }: PricingInstallmentsProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.bestInstallment) return null;\n\n return (\n <InstallmentItemContext value={ctx.bestInstallment}>\n <div {...props} className={className} data-fs-pricing-installments=\"\">\n {children}\n </div>\n </InstallmentItemContext>\n );\n}\n\nexport function PricingInstallmentPlans({ className, children, ...props }: PricingInstallmentPlansProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n const sortedPlans = ctx.installmentPlans\n .map((plan) => ({ plan, bestInstallment: findBestInstallment([plan]) }))\n .sort((a, b) => {\n const aCount = a.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n const bCount = b.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n return aCount - bCount;\n });\n\n return (\n <div {...props} className={className} data-fs-pricing-installment-plans=\"\">\n {sortedPlans.map(({ plan, bestInstallment }, index) => (\n <InstallmentPlanItemContext\n key={`${plan.paymentType}-${plan.paymentMethod}-${index}`}\n value={{\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments,\n bestInstallment,\n }}\n >\n {children}\n </InstallmentPlanItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingInstallmentPlan({ className, children, ...props }: PricingInstallmentPlanProps) {\n const plan = useInstallmentPlanItem();\n if (!plan.bestInstallment) return null;\n\n return (\n <InstallmentItemContext value={plan.bestInstallment}>\n <div\n {...props}\n className={className}\n data-fs-pricing-installment-plan=\"\"\n data-fs-pricing-installment-plan-type={plan.paymentType}\n >\n {children}\n </div>\n </InstallmentItemContext>\n );\n}\n\nexport function PricingInstallmentsForPlan({ className, children, ...props }: PricingInstallmentsForPlanProps) {\n const plan = useInstallmentPlanItem('PricingInstallmentsForPlan', 'PricingInstallmentPlan');\n if (plan.installments.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-installments-for-plan=\"\">\n {plan.installments.map((installment, index) => (\n <InstallmentItemContext key={`${installment.count}-${index}`} value={installment}>\n {children}\n </InstallmentItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPaymentMethodsTrigger({ className, children, ...props }: PricingPaymentMethodsTriggerProps) {\n return (\n <PopoverTrigger {...props} className={className} data-fs-pricing-payment-methods-trigger=\"\">\n {children}\n </PopoverTrigger>\n );\n}\n\nexport function PricingPaymentMethodsList({ className, children, ...props }: PricingPaymentMethodsListProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-payment-methods-list=\"\">\n <PricingInstallmentPlans>{children}</PricingInstallmentPlans>\n </div>\n );\n}\n\nfunction sortPlansForTabs(plans: InstallmentPlanData[]) {\n return plans\n .map((plan) => ({\n plan,\n bestInstallment: findBestInstallment([plan]),\n tabValue: `${plan.paymentType}-${plan.paymentMethod}`,\n }))\n .sort((a, b) => {\n const aCount = a.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n const bCount = b.bestInstallment?.count ?? Number.POSITIVE_INFINITY;\n return aCount - bCount;\n });\n}\n\nexport function PricingPaymentMethodsTabList({ className, children, ...props }: PricingPaymentMethodsTabListProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-payment-methods-tab-list=\"\">\n {sortPlansForTabs(ctx.installmentPlans).map(({ plan, bestInstallment, tabValue }) => (\n <InstallmentPlanItemContext\n key={tabValue}\n value={{\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments,\n bestInstallment,\n }}\n >\n <TabsTab value={tabValue}>{children}</TabsTab>\n </InstallmentPlanItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPaymentMethodsTabPanels({ className, children, ...props }: PricingPaymentMethodsTabPanelsProps) {\n const ctx = usePricing();\n if (!ctx || ctx.installmentPlans.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-payment-methods-tab-panels=\"\">\n {sortPlansForTabs(ctx.installmentPlans).map(({ plan, bestInstallment, tabValue }) => (\n <InstallmentPlanItemContext\n key={tabValue}\n value={{\n paymentMethod: plan.paymentMethod,\n paymentType: plan.paymentType,\n installments: plan.installments,\n bestInstallment,\n }}\n >\n <TabsPanel value={tabValue}>{children}</TabsPanel>\n </InstallmentPlanItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPaymentMethodName({ className, children, ...props }: PricingPaymentMethodNameProps) {\n const plan = useInstallmentPlanItem();\n\n return (\n <span {...props} className={className} data-fs-pricing-payment-method-name=\"\">\n {children ?? plan.paymentMethod}\n </span>\n );\n}\n\nexport function PricingInstallment({\n template = '{count}x de {value}',\n interestFreeLabel = 'sem juros',\n className,\n children,\n ...props\n}: PricingInstallmentProps) {\n const installment = useInstallmentItem();\n const ctx = usePricing();\n if (!ctx) return null;\n\n const formattedValue = formatPrice(installment.value, ctx.locale, ctx.currency);\n const base = template.replace('{count}', String(installment.count)).replace('{value}', formattedValue);\n const text = installment.interestFree && interestFreeLabel ? `${base} ${interestFreeLabel}` : base;\n\n return (\n <span {...props} className={className} data-fs-pricing-installment=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function PricingDiscount({\n template,\n format = 'percentage',\n className,\n children,\n ...props\n}: PricingDiscountProps) {\n const ctx = usePricing();\n if (!ctx || !ctx.hasDiscount) return null;\n\n const amount = ctx.listPrice - ctx.price;\n const formattedAmount = formatPrice(amount, ctx.locale, ctx.currency);\n const resolvedTemplate = template ?? (format === 'absolute' ? '-{amount}' : '-{percentage}%');\n const text = resolvedTemplate\n .replaceAll('{percentage}', String(ctx.discountPercentage))\n .replaceAll('{amount}', formattedAmount);\n\n return (\n <span {...props} className={className} data-fs-pricing-discount=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function PricingSpotDiscount({\n template = '-{percentage}%',\n className,\n children,\n ...props\n}: PricingSpotDiscountProps) {\n const ctx = usePricing();\n if (!ctx || ctx.spotDiscountPercentage <= 0) return null;\n\n const text = template.replace('{percentage}', String(ctx.spotDiscountPercentage));\n\n return (\n <span {...props} className={className} data-fs-pricing-spot-discount=\"\">\n {children ?? text}\n </span>\n );\n}\n\nexport function PricingHighlights({ className, children, ...props }: PricingHighlightsProps) {\n const ctx = usePricing();\n if (!ctx || ctx.discountHighlights.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-highlights=\"\">\n {ctx.discountHighlights.map((highlight, index) => (\n <HighlightItemContext key={`${highlight}-${index}`} value={highlight}>\n {children}\n </HighlightItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingHighlight({ className, children, ...props }: PricingHighlightProps) {\n const highlight = useHighlightItem();\n\n return (\n <span {...props} className={className} data-fs-pricing-highlight=\"\">\n {children ?? highlight}\n </span>\n );\n}\n\nexport function PricingPromotions({ className, children, ...props }: PricingPromotionsProps) {\n const ctx = usePricing();\n if (!ctx || ctx.promotions.length === 0) return null;\n\n return (\n <div {...props} className={className} data-fs-pricing-promotions=\"\">\n {ctx.promotions.map((promotion, index) => (\n <PromotionItemContext key={`${promotion.name}-${index}`} value={promotion}>\n {children}\n </PromotionItemContext>\n ))}\n </div>\n );\n}\n\nexport function PricingPromotion({ template = '{name}', className, children, ...props }: PricingPromotionProps) {\n const promotion = usePromotionItem();\n const text = template.replace('{name}', promotion.name);\n\n return (\n <span {...props} className={className} data-fs-pricing-promotion=\"\">\n {children ?? text}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Skeleton\n// ---------------------------------------------------------------------------\n\nexport function PricingSkeleton({ className, ...props }: ComponentPropsWithRef<'div'>) {\n return (\n <div {...props} className={className} data-fs-pricing-skeleton=\"\" aria-hidden=\"true\">\n <span data-fs-pricing-skeleton-line=\"\" />\n <span data-fs-pricing-skeleton-line=\"\" />\n </div>\n );\n}\n\nPricingRoot.Skeleton = PricingSkeleton;\n\n// ---------------------------------------------------------------------------\n// Namespace export\n// ---------------------------------------------------------------------------\n\nexport const Pricing = {\n Root: PricingRoot,\n SellingPrice: PricingSellingPrice,\n ListPrice: PricingListPrice,\n SpotPrice: PricingSpotPrice,\n Installments: PricingInstallments,\n InstallmentPlans: PricingInstallmentPlans,\n InstallmentPlan: PricingInstallmentPlan,\n InstallmentsForPlan: PricingInstallmentsForPlan,\n Installment: PricingInstallment,\n PaymentMethodsTrigger: PricingPaymentMethodsTrigger,\n PaymentMethodsList: PricingPaymentMethodsList,\n PaymentMethodsTabList: PricingPaymentMethodsTabList,\n PaymentMethodsTabPanels: PricingPaymentMethodsTabPanels,\n PaymentMethodName: PricingPaymentMethodName,\n Discount: PricingDiscount,\n SpotDiscount: PricingSpotDiscount,\n Highlights: PricingHighlights,\n Highlight: PricingHighlight,\n Promotions: PricingPromotions,\n Promotion: PricingPromotion,\n Skeleton: PricingSkeleton,\n};\n"],"mappings":"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"}