@cartbase/storefront 0.2.0 → 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.
@@ -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 StorePaymentProvider,
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 type { PublicCodConfig } from "../api/integrations"
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
- * - COD fee: Cartbase's fee is CART-LEVEL decoration (`cod_fee_total` /
74
- * `cod_fee_label`, folded into `cart.total` while a live pp_cod session
75
- * exists) not a metadata-flagged line item. The optimistic-fee math
76
- * reads `cart.cod_fee_total`; the prediction comes from the
77
- * integrations config `cod` block (never hardcoded).
78
- * - Provider ids: `pp_stripe` / `pp_cod` / `pp_manual` exactly
79
- * (lib/payment-constants + the pp_cod resolution below).
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
- /** COD checkout config the integrations `cod` block (api/integrations). */
97
- export type CheckoutCodConfig = PublicCodConfig | null
98
-
99
- /** Minimal provider row the hook accepts (SDK DTO or bare `{id}`). */
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
- /** Cartbase COD provider resolution: `pp_cod` exactly, with the Medusa-era
198
- * `pp_system_default*` prefix kept as fallback (lib/payment-constants),
199
- * and `pp_manual` accepted as the offline tab when no true COD provider
200
- * is enabled. Fee prediction only ever applies via `codConfig` (pp_cod). */
201
- const isCodLikeId = (id?: string): boolean =>
202
- !!id && (id === "pp_cod" || isManual(id))
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,
@@ -794,20 +793,20 @@ export function useCheckoutOrchestration({
794
793
  // ── Payment ─────────────────────────────────────────────────────────
795
794
  const [paymentError, setPaymentError] = useState<string | null>(null)
796
795
 
797
- const hasCard = !!effectiveAvailablePaymentMethods?.some((m) =>
798
- isStripeLike(m.id)
799
- )
800
- const hasCod = !!effectiveAvailablePaymentMethods?.some(
801
- (m) => isCodLikeId(m.id) || m.id === "pp_manual"
796
+ const hasCard = !!effectiveAvailablePaymentMethods?.some(
797
+ (m) => "id" in m && isStripeLike(m.id)
802
798
  )
803
- const cardId = effectiveAvailablePaymentMethods?.find((m) =>
804
- isStripeLike(m.id)
799
+ const cardId = (
800
+ effectiveAvailablePaymentMethods?.find(
801
+ (m) => "id" in m && isStripeLike(m.id)
802
+ ) as { id: string } | undefined
805
803
  )?.id
806
- // Prefer the true COD provider; fall back to pp_manual so single-
807
- // provider stores still get an offline tab.
808
- const codId =
809
- effectiveAvailablePaymentMethods?.find((m) => isCodLikeId(m.id))?.id ??
810
- effectiveAvailablePaymentMethods?.find((m) => m.id === "pp_manual")?.id
804
+ // The offline tab = a merchant METHOD (the COD switch, else the first
805
+ // manual method) sessions initiate by payment_method_id, provider NULL.
806
+ const offlineMethod = findOfflineMethod(effectiveAvailablePaymentMethods)
807
+ const hasCod = !!offlineMethod
808
+ const codMethodId = offlineMethod?.payment_method_id
809
+ const offlineIsCodKind = offlineMethod?.kind === "cod"
811
810
 
812
811
  // Default tab: card when available, else COD. The eager-session model
813
812
  // used to seed from the cart's pending session provider; in the
@@ -816,14 +815,15 @@ export function useCheckoutOrchestration({
816
815
  hasCard ? "card" : "cod"
817
816
  )
818
817
 
819
- // Optimistic COD-fee state. Painted instantly on tab toggle so the
820
- // totals row shows the predicted fee BEFORE the server applies the
821
- // native fee (Cartbase: at prepare, when the pp_cod session is minted).
818
+ // Optimistic method-fee state. Painted instantly on tab toggle so the
819
+ // totals row shows the predicted fee BEFORE the server applies it (at
820
+ // prepare, when the method session is minted). Any method may carry a
821
+ // fee — the prediction reads the selected entry's own fee_amount.
822
822
  // Three values:
823
823
  // - null → no prediction; render whatever the cart says
824
- // - 0 → predict no fee (toggling away from COD)
825
- // - positive → predict the fee at this amount (toggling to COD)
826
- const [optimisticCodFee, setOptimisticCodFee] = useState<number | null>(
824
+ // - 0 → predict no fee (toggling to a fee-less tender)
825
+ // - positive → predict the fee at this amount
826
+ const [optimisticMethodFee, setOptimisticMethodFee] = useState<number | null>(
827
827
  null
828
828
  )
829
829
 
@@ -840,30 +840,28 @@ export function useCheckoutOrchestration({
840
840
  setPaymentTab(tab)
841
841
  setPaymentError(null)
842
842
 
843
- // Optimistic COD-fee prediction so the totals row updates instantly.
844
- // Currency must match the configured fee currency or the backend
845
- // skips the fee at apply time, so we mirror that gate here. The
846
- // prediction ONLY applies when the offline tab is the true pp_cod
847
- // provider — pp_manual carries no fee.
848
- if (codConfig) {
849
- const codCurrencyMatches =
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
- }
843
+ // Optimistic fee prediction so the totals row updates instantly
844
+ // the selected METHOD entry carries its own fee; processors charge
845
+ // none. Mirrors the server exactly (resolveMethodFee reads the same
846
+ // row the listing serialized).
847
+ if (offlineMethod) {
848
+ const fee = Number(offlineMethod.fee_amount ?? 0)
849
+ setOptimisticMethodFee(tab === "cod" && fee > 0 ? fee : 0)
857
850
  }
858
851
 
859
- const provider = tab === "card" ? cardId : codId
860
- if (provider) {
861
- void syncPaymentAmountApi(client, cart.id, {
862
- provider_id: provider,
863
- }).catch(() => {})
852
+ const tender =
853
+ tab === "card"
854
+ ? cardId
855
+ ? { provider_id: cardId }
856
+ : null
857
+ : codMethodId
858
+ ? { payment_method_id: codMethodId }
859
+ : null
860
+ if (tender) {
861
+ void syncPaymentAmountApi(client, cart.id, tender).catch(() => {})
864
862
  }
865
863
  },
866
- [cart.currency_code, cart.id, client, codConfig, cardId, codId]
864
+ [cart.id, client, cardId, codMethodId, offlineMethod]
867
865
  )
868
866
 
869
867
  // Shipping selection is client state only. No addShippingMethod call,
@@ -1088,26 +1086,26 @@ export function useCheckoutOrchestration({
1088
1086
  // start = cart.total (covers subtotal + tax + any already-written
1089
1087
  // shipping/fee)
1090
1088
  // if optimisticShippingCost set: replace cart.shipping_total with it
1091
- // if optimisticCodFee set: replace cart.cod_fee_total with it
1092
- // (Cartbase: the COD fee is CART-LEVEL decoration folded into total,
1093
- // not a fee line item)
1089
+ // if optimisticMethodFee set: replace cart.payment_method_fee_total
1090
+ // with it (the fee is CART-LEVEL decoration folded into total,
1091
+ // not a fee line item)
1094
1092
  // When nothing is optimistic, this collapses to cart.total.
1095
1093
  const optimisticTotal = useMemo(() => {
1096
- const realCodFeeAmount = cart?.cod_fee_total ?? 0
1094
+ const realMethodFeeAmount = cart?.payment_method_fee_total ?? 0
1097
1095
  let total = cart?.total ?? 0
1098
1096
  if (optimisticShippingCost !== null) {
1099
1097
  total = total - (cart?.shipping_total ?? 0) + optimisticShippingCost
1100
1098
  }
1101
- if (optimisticCodFee !== null && optimisticCodFee !== undefined) {
1102
- total = total - realCodFeeAmount + optimisticCodFee
1099
+ if (optimisticMethodFee !== null && optimisticMethodFee !== undefined) {
1100
+ total = total - realMethodFeeAmount + optimisticMethodFee
1103
1101
  }
1104
1102
  return total
1105
1103
  }, [
1106
1104
  cart?.total,
1107
1105
  cart?.shipping_total,
1108
- cart?.cod_fee_total,
1106
+ cart?.payment_method_fee_total,
1109
1107
  optimisticShippingCost,
1110
- optimisticCodFee,
1108
+ optimisticMethodFee,
1111
1109
  ])
1112
1110
 
1113
1111
  // ── Optimistic total in cents (for Stripe Elements deferred-intent) ─
@@ -1157,9 +1155,18 @@ export function useCheckoutOrchestration({
1157
1155
  if (!shippingMethodId) {
1158
1156
  throw new Error("No shipping method selected")
1159
1157
  }
1160
- const paymentProvider = paymentTab === "card" ? cardId : codId
1161
- if (!paymentProvider) {
1162
- throw new Error("No payment provider available")
1158
+ // The tender: card tab the processor; offline tab → the merchant
1159
+ // method (provider-less session, pp_* kill).
1160
+ const tender =
1161
+ paymentTab === "card"
1162
+ ? cardId
1163
+ ? { payment_provider: cardId }
1164
+ : null
1165
+ : codMethodId
1166
+ ? { payment_method_id: codMethodId }
1167
+ : null
1168
+ if (!tender) {
1169
+ throw new Error("No payment method available")
1163
1170
  }
1164
1171
 
1165
1172
  return {
@@ -1175,7 +1182,7 @@ export function useCheckoutOrchestration({
1175
1182
  },
1176
1183
  shipping_method_id: shippingMethodId,
1177
1184
  carrier_metadata: carrierMetadata,
1178
- payment_provider: paymentProvider,
1185
+ ...tender,
1179
1186
  }
1180
1187
  }, [
1181
1188
  formData,
@@ -1184,7 +1191,7 @@ export function useCheckoutOrchestration({
1184
1191
  selectedBoxnowLocker,
1185
1192
  paymentTab,
1186
1193
  cardId,
1187
- codId,
1194
+ codMethodId,
1188
1195
  ])
1189
1196
 
1190
1197
  // ── Buy click ───────────────────────────────────────────────────────
@@ -1229,7 +1236,7 @@ export function useCheckoutOrchestration({
1229
1236
  cart_id: cart.id,
1230
1237
  paymentTab,
1231
1238
  cardId,
1232
- codId,
1239
+ codMethodId,
1233
1240
  selectedShippingMethod,
1234
1241
  selectedEcontOffice: selectedEcontOffice
1235
1242
  ? { code: selectedEcontOffice.code, name: selectedEcontOffice.name }
@@ -1268,7 +1275,8 @@ export function useCheckoutOrchestration({
1268
1275
  // eslint-disable-next-line no-console
1269
1276
  console.log("[buy-click] PAYLOAD →", payload)
1270
1277
  logError?.("other", "buy_click_payload", {
1271
- provider_id: payload.payment_provider,
1278
+ provider_id: payload.payment_provider ?? null,
1279
+ payment_method_id: payload.payment_method_id ?? null,
1272
1280
  shipping_method_id: payload.shipping_method_id,
1273
1281
  carrier_metadata_keys: Object.keys(payload.carrier_metadata ?? {}),
1274
1282
  country_code: payload.shipping_address.country_code,
@@ -1420,7 +1428,7 @@ export function useCheckoutOrchestration({
1420
1428
  cart.id,
1421
1429
  paymentTab,
1422
1430
  cardId,
1423
- codId,
1431
+ codMethodId,
1424
1432
  selectedShippingMethod,
1425
1433
  selectedEcontOffice,
1426
1434
  selectedBoxnowLocker,
@@ -1478,12 +1486,14 @@ export function useCheckoutOrchestration({
1478
1486
  hasCard,
1479
1487
  hasCod,
1480
1488
  cardId,
1481
- codId,
1489
+ /** The offline tab's method (the COD switch or a manual method). */
1490
+ codMethodId,
1491
+ offlineMethod,
1482
1492
  paymentError,
1483
1493
  setPaymentError,
1484
1494
  deliveryReady,
1485
- optimisticCodFee,
1486
- setOptimisticCodFee,
1495
+ optimisticMethodFee,
1496
+ setOptimisticMethodFee,
1487
1497
  handlePaymentTab,
1488
1498
  handlePaymentElementChange,
1489
1499
 
@@ -1,66 +1,53 @@
1
- /**
2
- * Payment provider helpers — identifier sniffing for store payment sessions.
3
- *
4
- * Ported from `@1click/ui/src/lib/payment-constants.ts` (v2.3.1) and
5
- * translated to the Cartbase provider-id seam (code truth:
6
- * `src/lib/stripe/providers.ts isStripeProviderId` matches exactly
7
- * `"pp_stripe" | "stripe"`; the accepted checkout ids are
8
- * `pp_stripe | pp_cod | pp_manual` — docs/contracts/store-api.md).
9
- * `pp_system_default` is the RETIRED legacy manual twin (payments-registry
10
- * card): no longer provisioned, hidden from merchants, kept here only so
11
- * historic orders keep rendering. The Medusa-era prefixes (`pp_stripe_*`,
12
- * `pp_medusa-*`) are kept as fallbacks so components ported later keep
13
- * working against either wire.
14
- *
15
- * Intentionally ships NO icons stores render their own icons via their
16
- * own icon set. The library stays free of icon-kit imports at this layer.
17
- */
18
-
19
- /**
20
- * True if the provider id is a Stripe-backed card payment provider.
21
- * Cartbase's canonical ids first (`pp_stripe` / `stripe`), then the
22
- * Medusa-era prefixes (`pp_stripe_*`, `pp_medusa-*`).
23
- */
24
- export const isStripeLike = (providerId?: string): boolean => {
25
- return Boolean(
26
- providerId &&
27
- (providerId === "pp_stripe" ||
28
- providerId === "stripe" ||
29
- providerId.startsWith("pp_stripe_") ||
30
- providerId.startsWith("pp_medusa-"))
31
- )
32
- }
33
-
34
- /** True if the provider id is PayPal. */
35
- export const isPaypal = (providerId?: string): boolean => {
36
- return Boolean(providerId?.startsWith("pp_paypal"))
37
- }
38
-
39
- /**
40
- * True if the provider id is an offline/manual provider: `pp_manual` (the
41
- * id checkout actually charges — payments-registry card) with the retired
42
- * `pp_system_default*` legacy twin as fallback for historic orders. COD is
43
- * NOT manual — `pp_cod` has its own id and its own fee flow.
44
- */
45
- export const isManual = (providerId?: string): boolean => {
46
- return Boolean(
47
- providerId &&
48
- (providerId === "pp_manual" || providerId.startsWith("pp_system_default"))
49
- )
50
- }
51
-
52
- export const paymentInfoMap: Record<
53
- string,
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
+ }
@@ -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
- codFee: "Такса наложен платеж",
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
+ }