create-cartbase 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -147,10 +147,12 @@ curl -sf -X POST "$BASE/api/store/shipping-options/$SO_ID/calculate" \
|
|
|
147
147
|
|
|
148
148
|
- **Purpose** — render the payment-method picker.
|
|
149
149
|
- **Auth** — anon `x-client-id`.
|
|
150
|
-
- **Request** — `GET ?region_id=…&cart_id=…`,
|
|
150
|
+
- **Request** — `GET ?region_id=…&cart_id=…&shipping_option_id=…`, all optional. Without
|
|
151
151
|
`region_id`: the tenant's enabled providers (global catalog ∩ tenant
|
|
152
152
|
enablement). With it: providers linked to that region. `cart_id` feeds
|
|
153
153
|
the rules engine — storefronts SHOULD pass it during checkout.
|
|
154
|
+
`shipping_option_id` evaluates a prospective delivery click immediately,
|
|
155
|
+
before its separate cart-preference write finishes.
|
|
154
156
|
- **Response** — list envelope, full filtered list. Two entry shapes share
|
|
155
157
|
the array: connected PROCESSORS (`{id}` — pp_stripe) and merchant
|
|
156
158
|
payment METHODS (`{payment_method_id, name, kind, instructions,
|
|
@@ -174,6 +176,13 @@ curl -sf -X POST "$BASE/api/store/shipping-options/$SO_ID/calculate" \
|
|
|
174
176
|
"fee_amount": 4.99, "fee_label": "COD fee" }
|
|
175
177
|
// pp_giftcard is INTERNAL tender and is never listed
|
|
176
178
|
],
|
|
179
|
+
"payment_providers_by_shipping_option": {
|
|
180
|
+
"so_boxnow": [{ "id": "pp_stripe", "is_enabled": true }],
|
|
181
|
+
"so_speedy": [
|
|
182
|
+
{ "id": "pp_stripe", "is_enabled": true },
|
|
183
|
+
{ "payment_method_id": "pm_cod", "name": "Cash on delivery", "kind": "cod" }
|
|
184
|
+
]
|
|
185
|
+
},
|
|
177
186
|
"count": 3, "offset": 0, "limit": 3
|
|
178
187
|
}
|
|
179
188
|
```
|
|
@@ -191,7 +200,16 @@ curl -sf -X POST "$BASE/api/store/shipping-options/$SO_ID/calculate" \
|
|
|
191
200
|
- **Errors** — none beyond the standard envelope (empty list when nothing
|
|
192
201
|
is enabled); initiate 400s on unknown/disabled/foreign method ids and
|
|
193
202
|
`payment_method_not_in_region` for an unclaimed region.
|
|
194
|
-
- **SDK** — `checkout.listPaymentProviders(client, {region_id, cart_id
|
|
203
|
+
- **SDK** — `checkout.listPaymentProviders(client, {region_id, cart_id,
|
|
204
|
+
shipping_option_id})`.
|
|
205
|
+
- **Delivery-dependent payment rules** — selecting a delivery option is
|
|
206
|
+
remembered on the cart before the atomic Buy call. The initial listing's
|
|
207
|
+
`payment_providers_by_shipping_option` map is evaluated by the server from
|
|
208
|
+
the same cart context and live rules. `CheckoutClient` selects the mapped
|
|
209
|
+
list synchronously on every carrier click; older fallback responses are
|
|
210
|
+
discarded, and remembered choices are serialized with latest-intent wins.
|
|
211
|
+
The completion guard repeats the decision against the attached shipping
|
|
212
|
+
method.
|
|
195
213
|
- **Components** — payment picker.
|
|
196
214
|
- **Settings** — Stripe connects in Settings, Payments (provisions
|
|
197
215
|
`pp_stripe` + credentials); payment methods live in the same screen
|
|
@@ -433,11 +433,15 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
433
433
|
`customers.updateMe` (best-effort profile sync incl. Cartbase's first-class
|
|
434
434
|
`company_name`/`company_eik`), `checkout.calculateShippingOption`
|
|
435
435
|
(calculated-rate forward-compat), `checkout.prepareCheckout`,
|
|
436
|
-
`checkout.syncPaymentAmount` (exposed + fired on payment-tab switch with
|
|
437
|
-
the new `provider_id`), `checkout.refreshPaymentIfTerminal` (exposed —
|
|
438
|
-
call REACTIVELY from Elements `loaderror` only),
|
|
439
|
-
-
|
|
440
|
-
|
|
436
|
+
`checkout.syncPaymentAmount` (exposed + fired on payment-tab switch with
|
|
437
|
+
the new `provider_id`), `checkout.refreshPaymentIfTerminal` (exposed —
|
|
438
|
+
call REACTIVELY from Elements `loaderror` only),
|
|
439
|
+
the server-evaluated payment availability map from
|
|
440
|
+
`checkout.listPaymentProviders` so delivery-option payment rules update
|
|
441
|
+
synchronously; a prospective-option request is the fallback for older hosts,
|
|
442
|
+
`carts.completeCart`.
|
|
443
|
+
- **Props contract** — `{client, cart, customer, availableShippingMethods,
|
|
444
|
+
availablePaymentMethods, paymentMethodsByShippingOption?, countryCode?, countries?, paymentMethodFilter?,
|
|
441
445
|
orderConfirmedPath?, onOrderPlaced?,
|
|
442
446
|
resolveTrackingMetadata?, logError?}`. `countries` is OPTIONAL and is an
|
|
443
447
|
override: omit it and the hook calls `GET /api/store/countries` itself, so
|
|
@@ -471,7 +475,8 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
471
475
|
fetches `listShippingOptions`/`listPaymentProviders` (+ customer, +
|
|
472
476
|
`getIntegrationsConfig().cod`) and passes them down.
|
|
473
477
|
- **Props contract** — hook options + `showGiftCards?`,
|
|
474
|
-
`
|
|
478
|
+
`showSecureCheckout?`, `paymentMarks?`, `termsContent?`,
|
|
479
|
+
`logoByFulfillmentOptionId?`, Stripe `appearance`/`fonts`, `onCartChange?`
|
|
475
480
|
(receives every decorated cart from summary mutations; the layout also
|
|
476
481
|
re-runs `syncPaymentAmount` on those).
|
|
477
482
|
- **Mount rules** — `"use client"`; inside `CheckoutProvider`; redirect
|
|
@@ -528,9 +533,13 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
528
533
|
|
|
529
534
|
### `<CheckoutShippingMethodList />` — `checkout/shipping-method-list`
|
|
530
535
|
|
|
531
|
-
- **Purpose** — radio list of shipping options with inline carrier-picker
|
|
532
|
-
expansion, free-shipping label, optional per-carrier logos, optional
|
|
533
|
-
read-only price preview pre-address (`previewWhenAddressNotReady`).
|
|
536
|
+
- **Purpose** — radio list of shipping options with inline carrier-picker
|
|
537
|
+
expansion, free-shipping label, optional per-carrier logos, optional
|
|
538
|
+
read-only price preview pre-address (`previewWhenAddressNotReady`).
|
|
539
|
+
- **Presentation** — visible shipping-option titles are uppercase so merchant
|
|
540
|
+
and carrier naming conventions do not create mixed capitalization in one
|
|
541
|
+
list. An unselected option keeps its card background and uses the primary
|
|
542
|
+
border color on hover.
|
|
534
543
|
- **SDK calls** — renders `checkout.listShippingOptions(client, {cart_id})`
|
|
535
544
|
rows AS SERVED (rule-filtering + `checkout_method_order` are server-side).
|
|
536
545
|
- **Props contract** — hook state + `logoByFulfillmentOptionId?` as an
|
|
@@ -560,8 +569,11 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
560
569
|
- **Purpose** — THE pickup picker, every carrier, mounted by
|
|
561
570
|
`CheckoutClient` when the option's adapter says its destination is an
|
|
562
571
|
office or locker. Nearest three by haversine distance to the typed address, each
|
|
563
|
-
with its distance, and a door to search the whole catalogue. The shape
|
|
564
|
-
Alenika's checkout has carried since it was built.
|
|
572
|
+
with its distance, and a door to search the whole catalogue. The shape
|
|
573
|
+
Alenika's checkout has carried since it was built. Primary office and locker
|
|
574
|
+
names render uppercase across carriers; secondary addresses retain their
|
|
575
|
+
source casing. Point rows stay on the card surface and show only a primary
|
|
576
|
+
border on hover.
|
|
565
577
|
- **SDK calls** — `integrations.listPickupPoints(client, provider, {mode,
|
|
566
578
|
catalogue: true, locale})`, one door for all carriers. The complete eligible
|
|
567
579
|
catalogue is cached per SDK client, carrier, mode and language for ten
|
|
@@ -630,7 +642,12 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
630
642
|
is on screen from arrival and the Buy button carries the gate, naming the
|
|
631
643
|
missing step; pass true for the older dimmed-until-delivery flow),
|
|
632
644
|
`beforePaymentButton?` slot, `total` (pass `optimisticTotal`),
|
|
633
|
-
`nothingToPay?` (pass the hook's), `
|
|
645
|
+
`nothingToPay?` (pass the hook's), `paymentMarks?` (the ordered result of
|
|
646
|
+
`getPaymentMarks`), `termsContent?` (the store's own linked policy notice),
|
|
647
|
+
`logError?`. Payment tabs follow the server's checkout-method order. The
|
|
648
|
+
offline tab prints the configured method name and instructions; the
|
|
649
|
+
connected processor tab shows up to three enabled payment marks and a
|
|
650
|
+
`+N` remainder.
|
|
634
651
|
- **An order that asks for no money** (2026-09-18) — with `nothingToPay` the
|
|
635
652
|
rail is replaced by one line saying the order is covered and the button
|
|
636
653
|
becomes **Complete order**, carrying no amount and waiting on no card
|
|
@@ -663,7 +680,7 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
663
680
|
|
|
664
681
|
- **Purpose** — items (flat rows, READ-ONLY), promo + gift-card widgets,
|
|
665
682
|
totals breakdown (subtotal / shipping / COD fee / discount / total +
|
|
666
|
-
gift-card tender rows UNDER the unchanged total), secure badge.
|
|
683
|
+
gift-card tender rows UNDER the unchanged total), optional secure badge.
|
|
667
684
|
`LineItemCard` is the standalone card variant.
|
|
668
685
|
- **A CHECKOUT IS A CHECKOUT** (2026-09-18) — the rows carry no quantity
|
|
669
686
|
control and call no cart endpoint. The order is stated here and changed in
|
|
@@ -686,7 +703,8 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
686
703
|
`tax_total`, `total`, `gift_card_total`, `gift_card_remainder`.
|
|
687
704
|
- **Props contract** — `{client, cart, optimisticShippingCost,
|
|
688
705
|
onOptimisticShippingClear?, optimisticMethodFee?,
|
|
689
|
-
onOptimisticMethodFeeClear?, methodFeeLabel?, showGiftCards?,
|
|
706
|
+
onOptimisticMethodFeeClear?, methodFeeLabel?, showGiftCards?,
|
|
707
|
+
showSecureCheckout?,
|
|
690
708
|
onCartChange?}`. Optimistic values clear automatically once the server
|
|
691
709
|
cart catches up.
|
|
692
710
|
- **The numbers** — every figure comes from `checkoutTotals`
|
|
@@ -713,7 +731,9 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
713
731
|
`<MobileOrderSummaryBody />`: the items with their quantity pills, the
|
|
714
732
|
code and gift-card doors, then subtotal, shipping, the method fee,
|
|
715
733
|
discount, VAT and the gift-card tender pair. The grand total is not
|
|
716
|
-
repeated inside, because the bar's own row carries it open or closed.
|
|
734
|
+
repeated inside, because the bar's own row carries it open or closed.
|
|
735
|
+
The top bar and its open body use the normal card surface, preserving the
|
|
736
|
+
contrast of item copy, widgets and totals on small screens.
|
|
717
737
|
- **Mount rules** — `CheckoutClient` mounts both (the bottom one through
|
|
718
738
|
`beforePaymentButton`, with `hideDiscount`, beside an always-open
|
|
719
739
|
`DiscountSection`, because a code field two taps deep inside a closed bar
|
|
@@ -731,10 +751,11 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
731
751
|
|
|
732
752
|
### `<DiscountSection />` — `checkout/discount-section`
|
|
733
753
|
|
|
734
|
-
- **Purpose** — promo-code input + applied-promotion list (percentage or
|
|
735
|
-
fixed amount display). Collapsed behind its own door by default;
|
|
736
|
-
`alwaysOpen` renders the field itself, which is what the checkout passes
|
|
737
|
-
on a phone.
|
|
754
|
+
- **Purpose** — promo-code input + applied-promotion list (percentage or
|
|
755
|
+
fixed amount display). Collapsed behind its own door by default;
|
|
756
|
+
`alwaysOpen` renders the field itself, which is what the checkout passes
|
|
757
|
+
on a phone. The door and open field use bounded grids: the action never
|
|
758
|
+
wraps or escapes the card, and the supporting line is hidden below 380px.
|
|
738
759
|
- **SDK calls** — `POST /api/store/carts/:id/promotions {promo_codes}`
|
|
739
760
|
via the client transport (additive apply; the carts SDK module ships no
|
|
740
761
|
wrapper for this route yet — see [carts.md](carts.md) for the cart
|
|
@@ -748,9 +769,10 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
748
769
|
|
|
749
770
|
### `<GiftCardSection />` — `checkout/gift-card-section`
|
|
750
771
|
|
|
751
|
-
- **Purpose** — gift-card code input + applied-cards chips (masked
|
|
752
|
-
`••••last4`, per-card live coverage, remove). Cartbase-new — no legacy
|
|
753
|
-
equivalent.
|
|
772
|
+
- **Purpose** — gift-card code input + applied-cards chips (masked
|
|
773
|
+
`••••last4`, per-card live coverage, remove). Cartbase-new — no legacy
|
|
774
|
+
equivalent. Its narrow-screen door follows the same bounded grid as the
|
|
775
|
+
promo door, so the label cannot turn the action into a four-line row.
|
|
754
776
|
- **SDK calls** — `giftCards.applyGiftCard` / `giftCards.removeGiftCard`
|
|
755
777
|
([gift-cards.md](gift-cards.md)). Renders `cart.gift_cards[]` /
|
|
756
778
|
`gift_card_total` / `gift_card_remainder` — server truth, no client
|
|
@@ -17,10 +17,12 @@ export function CheckoutPageClient({
|
|
|
17
17
|
cart,
|
|
18
18
|
shippingOptions,
|
|
19
19
|
paymentProviders,
|
|
20
|
+
paymentMethodsByShippingOption,
|
|
20
21
|
}: {
|
|
21
22
|
cart: Cart
|
|
22
23
|
shippingOptions: StoreShippingOption[]
|
|
23
24
|
paymentProviders: StorePaymentEntry[]
|
|
25
|
+
paymentMethodsByShippingOption?: Record<string, StorePaymentEntry[]>
|
|
24
26
|
}) {
|
|
25
27
|
const router = useRouter()
|
|
26
28
|
|
|
@@ -32,6 +34,7 @@ export function CheckoutPageClient({
|
|
|
32
34
|
customer={null}
|
|
33
35
|
availableShippingMethods={shippingOptions}
|
|
34
36
|
availablePaymentMethods={paymentProviders}
|
|
37
|
+
paymentMethodsByShippingOption={paymentMethodsByShippingOption}
|
|
35
38
|
// NO COUNTRY LIST HERE, on purpose (2026-09-13). This file is the
|
|
36
39
|
// seed for every scaffolded store, and it used to pass
|
|
37
40
|
// `countries={[{iso_2:"bg", display_name:"Bulgaria"}]}` with
|
|
@@ -61,8 +61,11 @@ async function Checkout() {
|
|
|
61
61
|
return (
|
|
62
62
|
<CheckoutPageClient
|
|
63
63
|
cart={cart}
|
|
64
|
-
shippingOptions={shippingOptions.shipping_options}
|
|
65
|
-
paymentProviders={paymentProviders.payment_providers}
|
|
64
|
+
shippingOptions={shippingOptions.shipping_options}
|
|
65
|
+
paymentProviders={paymentProviders.payment_providers}
|
|
66
|
+
paymentMethodsByShippingOption={
|
|
67
|
+
paymentProviders.payment_providers_by_shipping_option
|
|
68
|
+
}
|
|
66
69
|
/>
|
|
67
70
|
)
|
|
68
71
|
}
|