@cartbase/storefront 0.1.2 → 0.3.0

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 (106) hide show
  1. package/README.md +3 -3
  2. package/package.json +231 -226
  3. package/src/api/auth.ts +1 -1
  4. package/src/api/carts.ts +5 -3
  5. package/src/api/checkout.ts +91 -40
  6. package/src/api/consent.ts +2 -2
  7. package/src/api/integrations.ts +4 -17
  8. package/src/api/regions.ts +1 -1
  9. package/src/cart-drawer/context.tsx +4 -4
  10. package/src/cart-drawer/cross-sell-carousel.tsx +1 -1
  11. package/src/cart-drawer/cross-sell-sidebar.tsx +1 -1
  12. package/src/cart-drawer/header.tsx +1 -1
  13. package/src/cart-drawer/item/index.tsx +2 -2
  14. package/src/cart-drawer/item/quantity.tsx +2 -2
  15. package/src/cart-drawer/item/upsell.tsx +3 -3
  16. package/src/cart-drawer/item/variant.tsx +2 -2
  17. package/src/cart-drawer/labels-bg.ts +2 -2
  18. package/src/cart-drawer/labels.ts +119 -119
  19. package/src/cart-drawer/summary-breakdown.tsx +197 -196
  20. package/src/cart-drawer/template.tsx +2 -2
  21. package/src/cart-drawer/tiered-progress.tsx +1 -1
  22. package/src/checkout/address-error-copy.ts +3 -3
  23. package/src/checkout/address-form.tsx +2 -2
  24. package/src/checkout/address-select.tsx +1 -1
  25. package/src/checkout/boxnow-locker-selector.tsx +3 -3
  26. package/src/checkout/checkout-client.tsx +15 -12
  27. package/src/checkout/company-details.tsx +1 -1
  28. package/src/checkout/compare-addresses.ts +1 -1
  29. package/src/checkout/discount-section.tsx +5 -5
  30. package/src/checkout/econt-office-selector.tsx +2 -2
  31. package/src/checkout/gift-card-section.tsx +2 -2
  32. package/src/checkout/index.ts +0 -1
  33. package/src/checkout/labels-bg.ts +2 -2
  34. package/src/checkout/labels.ts +263 -263
  35. package/src/checkout/line-item-card.tsx +2 -2
  36. package/src/checkout/order-summary.tsx +48 -48
  37. package/src/checkout/payment-button.tsx +4 -4
  38. package/src/checkout/payment-error-copy.ts +6 -6
  39. package/src/checkout/payment-method-list.tsx +93 -33
  40. package/src/checkout/payment-wrapper.tsx +8 -11
  41. package/src/checkout/promotion-error-copy.ts +2 -2
  42. package/src/checkout/shipping-method-list.tsx +2 -2
  43. package/src/checkout/stripe-wrapper.tsx +1 -1
  44. package/src/checkout/use-checkout-orchestration.ts +108 -98
  45. package/src/common/cart-button-client.tsx +1 -1
  46. package/src/common/cart-button.tsx +1 -1
  47. package/src/common/country-select.tsx +2 -2
  48. package/src/common/delete-button.tsx +1 -1
  49. package/src/common/index.ts +1 -1
  50. package/src/common/language-select.tsx +2 -2
  51. package/src/common/localized-link.tsx +1 -1
  52. package/src/lib/cart-helpers.ts +2 -2
  53. package/src/lib/cookie-names.ts +41 -0
  54. package/src/lib/get-product-price.ts +3 -3
  55. package/src/lib/payment-constants.ts +53 -66
  56. package/src/lib/store-api-error.ts +1 -1
  57. package/src/order/index.ts +1 -1
  58. package/src/order/labels-bg.ts +39 -39
  59. package/src/order/labels.ts +79 -79
  60. package/src/order/order-address-card.tsx +1 -1
  61. package/src/order/order-completed-template.tsx +20 -12
  62. package/src/order/order-confirmation-header.tsx +1 -1
  63. package/src/order/order-delivery-card.tsx +3 -3
  64. package/src/order/order-item.tsx +2 -2
  65. package/src/order/order-items-list.tsx +3 -3
  66. package/src/order/order-payment-card.tsx +27 -36
  67. package/src/order/order-timeline.tsx +2 -2
  68. package/src/order/order-totals.tsx +250 -245
  69. package/src/platform/identity.ts +18 -0
  70. package/src/platform/index.ts +8 -0
  71. package/src/platform/metadata.ts +26 -0
  72. package/src/platform/platform-init.tsx +46 -0
  73. package/src/products/image-gallery.tsx +1 -1
  74. package/src/products/mobile-actions.tsx +1 -1
  75. package/src/products/option-select.tsx +1 -1
  76. package/src/products/preview-price.tsx +1 -1
  77. package/src/products/product-actions.tsx +6 -6
  78. package/src/products/product-info.tsx +1 -1
  79. package/src/products/product-preview.tsx +1 -1
  80. package/src/products/product-price.tsx +2 -2
  81. package/src/products/product-tabs.tsx +1 -1
  82. package/src/products/purchase-options.tsx +1 -1
  83. package/src/products/related-products.tsx +3 -3
  84. package/src/products/variant-matching.ts +4 -4
  85. package/src/reviews-ui/labels.ts +1 -1
  86. package/src/reviews-ui/photo-upload.tsx +1 -1
  87. package/src/reviews-ui/review-list.tsx +1 -1
  88. package/src/reviews-ui/review-widget.tsx +1 -1
  89. package/src/reviews-ui/review-wizard.tsx +1 -1
  90. package/src/reviews-ui/wizard-state.ts +1 -1
  91. package/src/store/category-template.tsx +2 -2
  92. package/src/store/collection-template.tsx +2 -2
  93. package/src/store/labels.ts +2 -2
  94. package/src/store/paginated-products.tsx +1 -1
  95. package/src/store/search-params.ts +1 -1
  96. package/src/store/search-template.tsx +1 -1
  97. package/src/tracking/consent-banner.tsx +1 -1
  98. package/src/tracking/consent-init.tsx +1 -1
  99. package/src/tracking/consent.ts +6 -6
  100. package/src/tracking/fbq.ts +2 -2
  101. package/src/tracking/get-tracking-attribution.ts +1 -1
  102. package/src/tracking/get-tracking-config.ts +2 -2
  103. package/src/tracking/index.ts +2 -2
  104. package/src/tracking/meta-pixel.tsx +1 -1
  105. package/src/tracking/rybbit.tsx +1 -1
  106. package/src/tracking/types.ts +6 -6
@@ -29,7 +29,7 @@ import { isProductLine } from "../lib/cart-helpers"
29
29
  * body inside a `<CartDrawer>` shell. That way the store owns its
30
30
  * composition and still gets library updates to every primitive.
31
31
  *
32
- * Ported from `@1click/ui/src/cart-drawer/template.tsx` (v2.3.1). Barter
32
+ * Ported from `@1click/ui/src/cart-drawer/template.tsx` (v2.3.1). Cartbase
33
33
  * adaptations:
34
34
  * - Amounts are EUR major units — `rewards.pointsPerCurrency` is points
35
35
  * per 1 EUR (the source's `/100` minor-unit division is gone), and
@@ -130,7 +130,7 @@ export function CartDrawerTemplate({
130
130
  .finally(() => setCrossSellLoaded(true))
131
131
  }, [hasItems, crossSellLoaded, config.crossSell?.loader])
132
132
 
133
- // Cross-sell add → the provider's SDK addItem (barter adds by variant
133
+ // Cross-sell add → the provider's SDK addItem (Cartbase adds by variant
134
134
  // id). Cards built without a variantId no-op.
135
135
  const handleCrossSellAdd = useCallback(
136
136
  (_productId: string, variantId?: string) => {
@@ -11,7 +11,7 @@ import { useCartDrawer } from "./context"
11
11
  * originally extracted from mindpages-storefront
12
12
  * src/modules/cart-drawer/cart-tiered-progress.tsx.
13
13
  *
14
- * Barter money note: `cart.total` and tier `threshold`s are EUR decimal
14
+ * Cartbase money note: `cart.total` and tier `threshold`s are EUR decimal
15
15
  * major units (e.g. `{ threshold: 50 }` = €50) — configure tiers in major
16
16
  * units, not cents.
17
17
  */
@@ -3,7 +3,7 @@
3
3
  * checkout address surface.
4
4
  *
5
5
  * Ported from `@1click/ui/src/checkout/address-error-copy.ts` (v2.3.1) and
6
- * adapted to the barter error envelope: `StoreApiError` carries a structured
6
+ * adapted to the Cartbase error envelope: `StoreApiError` carries a structured
7
7
  * `code` (POST /api/store/carts/:id — docs/storefront/carts.md), so
8
8
  * translation is code-first; the substring patterns stay as the fallback for
9
9
  * network failures and any legacy wire.
@@ -20,7 +20,7 @@ const NETWORK_FALLBACK =
20
20
  "Няма връзка със сървъра. Моля, проверете интернет връзката и опитайте отново."
21
21
 
22
22
  /**
23
- * Barter cart-update error codes → BG copy (POST /api/store/carts/:id,
23
+ * Cartbase cart-update error codes → BG copy (POST /api/store/carts/:id,
24
24
  * docs/storefront/carts.md). Code-first, matched before any pattern.
25
25
  */
26
26
  export const ADDRESS_ERROR_CODE_COPY: Record<string, string> = {
@@ -76,7 +76,7 @@ const PATTERNS: Array<{ match: RegExp; copy: string }> = [
76
76
  copy: NETWORK_FALLBACK,
77
77
  },
78
78
  // The Next.js canned Server Components production message — surface a
79
- // clean fallback instead of the English placeholder. (The barter SDK
79
+ // clean fallback instead of the English placeholder. (The Cartbase SDK
80
80
  // throws from the browser, so this only fires for stores that proxy the
81
81
  // save through a server action.)
82
82
  {
@@ -17,9 +17,9 @@ import { ErrorMessage } from "./error-message"
17
17
  * (`CheckoutClient` / `useCheckoutOrchestration`).
18
18
  *
19
19
  * Ported from `@1click/ui/src/checkout/address-form.tsx` (v2.3.1) with the
20
- * barter type seam only: `@medusajs/types` → the SDK's `CustomerAddress` /
20
+ * Cartbase type seam only: `@medusajs/types` → the SDK's `CustomerAddress` /
21
21
  * `CartAddress` partials. The `countries` list comes from the orchestration
22
- * hook's `regionCountries` — barter regions carry NO embedded countries
22
+ * hook's `regionCountries` — Cartbase regions carry NO embedded countries
23
23
  * array (api/regions.ts divergence), so the host supplies the list via the
24
24
  * hook's `countries` option (single-entry `countryCode` fallback).
25
25
  */
@@ -15,7 +15,7 @@ import { useCheckoutLabels } from "./context"
15
15
  * replace this one file locally.
16
16
  *
17
17
  * Ported from `@1click/ui/src/checkout/address-select.tsx` (v2.3.1) with
18
- * the barter type seam: `@medusajs/types` address DTOs → the SDK's
18
+ * the Cartbase type seam: `@medusajs/types` address DTOs → the SDK's
19
19
  * `CustomerAddress` (GET /api/store/customers/me — addresses embedded,
20
20
  * docs/storefront/customers.md) and `CartAddress` partials. Field names are
21
21
  * identical across both wires, so the compare/format logic is unchanged.
@@ -17,11 +17,11 @@ import { useCheckoutLabels } from "./context"
17
17
  * BoxNowLockerSelector — full BoxNow locker picker for Bulgarian shipping.
18
18
  *
19
19
  * Ported from `@1click/ui/src/checkout/boxnow-locker-selector.tsx` (v2.3.1)
20
- * with the barter data seam: the locker directory comes from
20
+ * with the Cartbase data seam: the locker directory comes from
21
21
  * `listBoxNowLockers(client)` (`@cartbase/storefront/api/integrations`,
22
22
  * GET /api/store/integrations/boxnow/lockers — backend owns BoxNow API auth
23
23
  * + the 10-min cache; docs/storefront/integrations.md). The @1click data
24
- * helper returned `{ok, lockers}`; the barter SDK THROWS on 503 (not
24
+ * helper returned `{ok, lockers}`; the Cartbase SDK THROWS on 503 (not
25
25
  * configured) / 502 (carrier failure), so the fetch wrapper catches and
26
26
  * maps both to the same "temporarily unavailable" state. Availability
27
27
  * should be discovered via `carriers.boxnow.lockers_url` on the
@@ -38,7 +38,7 @@ import { useCheckoutLabels } from "./context"
38
38
  * - title (not name)
39
39
  * - addressLine1 / addressLine2 (not address.street/num)
40
40
  * - postalCode (not address.city.name)
41
- * - lat / lng on the root (numbers or null — the barter route coerces
41
+ * - lat / lng on the root (numbers or null — the Cartbase route coerces
42
42
  * malformed carrier coordinates to null, never NaN)
43
43
  * - No isAPS / code / phones
44
44
  *
@@ -13,7 +13,6 @@ import { CheckoutShippingMethodList } from "./shipping-method-list"
13
13
  import { PaymentWrapper } from "./payment-wrapper"
14
14
  import {
15
15
  useCheckoutOrchestration,
16
- type CheckoutCodConfig,
17
16
  type CheckoutLogError,
18
17
  type PaymentProviderLike,
19
18
  } from "./use-checkout-orchestration"
@@ -27,7 +26,7 @@ import {
27
26
  * automatically.
28
27
  *
29
28
  * Ported from `@1click/ui/src/checkout/checkout-client.tsx` (v2.3.1) with
30
- * the barter data seam:
29
+ * the Cartbase data seam:
31
30
  *
32
31
  * - Takes the SDK `client` — every server call (address autosave,
33
32
  * prepare-checkout, sync, complete, promo/gift-card apply, quantity
@@ -35,9 +34,9 @@ import {
35
34
  * - The listings arrive as SDK DTOs: `listShippingOptions` /
36
35
  * `listPaymentProviders` (both rule-filtered server-side) — fetch them
37
36
  * in the host and pass down (docs/storefront/checkout.md).
38
- * - `codConfig` = the integrations config `cod` block
39
- * (`getIntegrationsConfig(client).cod`) the COD fee prediction is
40
- * NEVER hardcoded (docs/storefront/integrations.md).
37
+ * - Fee prediction is NEVER hardcoded: the payment listing entries carry
38
+ * each method's own `fee_amount`/`fee_label` (the integrations `cod`
39
+ * block died 2026-08-11 — any method may carry a fee).
41
40
  * - `onCartChange` closes the loop for summary mutations: the decorated
42
41
  * cart returned by promo/gift-card/quantity calls is handed up so the
43
42
  * host updates its cart state (`router.refresh()` in an RSC app) AND
@@ -55,14 +54,12 @@ type CheckoutClientProps = {
55
54
  availableShippingMethods: StoreShippingOption[] | null
56
55
  availablePaymentMethods: PaymentProviderLike[] | null
57
56
  countryCode: string
58
- /** Countries for the address form (barter regions embed none). */
57
+ /** Countries for the address form (Cartbase regions embed none). */
59
58
  countries?: Array<{ iso_2: string; display_name: string }>
60
59
  paymentMethodFilter?: (
61
60
  methods: PaymentProviderLike[] | null,
62
61
  selectedShippingOption: StoreShippingOption | null
63
62
  ) => PaymentProviderLike[] | null
64
- /** The integrations config `cod` block — drives the optimistic COD fee. */
65
- codConfig?: CheckoutCodConfig
66
63
  /** Show the gift-card widget in the summary (default true). */
67
64
  showGiftCards?: boolean
68
65
  logoByFulfillmentOptionId?: Record<string, { src: string; alt: string }>
@@ -81,6 +78,12 @@ type CheckoutClientProps = {
81
78
  logError?: CheckoutLogError
82
79
  /** Receives every decorated cart returned by a summary mutation. */
83
80
  onCartChange?: (cart: Cart) => void
81
+ /**
82
+ * Extra payment tabs forwarded to CheckoutPaymentMethodList — the seam
83
+ * for embedded third-party providers rendered in the same radio-card
84
+ * style as card/cod. See the prop's JSDoc there.
85
+ */
86
+ extraPaymentTabs?: Array<{ id: string; label: string; content: React.ReactNode }>
84
87
  }
85
88
 
86
89
  export function CheckoutClient({
@@ -92,7 +95,6 @@ export function CheckoutClient({
92
95
  countryCode,
93
96
  countries,
94
97
  paymentMethodFilter,
95
- codConfig,
96
98
  showGiftCards = true,
97
99
  logoByFulfillmentOptionId,
98
100
  appearance,
@@ -102,6 +104,7 @@ export function CheckoutClient({
102
104
  resolveTrackingMetadata,
103
105
  logError,
104
106
  onCartChange,
107
+ extraPaymentTabs,
105
108
  }: CheckoutClientProps) {
106
109
  const o = useCheckoutOrchestration({
107
110
  client,
@@ -112,7 +115,6 @@ export function CheckoutClient({
112
115
  countryCode,
113
116
  countries,
114
117
  paymentMethodFilter,
115
- codConfig,
116
118
  orderConfirmedPath,
117
119
  onOrderPlaced,
118
120
  resolveTrackingMetadata,
@@ -195,6 +197,7 @@ export function CheckoutClient({
195
197
  }
196
198
  total={o.optimisticTotal}
197
199
  logError={logError}
200
+ extraTabs={extraPaymentTabs}
198
201
  />
199
202
  </div>
200
203
 
@@ -208,8 +211,8 @@ export function CheckoutClient({
208
211
  onOptimisticShippingClear={() =>
209
212
  o.setOptimisticShippingCost(null)
210
213
  }
211
- optimisticCodFee={o.optimisticCodFee}
212
- onOptimisticCodFeeClear={() => o.setOptimisticCodFee(null)}
214
+ optimisticMethodFee={o.optimisticMethodFee}
215
+ onOptimisticMethodFeeClear={() => o.setOptimisticMethodFee(null)}
213
216
  showGiftCards={showGiftCards}
214
217
  onCartChange={handleCartChange}
215
218
  />
@@ -13,7 +13,7 @@ import { useCheckoutLabels } from "./context"
13
13
  * Ported from `@1click/ui/src/checkout/company-details.tsx` (v2.3.1)
14
14
  * unchanged — pure form UI; the values ride `formData` and the
15
15
  * orchestration hook persists them into `cart.metadata`
16
- * (company_name/company_vat/company_mol/company_address). Barter upgrade
16
+ * (company_name/company_vat/company_mol/company_address). Cartbase upgrade
17
17
  * over the @1click KNOWN_ISSUES state: the hook ALSO syncs
18
18
  * `company_name`/`company_eik` onto the signed-in customer profile
19
19
  * (PATCH /api/store/customers/me — first-class columns,
@@ -3,7 +3,7 @@
3
3
  * shipping-address fields. Returns true if every field matches.
4
4
  *
5
5
  * Ported from `@1click/ui/src/data/util/compare-addresses.ts` (v2.3.1)
6
- * unchanged. Lives in the checkout family because the barter SDK has no
6
+ * unchanged. Lives in the checkout family because the Cartbase SDK has no
7
7
  * data/util layer (the @1click data layer became `@cartbase/storefront/api`).
8
8
  * Extra file beyond the pre-declared export list → exported from the
9
9
  * family barrel only.
@@ -15,16 +15,16 @@ import { translatePromotionError } from "./promotion-error-copy"
15
15
  * amount.
16
16
  *
17
17
  * Ported from `@1click/ui/src/checkout/discount-section.tsx` (v2.3.1) with
18
- * the barter data seam:
18
+ * the Cartbase data seam:
19
19
  *
20
20
  * - `applyPromotions(codes)` (Medusa js-sdk server action, full-list
21
21
  * replace) → `POST /api/store/carts/:id/promotions {promo_codes}` — the
22
- * barter route is ADDITIVE (upserts each code's link, then re-applies),
22
+ * Cartbase route is ADDITIVE (upserts each code's link, then re-applies),
23
23
  * so only the NEW code is sent; already-applied codes stay put. The SDK
24
24
  * carts module ships no wrapper for this route yet, so the component
25
25
  * calls it through the client transport with the documented DTO
26
26
  * (verified against src/app/api/store/carts/[id]/promotions/route.ts).
27
- * - `cart.promotions` on the barter wire is the raw pivot embed
27
+ * - `cart.promotions` on the Cartbase wire is the raw pivot embed
28
28
  * (`[{promotion: {..., application_method}}]`) — unwrapped here, with a
29
29
  * flat-row fallback should the decoration ever flatten it.
30
30
  * - Errors are code-first (`promotion_not_found` / `promotion_inactive` /
@@ -46,7 +46,7 @@ type AppliedPromotion = {
46
46
  } | null
47
47
  }
48
48
 
49
- /** Unwrap the barter pivot embed; tolerate an already-flat row. */
49
+ /** Unwrap the Cartbase pivot embed; tolerate an already-flat row. */
50
50
  function extractPromotions(cart: Cart): AppliedPromotion[] {
51
51
  const raw = (cart.promotions ?? []) as Array<Record<string, unknown>>
52
52
  return raw
@@ -84,7 +84,7 @@ export function DiscountSection({
84
84
  setLoading(true)
85
85
  setError("")
86
86
  try {
87
- // Additive apply — the barter route upserts the new code's link and
87
+ // Additive apply — the Cartbase route upserts the new code's link and
88
88
  // re-applies every cart promotion; already-applied codes stay.
89
89
  const { cart: updated } = await applyPromotions(client, cart.id, [code.trim()])
90
90
  onCartChange?.(updated)
@@ -10,13 +10,13 @@ import { useCheckoutLabels } from "./context"
10
10
  * EcontOfficeSelector — full Econt office picker for Bulgarian shipping.
11
11
  *
12
12
  * Ported from `@1click/ui/src/checkout/econt-office-selector.tsx` (v2.3.1)
13
- * verbatim — this component has NO barter data seam: the office directory
13
+ * verbatim — this component has NO Cartbase data seam: the office directory
14
14
  * comes straight from Econt's public Nomenclatures endpoint (client-side,
15
15
  * cached globally per page load), and the CHOSEN office is handed to the
16
16
  * orchestration hook, which writes it into `carrier_metadata` exactly once
17
17
  * at Buy click (POST /api/store/carts/:id/prepare-checkout —
18
18
  * docs/storefront/checkout.md). The geocode helpers moved into the checkout
19
- * family (`./geocode`) because the barter lib family doesn't ship one.
19
+ * family (`./geocode`) because the Cartbase lib family doesn't ship one.
20
20
  *
21
21
  * Behavior:
22
22
  * - On mount, fetches the full Econt offices list from the public Econt
@@ -15,8 +15,8 @@ import { translateGiftCardError } from "./payment-error-copy"
15
15
  * summary card, plus the applied-cards chip list (masked `last4`, per-card
16
16
  * coverage, remove).
17
17
  *
18
- * NEW in the barter port (no @1click equivalent — gift-card tender is a
19
- * barter feature, docs/storefront/gift-cards.md). Built in the
18
+ * NEW in the Cartbase port (no @1click equivalent — gift-card tender is a
19
+ * Cartbase feature, docs/storefront/gift-cards.md). Built in the
20
20
  * DiscountSection idiom so the two summary widgets read as one family.
21
21
  *
22
22
  * Contract discipline baked in:
@@ -45,7 +45,6 @@ export {
45
45
  useCheckoutOrchestration,
46
46
  resolveOrderConfirmedPath,
47
47
  type UseCheckoutOrchestrationOptions,
48
- type CheckoutCodConfig,
49
48
  type CheckoutLogError,
50
49
  type PaymentProviderLike,
51
50
  } from "./use-checkout-orchestration"
@@ -3,7 +3,7 @@ import type { CheckoutLabels } from "./labels"
3
3
  /**
4
4
  * Bulgarian translations for the checkout.
5
5
  *
6
- * Ported from `@1click/ui/src/checkout/labels-bg.ts` (v2.3.1) + the barter
6
+ * Ported from `@1click/ui/src/checkout/labels-bg.ts` (v2.3.1) + the Cartbase
7
7
  * gift-card keys. Strings match the originals from mindpages-storefront's
8
8
  * checkout-client monolith.
9
9
  *
@@ -73,7 +73,7 @@ export const bulgarianCheckoutLabels: CheckoutLabels = {
73
73
  discount: "Отстъпка",
74
74
  discountCode: "Код за отстъпка",
75
75
  discountSub: "Спестете с промо код",
76
- codFee: "Такса наложен платеж",
76
+ paymentMethodFee: "Такса за плащане",
77
77
  recommended: "Препоръчано за вас",
78
78
  recommendedSoon: "Скоро тук",
79
79
  recommendedSoonSub: "Персонализирани предложения за вас",