@cartbase/storefront 0.2.0 → 0.4.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.
- package/package.json +1 -1
- package/src/api/carts.ts +5 -3
- package/src/api/checkout.ts +93 -43
- package/src/api/integrations.ts +4 -17
- package/src/cart-drawer/labels-bg.ts +1 -1
- package/src/cart-drawer/labels.ts +119 -119
- package/src/cart-drawer/summary-breakdown.tsx +197 -196
- package/src/checkout/checkout-client.tsx +13 -10
- package/src/checkout/index.ts +0 -1
- package/src/checkout/labels-bg.ts +1 -1
- package/src/checkout/labels.ts +263 -263
- package/src/checkout/order-summary.tsx +45 -45
- package/src/checkout/payment-method-list.tsx +92 -32
- package/src/checkout/use-checkout-orchestration.ts +100 -92
- package/src/lib/payment-constants.ts +53 -66
- package/src/order/labels-bg.ts +39 -39
- package/src/order/labels.ts +79 -79
- package/src/order/order-completed-template.tsx +17 -9
- package/src/order/order-payment-card.tsx +26 -35
- package/src/order/order-totals.tsx +250 -245
|
@@ -23,9 +23,11 @@ import {
|
|
|
23
23
|
prepareCheckout,
|
|
24
24
|
refreshPaymentIfTerminal as refreshPaymentIfTerminalApi,
|
|
25
25
|
syncPaymentAmount as syncPaymentAmountApi,
|
|
26
|
+
isMethodEntry,
|
|
26
27
|
type PrepareCheckoutInput,
|
|
27
28
|
type RefreshPaymentResult,
|
|
28
|
-
type
|
|
29
|
+
type StorePaymentEntry,
|
|
30
|
+
type StorePaymentMethodEntry,
|
|
29
31
|
type StoreShippingOption,
|
|
30
32
|
type SyncPaymentAmountResult,
|
|
31
33
|
} from "../api/checkout"
|
|
@@ -35,8 +37,7 @@ import {
|
|
|
35
37
|
type StoreCustomer,
|
|
36
38
|
type UpdateCustomerInput,
|
|
37
39
|
} from "../api/customers"
|
|
38
|
-
import
|
|
39
|
-
import { isManual, isStripeLike } from "../lib/payment-constants"
|
|
40
|
+
import { isStripeLike } from "../lib/payment-constants"
|
|
40
41
|
import compareAddresses from "./compare-addresses"
|
|
41
42
|
import { translateAddressError } from "./address-error-copy"
|
|
42
43
|
import { translatePaymentError } from "./payment-error-copy"
|
|
@@ -70,13 +71,14 @@ import type { BoxNowLocker } from "../api/integrations"
|
|
|
70
71
|
* entirely — the cart completes on the gift session alone. The @1click
|
|
71
72
|
* original threw on a missing client_secret; Cartbase treats
|
|
72
73
|
* null-secret + null-provider as the documented gift path.
|
|
73
|
-
* -
|
|
74
|
-
* `
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
74
|
+
* - The payment method fee: CART-LEVEL decoration
|
|
75
|
+
* (`payment_method_fee_total` / `payment_method_fee_label`, folded into
|
|
76
|
+
* `cart.total` while a live method session exists) — not a
|
|
77
|
+
* metadata-flagged line item. ANY method may carry a fee; the optimistic
|
|
78
|
+
* prediction reads `fee_amount` off the selected LISTING entry (the
|
|
79
|
+
* integrations `cod` block died 2026-08-11).
|
|
80
|
+
* - Processor ids: `pp_stripe` exactly (lib/payment-constants); merchant
|
|
81
|
+
* methods have no provider id — sessions ride `payment_method_id`.
|
|
80
82
|
* - `logCheckoutError`/`logEvent` (Supabase-side sinks in @1click) have no
|
|
81
83
|
* Cartbase store endpoint — the hook takes an optional `logError` callback
|
|
82
84
|
* so stores wire their own sink; all production log points are kept.
|
|
@@ -93,11 +95,10 @@ import type { BoxNowLocker } from "../api/integrations"
|
|
|
93
95
|
* class of fork-rot bug structurally impossible.
|
|
94
96
|
*/
|
|
95
97
|
|
|
96
|
-
/**
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
export type PaymentProviderLike = StorePaymentProvider | { id: string }
|
|
98
|
+
/** A payable entry the hook accepts: a processor row (`{id}`) or a
|
|
99
|
+
* merchant-method row (`{payment_method_id, name, kind}`) — the two wire
|
|
100
|
+
* shapes of GET /api/store/payment-providers since the pp_* kill. */
|
|
101
|
+
export type PaymentProviderLike = StorePaymentEntry | { id: string }
|
|
101
102
|
|
|
102
103
|
export type CheckoutLogError = (
|
|
103
104
|
errorType: string,
|
|
@@ -128,13 +129,6 @@ export type UseCheckoutOrchestrationOptions = {
|
|
|
128
129
|
methods: PaymentProviderLike[] | null,
|
|
129
130
|
selectedShippingOption: StoreShippingOption | null
|
|
130
131
|
) => PaymentProviderLike[] | null
|
|
131
|
-
/**
|
|
132
|
-
* Optional cash-on-delivery configuration — pass the integrations config
|
|
133
|
-
* `cod` block (`getIntegrationsConfig(client).cod`). When present, the
|
|
134
|
-
* hook paints `optimisticCodFee` on tab-toggle so the totals row updates
|
|
135
|
-
* before the server-side fee (applied at prepare) arrives.
|
|
136
|
-
*/
|
|
137
|
-
codConfig?: CheckoutCodConfig
|
|
138
132
|
/**
|
|
139
133
|
* Order-confirmed redirect path template (`{id}` → order.id,
|
|
140
134
|
* `{country}` → shipping country). Falls back to the CheckoutProvider
|
|
@@ -194,12 +188,18 @@ const REQUIRED_ADDRESS_FIELDS = [
|
|
|
194
188
|
*/
|
|
195
189
|
const ADDRESS_AUTO_SAVE_DEBOUNCE_MS = 600
|
|
196
190
|
|
|
197
|
-
/**
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
191
|
+
/** The offline tab's tender: a merchant METHOD entry (pp_* kill). The COD
|
|
192
|
+
* method (kind 'cod') wins; any manual method serves as the offline tab
|
|
193
|
+
* when no COD switch is on. The entry carries its own fee for prediction. */
|
|
194
|
+
const findOfflineMethod = (
|
|
195
|
+
entries: PaymentProviderLike[] | null | undefined
|
|
196
|
+
): StorePaymentMethodEntry | null => {
|
|
197
|
+
const methods = (entries ?? []).filter(
|
|
198
|
+
(m): m is Extract<PaymentProviderLike, { payment_method_id: string }> =>
|
|
199
|
+
"payment_method_id" in m && isMethodEntry(m as StorePaymentEntry)
|
|
200
|
+
)
|
|
201
|
+
return methods.find((m) => m.kind === "cod") ?? methods[0] ?? null
|
|
202
|
+
}
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
205
|
* Snapshot the address-relevant subset of formData. Used to skip
|
|
@@ -250,7 +250,6 @@ export function useCheckoutOrchestration({
|
|
|
250
250
|
countryCode = "",
|
|
251
251
|
countries,
|
|
252
252
|
paymentMethodFilter,
|
|
253
|
-
codConfig,
|
|
254
253
|
orderConfirmedPath: orderConfirmedPathProp,
|
|
255
254
|
onOrderPlaced,
|
|
256
255
|
resolveTrackingMetadata,
|
|
@@ -678,13 +677,11 @@ export function useCheckoutOrchestration({
|
|
|
678
677
|
string | null
|
|
679
678
|
>(cart?.shipping_methods?.at(-1)?.shipping_option_id || null)
|
|
680
679
|
|
|
680
|
+
// Every listed option is offerable: the Medusa-era pickup filter read an
|
|
681
|
+
// embedded fulfillment_set the Cartbase API never sends (it never fired),
|
|
682
|
+
// and the concept itself died in the shipping vocabulary trial.
|
|
681
683
|
const shippingMethods = useMemo(
|
|
682
|
-
() =>
|
|
683
|
-
(availableShippingMethods ?? []).filter(
|
|
684
|
-
(sm) =>
|
|
685
|
-
(sm as { service_zone?: { fulfillment_set?: { type?: string } } })
|
|
686
|
-
.service_zone?.fulfillment_set?.type !== "pickup"
|
|
687
|
-
),
|
|
684
|
+
() => availableShippingMethods ?? [],
|
|
688
685
|
[availableShippingMethods]
|
|
689
686
|
)
|
|
690
687
|
|
|
@@ -794,20 +791,20 @@ export function useCheckoutOrchestration({
|
|
|
794
791
|
// ── Payment ─────────────────────────────────────────────────────────
|
|
795
792
|
const [paymentError, setPaymentError] = useState<string | null>(null)
|
|
796
793
|
|
|
797
|
-
const hasCard = !!effectiveAvailablePaymentMethods?.some(
|
|
798
|
-
isStripeLike(m.id)
|
|
794
|
+
const hasCard = !!effectiveAvailablePaymentMethods?.some(
|
|
795
|
+
(m) => "id" in m && isStripeLike(m.id)
|
|
799
796
|
)
|
|
800
|
-
const
|
|
801
|
-
(
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
isStripeLike(m.id)
|
|
797
|
+
const cardId = (
|
|
798
|
+
effectiveAvailablePaymentMethods?.find(
|
|
799
|
+
(m) => "id" in m && isStripeLike(m.id)
|
|
800
|
+
) as { id: string } | undefined
|
|
805
801
|
)?.id
|
|
806
|
-
//
|
|
807
|
-
//
|
|
808
|
-
const
|
|
809
|
-
|
|
810
|
-
|
|
802
|
+
// The offline tab = a merchant METHOD (the COD switch, else the first
|
|
803
|
+
// manual method) — sessions initiate by payment_method_id, provider NULL.
|
|
804
|
+
const offlineMethod = findOfflineMethod(effectiveAvailablePaymentMethods)
|
|
805
|
+
const hasCod = !!offlineMethod
|
|
806
|
+
const codMethodId = offlineMethod?.payment_method_id
|
|
807
|
+
const offlineIsCodKind = offlineMethod?.kind === "cod"
|
|
811
808
|
|
|
812
809
|
// Default tab: card when available, else COD. The eager-session model
|
|
813
810
|
// used to seed from the cart's pending session provider; in the
|
|
@@ -816,14 +813,15 @@ export function useCheckoutOrchestration({
|
|
|
816
813
|
hasCard ? "card" : "cod"
|
|
817
814
|
)
|
|
818
815
|
|
|
819
|
-
// Optimistic
|
|
820
|
-
// totals row shows the predicted fee BEFORE the server applies
|
|
821
|
-
//
|
|
816
|
+
// Optimistic method-fee state. Painted instantly on tab toggle so the
|
|
817
|
+
// totals row shows the predicted fee BEFORE the server applies it (at
|
|
818
|
+
// prepare, when the method session is minted). Any method may carry a
|
|
819
|
+
// fee — the prediction reads the selected entry's own fee_amount.
|
|
822
820
|
// Three values:
|
|
823
821
|
// - null → no prediction; render whatever the cart says
|
|
824
|
-
// - 0 → predict no fee (toggling
|
|
825
|
-
// - positive → predict the fee at this amount
|
|
826
|
-
const [
|
|
822
|
+
// - 0 → predict no fee (toggling to a fee-less tender)
|
|
823
|
+
// - positive → predict the fee at this amount
|
|
824
|
+
const [optimisticMethodFee, setOptimisticMethodFee] = useState<number | null>(
|
|
827
825
|
null
|
|
828
826
|
)
|
|
829
827
|
|
|
@@ -840,30 +838,28 @@ export function useCheckoutOrchestration({
|
|
|
840
838
|
setPaymentTab(tab)
|
|
841
839
|
setPaymentError(null)
|
|
842
840
|
|
|
843
|
-
// Optimistic
|
|
844
|
-
//
|
|
845
|
-
//
|
|
846
|
-
//
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
codConfig.fee_currency.toLowerCase() ===
|
|
851
|
-
(cart.currency_code || "").toLowerCase()
|
|
852
|
-
if (tab === "cod" && codCurrencyMatches && codId === "pp_cod") {
|
|
853
|
-
setOptimisticCodFee(codConfig.fee_amount)
|
|
854
|
-
} else {
|
|
855
|
-
setOptimisticCodFee(0)
|
|
856
|
-
}
|
|
841
|
+
// Optimistic fee prediction so the totals row updates instantly —
|
|
842
|
+
// the selected METHOD entry carries its own fee; processors charge
|
|
843
|
+
// none. Mirrors the server exactly (resolveMethodFee reads the same
|
|
844
|
+
// row the listing serialized).
|
|
845
|
+
if (offlineMethod) {
|
|
846
|
+
const fee = Number(offlineMethod.fee_amount ?? 0)
|
|
847
|
+
setOptimisticMethodFee(tab === "cod" && fee > 0 ? fee : 0)
|
|
857
848
|
}
|
|
858
849
|
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
850
|
+
const tender =
|
|
851
|
+
tab === "card"
|
|
852
|
+
? cardId
|
|
853
|
+
? { provider_id: cardId }
|
|
854
|
+
: null
|
|
855
|
+
: codMethodId
|
|
856
|
+
? { payment_method_id: codMethodId }
|
|
857
|
+
: null
|
|
858
|
+
if (tender) {
|
|
859
|
+
void syncPaymentAmountApi(client, cart.id, tender).catch(() => {})
|
|
864
860
|
}
|
|
865
861
|
},
|
|
866
|
-
[cart.
|
|
862
|
+
[cart.id, client, cardId, codMethodId, offlineMethod]
|
|
867
863
|
)
|
|
868
864
|
|
|
869
865
|
// Shipping selection is client state only. No addShippingMethod call,
|
|
@@ -1088,26 +1084,26 @@ export function useCheckoutOrchestration({
|
|
|
1088
1084
|
// start = cart.total (covers subtotal + tax + any already-written
|
|
1089
1085
|
// shipping/fee)
|
|
1090
1086
|
// if optimisticShippingCost set: replace cart.shipping_total with it
|
|
1091
|
-
// if
|
|
1092
|
-
// (
|
|
1093
|
-
//
|
|
1087
|
+
// if optimisticMethodFee set: replace cart.payment_method_fee_total
|
|
1088
|
+
// with it (the fee is CART-LEVEL decoration folded into total,
|
|
1089
|
+
// not a fee line item)
|
|
1094
1090
|
// When nothing is optimistic, this collapses to cart.total.
|
|
1095
1091
|
const optimisticTotal = useMemo(() => {
|
|
1096
|
-
const
|
|
1092
|
+
const realMethodFeeAmount = cart?.payment_method_fee_total ?? 0
|
|
1097
1093
|
let total = cart?.total ?? 0
|
|
1098
1094
|
if (optimisticShippingCost !== null) {
|
|
1099
1095
|
total = total - (cart?.shipping_total ?? 0) + optimisticShippingCost
|
|
1100
1096
|
}
|
|
1101
|
-
if (
|
|
1102
|
-
total = total -
|
|
1097
|
+
if (optimisticMethodFee !== null && optimisticMethodFee !== undefined) {
|
|
1098
|
+
total = total - realMethodFeeAmount + optimisticMethodFee
|
|
1103
1099
|
}
|
|
1104
1100
|
return total
|
|
1105
1101
|
}, [
|
|
1106
1102
|
cart?.total,
|
|
1107
1103
|
cart?.shipping_total,
|
|
1108
|
-
cart?.
|
|
1104
|
+
cart?.payment_method_fee_total,
|
|
1109
1105
|
optimisticShippingCost,
|
|
1110
|
-
|
|
1106
|
+
optimisticMethodFee,
|
|
1111
1107
|
])
|
|
1112
1108
|
|
|
1113
1109
|
// ── Optimistic total in cents (for Stripe Elements deferred-intent) ─
|
|
@@ -1157,9 +1153,18 @@ export function useCheckoutOrchestration({
|
|
|
1157
1153
|
if (!shippingMethodId) {
|
|
1158
1154
|
throw new Error("No shipping method selected")
|
|
1159
1155
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1156
|
+
// The tender: card tab → the processor; offline tab → the merchant
|
|
1157
|
+
// method (provider-less session, pp_* kill).
|
|
1158
|
+
const tender =
|
|
1159
|
+
paymentTab === "card"
|
|
1160
|
+
? cardId
|
|
1161
|
+
? { payment_provider: cardId }
|
|
1162
|
+
: null
|
|
1163
|
+
: codMethodId
|
|
1164
|
+
? { payment_method_id: codMethodId }
|
|
1165
|
+
: null
|
|
1166
|
+
if (!tender) {
|
|
1167
|
+
throw new Error("No payment method available")
|
|
1163
1168
|
}
|
|
1164
1169
|
|
|
1165
1170
|
return {
|
|
@@ -1175,7 +1180,7 @@ export function useCheckoutOrchestration({
|
|
|
1175
1180
|
},
|
|
1176
1181
|
shipping_method_id: shippingMethodId,
|
|
1177
1182
|
carrier_metadata: carrierMetadata,
|
|
1178
|
-
|
|
1183
|
+
...tender,
|
|
1179
1184
|
}
|
|
1180
1185
|
}, [
|
|
1181
1186
|
formData,
|
|
@@ -1184,7 +1189,7 @@ export function useCheckoutOrchestration({
|
|
|
1184
1189
|
selectedBoxnowLocker,
|
|
1185
1190
|
paymentTab,
|
|
1186
1191
|
cardId,
|
|
1187
|
-
|
|
1192
|
+
codMethodId,
|
|
1188
1193
|
])
|
|
1189
1194
|
|
|
1190
1195
|
// ── Buy click ───────────────────────────────────────────────────────
|
|
@@ -1229,7 +1234,7 @@ export function useCheckoutOrchestration({
|
|
|
1229
1234
|
cart_id: cart.id,
|
|
1230
1235
|
paymentTab,
|
|
1231
1236
|
cardId,
|
|
1232
|
-
|
|
1237
|
+
codMethodId,
|
|
1233
1238
|
selectedShippingMethod,
|
|
1234
1239
|
selectedEcontOffice: selectedEcontOffice
|
|
1235
1240
|
? { code: selectedEcontOffice.code, name: selectedEcontOffice.name }
|
|
@@ -1268,7 +1273,8 @@ export function useCheckoutOrchestration({
|
|
|
1268
1273
|
// eslint-disable-next-line no-console
|
|
1269
1274
|
console.log("[buy-click] PAYLOAD →", payload)
|
|
1270
1275
|
logError?.("other", "buy_click_payload", {
|
|
1271
|
-
provider_id: payload.payment_provider,
|
|
1276
|
+
provider_id: payload.payment_provider ?? null,
|
|
1277
|
+
payment_method_id: payload.payment_method_id ?? null,
|
|
1272
1278
|
shipping_method_id: payload.shipping_method_id,
|
|
1273
1279
|
carrier_metadata_keys: Object.keys(payload.carrier_metadata ?? {}),
|
|
1274
1280
|
country_code: payload.shipping_address.country_code,
|
|
@@ -1420,7 +1426,7 @@ export function useCheckoutOrchestration({
|
|
|
1420
1426
|
cart.id,
|
|
1421
1427
|
paymentTab,
|
|
1422
1428
|
cardId,
|
|
1423
|
-
|
|
1429
|
+
codMethodId,
|
|
1424
1430
|
selectedShippingMethod,
|
|
1425
1431
|
selectedEcontOffice,
|
|
1426
1432
|
selectedBoxnowLocker,
|
|
@@ -1478,12 +1484,14 @@ export function useCheckoutOrchestration({
|
|
|
1478
1484
|
hasCard,
|
|
1479
1485
|
hasCod,
|
|
1480
1486
|
cardId,
|
|
1481
|
-
|
|
1487
|
+
/** The offline tab's method (the COD switch or a manual method). */
|
|
1488
|
+
codMethodId,
|
|
1489
|
+
offlineMethod,
|
|
1482
1490
|
paymentError,
|
|
1483
1491
|
setPaymentError,
|
|
1484
1492
|
deliveryReady,
|
|
1485
|
-
|
|
1486
|
-
|
|
1493
|
+
optimisticMethodFee,
|
|
1494
|
+
setOptimisticMethodFee,
|
|
1487
1495
|
handlePaymentTab,
|
|
1488
1496
|
handlePaymentElementChange,
|
|
1489
1497
|
|
|
@@ -1,66 +1,53 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payment
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{ title: string; icon: React.JSX.Element | null }
|
|
55
|
-
> = {
|
|
56
|
-
pp_stripe: { title: "Credit / debit card", icon: null },
|
|
57
|
-
pp_stripe_stripe: { title: "Credit / debit card", icon: null },
|
|
58
|
-
"pp_medusa-payments_default": { title: "Credit / debit card", icon: null },
|
|
59
|
-
"pp_stripe-ideal_stripe": { title: "iDeal", icon: null },
|
|
60
|
-
"pp_stripe-bancontact_stripe": { title: "Bancontact", icon: null },
|
|
61
|
-
pp_paypal_paypal: { title: "PayPal", icon: null },
|
|
62
|
-
pp_cod: { title: "Cash on delivery", icon: null },
|
|
63
|
-
pp_manual: { title: "Manual payment", icon: null },
|
|
64
|
-
// Retired legacy manual twin — historic orders only (payments-registry).
|
|
65
|
-
pp_system_default: { title: "Manual payment", icon: null },
|
|
66
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Payment tender helpers — identifier sniffing for store payment sessions.
|
|
3
|
+
*
|
|
4
|
+
* The Cartbase wire has exactly TWO tender shapes since the pp_* kill
|
|
5
|
+
* (20260811250000, no-payment-method-by-default card):
|
|
6
|
+
*
|
|
7
|
+
* - a PROCESSOR the merchant connected — `provider_id` (`pp_stripe`
|
|
8
|
+
* today; PayPal etc. as integrations land);
|
|
9
|
+
* - a merchant-operated PAYMENT METHOD — `payment_method_id` + `name` +
|
|
10
|
+
* `kind` (`manual` for Bank transfer / Pay in store, `cod` for the
|
|
11
|
+
* collection-on-delivery switch). Its session carries `provider_id`
|
|
12
|
+
* NULL; the merchant's NAME is the display everywhere.
|
|
13
|
+
*
|
|
14
|
+
* The dead ids (`pp_cod`, `pp_manual`, `pp_system_default`) are gone from
|
|
15
|
+
* the wire and from this module. The Medusa-era Stripe prefixes
|
|
16
|
+
* (`pp_stripe_*`, `pp_medusa-*`) are kept as fallbacks so components
|
|
17
|
+
* ported later keep working against either wire.
|
|
18
|
+
*
|
|
19
|
+
* Intentionally ships NO icons — stores render their own icons via their
|
|
20
|
+
* own icon set. The library stays free of icon-kit imports at this layer.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* True if the provider id is a Stripe-backed card payment provider.
|
|
25
|
+
* Cartbase's canonical ids first (`pp_stripe` / `stripe`), then the
|
|
26
|
+
* Medusa-era prefixes (`pp_stripe_*`, `pp_medusa-*`).
|
|
27
|
+
*/
|
|
28
|
+
export const isStripeLike = (providerId?: string | null): boolean => {
|
|
29
|
+
return Boolean(
|
|
30
|
+
providerId &&
|
|
31
|
+
(providerId === "pp_stripe" ||
|
|
32
|
+
providerId === "stripe" ||
|
|
33
|
+
providerId.startsWith("pp_stripe_") ||
|
|
34
|
+
providerId.startsWith("pp_medusa-"))
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** True if the provider id is PayPal. */
|
|
39
|
+
export const isPaypal = (providerId?: string | null): boolean => {
|
|
40
|
+
return Boolean(providerId?.startsWith("pp_paypal"))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const paymentInfoMap: Record<
|
|
44
|
+
string,
|
|
45
|
+
{ title: string; icon: React.JSX.Element | null }
|
|
46
|
+
> = {
|
|
47
|
+
pp_stripe: { title: "Credit / debit card", icon: null },
|
|
48
|
+
pp_stripe_stripe: { title: "Credit / debit card", icon: null },
|
|
49
|
+
"pp_medusa-payments_default": { title: "Credit / debit card", icon: null },
|
|
50
|
+
"pp_stripe-ideal_stripe": { title: "iDeal", icon: null },
|
|
51
|
+
"pp_stripe-bancontact_stripe": { title: "Bancontact", icon: null },
|
|
52
|
+
pp_paypal_paypal: { title: "PayPal", icon: null },
|
|
53
|
+
}
|
package/src/order/labels-bg.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import type { OrderLabels } from "./labels"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Bulgarian order labels — the Alenika/mindpages production copy, ported
|
|
5
|
-
* from `@1click/ui/src/order/labels-bg.ts` (v2.3.1) + `tracking`.
|
|
6
|
-
*/
|
|
7
|
-
export const bulgarianOrderLabels: OrderLabels = {
|
|
8
|
-
orderConfirmed: "Поръчката е потвърдена",
|
|
9
|
-
confirmationSent: "Изпратихме потвърждение на",
|
|
10
|
-
orderNumber: "Поръчка",
|
|
11
|
-
orderDate: "Дата",
|
|
12
|
-
summary: "Обобщение на поръчката",
|
|
13
|
-
subtotal: "Междинна сума",
|
|
14
|
-
shipping: "Доставка",
|
|
15
|
-
discount: "Отстъпка",
|
|
16
|
-
tax: "ДДС",
|
|
17
|
-
total: "Общо",
|
|
18
|
-
|
|
19
|
-
contactInfo: "Данни за контакт",
|
|
20
|
-
delivery: "Доставка",
|
|
21
|
-
paymentMethod: "Метод на плащане",
|
|
22
|
-
paymentMethodTitles: {
|
|
23
|
-
card: "Кредитна / дебитна карта",
|
|
24
|
-
cod: "Наложен платеж",
|
|
25
|
-
manual: "Друг начин на плащане",
|
|
26
|
-
paypal: "PayPal",
|
|
27
|
-
},
|
|
28
|
-
needHelp: "Имате нужда от помощ?",
|
|
29
|
-
contactUs: "Свържете се с нас",
|
|
30
|
-
returnsExchanges: "Връщания и замени",
|
|
31
|
-
orderPlaced: "Приета",
|
|
32
|
-
processing: "Обработка",
|
|
33
|
-
shipped: "Изпратена",
|
|
34
|
-
delivered: "Доставена",
|
|
35
|
-
free: "БЕЗПЛАТНА",
|
|
36
|
-
continueShopping: "Продължи пазаруването",
|
|
37
|
-
qty: "бр.",
|
|
38
|
-
tracking: "Проследяване",
|
|
39
|
-
}
|
|
1
|
+
import type { OrderLabels } from "./labels"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bulgarian order labels — the Alenika/mindpages production copy, ported
|
|
5
|
+
* from `@1click/ui/src/order/labels-bg.ts` (v2.3.1) + `tracking`.
|
|
6
|
+
*/
|
|
7
|
+
export const bulgarianOrderLabels: OrderLabels = {
|
|
8
|
+
orderConfirmed: "Поръчката е потвърдена",
|
|
9
|
+
confirmationSent: "Изпратихме потвърждение на",
|
|
10
|
+
orderNumber: "Поръчка",
|
|
11
|
+
orderDate: "Дата",
|
|
12
|
+
summary: "Обобщение на поръчката",
|
|
13
|
+
subtotal: "Междинна сума",
|
|
14
|
+
shipping: "Доставка",
|
|
15
|
+
discount: "Отстъпка",
|
|
16
|
+
tax: "ДДС",
|
|
17
|
+
total: "Общо",
|
|
18
|
+
paymentMethodFee: "Такса за плащане",
|
|
19
|
+
contactInfo: "Данни за контакт",
|
|
20
|
+
delivery: "Доставка",
|
|
21
|
+
paymentMethod: "Метод на плащане",
|
|
22
|
+
paymentMethodTitles: {
|
|
23
|
+
card: "Кредитна / дебитна карта",
|
|
24
|
+
cod: "Наложен платеж",
|
|
25
|
+
manual: "Друг начин на плащане",
|
|
26
|
+
paypal: "PayPal",
|
|
27
|
+
},
|
|
28
|
+
needHelp: "Имате нужда от помощ?",
|
|
29
|
+
contactUs: "Свържете се с нас",
|
|
30
|
+
returnsExchanges: "Връщания и замени",
|
|
31
|
+
orderPlaced: "Приета",
|
|
32
|
+
processing: "Обработка",
|
|
33
|
+
shipped: "Изпратена",
|
|
34
|
+
delivered: "Доставена",
|
|
35
|
+
free: "БЕЗПЛАТНА",
|
|
36
|
+
continueShopping: "Продължи пазаруването",
|
|
37
|
+
qty: "бр.",
|
|
38
|
+
tracking: "Проследяване",
|
|
39
|
+
}
|