@sazito/checkout 0.1.0 → 0.1.2
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/README.md +34 -0
- package/dist/chunks/{labels-ChywPk2i.js → labels-ByA_yGKl.js} +131 -53
- package/dist/chunks/labels-ByA_yGKl.js.map +1 -0
- package/dist/chunks/{labels-BlMZkOsV.cjs → labels-DJ_RnkCQ.cjs} +132 -52
- package/dist/chunks/labels-DJ_RnkCQ.cjs.map +1 -0
- package/dist/chunks/{use-checkout-Cvp_K3UW.cjs → use-checkout-CQBSONj1.cjs} +2 -2
- package/dist/chunks/{use-checkout-Cvp_K3UW.cjs.map → use-checkout-CQBSONj1.cjs.map} +1 -1
- package/dist/chunks/{use-checkout-E0O8HsSs.js → use-checkout-gAjnCzae.js} +2 -2
- package/dist/chunks/{use-checkout-E0O8HsSs.js.map → use-checkout-gAjnCzae.js.map} +1 -1
- package/dist/core/index.cjs +3 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +9 -4
- package/dist/core/index.d.ts +9 -4
- package/dist/core/index.js +1 -1
- package/dist/next/index.cjs +19 -9
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +1 -0
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.js +21 -11
- package/dist/next/index.js.map +1 -1
- package/dist/react/index.cjs +2 -2
- package/dist/react/index.d.cts +1 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +2 -2
- package/dist/styles.css +123 -8
- package/package.json +12 -6
- package/dist/chunks/labels-BlMZkOsV.cjs.map +0 -1
- package/dist/chunks/labels-ChywPk2i.js.map +0 -1
package/README.md
CHANGED
|
@@ -83,6 +83,40 @@ export default function Checkout() {
|
|
|
83
83
|
The component **inherits the host font** (`--szc-font: inherit`). The demo app
|
|
84
84
|
loads Vazirmatn on `<body>`; that's all it takes for a Persian/RTL checkout.
|
|
85
85
|
|
|
86
|
+
Theme values may reference host application tokens directly. Changes to those
|
|
87
|
+
tokens, including dark-mode changes, are reflected without rerendering:
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
config={{
|
|
91
|
+
theme: {
|
|
92
|
+
accent: 'var(--color-primary)',
|
|
93
|
+
accentForeground: 'var(--color-on-primary)',
|
|
94
|
+
background: 'var(--color-background)',
|
|
95
|
+
foreground: 'var(--color-foreground)',
|
|
96
|
+
card: 'var(--color-card)',
|
|
97
|
+
border: 'var(--color-border)',
|
|
98
|
+
fontFamily: 'var(--font-sans)',
|
|
99
|
+
},
|
|
100
|
+
}}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Alternatively, pass `className="store-checkout"` and map the native variables
|
|
104
|
+
in CSS imported after the checkout stylesheet:
|
|
105
|
+
|
|
106
|
+
```css
|
|
107
|
+
.szc-root.store-checkout {
|
|
108
|
+
--szc-accent: var(--color-primary);
|
|
109
|
+
--szc-bg: var(--color-background);
|
|
110
|
+
--szc-fg: var(--color-foreground);
|
|
111
|
+
--szc-card: var(--color-card);
|
|
112
|
+
--szc-border: var(--color-border);
|
|
113
|
+
--szc-radius: var(--radius-lg);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Avoid configuring the same token through both methods: `config.theme` writes
|
|
118
|
+
inline variables and therefore wins over ordinary stylesheet declarations.
|
|
119
|
+
|
|
86
120
|
## Flow (v1 scope)
|
|
87
121
|
|
|
88
122
|
4 states — `cart → shipping → payment → result`:
|
|
@@ -200,6 +200,30 @@ function createBrowserEffectExecutor(config) {
|
|
|
200
200
|
const noopEffectExecutor = () => { };
|
|
201
201
|
|
|
202
202
|
const idStr = (value) => String(value);
|
|
203
|
+
function cartItemCreatedAt(item) {
|
|
204
|
+
if (!item.createdAt)
|
|
205
|
+
return null;
|
|
206
|
+
const timestamp = Date.parse(item.createdAt);
|
|
207
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
208
|
+
}
|
|
209
|
+
/** Return cart lines newest-first without mutating SDK state. */
|
|
210
|
+
function sortCartItemsNewestFirst(items) {
|
|
211
|
+
return [...items].sort((a, b) => {
|
|
212
|
+
const aCreatedAt = cartItemCreatedAt(a);
|
|
213
|
+
const bCreatedAt = cartItemCreatedAt(b);
|
|
214
|
+
if (aCreatedAt != null || bCreatedAt != null) {
|
|
215
|
+
if (aCreatedAt == null)
|
|
216
|
+
return 1;
|
|
217
|
+
if (bCreatedAt == null)
|
|
218
|
+
return -1;
|
|
219
|
+
if (aCreatedAt !== bCreatedAt)
|
|
220
|
+
return bCreatedAt - aCreatedAt;
|
|
221
|
+
}
|
|
222
|
+
const aId = Number(a.id);
|
|
223
|
+
const bId = Number(b.id);
|
|
224
|
+
return Number.isFinite(aId) && Number.isFinite(bId) ? bId - aId : 0;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
203
227
|
function emptyAddressForm() {
|
|
204
228
|
return {
|
|
205
229
|
firstName: '',
|
|
@@ -298,6 +322,28 @@ function uniqueRates(rates) {
|
|
|
298
322
|
}
|
|
299
323
|
return out;
|
|
300
324
|
}
|
|
325
|
+
function isDigitalServiceLabel(value) {
|
|
326
|
+
if (!value)
|
|
327
|
+
return false;
|
|
328
|
+
const normalized = value.trim().toLocaleLowerCase('en-US');
|
|
329
|
+
return (normalized.includes('digital') ||
|
|
330
|
+
normalized.includes('service') ||
|
|
331
|
+
normalized.includes('دیجیتال') ||
|
|
332
|
+
normalized.includes('خدمات') ||
|
|
333
|
+
normalized.includes('خدمت'));
|
|
334
|
+
}
|
|
335
|
+
function isDigitalServiceItem(item) {
|
|
336
|
+
return isDigitalServiceLabel(item.productType);
|
|
337
|
+
}
|
|
338
|
+
/** True for the API's automatic digital/service delivery group. */
|
|
339
|
+
function isDigitalServiceGroup(group) {
|
|
340
|
+
if (isDigitalServiceLabel(group.key) || isDigitalServiceLabel(group.title)) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
const ratesAreDigitalService = group.rates.length > 0 &&
|
|
344
|
+
group.rates.every((rate) => isDigitalServiceLabel(rate.type) || isDigitalServiceLabel(rate.name));
|
|
345
|
+
return ratesAreDigitalService || (group.items.length > 0 && group.items.every(isDigitalServiceItem));
|
|
346
|
+
}
|
|
301
347
|
/**
|
|
302
348
|
* Group invoice items into shippable bundles with their switchable rates and
|
|
303
349
|
* the currently selected rate. Digital-only invoices yield an empty list.
|
|
@@ -317,10 +363,12 @@ function deriveShippingGroups(invoice, applicable) {
|
|
|
317
363
|
return [];
|
|
318
364
|
}
|
|
319
365
|
const itemById = new Map(invoice.items.map((item) => [idStr(item.id), item]));
|
|
320
|
-
//
|
|
366
|
+
// The API's plain `digital` products never receive a shipping assignment.
|
|
367
|
+
// Other digital/service variants may arrive through an automatic fulfillment
|
|
368
|
+
// rate; retain those groups for the API assignment and hide them in the UI.
|
|
321
369
|
const physicalItemsRate = (applicable.itemsShippingRate ?? []).filter((isr) => {
|
|
322
370
|
const item = itemById.get(idStr(isr.invoiceItemId));
|
|
323
|
-
return !item || item.productType !== 'digital';
|
|
371
|
+
return !item || item.productType?.trim().toLocaleLowerCase('en-US') !== 'digital';
|
|
324
372
|
});
|
|
325
373
|
if (physicalItemsRate.length === 0)
|
|
326
374
|
return [];
|
|
@@ -419,24 +467,27 @@ function deriveShippingGroups(invoice, applicable) {
|
|
|
419
467
|
}
|
|
420
468
|
];
|
|
421
469
|
}
|
|
422
|
-
/** Build the API payload from
|
|
470
|
+
/** Build the API payload from physical shipping selections. */
|
|
423
471
|
function buildShippingAssignments(groups) {
|
|
424
472
|
return groups
|
|
425
|
-
.filter((group) => group.selectedRateId != null)
|
|
473
|
+
.filter((group) => !isDigitalServiceGroup(group) && group.selectedRateId != null)
|
|
426
474
|
.map((group) => ({
|
|
427
475
|
rateId: group.selectedRateId,
|
|
428
476
|
invoiceItemIds: group.itemIds
|
|
429
477
|
}));
|
|
430
478
|
}
|
|
431
|
-
/** True once every
|
|
479
|
+
/** True once every physical shipping group has a selected rate. */
|
|
432
480
|
function isShippingComplete(invoice, groups) {
|
|
433
481
|
if (!invoice?.needsShipping) {
|
|
434
482
|
return true;
|
|
435
483
|
}
|
|
436
|
-
|
|
437
|
-
|
|
484
|
+
const physicalGroups = groups.filter((group) => !isDigitalServiceGroup(group));
|
|
485
|
+
if (physicalGroups.length === 0) {
|
|
486
|
+
// The API may set needsShipping for an automatic Digital/Service group.
|
|
487
|
+
// It is fulfillment metadata, not a customer-selectable shipping method.
|
|
488
|
+
return groups.length > 0 && groups.every(isDigitalServiceGroup);
|
|
438
489
|
}
|
|
439
|
-
return
|
|
490
|
+
return physicalGroups.every((group) => group.selectedRateId != null);
|
|
440
491
|
}
|
|
441
492
|
const codeDiscountTotal = (invoice) => (invoice.couponTotal || 0) + (invoice.discountTotal || 0);
|
|
442
493
|
/**
|
|
@@ -540,14 +591,22 @@ function selectDigitalItems(invoice, groups, applicable) {
|
|
|
540
591
|
// Before shipping methods are loaded, only explicitly-digital items are known.
|
|
541
592
|
// Showing everything as "digital" when applicable is null would be wrong.
|
|
542
593
|
if (applicable == null) {
|
|
543
|
-
return invoice.items.filter(
|
|
594
|
+
return invoice.items.filter(isDigitalServiceItem);
|
|
544
595
|
}
|
|
545
|
-
//
|
|
546
|
-
|
|
547
|
-
|
|
596
|
+
// The backend may model digital/service fulfillment as an automatic zero-cost
|
|
597
|
+
// shipping group. Treat its products as non-shippable in the UI while keeping
|
|
598
|
+
// the group in state so its assignment can still be submitted.
|
|
599
|
+
const digitalGroupItems = new Set(groups
|
|
600
|
+
.filter(isDigitalServiceGroup)
|
|
601
|
+
.flatMap((group) => group.itemIds.map(idStr)));
|
|
602
|
+
const groupedItems = new Set(groups.flatMap((group) => group.itemIds.map(idStr)));
|
|
603
|
+
return invoice.items.filter((item) => isDigitalServiceItem(item) ||
|
|
604
|
+
digitalGroupItems.has(idStr(item.id)) ||
|
|
605
|
+
!groupedItems.has(idStr(item.id)));
|
|
548
606
|
}
|
|
549
607
|
|
|
550
608
|
const STEP_ORDER = ['cart', 'shipping', 'payment', 'result'];
|
|
609
|
+
const ADDRESS_AUTOSUBMIT_DEBOUNCE_MS = 350;
|
|
551
610
|
function initialFlags() {
|
|
552
611
|
return {
|
|
553
612
|
bootstrapping: false,
|
|
@@ -594,6 +653,7 @@ function createCheckoutEngine(options) {
|
|
|
594
653
|
let effectExecutor = noopEffectExecutor;
|
|
595
654
|
let lock = Promise.resolve();
|
|
596
655
|
let addressRevision = 0;
|
|
656
|
+
let addressAutoSubmitTimer = null;
|
|
597
657
|
// ---- internal helpers -------------------------------------------------
|
|
598
658
|
const get = () => store.getState();
|
|
599
659
|
const set = store.setState;
|
|
@@ -614,6 +674,19 @@ function createCheckoutEngine(options) {
|
|
|
614
674
|
lock = next.then(() => undefined, () => undefined);
|
|
615
675
|
return next;
|
|
616
676
|
}
|
|
677
|
+
function clearAddressAutoSubmit() {
|
|
678
|
+
if (addressAutoSubmitTimer) {
|
|
679
|
+
clearTimeout(addressAutoSubmitTimer);
|
|
680
|
+
addressAutoSubmitTimer = null;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function scheduleAddressAutoSubmit(delay = ADDRESS_AUTOSUBMIT_DEBOUNCE_MS) {
|
|
684
|
+
clearAddressAutoSubmit();
|
|
685
|
+
addressAutoSubmitTimer = setTimeout(() => {
|
|
686
|
+
addressAutoSubmitTimer = null;
|
|
687
|
+
void withLock(submitAddressInternal);
|
|
688
|
+
}, delay);
|
|
689
|
+
}
|
|
617
690
|
function recomputeGroups() {
|
|
618
691
|
const { invoice, applicable } = get();
|
|
619
692
|
const groups = deriveShippingGroups(invoice, applicable);
|
|
@@ -809,13 +882,17 @@ function createCheckoutEngine(options) {
|
|
|
809
882
|
}
|
|
810
883
|
// ---- public actions ---------------------------------------------------
|
|
811
884
|
function goToStep(step) {
|
|
885
|
+
if (step !== 'shipping') {
|
|
886
|
+
clearAddressAutoSubmit();
|
|
887
|
+
}
|
|
812
888
|
set({ step, error: null });
|
|
813
889
|
emit('step_viewed', { step });
|
|
814
890
|
// When landing on shipping with a complete address but no methods fetched yet,
|
|
815
891
|
// auto-submit so methods appear without requiring a manual Continue press.
|
|
816
892
|
if (step === 'shipping') {
|
|
817
|
-
const { addressForm, invoice, applicable } = get();
|
|
818
|
-
|
|
893
|
+
const { addressForm, addressDirty, invoice, applicable, shippingGroups } = get();
|
|
894
|
+
const methodsUnresolved = Boolean(invoice?.needsShipping) && shippingGroups.length === 0;
|
|
895
|
+
if ((addressDirty || !applicable || methodsUnresolved) && isAddressComplete(addressForm, invoice?.needsShipping ?? true, get().postalCodeMandatory, get().emailMandatory)) {
|
|
819
896
|
void withLock(submitAddressInternal);
|
|
820
897
|
}
|
|
821
898
|
}
|
|
@@ -918,13 +995,18 @@ function createCheckoutEngine(options) {
|
|
|
918
995
|
// the Shipping step becomes visible.
|
|
919
996
|
const invoice = get().invoice;
|
|
920
997
|
if (isUsableSavedAddress(invoice?.shippingAddress)) {
|
|
921
|
-
|
|
998
|
+
const addressForm = reconcileAddressWithRegions(addressFormFromInvoice(invoice), get().regions, savedAddressCityName(invoice?.shippingAddress));
|
|
999
|
+
set({
|
|
1000
|
+
addressForm,
|
|
1001
|
+
addressDirty: isAddressDirty(addressForm, invoice)
|
|
1002
|
+
});
|
|
922
1003
|
}
|
|
923
1004
|
goToStep('shipping');
|
|
924
1005
|
}
|
|
925
1006
|
return;
|
|
926
1007
|
}
|
|
927
1008
|
if (state.step === 'shipping') {
|
|
1009
|
+
clearAddressAutoSubmit();
|
|
928
1010
|
// Phase 1: address not saved yet (or changed) → save it and reveal the
|
|
929
1011
|
// shipping methods, staying on the shipping step.
|
|
930
1012
|
const needsSave = state.addressDirty || !state.applicable;
|
|
@@ -969,10 +1051,6 @@ function createCheckoutEngine(options) {
|
|
|
969
1051
|
const res = await binding.client.cart.updateItem(cartProductId, variantId, quantity);
|
|
970
1052
|
if (res.data) {
|
|
971
1053
|
set({ cart: res.data });
|
|
972
|
-
// Optimistically update summary from cart data, then confirm with server.
|
|
973
|
-
const inv = get().invoice;
|
|
974
|
-
if (inv)
|
|
975
|
-
set({ invoice: applyCartToInvoice(inv, res.data) });
|
|
976
1054
|
await refreshInvoice();
|
|
977
1055
|
}
|
|
978
1056
|
else if (res.error) {
|
|
@@ -987,9 +1065,6 @@ function createCheckoutEngine(options) {
|
|
|
987
1065
|
const res = await binding.client.cart.removeItem(cartProductId, variantId);
|
|
988
1066
|
if (res.data) {
|
|
989
1067
|
set({ cart: res.data });
|
|
990
|
-
const inv = get().invoice;
|
|
991
|
-
if (inv)
|
|
992
|
-
set({ invoice: applyCartToInvoice(inv, res.data) });
|
|
993
1068
|
await refreshInvoice();
|
|
994
1069
|
}
|
|
995
1070
|
else if (res.error) {
|
|
@@ -1001,6 +1076,7 @@ function createCheckoutEngine(options) {
|
|
|
1001
1076
|
setAddressField(key, value) {
|
|
1002
1077
|
const before = get().addressForm;
|
|
1003
1078
|
const changed = before[key] !== value || (key === 'regionId' && before.cityId !== null);
|
|
1079
|
+
const destinationChanged = changed && (key === 'regionId' || key === 'cityId');
|
|
1004
1080
|
if (changed) {
|
|
1005
1081
|
addressRevision += 1;
|
|
1006
1082
|
}
|
|
@@ -1014,22 +1090,28 @@ function createCheckoutEngine(options) {
|
|
|
1014
1090
|
return {
|
|
1015
1091
|
addressForm,
|
|
1016
1092
|
addressDirty,
|
|
1017
|
-
//
|
|
1018
|
-
//
|
|
1019
|
-
...(
|
|
1093
|
+
// Shipping rates depend on region/city. Contact and street edits must
|
|
1094
|
+
// not discard valid methods for the same destination.
|
|
1095
|
+
...(destinationChanged ? { applicable: null, shippingGroups: [] } : {})
|
|
1020
1096
|
};
|
|
1021
1097
|
});
|
|
1022
|
-
//
|
|
1023
|
-
//
|
|
1024
|
-
//
|
|
1025
|
-
if (changed &&
|
|
1098
|
+
// Browser autofill often populates the selects before the final required
|
|
1099
|
+
// text field. Once the form becomes complete, debounce text changes and
|
|
1100
|
+
// submit automatically; a discrete city selection can submit immediately.
|
|
1101
|
+
if (changed && get().step === 'shipping') {
|
|
1026
1102
|
const state = get();
|
|
1027
|
-
|
|
1028
|
-
|
|
1103
|
+
const methodsUnresolved = !state.applicable
|
|
1104
|
+
|| (Boolean(state.invoice?.needsShipping) && state.shippingGroups.length === 0);
|
|
1105
|
+
if (isAddressComplete(state.addressForm, state.invoice?.needsShipping ?? true, state.postalCodeMandatory, state.emailMandatory) && (destinationChanged || methodsUnresolved)) {
|
|
1106
|
+
scheduleAddressAutoSubmit(key === 'cityId' ? 0 : undefined);
|
|
1107
|
+
}
|
|
1108
|
+
else if (!isAddressComplete(state.addressForm, state.invoice?.needsShipping ?? true, state.postalCodeMandatory, state.emailMandatory)) {
|
|
1109
|
+
clearAddressAutoSubmit();
|
|
1029
1110
|
}
|
|
1030
1111
|
}
|
|
1031
1112
|
},
|
|
1032
1113
|
async submitAddress() {
|
|
1114
|
+
clearAddressAutoSubmit();
|
|
1033
1115
|
return withLock(submitAddressInternal);
|
|
1034
1116
|
},
|
|
1035
1117
|
async selectShippingRate(groupKey, rateId) {
|
|
@@ -1151,6 +1233,8 @@ function createCheckoutEngine(options) {
|
|
|
1151
1233
|
const state = get();
|
|
1152
1234
|
const submittedAddressRevision = addressRevision;
|
|
1153
1235
|
const needsShipping = state.invoice?.needsShipping ?? true;
|
|
1236
|
+
const shouldReloadShipping = needsShipping
|
|
1237
|
+
&& (!state.applicable || state.shippingGroups.length === 0);
|
|
1154
1238
|
const abandonStaleSubmission = (invoice) => {
|
|
1155
1239
|
set({
|
|
1156
1240
|
...(invoice ? { invoice } : {}),
|
|
@@ -1195,7 +1279,15 @@ function createCheckoutEngine(options) {
|
|
|
1195
1279
|
}
|
|
1196
1280
|
set({ invoice: linkRes.data, addressDirty: false });
|
|
1197
1281
|
if (needsShipping) {
|
|
1198
|
-
|
|
1282
|
+
let ok = true;
|
|
1283
|
+
if (shouldReloadShipping) {
|
|
1284
|
+
ok = await loadApplicableShipping(submittedAddressRevision);
|
|
1285
|
+
}
|
|
1286
|
+
else if (recomputeGroups().length === 0) {
|
|
1287
|
+
// Invoice item IDs can change when the new address snapshot is linked.
|
|
1288
|
+
// Reload only if the existing applicable data can no longer form groups.
|
|
1289
|
+
ok = await loadApplicableShipping(submittedAddressRevision);
|
|
1290
|
+
}
|
|
1199
1291
|
if (ok) {
|
|
1200
1292
|
await assignCurrentShipping();
|
|
1201
1293
|
if (addressRevision !== submittedAddressRevision) {
|
|
@@ -1222,6 +1314,7 @@ function createCheckoutEngine(options) {
|
|
|
1222
1314
|
effectExecutor = executor;
|
|
1223
1315
|
},
|
|
1224
1316
|
destroy() {
|
|
1317
|
+
clearAddressAutoSubmit();
|
|
1225
1318
|
effectExecutor = noopEffectExecutor;
|
|
1226
1319
|
}
|
|
1227
1320
|
};
|
|
@@ -1274,23 +1367,6 @@ function toAddressInput(form) {
|
|
|
1274
1367
|
description: form.description.trim() || undefined
|
|
1275
1368
|
};
|
|
1276
1369
|
}
|
|
1277
|
-
/**
|
|
1278
|
-
* Immediately derive updated invoice item quantities and totals from a fresh
|
|
1279
|
-
* cart response so the summary panel doesn't wait for the invoice refresh.
|
|
1280
|
-
*/
|
|
1281
|
-
function applyCartToInvoice(invoice, cart) {
|
|
1282
|
-
const byVariant = new Map(cart.items.map((i) => [i.productVariantId, i]));
|
|
1283
|
-
const newItems = invoice.items
|
|
1284
|
-
.filter((item) => byVariant.has(item.productVariantId))
|
|
1285
|
-
.map((item) => {
|
|
1286
|
-
const ci = byVariant.get(item.productVariantId);
|
|
1287
|
-
return { ...item, quantity: ci.quantity, lineTotal: ci.lineTotal };
|
|
1288
|
-
});
|
|
1289
|
-
const subtotal = newItems.reduce((s, i) => s + i.lineTotal, 0);
|
|
1290
|
-
const discount = (invoice.itemsDiscount || 0) + (invoice.discountTotal || 0) + (invoice.couponTotal || 0);
|
|
1291
|
-
const finalTotal = Math.max(0, subtotal - discount + (invoice.shippingTotal || 0) + (invoice.vat || 0) - (invoice.creditTotal || 0));
|
|
1292
|
-
return { ...invoice, items: newItems, itemsTotalRawPrice: subtotal, netTotal: subtotal, finalTotal };
|
|
1293
|
-
}
|
|
1294
1370
|
// Map raw gateway-return query params into the typed payment-step input.
|
|
1295
1371
|
// Only the string-valued callback fields are forwarded; `trackingData` /
|
|
1296
1372
|
// `payload` are parsed from JSON when the gateway sends them encoded.
|
|
@@ -1451,7 +1527,8 @@ const fa = {
|
|
|
1451
1527
|
shippingMethod: 'روش ارسال',
|
|
1452
1528
|
shippingMethods: 'روشهای ارسال',
|
|
1453
1529
|
shippingMethodsHint: 'پس از ثبت نشانی، روشهای قابل استفاده نمایش داده میشوند.',
|
|
1454
|
-
digitalNoShipping: '
|
|
1530
|
+
digitalNoShipping: 'محصولات دیجیتال و خدمات',
|
|
1531
|
+
digitalNoShippingHint: 'این موارد به ارسال فیزیکی نیاز ندارند.',
|
|
1455
1532
|
errorRequired: 'این فیلد اجباری است',
|
|
1456
1533
|
errorMobilePhone: 'شماره موبایل معتبر وارد کنید (مثلاً ۰۹۱۲۳۴۵۶۷۸۹)',
|
|
1457
1534
|
errorEmail: 'آدرس ایمیل معتبر نیست',
|
|
@@ -1531,7 +1608,8 @@ const en = {
|
|
|
1531
1608
|
shippingMethod: 'Shipping method',
|
|
1532
1609
|
shippingMethods: 'Shipping methods',
|
|
1533
1610
|
shippingMethodsHint: 'Available delivery options will appear after you save this address.',
|
|
1534
|
-
digitalNoShipping: 'Digital
|
|
1611
|
+
digitalNoShipping: 'Digital products and services',
|
|
1612
|
+
digitalNoShippingHint: 'These items do not require physical delivery.',
|
|
1535
1613
|
errorRequired: 'This field is required',
|
|
1536
1614
|
errorMobilePhone: 'Enter a valid mobile number (e.g. 09123456789)',
|
|
1537
1615
|
errorEmail: 'Enter a valid email address',
|
|
@@ -1609,5 +1687,5 @@ function paymentMethodInfo(code, locale) {
|
|
|
1609
1687
|
};
|
|
1610
1688
|
}
|
|
1611
1689
|
|
|
1612
|
-
export {
|
|
1613
|
-
//# sourceMappingURL=labels-
|
|
1690
|
+
export { paymentMethodInfo as A, paymentMethodLabel as B, selectDigitalItems as C, selectSummary as D, sortCartItemsNewestFirst as E, strings as F, toEnglishDigits as G, toPersianDigits as H, addressFormFromInvoice as a, buildShippingAssignments as b, classifyAppliedDiscount as c, createBrowserEffectExecutor as d, createCheckoutEngine as e, createSdkBinding as f, createStore as g, defaultCurrencyLabel as h, deriveShippingGroups as i, emptyAddressForm as j, formatMoney as k, formatNumber as l, formatPercent as m, formatPrice as n, fromSdkError as o, isAddressComplete as p, isAddressDirty as q, isDigitalServiceGroup as r, isShippingComplete as s, isValidIranianMobile as t, isValidIranianPhone as u, makeError as v, makeEvent as w, messageForCode as x, noopEffectExecutor as y, normalizeIranianPhone as z };
|
|
1691
|
+
//# sourceMappingURL=labels-ByA_yGKl.js.map
|