create-cartbase 0.1.25 → 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
|
|
@@ -529,9 +533,13 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
529
533
|
|
|
530
534
|
### `<CheckoutShippingMethodList />` — `checkout/shipping-method-list`
|
|
531
535
|
|
|
532
|
-
- **Purpose** — radio list of shipping options with inline carrier-picker
|
|
533
|
-
expansion, free-shipping label, optional per-carrier logos, optional
|
|
534
|
-
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.
|
|
535
543
|
- **SDK calls** — renders `checkout.listShippingOptions(client, {cart_id})`
|
|
536
544
|
rows AS SERVED (rule-filtering + `checkout_method_order` are server-side).
|
|
537
545
|
- **Props contract** — hook state + `logoByFulfillmentOptionId?` as an
|
|
@@ -561,8 +569,11 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
561
569
|
- **Purpose** — THE pickup picker, every carrier, mounted by
|
|
562
570
|
`CheckoutClient` when the option's adapter says its destination is an
|
|
563
571
|
office or locker. Nearest three by haversine distance to the typed address, each
|
|
564
|
-
with its distance, and a door to search the whole catalogue. The shape
|
|
565
|
-
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.
|
|
566
577
|
- **SDK calls** — `integrations.listPickupPoints(client, provider, {mode,
|
|
567
578
|
catalogue: true, locale})`, one door for all carriers. The complete eligible
|
|
568
579
|
catalogue is cached per SDK client, carrier, mode and language for ten
|
|
@@ -720,7 +731,9 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
720
731
|
`<MobileOrderSummaryBody />`: the items with their quantity pills, the
|
|
721
732
|
code and gift-card doors, then subtotal, shipping, the method fee,
|
|
722
733
|
discount, VAT and the gift-card tender pair. The grand total is not
|
|
723
|
-
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.
|
|
724
737
|
- **Mount rules** — `CheckoutClient` mounts both (the bottom one through
|
|
725
738
|
`beforePaymentButton`, with `hideDiscount`, beside an always-open
|
|
726
739
|
`DiscountSection`, because a code field two taps deep inside a closed bar
|
|
@@ -738,10 +751,11 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
738
751
|
|
|
739
752
|
### `<DiscountSection />` — `checkout/discount-section`
|
|
740
753
|
|
|
741
|
-
- **Purpose** — promo-code input + applied-promotion list (percentage or
|
|
742
|
-
fixed amount display). Collapsed behind its own door by default;
|
|
743
|
-
`alwaysOpen` renders the field itself, which is what the checkout passes
|
|
744
|
-
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.
|
|
745
759
|
- **SDK calls** — `POST /api/store/carts/:id/promotions {promo_codes}`
|
|
746
760
|
via the client transport (additive apply; the carts SDK module ships no
|
|
747
761
|
wrapper for this route yet — see [carts.md](carts.md) for the cart
|
|
@@ -755,9 +769,10 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
755
769
|
|
|
756
770
|
### `<GiftCardSection />` — `checkout/gift-card-section`
|
|
757
771
|
|
|
758
|
-
- **Purpose** — gift-card code input + applied-cards chips (masked
|
|
759
|
-
`••••last4`, per-card live coverage, remove). Cartbase-new — no legacy
|
|
760
|
-
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.
|
|
761
776
|
- **SDK calls** — `giftCards.applyGiftCard` / `giftCards.removeGiftCard`
|
|
762
777
|
([gift-cards.md](gift-cards.md)). Renders `cart.gift_cards[]` /
|
|
763
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
|
}
|