@sazito/checkout 0.1.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.
@@ -0,0 +1,845 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var react = require('react');
6
+ var useCheckout = require('../chunks/use-checkout-Cvp_K3UW.cjs');
7
+ var labels = require('../chunks/labels-BlMZkOsV.cjs');
8
+ require('@sazito/client-sdk');
9
+
10
+ /**
11
+ * When `asChild` is true, merges the parent's props onto the single React child
12
+ * element instead of rendering a wrapper element — the same pattern Radix UI /
13
+ * shadcn/ui uses. Class names and event handlers are merged; all other props
14
+ * from the parent win (child props act as defaults).
15
+ */
16
+ function Slot({ children, ...slotProps }) {
17
+ if (!react.isValidElement(children)) {
18
+ if (process.env.NODE_ENV !== 'production') {
19
+ console.warn('[Slot] Must receive exactly one valid React element as child.');
20
+ }
21
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
22
+ }
23
+ const child = children;
24
+ const childProps = child.props;
25
+ const mergedClassName = [slotProps.className, childProps.className].filter(Boolean).join(' ') || undefined;
26
+ // Merge event handlers: call both if both exist.
27
+ const merged = { ...childProps, ...slotProps };
28
+ if (mergedClassName)
29
+ merged.className = mergedClassName;
30
+ for (const key of Object.keys(childProps)) {
31
+ if (key.startsWith('on') && typeof childProps[key] === 'function' && typeof slotProps[key] === 'function') {
32
+ const slotHandler = slotProps[key];
33
+ const childHandler = childProps[key];
34
+ merged[key] = (...args) => {
35
+ slotHandler(...args);
36
+ childHandler(...args);
37
+ };
38
+ }
39
+ }
40
+ return react.cloneElement(child, merged);
41
+ }
42
+
43
+ function cx(...parts) {
44
+ return parts.filter(Boolean).join(' ');
45
+ }
46
+ function Button({ variant = 'primary', block, loading, asChild, className, children, disabled, ...rest }) {
47
+ const props = {
48
+ className: cx('szc-btn', `szc-btn--${variant}`, block && 'szc-btn--block', className),
49
+ disabled: disabled || loading,
50
+ 'aria-busy': loading || undefined,
51
+ ...rest,
52
+ };
53
+ if (asChild) {
54
+ return jsxRuntime.jsx(Slot, { ...props, children: children });
55
+ }
56
+ return (jsxRuntime.jsxs("button", { type: "button", ...props, children: [loading ? jsxRuntime.jsx(Spinner, {}) : null, jsxRuntime.jsx("span", { children: children })] }));
57
+ }
58
+ function Spinner({ asChild, className, children } = {}) {
59
+ if (asChild && children) {
60
+ return jsxRuntime.jsx(Slot, { className: cx('szc-spinner', className), children: children });
61
+ }
62
+ return jsxRuntime.jsx("span", { className: cx('szc-spinner', className), "aria-hidden": "true", children: children });
63
+ }
64
+ function ProductPlaceholder({ asChild, className, children } = {}) {
65
+ const props = { className: cx('szc-product-placeholder', className) };
66
+ if (asChild && children) {
67
+ return jsxRuntime.jsx(Slot, { ...props, children: children });
68
+ }
69
+ return (jsxRuntime.jsx("span", { ...props, children: children ?? (jsxRuntime.jsxs("svg", { viewBox: "0 0 64 64", width: "30", height: "30", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("path", { d: "M32 12 49 21.5v21L32 52 15 42.5v-21L32 12Z", stroke: "currentColor", strokeWidth: "2.25", strokeLinejoin: "round" }), jsxRuntime.jsx("path", { d: "m15 21.5 17 9.5 17-9.5M32 31v21", stroke: "currentColor", strokeWidth: "2.25", strokeLinecap: "round", strokeLinejoin: "round" })] })) }));
70
+ }
71
+ function FieldLabel({ label, required, optionalLabel }) {
72
+ return (jsxRuntime.jsxs("span", { className: "szc-field__label", children: [label, !required && optionalLabel ? (jsxRuntime.jsxs("span", { className: "szc-field__optional", children: ["(", optionalLabel, ")"] })) : null] }));
73
+ }
74
+ function Field({ label, id, className, error, required, optionalLabel, asChild, children, ...rest }) {
75
+ const inputProps = {
76
+ id,
77
+ required,
78
+ className: cx('szc-input', error && 'szc-input--error', className),
79
+ ...rest,
80
+ };
81
+ return (jsxRuntime.jsxs("label", { className: "szc-field", htmlFor: id, children: [jsxRuntime.jsx(FieldLabel, { label: label, required: required, optionalLabel: optionalLabel }), asChild && children
82
+ ? jsxRuntime.jsx(Slot, { ...inputProps, children: children })
83
+ : jsxRuntime.jsx("input", { ...inputProps }), error ? jsxRuntime.jsx("span", { className: "szc-field__error", children: error }) : null] }));
84
+ }
85
+ function SectionTitle({ children, asChild, className }) {
86
+ const props = { className: cx('szc-section-title', className) };
87
+ if (asChild && children) {
88
+ return jsxRuntime.jsx(Slot, { ...props, children: children });
89
+ }
90
+ return jsxRuntime.jsx("h3", { ...props, children: children });
91
+ }
92
+ function ErrorBanner({ message, asChild, children, className }) {
93
+ const props = {
94
+ className: cx('szc-error', className),
95
+ role: 'alert',
96
+ };
97
+ if (asChild && children) {
98
+ return jsxRuntime.jsx(Slot, { ...props, children: children });
99
+ }
100
+ return jsxRuntime.jsx("div", { ...props, children: message });
101
+ }
102
+
103
+ const STEPS = ['cart', 'shipping', 'payment', 'result'];
104
+ const STEP_ICONS = {
105
+ cart: CartIcon,
106
+ shipping: TruckIcon$1,
107
+ payment: CardIcon,
108
+ result: ClipboardIcon
109
+ };
110
+ function Stepper() {
111
+ const { state, t } = useCheckout.useCheckout();
112
+ const labels = {
113
+ cart: t.stepCart,
114
+ shipping: t.stepShipping,
115
+ payment: t.stepPayment,
116
+ result: t.stepResult
117
+ };
118
+ const currentIndex = STEPS.indexOf(state.step);
119
+ return (jsxRuntime.jsx("ol", { className: "szc-stepper", children: STEPS.map((step, index) => {
120
+ const status = index < currentIndex ? 'done' : index === currentIndex ? 'active' : 'todo';
121
+ const Icon = STEP_ICONS[step];
122
+ return (jsxRuntime.jsxs("li", { className: `szc-step szc-step--${status}`, children: [jsxRuntime.jsx("span", { className: "szc-step__dot", children: status === 'done' ? jsxRuntime.jsx(CheckIcon$2, {}) : jsxRuntime.jsx(Icon, {}) }), jsxRuntime.jsx("span", { className: "szc-step__label", children: labels[step] }), index < STEPS.length - 1 ? jsxRuntime.jsx("span", { className: "szc-step__line" }) : null] }, step));
123
+ }) }));
124
+ }
125
+ function CheckIcon$2() {
126
+ return (jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "15", height: "15", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M3.5 8.5l3 3 6-6.5", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
127
+ }
128
+ function CartIcon() {
129
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", width: "15", height: "15", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("path", { d: "M1.5 2h1.8l1.9 7.5h6.3l1.5-5H4.8", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }), jsxRuntime.jsx("circle", { cx: "6.5", cy: "13", r: "1", fill: "currentColor" }), jsxRuntime.jsx("circle", { cx: "11", cy: "13", r: "1", fill: "currentColor" })] }));
130
+ }
131
+ function TruckIcon$1() {
132
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", width: "15", height: "15", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("rect", { x: "1", y: "4", width: "9", height: "7", rx: "1", stroke: "currentColor", strokeWidth: "1.6" }), jsxRuntime.jsx("path", { d: "M10 6.5h2.5l2 2.5V11h-4.5V6.5z", stroke: "currentColor", strokeWidth: "1.6", strokeLinejoin: "round" }), jsxRuntime.jsx("circle", { cx: "4", cy: "12.5", r: "1.2", stroke: "currentColor", strokeWidth: "1.3" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12.5", r: "1.2", stroke: "currentColor", strokeWidth: "1.3" })] }));
133
+ }
134
+ function CardIcon() {
135
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", width: "15", height: "15", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("rect", { x: "1.5", y: "3.5", width: "13", height: "9", rx: "1.5", stroke: "currentColor", strokeWidth: "1.6" }), jsxRuntime.jsx("path", { d: "M1.5 6.5h13", stroke: "currentColor", strokeWidth: "1.6" }), jsxRuntime.jsx("rect", { x: "3", y: "8.5", width: "3", height: "1.5", rx: ".5", fill: "currentColor" })] }));
136
+ }
137
+ function ClipboardIcon() {
138
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", width: "15", height: "15", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("rect", { x: "2.5", y: "2.5", width: "11", height: "12", rx: "1.5", stroke: "currentColor", strokeWidth: "1.6" }), jsxRuntime.jsx("path", { d: "M5.5 2.5A1.5 1.5 0 0 1 7 1h2a1.5 1.5 0 0 1 1.5 1.5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }), jsxRuntime.jsx("path", { d: "M5 7h6M5 9.5h4", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round" })] }));
139
+ }
140
+
141
+ function OrderSummary() {
142
+ const { state, summary, money, t } = useCheckout.useCheckout();
143
+ const percentSign = state.locale === 'fa' ? '٪' : '%';
144
+ const lineLabels = {
145
+ subtotal: t.subtotal,
146
+ discount: t.yourSavings,
147
+ shipping: t.shipping,
148
+ credit: t.credit,
149
+ vat: t.vat
150
+ };
151
+ return (jsxRuntime.jsxs("aside", { className: "szc-summary", children: [jsxRuntime.jsxs("div", { className: "szc-summary__total-head", children: [jsxRuntime.jsx("span", { className: "szc-summary__total-label", children: t.totalAmount }), jsxRuntime.jsx("span", { className: "szc-summary__total-value", children: money(summary.total) })] }), jsxRuntime.jsx("dl", { className: "szc-summary__lines", children: summary.lines.map((line) => (jsxRuntime.jsxs("div", { className: `szc-summary__line${line.key === 'discount' ? ' szc-summary__line--discount' : ''}`, children: [jsxRuntime.jsxs("dt", { children: [lineLabels[line.key], (line.percent ?? 0) > 0
152
+ ? ` (${labels.formatPercent(line.percent, state.locale)}${percentSign})`
153
+ : ''] }), jsxRuntime.jsx("dd", { className: line.negative ? 'szc-summary__line--neg' : undefined, children: line.free ? (jsxRuntime.jsx("span", { className: "szc-summary__free", children: t.free })) : (`${line.negative ? '−' : ''}${money(line.amount)}`) })] }, line.key))) }), jsxRuntime.jsxs("div", { className: "szc-summary__grand", children: [jsxRuntime.jsx("span", { children: t.total }), jsxRuntime.jsx("span", { children: money(summary.total) })] })] }));
154
+ }
155
+
156
+ const PERSIAN_DIGITS = '۰۱۲۳۴۵۶۷۸۹';
157
+ const ARABIC_DIGITS = '٠١٢٣٤٥٦٧٨٩';
158
+ const QUANTITY_DEBOUNCE_MS = 600;
159
+ function toLatinDigits(value) {
160
+ return value
161
+ .replace(/[۰-۹]/g, (digit) => String(PERSIAN_DIGITS.indexOf(digit)))
162
+ .replace(/[٠-٩]/g, (digit) => String(ARABIC_DIGITS.indexOf(digit)));
163
+ }
164
+ const HEX_COLOR_RE = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
165
+ function attrValueToString(value) {
166
+ if (value == null)
167
+ return '';
168
+ if (typeof value === 'object') {
169
+ const v = value.value;
170
+ return v == null ? '' : String(v);
171
+ }
172
+ return String(value);
173
+ }
174
+ function toHexColor(value) {
175
+ if (typeof value !== 'string')
176
+ return null;
177
+ const trimmed = value.trim();
178
+ return HEX_COLOR_RE.test(trimmed) ? (trimmed.startsWith('#') ? trimmed : `#${trimmed}`) : null;
179
+ }
180
+ // Hex can arrive as the raw value, or nested in `extra`/`value` of an object attribute.
181
+ function attrHexColor(value) {
182
+ if (value && typeof value === 'object') {
183
+ const obj = value;
184
+ return toHexColor(obj.extra) ?? toHexColor(obj.value);
185
+ }
186
+ return toHexColor(value);
187
+ }
188
+ function CartStep({ continueShoppingUrl, renderEmpty, }) {
189
+ const { state, actions, money, t } = useCheckout.useCheckout();
190
+ const cart = state.cart;
191
+ const busy = state.flags.updatingCart;
192
+ const invoiceItemsByVariant = new Map((state.invoice?.items ?? []).map((item) => [item.productVariantId, item]));
193
+ if (!cart || cart.items.length === 0) {
194
+ if (renderEmpty) {
195
+ return renderEmpty({ continueShoppingUrl });
196
+ }
197
+ return (jsxRuntime.jsx("section", { className: "szc-empty", role: "status", "aria-live": "polite", children: jsxRuntime.jsxs("div", { className: "szc-empty__card", children: [jsxRuntime.jsx("span", { className: "szc-empty__badge", children: jsxRuntime.jsx(CartIcon, {}) }), jsxRuntime.jsxs("div", { className: "szc-empty__copy", children: [jsxRuntime.jsx("h3", { className: "szc-empty__title", children: t.cartEmpty }), jsxRuntime.jsx("p", { className: "szc-empty__hint", children: t.cartEmptyHint })] }), continueShoppingUrl ? (jsxRuntime.jsx(Button, { className: "szc-empty__cta", variant: "primary", onClick: () => { window.location.href = continueShoppingUrl; }, children: t.continueShopping })) : null] }) }));
198
+ }
199
+ return (jsxRuntime.jsx("section", { className: "szc-step-panel", children: jsxRuntime.jsx("ul", { className: "szc-cart-list", children: cart.items.map((item) => {
200
+ const max = item.product.maxOrderQuantity;
201
+ const min = item.product.minOrderQuantity ?? 1;
202
+ const invoiceItem = invoiceItemsByVariant.get(item.product.variantId);
203
+ const rawLineTotal = (invoiceItem?.rawPrice ?? item.unitPrice) * item.quantity;
204
+ const itemDiscount = invoiceItem?.customerProfit
205
+ || Math.max(0, rawLineTotal - item.lineTotal);
206
+ return (jsxRuntime.jsxs("li", { className: "szc-cart-row", children: [item.product.image?.url ? (
207
+ // eslint-disable-next-line @next/next/no-img-element
208
+ jsxRuntime.jsx("img", { className: "szc-cart-row__thumb", src: item.product.image.url, alt: "" })) : (jsxRuntime.jsx(ProductPlaceholder, {})), jsxRuntime.jsxs("div", { className: "szc-cart-row__main", children: [jsxRuntime.jsx("span", { className: "szc-cart-row__name", children: item.product.name }), item.product.attributes?.length ? (jsxRuntime.jsx("span", { className: "szc-cart-row__attrs", children: item.product.attributes.map((a, i) => {
209
+ const value = attrValueToString(a.value);
210
+ const hex = attrHexColor(a.value);
211
+ return (jsxRuntime.jsxs("span", { className: "szc-cart-row__attr", children: [i > 0 ? jsxRuntime.jsx("span", { className: "szc-cart-row__attr-sep", children: "\u00B7" }) : null, jsxRuntime.jsxs("span", { children: [a.name, ":"] }), hex ? (jsxRuntime.jsx("span", { className: "szc-cart-row__swatch", style: { backgroundColor: hex }, title: hex, "aria-hidden": "true" })) : null, value ? jsxRuntime.jsx("span", { children: value }) : null] }, `${a.name}-${i}`));
212
+ }) })) : null, jsxRuntime.jsx("span", { className: "szc-cart-row__price", children: money(item.unitPrice) })] }), jsxRuntime.jsxs("div", { className: "szc-cart-row__side", children: [jsxRuntime.jsx(QuantityControl, { value: item.quantity, min: min, max: max, label: t.quantity, onChange: (quantity) => actions.updateItemQuantity(item.id, item.product.variantId, quantity) }), itemDiscount > 0 ? (jsxRuntime.jsx("span", { className: "szc-cart-row__discount", children: t.itemDiscount(money(itemDiscount)) })) : null, jsxRuntime.jsx("span", { className: "szc-cart-row__line-total", children: money(item.lineTotal) }), jsxRuntime.jsx("button", { type: "button", className: "szc-cart-row__remove", "aria-label": t.remove, disabled: busy, onClick: () => actions.removeItem(item.id, item.product.variantId), children: jsxRuntime.jsx(TrashIcon, {}) })] })] }, item.id));
213
+ }) }) }));
214
+ }
215
+ function QuantityControl({ value, min, max, label, onChange }) {
216
+ const [draft, setDraft] = react.useState(() => labels.toPersianDigits(String(value)));
217
+ const [pending, setPending] = react.useState(false);
218
+ const draftRef = react.useRef(draft);
219
+ const pendingValueRef = react.useRef(null);
220
+ const timerRef = react.useRef(null);
221
+ const inFlightRef = react.useRef(false);
222
+ const serverValueRef = react.useRef(value);
223
+ const onChangeRef = react.useRef(onChange);
224
+ serverValueRef.current = value;
225
+ onChangeRef.current = onChange;
226
+ const updateDraft = (next) => {
227
+ draftRef.current = next;
228
+ setDraft(next);
229
+ };
230
+ react.useEffect(() => {
231
+ if (!pending || pendingValueRef.current === value) {
232
+ updateDraft(labels.toPersianDigits(String(value)));
233
+ }
234
+ }, [value, pending]);
235
+ react.useEffect(() => () => {
236
+ if (timerRef.current)
237
+ clearTimeout(timerRef.current);
238
+ }, []);
239
+ const normalize = (next) => Math.min(max ?? Number.POSITIVE_INFINITY, Math.max(min, Math.trunc(next)));
240
+ async function flushPendingUpdate() {
241
+ if (inFlightRef.current)
242
+ return;
243
+ const target = pendingValueRef.current;
244
+ if (target == null)
245
+ return;
246
+ if (target === serverValueRef.current) {
247
+ pendingValueRef.current = null;
248
+ setPending(false);
249
+ return;
250
+ }
251
+ inFlightRef.current = true;
252
+ try {
253
+ await onChangeRef.current(target);
254
+ }
255
+ finally {
256
+ inFlightRef.current = false;
257
+ if (pendingValueRef.current === target) {
258
+ pendingValueRef.current = null;
259
+ setPending(false);
260
+ }
261
+ else if (timerRef.current == null) {
262
+ timerRef.current = setTimeout(() => {
263
+ timerRef.current = null;
264
+ void flushPendingUpdate();
265
+ }, QUANTITY_DEBOUNCE_MS);
266
+ }
267
+ }
268
+ }
269
+ const scheduleUpdate = (rawValue) => {
270
+ const parsed = typeof rawValue === 'number' ? rawValue : Number(toLatinDigits(rawValue));
271
+ const next = normalize(Number.isFinite(parsed) ? parsed : value);
272
+ updateDraft(labels.toPersianDigits(String(next)));
273
+ if (next === serverValueRef.current && !pending && !inFlightRef.current)
274
+ return;
275
+ pendingValueRef.current = next;
276
+ setPending(true);
277
+ if (timerRef.current)
278
+ clearTimeout(timerRef.current);
279
+ timerRef.current = setTimeout(() => {
280
+ timerRef.current = null;
281
+ void flushPendingUpdate();
282
+ }, QUANTITY_DEBOUNCE_MS);
283
+ };
284
+ const step = (amount) => {
285
+ const parsedDraft = Number(toLatinDigits(draftRef.current));
286
+ const base = Number.isFinite(parsedDraft) ? parsedDraft : value;
287
+ scheduleUpdate(base + amount);
288
+ };
289
+ const parsedDraft = Number(toLatinDigits(draft));
290
+ const displayedValue = Number.isFinite(parsedDraft) ? normalize(parsedDraft) : value;
291
+ return (jsxRuntime.jsxs("div", { className: `szc-qty${pending ? ' szc-qty--pending' : ''}`, "aria-busy": pending, children: [jsxRuntime.jsx("button", { type: "button", className: "szc-qty__btn", "aria-label": `${label} −`, disabled: displayedValue <= min, onMouseDown: (event) => event.preventDefault(), onClick: () => step(-1), children: jsxRuntime.jsx(MinusIcon, {}) }), jsxRuntime.jsx("input", { className: "szc-qty__input", type: "text", inputMode: "numeric", pattern: "[\u06F0-\u06F9\u0660-\u06690-9]*", role: "spinbutton", value: draft, "aria-label": label, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": displayedValue, onChange: (event) => {
292
+ const digits = toLatinDigits(event.target.value).replace(/\D/g, '');
293
+ if (!digits) {
294
+ if (timerRef.current)
295
+ clearTimeout(timerRef.current);
296
+ timerRef.current = null;
297
+ updateDraft('');
298
+ return;
299
+ }
300
+ scheduleUpdate(Number(digits));
301
+ }, onBlur: () => scheduleUpdate(draftRef.current), onKeyDown: (event) => {
302
+ if (event.key === 'Enter') {
303
+ event.currentTarget.blur();
304
+ }
305
+ else if (event.key === 'Escape') {
306
+ event.preventDefault();
307
+ if (timerRef.current)
308
+ clearTimeout(timerRef.current);
309
+ timerRef.current = null;
310
+ pendingValueRef.current = null;
311
+ setPending(false);
312
+ updateDraft(labels.toPersianDigits(String(value)));
313
+ }
314
+ else if (event.key === 'ArrowUp') {
315
+ event.preventDefault();
316
+ step(1);
317
+ }
318
+ else if (event.key === 'ArrowDown') {
319
+ event.preventDefault();
320
+ step(-1);
321
+ }
322
+ } }), jsxRuntime.jsx("button", { type: "button", className: "szc-qty__btn", "aria-label": `${label} +`, disabled: max != null && displayedValue >= max, onMouseDown: (event) => event.preventDefault(), onClick: () => step(1), children: jsxRuntime.jsx(PlusIcon, {}) })] }));
323
+ }
324
+ function MinusIcon() {
325
+ return (jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "14", height: "14", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M3.5 8h9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
326
+ }
327
+ function PlusIcon() {
328
+ return (jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "14", height: "14", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M8 3.5v9M3.5 8h9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
329
+ }
330
+ function TrashIcon() {
331
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [jsxRuntime.jsx("path", { d: "M3 6h18" }), jsxRuntime.jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }), jsxRuntime.jsx("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), jsxRuntime.jsx("path", { d: "M10 11v6M14 11v6" })] }));
332
+ }
333
+
334
+ function validate(form, needsShipping, postalCodeMandatory, emailMandatory, t) {
335
+ const e = {};
336
+ if (!form.firstName.trim())
337
+ e.firstName = t.errorRequired;
338
+ if (!form.lastName.trim())
339
+ e.lastName = t.errorRequired;
340
+ if (!form.mobilePhone.trim()) {
341
+ e.mobilePhone = t.errorRequired;
342
+ }
343
+ else if (!labels.isValidIranianMobile(form.mobilePhone)) {
344
+ e.mobilePhone = t.errorMobilePhone;
345
+ }
346
+ if (emailMandatory && !form.email.trim()) {
347
+ e.email = t.errorRequired;
348
+ }
349
+ else if (form.email.trim() && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email.trim())) {
350
+ e.email = t.errorEmail;
351
+ }
352
+ if (needsShipping) {
353
+ if (!form.regionId)
354
+ e.regionId = t.errorRequired;
355
+ if (!form.cityId)
356
+ e.cityId = t.errorRequired;
357
+ if (postalCodeMandatory && !form.postalCode.trim())
358
+ e.postalCode = t.errorRequired;
359
+ if (!form.address.trim())
360
+ e.address = t.errorRequired;
361
+ }
362
+ return e;
363
+ }
364
+ function ShippingStep() {
365
+ const { state, actions, t, digitalItems } = useCheckout.useCheckout();
366
+ const { addressForm, regions, shippingGroups } = state;
367
+ const [touched, setTouched] = react.useState({});
368
+ const needsShipping = state.invoice?.needsShipping ?? true;
369
+ const touch = react.useCallback((key) => {
370
+ setTouched((prev) => ({ ...prev, [key]: true }));
371
+ }, []);
372
+ const allErrors = validate(addressForm, needsShipping, state.postalCodeMandatory, state.emailMandatory, t);
373
+ const errors = Object.fromEntries(Object.entries(allErrors).filter(([k]) => touched[k]));
374
+ const selectedRegion = regions.find((r) => r.id === addressForm.regionId);
375
+ const handleBlurPhone = (key) => {
376
+ const raw = addressForm[key];
377
+ if (raw) {
378
+ const normalized = labels.normalizeIranianPhone(raw);
379
+ if (normalized !== raw)
380
+ actions.setAddressField(key, normalized);
381
+ }
382
+ touch(key);
383
+ };
384
+ const busy = state.flags.savingAddress || state.flags.loadingShipping;
385
+ return (jsxRuntime.jsxs("section", { className: `szc-step-panel${busy ? ' szc-step-panel--loading' : ''}`, children: [jsxRuntime.jsxs("div", { className: "szc-shipping-form-card", children: [jsxRuntime.jsxs("section", { className: "szc-shipping-section", "aria-labelledby": "szc-contact-title", children: [jsxRuntime.jsx(ShippingSectionHeader, { id: "szc-contact-title", title: t.contactInfo, icon: "contact" }), jsxRuntime.jsxs("div", { className: "szc-form-grid", children: [jsxRuntime.jsx(Field, { id: "szc-first-name", label: t.firstName, required: true, optionalLabel: t.optional, value: addressForm.firstName, error: errors.firstName, onChange: (e) => actions.setAddressField('firstName', e.target.value), onBlur: () => touch('firstName') }), jsxRuntime.jsx(Field, { id: "szc-last-name", label: t.lastName, required: true, optionalLabel: t.optional, value: addressForm.lastName, error: errors.lastName, onChange: (e) => actions.setAddressField('lastName', e.target.value), onBlur: () => touch('lastName') }), jsxRuntime.jsx(Field, { id: "szc-mobile", label: t.mobilePhone, required: true, optionalLabel: t.optional, className: "szc-input--ltr", dir: "ltr", inputMode: "tel", value: addressForm.mobilePhone, error: errors.mobilePhone, onChange: (e) => actions.setAddressField('mobilePhone', e.target.value), onBlur: () => handleBlurPhone('mobilePhone') }), jsxRuntime.jsx(Field, { id: "szc-email", label: t.email, required: state.emailMandatory, optionalLabel: t.optional, className: "szc-input--ltr", dir: "ltr", inputMode: "email", value: addressForm.email, error: errors.email, onChange: (e) => actions.setAddressField('email', e.target.value), onBlur: () => touch('email') })] })] }), needsShipping ? (jsxRuntime.jsxs("section", { className: "szc-shipping-section", "aria-labelledby": "szc-address-title", children: [jsxRuntime.jsx(ShippingSectionHeader, { id: "szc-address-title", title: t.reviewAddress, icon: "address" }), jsxRuntime.jsxs("div", { className: "szc-form-grid", children: [jsxRuntime.jsx(EnhancedSelect, { id: "szc-region", label: t.region, required: true, optionalLabel: t.optional, value: addressForm.regionId ?? '', error: errors.regionId, onChange: (v) => {
386
+ actions.setAddressField('regionId', v ? Number(v) : null);
387
+ touch('regionId');
388
+ }, placeholder: t.selectRegion, options: regions.map((r) => ({ value: r.id, label: r.name })) }), jsxRuntime.jsx(EnhancedSelect, { id: "szc-city", label: t.city, required: true, optionalLabel: t.optional, value: addressForm.cityId ?? '', disabled: !selectedRegion, error: errors.cityId, onChange: (v) => {
389
+ actions.setAddressField('cityId', v ? Number(v) : null);
390
+ touch('cityId');
391
+ }, placeholder: t.selectCity, options: selectedRegion?.cities.map((c) => ({ value: c.id, label: c.name })) ?? [] }), jsxRuntime.jsx(Field, { id: "szc-postal", label: t.postalCode, required: state.postalCodeMandatory, optionalLabel: t.optional, className: "szc-input--ltr", dir: "ltr", inputMode: "numeric", value: addressForm.postalCode, error: errors.postalCode, onChange: (e) => actions.setAddressField('postalCode', e.target.value), onBlur: () => touch('postalCode') }), jsxRuntime.jsx(Field, { id: "szc-phone", label: t.phoneNumber, optionalLabel: t.optional, className: "szc-input--ltr", dir: "ltr", inputMode: "tel", value: addressForm.phoneNumber, onChange: (e) => actions.setAddressField('phoneNumber', e.target.value), onBlur: () => handleBlurPhone('phoneNumber') })] }), jsxRuntime.jsx(Field, { id: "szc-address", label: t.addressLine, required: true, optionalLabel: t.optional, value: addressForm.address, error: errors.address, onChange: (e) => actions.setAddressField('address', e.target.value), onBlur: () => touch('address') }), jsxRuntime.jsx(Field, { id: "szc-description", label: t.description, optionalLabel: t.optional, value: addressForm.description, onChange: (e) => actions.setAddressField('description', e.target.value), onBlur: () => touch('description') })] })) : null] }), shippingGroups.length > 0 ? (jsxRuntime.jsxs("section", { className: "szc-shipping-methods", "aria-labelledby": "szc-methods-title", children: [jsxRuntime.jsx(ShippingSectionHeader, { id: "szc-methods-title", title: t.shippingMethods, icon: "shipping" }), jsxRuntime.jsx("div", { className: "szc-ship-groups", children: shippingGroups.map((group) => (jsxRuntime.jsx(ShippingGroupCard, { group: group }, group.key))) })] })) : needsShipping ? (jsxRuntime.jsxs("div", { className: "szc-shipping-pending", role: "note", children: [jsxRuntime.jsx("span", { className: "szc-shipping-pending__icon", "aria-hidden": "true", children: jsxRuntime.jsx(TruckIcon, {}) }), jsxRuntime.jsxs("div", { className: "szc-shipping-pending__copy", children: [jsxRuntime.jsx("strong", { children: t.shippingMethods }), jsxRuntime.jsx("span", { children: t.shippingMethodsHint })] })] })) : null, digitalItems.length > 0 ? (jsxRuntime.jsxs("div", { className: "szc-digital-note", children: [jsxRuntime.jsx("span", { className: "szc-digital-note__icon", children: "\u2B07\uFE0E" }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("strong", { children: t.digitalNoShipping }), jsxRuntime.jsx("ul", { children: digitalItems.map((item) => (jsxRuntime.jsx("li", { children: item.name }, item.id))) })] })] })) : null] }));
392
+ }
393
+ function ShippingSectionHeader({ id, title, icon }) {
394
+ return (jsxRuntime.jsxs("header", { className: "szc-shipping-section__head", children: [jsxRuntime.jsx("span", { className: "szc-shipping-section__icon", "aria-hidden": "true", children: icon === 'contact' ? jsxRuntime.jsx(ContactIcon, {}) : icon === 'address' ? jsxRuntime.jsx(AddressIcon, {}) : jsxRuntime.jsx(TruckIcon, {}) }), jsxRuntime.jsx("h2", { id: id, className: "szc-shipping-section__title", children: title })] }));
395
+ }
396
+ function ContactIcon() {
397
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "8", r: "3.25", stroke: "currentColor", strokeWidth: "1.7" }), jsxRuntime.jsx("path", { d: "M5.5 19c.65-3.35 3-5.25 6.5-5.25s5.85 1.9 6.5 5.25", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" })] }));
398
+ }
399
+ function AddressIcon() {
400
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("path", { d: "M19 10c0 4.7-7 10-7 10S5 14.7 5 10a7 7 0 1 1 14 0Z", stroke: "currentColor", strokeWidth: "1.7", strokeLinejoin: "round" }), jsxRuntime.jsx("circle", { cx: "12", cy: "10", r: "2.25", stroke: "currentColor", strokeWidth: "1.7" })] }));
401
+ }
402
+ function EnhancedSelect({ id, label, value, placeholder, options, required, optionalLabel, disabled, error, onChange }) {
403
+ return (jsxRuntime.jsxs("label", { className: "szc-field", htmlFor: id, children: [jsxRuntime.jsx(FieldLabel, { label: label, required: required, optionalLabel: optionalLabel }), jsxRuntime.jsxs("div", { className: "szc-select-wrap", children: [jsxRuntime.jsxs("select", { id: id, className: `szc-input szc-select-enhanced${error ? ' szc-input--error' : ''}`, value: value, required: required, disabled: disabled, onChange: (e) => onChange(e.target.value), children: [jsxRuntime.jsx("option", { value: "", children: placeholder }), options.map((opt) => (jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }), jsxRuntime.jsx("span", { className: "szc-select-chevron", "aria-hidden": "true", children: jsxRuntime.jsx(ChevronIcon, {}) })] }), error ? jsxRuntime.jsx("span", { className: "szc-field__error", children: error }) : null] }));
404
+ }
405
+ function ChevronIcon() {
406
+ return (jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "14", height: "14", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M4 6l4 4 4-4", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }));
407
+ }
408
+ /**
409
+ * Click-and-drag horizontal scrolling for a container with a hidden scrollbar.
410
+ * Also maps vertical mouse-wheel deltas to horizontal scroll so a plain mouse
411
+ * (no horizontal wheel) can still pan the list.
412
+ */
413
+ function useDragScroll() {
414
+ const ref = react.useRef(null);
415
+ const drag = react.useRef({ down: false, startX: 0, startLeft: 0 });
416
+ react.useEffect(() => {
417
+ const el = ref.current;
418
+ if (!el)
419
+ return;
420
+ const onWheel = (e) => {
421
+ if (el.scrollWidth <= el.clientWidth)
422
+ return; // nothing to pan
423
+ if (Math.abs(e.deltaY) <= Math.abs(e.deltaX))
424
+ return; // already horizontal
425
+ e.preventDefault();
426
+ el.scrollLeft += e.deltaY;
427
+ };
428
+ el.addEventListener('wheel', onWheel, { passive: false });
429
+ return () => el.removeEventListener('wheel', onWheel);
430
+ }, []);
431
+ const onPointerDown = (e) => {
432
+ const el = ref.current;
433
+ if (!el)
434
+ return;
435
+ drag.current = { down: true, startX: e.clientX, startLeft: el.scrollLeft };
436
+ el.setPointerCapture(e.pointerId);
437
+ el.classList.add('szc-dragging');
438
+ };
439
+ const onPointerMove = (e) => {
440
+ const el = ref.current;
441
+ if (!el || !drag.current.down)
442
+ return;
443
+ el.scrollLeft = drag.current.startLeft - (e.clientX - drag.current.startX);
444
+ };
445
+ const onPointerUp = (e) => {
446
+ const el = ref.current;
447
+ if (!el || !drag.current.down)
448
+ return;
449
+ drag.current.down = false;
450
+ el.classList.remove('szc-dragging');
451
+ try {
452
+ el.releasePointerCapture(e.pointerId);
453
+ }
454
+ catch {
455
+ /* pointer already released */
456
+ }
457
+ };
458
+ return { ref, onPointerDown, onPointerMove, onPointerUp };
459
+ }
460
+ function ShippingGroupCard({ group }) {
461
+ const { actions, price, state, t } = useCheckout.useCheckout();
462
+ const busy = state.flags.selectingRate;
463
+ const selectedRate = group.rates.find((rate) => rate.id === group.selectedRateId);
464
+ const showRateSelector = group.items.length !== 1 || group.rates.length !== 1;
465
+ const itemsScroll = useDragScroll();
466
+ return (jsxRuntime.jsxs("div", { className: "szc-ship-group", children: [jsxRuntime.jsxs("header", { className: "szc-ship-group__head", children: [jsxRuntime.jsx("span", { className: "szc-ship-group__mark", style: shippingRateIconStyle(selectedRate?.color), "aria-hidden": "true", children: selectedRate ? jsxRuntime.jsx(ShippingRateIcon, { rate: selectedRate }) : jsxRuntime.jsx(TruckIcon, {}) }), jsxRuntime.jsxs("div", { className: "szc-ship-group__heading", children: [jsxRuntime.jsxs("div", { className: "szc-ship-group__title-row", children: [jsxRuntime.jsx("strong", { className: "szc-ship-group__title", children: group.title || selectedRate?.name || t.shippingMethod }), jsxRuntime.jsx("span", { className: "szc-ship-group__count", children: t.productCount(labels.toPersianDigits(String(group.items.length))) })] }), selectedRate ? (jsxRuntime.jsxs("span", { className: "szc-ship-group__hint", children: [selectedRate.description ? (jsxRuntime.jsx("span", { className: "szc-ship-group__desc", children: selectedRate.description })) : null, jsxRuntime.jsx("span", { className: "szc-ship-group__rate-price", children: selectedRate.price > 0 ? price(selectedRate.price) : t.free })] })) : (jsxRuntime.jsx("span", { className: "szc-ship-group__hint", children: t.shippingMethods }))] })] }), jsxRuntime.jsx("div", { className: "szc-ship-group__items", ref: itemsScroll.ref, onPointerDown: itemsScroll.onPointerDown, onPointerMove: itemsScroll.onPointerMove, onPointerUp: itemsScroll.onPointerUp, onPointerCancel: itemsScroll.onPointerUp, children: group.items.map((item) => (jsxRuntime.jsxs("article", { className: "szc-ship-product", children: [jsxRuntime.jsxs("div", { className: "szc-ship-product__media", children: [item.image?.url ? (jsxRuntime.jsx("img", { src: item.image.url, alt: item.image.alt || item.name })) : (jsxRuntime.jsx(ProductPlaceholder, {})), jsxRuntime.jsx("span", { className: "szc-ship-product__quantity", children: labels.toPersianDigits(String(item.quantity)) })] }), jsxRuntime.jsxs("div", { className: "szc-ship-product__copy", children: [jsxRuntime.jsx("strong", { className: "szc-ship-product__name", children: item.name }), item.attributes.length > 0 ? (jsxRuntime.jsx("span", { className: "szc-ship-product__attrs", children: item.attributes.map((attribute) => `${attribute.name}: ${attribute.value}`).join(' · ') })) : null] })] }, item.id))) }), !showRateSelector && selectedRate?.description?.trim() ? (jsxRuntime.jsx("div", { className: "szc-ship-group__description", children: selectedRate.description.trim() })) : null, showRateSelector ? (jsxRuntime.jsx("div", { className: "szc-rate-list", role: "radiogroup", children: group.rates.map((rate) => {
467
+ const selected = group.selectedRateId === rate.id;
468
+ const description = rate.description?.trim();
469
+ return (jsxRuntime.jsxs("button", { type: "button", role: "radio", "aria-checked": selected, "aria-label": description ? `${rate.name} — ${description}` : rate.name, disabled: busy, className: `szc-rate${selected ? ' szc-rate--selected' : ''}`, onClick: () => actions.selectShippingRate(group.key, rate.id), children: [jsxRuntime.jsx("span", { className: "szc-rate__icon", style: shippingRateIconStyle(rate.color), "aria-hidden": "true", children: jsxRuntime.jsx(ShippingRateIcon, { rate: rate }) }), jsxRuntime.jsxs("span", { className: "szc-rate__copy", children: [jsxRuntime.jsx("span", { className: "szc-rate__name", children: rate.name }), rate.price > 0 ? (jsxRuntime.jsx("span", { className: "szc-rate__price", children: price(rate.price) })) : null] }), jsxRuntime.jsx("span", { className: "szc-rate__radio", "aria-hidden": "true", children: selected ? jsxRuntime.jsx(CheckIcon$1, {}) : null }), description ? (jsxRuntime.jsx("span", { className: "szc-rate__description", children: description })) : null] }, rate.id));
470
+ }) })) : null] }));
471
+ }
472
+ const ICON_PROPS$1 = {
473
+ viewBox: '0 0 24 24',
474
+ width: 26,
475
+ height: 26,
476
+ fill: 'none',
477
+ stroke: 'currentColor',
478
+ strokeWidth: 1.8,
479
+ strokeLinecap: 'round',
480
+ strokeLinejoin: 'round',
481
+ 'aria-hidden': true,
482
+ };
483
+ function TruckIcon() {
484
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS$1, children: [jsxRuntime.jsx("path", { d: "M14 17V6a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h1" }), jsxRuntime.jsx("path", { d: "M9 18h5" }), jsxRuntime.jsx("path", { d: "M18 18h1a1 1 0 0 0 1-1v-3.28a1 1 0 0 0-.21-.62l-2.7-3.39A1 1 0 0 0 16.3 9H14" }), jsxRuntime.jsx("circle", { cx: "7", cy: "18", r: "2" }), jsxRuntime.jsx("circle", { cx: "16", cy: "18", r: "2" })] }));
485
+ }
486
+ function ShippingRateIcon({ rate }) {
487
+ const iconKey = shippingRateIconKey(rate);
488
+ switch (iconKey) {
489
+ case 'post':
490
+ return jsxRuntime.jsx(PostIcon, {});
491
+ case 'free-delivery':
492
+ return jsxRuntime.jsx(FreeDeliveryIcon, {});
493
+ case 'courier':
494
+ return jsxRuntime.jsx(CourierIcon, {});
495
+ case 'delivery-man':
496
+ return jsxRuntime.jsx(DeliveryManIcon, {});
497
+ default:
498
+ return rate.icon && isImageUrl(rate.icon) ? jsxRuntime.jsx("img", { src: rate.icon, alt: "" }) : jsxRuntime.jsx(TruckIcon, {});
499
+ }
500
+ }
501
+ function shippingRateIconKey(rate) {
502
+ const explicit = (rate.icon || rate.type || '').trim().toLowerCase().replace(/_/g, '-');
503
+ if (explicit)
504
+ return explicit;
505
+ const name = rate.name.trim().toLowerCase();
506
+ if (name.includes('پست') || name.includes('post'))
507
+ return 'post';
508
+ if (name.includes('رایگان') || name.includes('free'))
509
+ return 'free-delivery';
510
+ if (name.includes('پیک') || name.includes('courier'))
511
+ return 'courier';
512
+ if (name.includes('حضوری') || name.includes('delivery man'))
513
+ return 'delivery-man';
514
+ return '';
515
+ }
516
+ /**
517
+ * The API returns `color` as a palette *token* (e.g. `mainColor`, `green`) — not
518
+ * always a CSS color. Map the known tokens to concrete CSS colors so each rate
519
+ * renders its own chip color instead of every icon falling back to the accent.
520
+ */
521
+ const SHIPPING_COLOR_TOKENS = {
522
+ green: '#16a34a',
523
+ red: '#dc2626',
524
+ blue: '#2563eb',
525
+ orange: '#ea580c',
526
+ yellow: '#eab308',
527
+ purple: '#7c3aed',
528
+ pink: '#db2777',
529
+ teal: '#0d9488',
530
+ cyan: '#0891b2',
531
+ indigo: '#4f46e5',
532
+ gray: '#6b7280',
533
+ grey: '#6b7280',
534
+ black: '#0f172a',
535
+ brown: '#92400e'
536
+ };
537
+ function resolveShippingColor(raw) {
538
+ const token = raw.trim().toLowerCase();
539
+ if (!token)
540
+ return undefined;
541
+ // The shop's "main color" is the theme accent → let the CSS fallback handle it.
542
+ if (token === 'maincolor' || token === 'main')
543
+ return undefined;
544
+ if (token === 'transparent' || token === 'white')
545
+ return '#ffffff';
546
+ if (SHIPPING_COLOR_TOKENS[token])
547
+ return SHIPPING_COLOR_TOKENS[token];
548
+ // Already a concrete CSS color value (hex / rgb()).
549
+ if (parseColorChannels(token))
550
+ return token;
551
+ return undefined;
552
+ }
553
+ function shippingRateIconStyle(color) {
554
+ if (!color)
555
+ return undefined;
556
+ const resolved = resolveShippingColor(color);
557
+ // Unknown token / unparseable → let CSS use the theme's soft accent treatment.
558
+ if (!resolved)
559
+ return undefined;
560
+ const rgb = parseColorChannels(resolved);
561
+ if (!rgb)
562
+ return undefined;
563
+ const luminance = (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]) / 255;
564
+ // A white / near-white brand color (common for "post") would vanish against
565
+ // the card. Render a neutral chip with a slate glyph instead.
566
+ if (luminance > 0.9) {
567
+ return {
568
+ '--szc-rate-color': '#eef0f5',
569
+ '--szc-rate-foreground': '#475569'
570
+ };
571
+ }
572
+ const foreground = luminance > 0.62
573
+ ? `rgb(${rgb.map((channel) => Math.round(channel * 0.58)).join(', ')})`
574
+ : resolved;
575
+ return {
576
+ '--szc-rate-color': `color-mix(in srgb, ${resolved} 13%, var(--szc-card))`,
577
+ '--szc-rate-foreground': foreground
578
+ };
579
+ }
580
+ function parseColorChannels(value) {
581
+ const hex = value.match(/^#([\da-f]{3}|[\da-f]{6}|[\da-f]{8})$/i)?.[1];
582
+ if (hex?.length === 3) {
583
+ return [0, 1, 2].map((index) => parseInt(hex[index] + hex[index], 16));
584
+ }
585
+ if (hex && hex.length >= 6) {
586
+ return [
587
+ parseInt(hex.slice(0, 2), 16),
588
+ parseInt(hex.slice(2, 4), 16),
589
+ parseInt(hex.slice(4, 6), 16)
590
+ ];
591
+ }
592
+ const channels = value.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
593
+ if (channels)
594
+ return [Number(channels[1]), Number(channels[2]), Number(channels[3])];
595
+ return null;
596
+ }
597
+ function isImageUrl(value) {
598
+ return /^(https?:)?\/\//i.test(value) || value.startsWith('/') || value.startsWith('data:');
599
+ }
600
+ function PostIcon() {
601
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS$1, children: [jsxRuntime.jsx("path", { d: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" }), jsxRuntime.jsx("path", { d: "M3.3 7 12 12l8.7-5" }), jsxRuntime.jsx("path", { d: "M12 22V12" }), jsxRuntime.jsx("path", { d: "m7.5 4.6 9 5.2" })] }));
602
+ }
603
+ function FreeDeliveryIcon() {
604
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS$1, children: [jsxRuntime.jsx("path", { d: "M21 11V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l1.5-.86" }), jsxRuntime.jsx("path", { d: "M3.3 7 12 12l8.7-5" }), jsxRuntime.jsx("path", { d: "M12 22V12" }), jsxRuntime.jsx("path", { d: "m15.5 17 2 2 4-4" })] }));
605
+ }
606
+ function CourierIcon() {
607
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS$1, children: [jsxRuntime.jsx("circle", { cx: "5.5", cy: "17.5", r: "3.5" }), jsxRuntime.jsx("circle", { cx: "18.5", cy: "17.5", r: "3.5" }), jsxRuntime.jsx("circle", { cx: "15", cy: "5", r: "1" }), jsxRuntime.jsx("path", { d: "M12 17.5V14l-3-3 4-3 2 3h2" })] }));
608
+ }
609
+ function DeliveryManIcon() {
610
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS$1, children: [jsxRuntime.jsx("circle", { cx: "9", cy: "4.5", r: "2.5" }), jsxRuntime.jsx("path", { d: "M5.5 21v-6.5a3.5 3.5 0 0 1 7 0V21" }), jsxRuntime.jsx("rect", { x: "14", y: "11.5", width: "6.5", height: "7", rx: "1.2" }), jsxRuntime.jsx("path", { d: "M14 15h6.5" }), jsxRuntime.jsx("path", { d: "M17.2 11.5v3.5" })] }));
611
+ }
612
+ function CheckIcon$1() {
613
+ return (jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "12", height: "12", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "m3.2 8.2 3 3 6.6-6.4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
614
+ }
615
+
616
+ /** Human line for the applied-code card: "20% off (50,000)", "Free shipping", … */
617
+ function describeDiscount(discount, t, money, locale) {
618
+ const parts = [];
619
+ if (discount.kind === 'percentage' && (discount.percent ?? 0) > 0) {
620
+ const percentOff = t.discountPercentOff(labels.formatPercent(discount.percent, locale));
621
+ parts.push(discount.amount > 0 ? `${percentOff} (${money(discount.amount)})` : percentOff);
622
+ }
623
+ else if (discount.amount > 0) {
624
+ parts.push(t.discountAmountOff(money(discount.amount)));
625
+ }
626
+ if (discount.kind === 'free_shipping' || (discount.shippingSaved ?? 0) > 0) {
627
+ parts.push(t.discountFreeShipping);
628
+ }
629
+ return parts.length > 0 ? parts.join(' + ') : null;
630
+ }
631
+ function PaymentStep() {
632
+ const { state, actions, t, money } = useCheckout.useCheckout();
633
+ const { paymentMethods, selectedPaymentMethodId, appliedDiscount, discountCode, discountError, flags, locale } = state;
634
+ return (jsxRuntime.jsxs("section", { className: "szc-step-panel", children: [jsxRuntime.jsx(SectionTitle, { children: t.paymentMethod }), flags.loadingPayments ? (jsxRuntime.jsxs("p", { className: "szc-inline-loading", children: [jsxRuntime.jsx(Spinner, {}), " ", t.loading] })) : (jsxRuntime.jsx("div", { className: "szc-pay-list", role: "radiogroup", "aria-label": t.paymentMethod, children: paymentMethods.map((method) => {
635
+ const selected = selectedPaymentMethodId === method.id;
636
+ const info = labels.paymentMethodInfo(method.code, locale);
637
+ // Prefer backend-provided title/description; fall back to derived labels.
638
+ const backendTitle = locale === 'fa' ? method.titleFa : method.title;
639
+ const title = backendTitle?.trim() || info.title;
640
+ const description = method.description?.trim() || info.description;
641
+ return (jsxRuntime.jsxs("button", { type: "button", role: "radio", "aria-checked": selected, className: `szc-pay${selected ? ' szc-pay--selected' : ''}`, onClick: () => actions.selectPaymentMethod(method.id), children: [jsxRuntime.jsx("span", { className: "szc-pay__icon", "aria-hidden": "true", children: jsxRuntime.jsx(PaymentIcon, { kind: info.kind }) }), jsxRuntime.jsxs("span", { className: "szc-pay__body", children: [jsxRuntime.jsx("span", { className: "szc-pay__name", children: title }), jsxRuntime.jsx("span", { className: "szc-pay__desc", children: description })] }), jsxRuntime.jsx("span", { className: "szc-pay__radio", "aria-hidden": "true", children: selected ? jsxRuntime.jsx(CheckIcon, {}) : null })] }, method.id));
642
+ }) })), jsxRuntime.jsx(SectionTitle, { children: t.discountCode }), appliedDiscount ? (jsxRuntime.jsxs("div", { className: "szc-discount szc-discount--applied", children: [jsxRuntime.jsx("span", { className: "szc-discount__icon", "aria-hidden": "true", children: jsxRuntime.jsx(TagIcon, {}) }), jsxRuntime.jsxs("span", { className: "szc-discount__body", children: [jsxRuntime.jsx("code", { className: "szc-discount__code", children: appliedDiscount.code }), jsxRuntime.jsx("span", { className: "szc-discount__desc", children: describeDiscount(appliedDiscount, t, money, locale) ?? t.applied })] }), jsxRuntime.jsxs("span", { className: "szc-discount__badge", children: [jsxRuntime.jsx(CheckIcon, {}), " ", t.applied] }), jsxRuntime.jsx(Button, { variant: "ghost", onClick: () => actions.removeDiscount(), loading: flags.applyingDiscount, children: t.remove })] })) : (jsxRuntime.jsxs("div", { className: "szc-discount-field", children: [jsxRuntime.jsxs("div", { className: "szc-discount", children: [jsxRuntime.jsxs("span", { className: "szc-discount__inputwrap", children: [jsxRuntime.jsx(TagIcon, {}), jsxRuntime.jsx("input", { className: `szc-input${discountError ? ' szc-input--error' : ''}`, placeholder: t.discountPlaceholder, value: discountCode, "aria-invalid": discountError ? true : undefined, onChange: (e) => actions.setDiscountCode(e.target.value), onKeyDown: (e) => {
643
+ if (e.key === 'Enter')
644
+ actions.applyDiscount();
645
+ } })] }), jsxRuntime.jsx(Button, { variant: "outline", onClick: () => actions.applyDiscount(), loading: flags.applyingDiscount, disabled: !discountCode.trim(), children: t.apply })] }), discountError ? (jsxRuntime.jsxs("p", { className: "szc-discount__error", role: "alert", children: [jsxRuntime.jsx(AlertIcon, {}), discountError] })) : null] }))] }));
646
+ }
647
+ function TagIcon() {
648
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", width: "18", height: "18", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [jsxRuntime.jsx("path", { d: "M10.5 2.5H16v5.5l-7.5 7.5a1.8 1.8 0 0 1-2.5 0L3 13a1.8 1.8 0 0 1 0-2.5z" }), jsxRuntime.jsx("circle", { cx: "12.8", cy: "5.7", r: "1", fill: "currentColor", stroke: "none" })] }));
649
+ }
650
+ const ICON_PROPS = {
651
+ viewBox: '0 0 20 20',
652
+ width: 20,
653
+ height: 20,
654
+ fill: 'none',
655
+ stroke: 'currentColor',
656
+ strokeWidth: 1.4,
657
+ strokeLinecap: 'round',
658
+ strokeLinejoin: 'round',
659
+ 'aria-hidden': true
660
+ };
661
+ function AlertIcon() {
662
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", width: "14", height: "14", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "6.5", stroke: "currentColor", strokeWidth: "1.4" }), jsxRuntime.jsx("path", { d: "M8 4.8v3.4", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round" }), jsxRuntime.jsx("circle", { cx: "8", cy: "11", r: "0.85", fill: "currentColor" })] }));
663
+ }
664
+ function CheckIcon() {
665
+ return (jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "12", height: "12", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "m3.2 8.2 3 3 6.6-6.4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
666
+ }
667
+ function PaymentIcon({ kind }) {
668
+ switch (kind) {
669
+ case 'card':
670
+ // two cards / transfer
671
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [jsxRuntime.jsx("rect", { x: "2", y: "5", width: "13", height: "9", rx: "2" }), jsxRuntime.jsx("path", { d: "M2 8h13M5.5 11.5h3" }), jsxRuntime.jsx("path", { d: "M15.5 6.5h2.5v9h-9v-1.5" })] }));
672
+ case 'cod':
673
+ // package / hand
674
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [jsxRuntime.jsx("path", { d: "M10 2.5 17 6v8l-7 3.5L3 14V6z" }), jsxRuntime.jsx("path", { d: "M3 6l7 3.5L17 6M10 9.5v8" })] }));
675
+ case 'bnpl':
676
+ // calendar / installments
677
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [jsxRuntime.jsx("rect", { x: "3", y: "4", width: "14", height: "13", rx: "2" }), jsxRuntime.jsx("path", { d: "M3 8h14M7 2.5v3M13 2.5v3M6.5 12h3" })] }));
678
+ case 'wallet':
679
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [jsxRuntime.jsx("rect", { x: "2.5", y: "5", width: "15", height: "11", rx: "2.5" }), jsxRuntime.jsx("path", { d: "M2.5 9h15" }), jsxRuntime.jsx("circle", { cx: "14", cy: "12.5", r: "1.1", fill: "currentColor", stroke: "none" })] }));
680
+ case 'free':
681
+ // tag
682
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [jsxRuntime.jsx("path", { d: "M10.5 2.5H16v5.5l-7.5 7.5a1.8 1.8 0 0 1-2.5 0L3 13a1.8 1.8 0 0 1 0-2.5z" }), jsxRuntime.jsx("circle", { cx: "12.8", cy: "5.7", r: "1", fill: "currentColor", stroke: "none" })] }));
683
+ case 'gateway':
684
+ default:
685
+ // single card / bank
686
+ return (jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [jsxRuntime.jsx("rect", { x: "2.5", y: "4.5", width: "15", height: "11", rx: "2" }), jsxRuntime.jsx("path", { d: "M2.5 8.5h15M5.5 12.5h4" })] }));
687
+ }
688
+ }
689
+
690
+ function ResultStep({ continueShoppingUrl }) {
691
+ const { state, actions, t } = useCheckout.useCheckout();
692
+ const result = state.result;
693
+ const status = result?.status ?? 'pending';
694
+ const titleMap = {
695
+ success: t.paymentSuccess,
696
+ failed: t.paymentFailed,
697
+ pending: t.paymentPending,
698
+ stock_violated: t.paymentFailed
699
+ };
700
+ return (jsxRuntime.jsxs("section", { className: `szc-result szc-result--${status}`, children: [jsxRuntime.jsx("div", { className: "szc-result__icon", children: status === 'success' ? (jsxRuntime.jsx(CheckCircle, {})) : status === 'pending' ? (jsxRuntime.jsx(Spinner, {})) : (jsxRuntime.jsx(CrossCircle, {})) }), jsxRuntime.jsx("h2", { className: "szc-result__title", children: titleMap[status] }), status === 'pending' ? jsxRuntime.jsx("p", { className: "szc-muted", children: t.paymentPendingHint }) : null, result?.message ? jsxRuntime.jsx("p", { className: "szc-muted", children: result.message }) : null, result?.order ? (jsxRuntime.jsxs("p", { className: "szc-result__order", children: [t.orderNumber, ": ", jsxRuntime.jsx("strong", { children: result.order.orderNumber })] })) : null, jsxRuntime.jsxs("div", { className: "szc-result__actions", children: [status === 'failed' || status === 'stock_violated' ? (jsxRuntime.jsx(Button, { onClick: () => actions.goToStep('payment'), children: t.tryAgain })) : null, continueShoppingUrl ? (jsxRuntime.jsx(Button, { variant: "outline", onClick: () => (window.location.href = continueShoppingUrl), children: t.continueShopping })) : null] })] }));
701
+ }
702
+ function CheckCircle() {
703
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 48 48", width: "48", height: "48", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("circle", { cx: "24", cy: "24", r: "22", stroke: "currentColor", strokeWidth: "2.5" }), jsxRuntime.jsx("path", { d: "M15 24.5l6 6 12-13", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" })] }));
704
+ }
705
+ function CrossCircle() {
706
+ return (jsxRuntime.jsxs("svg", { viewBox: "0 0 48 48", width: "48", height: "48", fill: "none", "aria-hidden": "true", children: [jsxRuntime.jsx("circle", { cx: "24", cy: "24", r: "22", stroke: "currentColor", strokeWidth: "2.5" }), jsxRuntime.jsx("path", { d: "M17 17l14 14M31 17L17 31", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" })] }));
707
+ }
708
+
709
+ function themeVars(theme) {
710
+ const vars = {};
711
+ if (theme?.accent)
712
+ vars['--szc-accent'] = theme.accent;
713
+ if (theme?.accentForeground)
714
+ vars['--szc-accent-foreground'] = theme.accentForeground;
715
+ if (theme?.accentSoft)
716
+ vars['--szc-accent-soft'] = theme.accentSoft;
717
+ if (theme?.background)
718
+ vars['--szc-bg'] = theme.background;
719
+ if (theme?.foreground)
720
+ vars['--szc-fg'] = theme.foreground;
721
+ if (theme?.muted)
722
+ vars['--szc-muted'] = theme.muted;
723
+ if (theme?.mutedForeground)
724
+ vars['--szc-muted-fg'] = theme.mutedForeground;
725
+ if (theme?.border)
726
+ vars['--szc-border'] = theme.border;
727
+ if (theme?.card)
728
+ vars['--szc-card'] = theme.card;
729
+ if (theme?.summaryBackground)
730
+ vars['--szc-summary-bg'] = theme.summaryBackground;
731
+ if (theme?.danger)
732
+ vars['--szc-danger'] = theme.danger;
733
+ if (theme?.success)
734
+ vars['--szc-success'] = theme.success;
735
+ if (theme?.radius != null)
736
+ vars['--szc-radius'] = `${theme.radius}px`;
737
+ if (theme?.fontFamily)
738
+ vars['--szc-font'] = theme.fontFamily;
739
+ return vars;
740
+ }
741
+ function CheckoutSkeleton({ label }) {
742
+ return (jsxRuntime.jsxs("div", { className: "szc-layout szc-skeleton-layout", role: "status", "aria-label": label, children: [jsxRuntime.jsxs("main", { className: "szc-main", "aria-hidden": "true", children: [jsxRuntime.jsxs("div", { className: "szc-skeleton-cart-row", children: [jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--thumb" }), jsxRuntime.jsxs("div", { className: "szc-skeleton-copy", children: [jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--title" }), jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--text" }), jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--price" })] }), jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--counter" })] }), jsxRuntime.jsxs("div", { className: "szc-skeleton-cart-row", children: [jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--thumb" }), jsxRuntime.jsxs("div", { className: "szc-skeleton-copy", children: [jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--title" }), jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--text" }), jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--price" })] }), jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--counter" })] })] }), jsxRuntime.jsxs("div", { className: "szc-side", "aria-hidden": "true", children: [jsxRuntime.jsxs("aside", { className: "szc-summary szc-summary--skeleton", children: [jsxRuntime.jsxs("div", { className: "szc-summary__total-head", children: [jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--summary-label" }), jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--summary-total" })] }), jsxRuntime.jsxs("div", { className: "szc-skeleton-summary-lines", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "szc-skeleton" }), jsxRuntime.jsx("span", { className: "szc-skeleton" })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("span", { className: "szc-skeleton" }), jsxRuntime.jsx("span", { className: "szc-skeleton" })] })] }), jsxRuntime.jsxs("div", { className: "szc-skeleton-summary-grand", children: [jsxRuntime.jsx("span", { className: "szc-skeleton" }), jsxRuntime.jsx("span", { className: "szc-skeleton" })] })] }), jsxRuntime.jsx("div", { className: "szc-side__cta", children: jsxRuntime.jsx("span", { className: "szc-skeleton szc-skeleton--button" }) })] })] }));
743
+ }
744
+ function SazitoCheckout({ theme, continueShoppingUrl, className, renderNextButton, renderBackButton, renderEmptyCart, }) {
745
+ const { state, actions, t, summary, money } = useCheckout.useCheckout();
746
+ const { step, direction, flags, error } = state;
747
+ const isResult = step === 'result';
748
+ const bootstrapping = step === 'cart' && !error && (!state.cart || !state.invoice || flags.bootstrapping);
749
+ const fatal = error && !state.cart && step === 'cart';
750
+ const cartEmpty = !state.cart || state.cart.items.length === 0;
751
+ const footerVisible = (step === 'cart' && !cartEmpty) || step === 'shipping' || step === 'payment';
752
+ const nextBusy = state.status === 'working' ||
753
+ flags.savingAddress ||
754
+ flags.loadingShipping ||
755
+ flags.loadingPayments ||
756
+ flags.placingOrder;
757
+ const needsShipping = state.invoice?.needsShipping !== false;
758
+ const shippingSavePhase = state.addressDirty || !state.applicable;
759
+ const shippingReady = !needsShipping ||
760
+ (state.shippingGroups.length > 0 &&
761
+ state.shippingGroups.every((g) => g.selectedRateId != null));
762
+ const paymentReady = state.paymentMethods.length > 0 && state.selectedPaymentMethodId != null;
763
+ const nextDisabled = step === 'cart'
764
+ ? cartEmpty
765
+ : step === 'shipping'
766
+ ? !shippingSavePhase && !shippingReady
767
+ : step === 'payment'
768
+ ? !paymentReady
769
+ : false;
770
+ const nextLabel = step === 'cart'
771
+ ? t.placeOrder
772
+ : step === 'shipping'
773
+ ? needsShipping && shippingSavePhase
774
+ ? t.saveShippingDetails
775
+ : t.continueToPayment
776
+ : t.finishPurchase;
777
+ const backOnClick = step === 'cart' && continueShoppingUrl
778
+ ? () => { window.location.href = continueShoppingUrl; }
779
+ : () => actions.back();
780
+ const backVisible = step !== 'cart' || !!continueShoppingUrl;
781
+ const nextButtonProps = {
782
+ loading: nextBusy,
783
+ disabled: nextDisabled,
784
+ onClick: () => actions.next(),
785
+ children: nextLabel,
786
+ };
787
+ const backButtonProps = {
788
+ loading: false,
789
+ disabled: false,
790
+ onClick: backOnClick,
791
+ children: t.back,
792
+ };
793
+ /* Rendered twice: under the order summary (desktop) and in the sticky
794
+ bottom bar (mobile). CSS shows exactly one of the two. */
795
+ const nextButtonNode = renderNextButton ? (renderNextButton(nextButtonProps)) : (jsxRuntime.jsx(Button, { className: "szc-footer__next", loading: nextBusy, disabled: nextDisabled, onClick: () => actions.next(), children: nextLabel }));
796
+ const backButtonNode = backVisible ? (renderBackButton ? (renderBackButton(backButtonProps)) : (jsxRuntime.jsxs(Button, { variant: "ghost", className: "szc-back-btn", onClick: backOnClick, children: [jsxRuntime.jsx("svg", { className: "szc-back-arrow", viewBox: "0 0 16 16", width: "15", height: "15", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M9.5 3.5 5 8l4.5 4.5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }), t.back] }))) : null;
797
+ const actionsVisible = !bootstrapping && !fatal && !isResult && footerVisible;
798
+ /* Mobile header (replaces the stepper on small screens): back chevron at the
799
+ inline start, current step title centered, "step n of m" at the end. */
800
+ const flowSteps = ['cart', 'shipping', 'payment'];
801
+ const flowIndex = flowSteps.indexOf(step);
802
+ const headTitle = step === 'cart'
803
+ ? t.stepCart
804
+ : step === 'shipping'
805
+ ? t.stepShippingInfo
806
+ : step === 'payment'
807
+ ? t.stepPayment
808
+ : t.stepResult;
809
+ const HeadIcon = step === 'cart'
810
+ ? CartIcon
811
+ : step === 'shipping'
812
+ ? TruckIcon$1
813
+ : step === 'payment'
814
+ ? CardIcon
815
+ : ClipboardIcon;
816
+ const mobileHead = (jsxRuntime.jsxs("div", { className: "szc-mobile-head", children: [footerVisible && backVisible ? (jsxRuntime.jsx("button", { type: "button", className: "szc-mobile-head__back", "aria-label": t.back, onClick: backOnClick, children: jsxRuntime.jsx("svg", { className: "szc-back-arrow", viewBox: "0 0 16 16", width: "18", height: "18", fill: "none", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M9.5 3.5 5 8l4.5 4.5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) })) : (jsxRuntime.jsx("span", {})), jsxRuntime.jsxs("span", { className: "szc-mobile-head__title", children: [jsxRuntime.jsx("span", { className: "szc-mobile-head__dot", children: jsxRuntime.jsx(HeadIcon, {}) }), headTitle] }), flowIndex >= 0 ? (jsxRuntime.jsx("span", { className: "szc-mobile-head__count", children: t.stepOf(labels.formatNumber(flowIndex + 1, state.locale), labels.formatNumber(flowSteps.length, state.locale)) })) : (jsxRuntime.jsx("span", {}))] }));
817
+ return (jsxRuntime.jsxs("div", { className: `szc-root${className ? ` ${className}` : ''}`, dir: direction, style: themeVars(theme), children: [mobileHead, jsxRuntime.jsx(Stepper, {}), bootstrapping ? (jsxRuntime.jsx(CheckoutSkeleton, { label: t.loading })) : fatal ? (jsxRuntime.jsx(ErrorBanner, { message: error.message })) : isResult ? (jsxRuntime.jsx("div", { className: "szc-result-wrap", children: jsxRuntime.jsx(ResultStep, { continueShoppingUrl: continueShoppingUrl }) })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs("div", { className: `szc-layout${cartEmpty ? ' szc-layout--full' : ''}`, children: [jsxRuntime.jsxs("main", { className: "szc-main", children: [error ? jsxRuntime.jsx(ErrorBanner, { message: error.message }) : null, step === 'cart' ? jsxRuntime.jsx(CartStep, { continueShoppingUrl: continueShoppingUrl, renderEmpty: renderEmptyCart }) : null, step === 'shipping' ? jsxRuntime.jsx(ShippingStep, {}) : null, step === 'payment' ? jsxRuntime.jsx(PaymentStep, {}) : null, actionsVisible && backButtonNode ? (jsxRuntime.jsx("div", { className: "szc-back-row", children: backButtonNode })) : null] }), !cartEmpty ? (jsxRuntime.jsxs("div", { className: "szc-side", children: [jsxRuntime.jsx(OrderSummary, {}), actionsVisible ? jsxRuntime.jsx("div", { className: "szc-side__cta", children: nextButtonNode }) : null] })) : null] }) })), actionsVisible ? (jsxRuntime.jsx("div", { className: "szc-footer-bar", children: jsxRuntime.jsxs("div", { className: "szc-footer", children: [jsxRuntime.jsxs("div", { className: "szc-footer__total", children: [jsxRuntime.jsx("span", { className: "szc-footer__total-label", children: t.total }), jsxRuntime.jsx("span", { className: "szc-footer__total-value", children: money(summary.total) })] }), jsxRuntime.jsx("div", { className: "szc-footer__actions", children: nextButtonNode })] }) })) : null] }));
818
+ }
819
+
820
+ function SazitoCheckoutPage({ credentials, config, paymentReturnParams, className, renderNextButton, renderBackButton, renderEmptyCart, }) {
821
+ const isReturn = paymentReturnParams != null;
822
+ const client = useCheckout.useSazitoClient();
823
+ return (jsxRuntime.jsxs(useCheckout.CheckoutProvider, { client: client, credentials: credentials, config: config, autoStart: !isReturn, children: [isReturn ? jsxRuntime.jsx(ResolveReturn, { params: paymentReturnParams }) : null, jsxRuntime.jsx(SazitoCheckout, { theme: config?.theme, continueShoppingUrl: config?.continueShoppingUrl, className: className, renderNextButton: renderNextButton, renderBackButton: renderBackButton, renderEmptyCart: renderEmptyCart })] }));
824
+ }
825
+ function ResolveReturn({ params }) {
826
+ const { actions } = useCheckout.useCheckout();
827
+ react.useEffect(() => {
828
+ void actions.resolvePaymentReturn(params);
829
+ // eslint-disable-next-line react-hooks/exhaustive-deps
830
+ }, []);
831
+ return null;
832
+ }
833
+
834
+ exports.CheckoutProvider = useCheckout.CheckoutProvider;
835
+ exports.SazitoProvider = useCheckout.SazitoProvider;
836
+ exports.useCheckout = useCheckout.useCheckout;
837
+ exports.Button = Button;
838
+ exports.ErrorBanner = ErrorBanner;
839
+ exports.Field = Field;
840
+ exports.ProductPlaceholder = ProductPlaceholder;
841
+ exports.SazitoCheckout = SazitoCheckout;
842
+ exports.SazitoCheckoutPage = SazitoCheckoutPage;
843
+ exports.SectionTitle = SectionTitle;
844
+ exports.Spinner = Spinner;
845
+ //# sourceMappingURL=index.cjs.map