@asteby/storefront-react 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/checkout.cjs +670 -49
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.css +230 -0
- package/dist/checkout.d.cts +323 -4
- package/dist/checkout.d.ts +323 -4
- package/dist/checkout.js +651 -44
- package/dist/checkout.js.map +1 -1
- package/dist/payments.cjs +162 -37
- package/dist/payments.cjs.map +1 -1
- package/dist/payments.css +6 -1
- package/dist/payments.d.cts +37 -1
- package/dist/payments.d.ts +37 -1
- package/dist/payments.js +162 -38
- package/dist/payments.js.map +1 -1
- package/package.json +1 -1
package/dist/checkout.cjs
CHANGED
|
@@ -1,9 +1,504 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
4
3
|
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var storefront = require('@asteby/storefront');
|
|
6
6
|
|
|
7
|
+
// src/checkout/address-fields.tsx
|
|
8
|
+
var ES = {
|
|
9
|
+
valueMissing: "Completa este campo.",
|
|
10
|
+
choiceMissing: "Elige una opci\xF3n.",
|
|
11
|
+
email: "Escribe un correo v\xE1lido, por ejemplo nombre@correo.com.",
|
|
12
|
+
tel: "Escribe un tel\xE9fono v\xE1lido.",
|
|
13
|
+
pattern: "Revisa el formato.",
|
|
14
|
+
tooShort: "Escribe al menos {n} caracteres.",
|
|
15
|
+
server: "Revisa este campo.",
|
|
16
|
+
summaryOne: "Revisa 1 campo para continuar",
|
|
17
|
+
summaryMany: "Revisa {n} campos para continuar",
|
|
18
|
+
optional: "(opcional)"
|
|
19
|
+
};
|
|
20
|
+
var EN = {
|
|
21
|
+
valueMissing: "Fill in this field.",
|
|
22
|
+
choiceMissing: "Choose an option.",
|
|
23
|
+
email: "Enter a valid email, like name@example.com.",
|
|
24
|
+
tel: "Enter a valid phone number.",
|
|
25
|
+
pattern: "Check the format.",
|
|
26
|
+
tooShort: "Enter at least {n} characters.",
|
|
27
|
+
server: "Check this field.",
|
|
28
|
+
summaryOne: "Check 1 field to continue",
|
|
29
|
+
summaryMany: "Check {n} fields to continue",
|
|
30
|
+
optional: "(optional)"
|
|
31
|
+
};
|
|
32
|
+
function fieldMessages(locale, overrides) {
|
|
33
|
+
const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ? EN : ES;
|
|
34
|
+
return overrides ? { ...base, ...overrides } : base;
|
|
35
|
+
}
|
|
36
|
+
var isControl = (el) => !!el && typeof el.tagName === "string" && ["INPUT", "SELECT", "TEXTAREA"].includes(el.tagName) && !!el.name;
|
|
37
|
+
function validationMessage(el, m = ES) {
|
|
38
|
+
const v = el.validity;
|
|
39
|
+
if (!v || v.valid) return null;
|
|
40
|
+
const own = el.getAttribute("data-sf-error");
|
|
41
|
+
if (own) return own;
|
|
42
|
+
if (v.valueMissing) return el instanceof HTMLInputElement && (el.type === "radio" || el.type === "checkbox") ? m.choiceMissing : m.valueMissing;
|
|
43
|
+
if (v.typeMismatch && el instanceof HTMLInputElement) return el.type === "email" ? m.email : el.type === "tel" ? m.tel : m.pattern;
|
|
44
|
+
if (v.patternMismatch) return el.getAttribute("title") || (el instanceof HTMLInputElement && el.type === "tel" ? m.tel : m.pattern);
|
|
45
|
+
if (v.tooShort && el instanceof HTMLInputElement) return m.tooShort.replace("{n}", String(el.minLength));
|
|
46
|
+
return el.validationMessage || m.pattern;
|
|
47
|
+
}
|
|
48
|
+
function labelOf(el) {
|
|
49
|
+
if (el instanceof HTMLInputElement && el.type === "radio") {
|
|
50
|
+
const legend = el.closest("fieldset")?.querySelector("legend");
|
|
51
|
+
if (legend?.textContent) return legend.textContent.trim();
|
|
52
|
+
}
|
|
53
|
+
const text = el.labels?.[0]?.getAttribute("data-sf-label") ?? el.labels?.[0]?.textContent ?? el.getAttribute("aria-label") ?? el.name;
|
|
54
|
+
return text.trim();
|
|
55
|
+
}
|
|
56
|
+
function useFieldErrors(formRef, options = {}) {
|
|
57
|
+
const m = fieldMessages(options.locale, options.messages);
|
|
58
|
+
const live = react.useRef(m);
|
|
59
|
+
live.current = m;
|
|
60
|
+
const server = [...options.serverFields ?? []];
|
|
61
|
+
const serverKey = server.join("|");
|
|
62
|
+
const [errors, setErrors] = react.useState(() => Object.fromEntries(server.map((n) => [n, options.serverMessages?.[n] ?? m.server])));
|
|
63
|
+
const [summary, setSummary] = react.useState(null);
|
|
64
|
+
const [summaryKey, setSummaryKey] = react.useState(0);
|
|
65
|
+
react.useEffect(() => {
|
|
66
|
+
if (!server.length) return;
|
|
67
|
+
const form = formRef.current;
|
|
68
|
+
const items = [];
|
|
69
|
+
const next = {};
|
|
70
|
+
for (const name of server) {
|
|
71
|
+
const msg = options.serverMessages?.[name] ?? live.current.server;
|
|
72
|
+
next[name] = msg;
|
|
73
|
+
const el = form?.elements.namedItem(name);
|
|
74
|
+
const ctl = el && "length" in el && !(el instanceof HTMLSelectElement) ? el[0] : el;
|
|
75
|
+
if (ctl) items.push({ name, id: ctl.id || name, label: labelOf(ctl), message: msg });
|
|
76
|
+
}
|
|
77
|
+
setErrors((e) => ({ ...e, ...next }));
|
|
78
|
+
if (items.length) {
|
|
79
|
+
setSummary(items);
|
|
80
|
+
setSummaryKey((k) => k + 1);
|
|
81
|
+
}
|
|
82
|
+
}, [serverKey]);
|
|
83
|
+
react.useEffect(() => {
|
|
84
|
+
const form = formRef.current;
|
|
85
|
+
if (!form) return;
|
|
86
|
+
let batch = null;
|
|
87
|
+
const set = (name, msg) => setErrors((e) => {
|
|
88
|
+
if (msg === null) {
|
|
89
|
+
if (!(name in e)) return e;
|
|
90
|
+
const { [name]: _gone, ...rest } = e;
|
|
91
|
+
return rest;
|
|
92
|
+
}
|
|
93
|
+
return e[name] === msg ? e : { ...e, [name]: msg };
|
|
94
|
+
});
|
|
95
|
+
const onBlur = (ev) => {
|
|
96
|
+
const el = ev.target;
|
|
97
|
+
if (!isControl(el) || el instanceof HTMLInputElement && (el.type === "radio" || el.type === "checkbox" || el.type === "hidden")) return;
|
|
98
|
+
if (!el.value) return;
|
|
99
|
+
set(el.name, validationMessage(el, live.current));
|
|
100
|
+
};
|
|
101
|
+
const onInput = (ev) => {
|
|
102
|
+
const el = ev.target;
|
|
103
|
+
if (!isControl(el)) return;
|
|
104
|
+
setErrors((e) => {
|
|
105
|
+
if (!(el.name in e)) return e;
|
|
106
|
+
const msg = el.validity.valid ? null : validationMessage(el, live.current);
|
|
107
|
+
if (msg !== null) return e;
|
|
108
|
+
const { [el.name]: _gone, ...rest } = e;
|
|
109
|
+
return rest;
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
const onInvalid = (ev) => {
|
|
113
|
+
const el = ev.target;
|
|
114
|
+
if (!isControl(el)) return;
|
|
115
|
+
ev.preventDefault();
|
|
116
|
+
if (!batch) {
|
|
117
|
+
batch = [];
|
|
118
|
+
queueMicrotask(() => {
|
|
119
|
+
const list = batch ?? [];
|
|
120
|
+
batch = null;
|
|
121
|
+
const seen = /* @__PURE__ */ new Set();
|
|
122
|
+
const items = [];
|
|
123
|
+
const next = {};
|
|
124
|
+
for (const c of list) {
|
|
125
|
+
if (seen.has(c.name)) continue;
|
|
126
|
+
seen.add(c.name);
|
|
127
|
+
const msg = validationMessage(c, live.current) ?? live.current.valueMissing;
|
|
128
|
+
next[c.name] = msg;
|
|
129
|
+
items.push({ name: c.name, id: c.id || c.name, label: labelOf(c), message: msg });
|
|
130
|
+
}
|
|
131
|
+
setErrors((e) => ({ ...e, ...next }));
|
|
132
|
+
setSummary(items);
|
|
133
|
+
setSummaryKey((k) => k + 1);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
batch.push(el);
|
|
137
|
+
};
|
|
138
|
+
form.addEventListener("focusout", onBlur);
|
|
139
|
+
form.addEventListener("input", onInput);
|
|
140
|
+
form.addEventListener("change", onInput);
|
|
141
|
+
form.addEventListener("invalid", onInvalid, true);
|
|
142
|
+
return () => {
|
|
143
|
+
form.removeEventListener("focusout", onBlur);
|
|
144
|
+
form.removeEventListener("input", onInput);
|
|
145
|
+
form.removeEventListener("change", onInput);
|
|
146
|
+
form.removeEventListener("invalid", onInvalid, true);
|
|
147
|
+
};
|
|
148
|
+
}, [formRef]);
|
|
149
|
+
const shown = summary ? summary.filter((s) => s.name in errors).map((s) => ({ ...s, message: errors[s.name] })) : null;
|
|
150
|
+
return {
|
|
151
|
+
errors,
|
|
152
|
+
summary: shown && shown.length ? shown : null,
|
|
153
|
+
summaryKey,
|
|
154
|
+
clear: () => {
|
|
155
|
+
setErrors({});
|
|
156
|
+
setSummary(null);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function ErrorSummary({ items, focusKey, locale, messages, title, className, classNames: cx = {} }) {
|
|
161
|
+
const ref = react.useRef(null);
|
|
162
|
+
const m = fieldMessages(locale, messages);
|
|
163
|
+
const has = !!items && items.length > 0;
|
|
164
|
+
react.useEffect(() => {
|
|
165
|
+
if (has) ref.current?.focus();
|
|
166
|
+
}, [focusKey]);
|
|
167
|
+
if (!has) return null;
|
|
168
|
+
const n = items.length;
|
|
169
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, role: "alert", tabIndex: -1, className, "data-sf-error-summary": true, "aria-labelledby": "sf-error-summary-title", children: [
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { id: "sf-error-summary-title", className: cx.title, "data-sf-error-summary-title": true, children: title ?? (n === 1 ? m.summaryOne : m.summaryMany.replace("{n}", String(n))) }),
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: cx.list, children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
172
|
+
"a",
|
|
173
|
+
{
|
|
174
|
+
href: `#${it.id}`,
|
|
175
|
+
className: cx.link,
|
|
176
|
+
onClick: (e) => {
|
|
177
|
+
const el = document.getElementById(it.id);
|
|
178
|
+
if (!el) return;
|
|
179
|
+
e.preventDefault();
|
|
180
|
+
el.focus();
|
|
181
|
+
el.scrollIntoView?.({ block: "center" });
|
|
182
|
+
},
|
|
183
|
+
children: [
|
|
184
|
+
it.label,
|
|
185
|
+
": ",
|
|
186
|
+
it.message
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
) }, it.name)) })
|
|
190
|
+
] });
|
|
191
|
+
}
|
|
192
|
+
function CheckoutField(props) {
|
|
193
|
+
const { name, label, id = name, error, hint, optional = false, classNames: cx = {}, locale, messages, ...rest } = props;
|
|
194
|
+
const m = fieldMessages(locale, messages);
|
|
195
|
+
const hintId = hint ? `${id}-hint` : void 0;
|
|
196
|
+
const errorId = `${id}-error`;
|
|
197
|
+
const describedBy = [hintId, error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
|
|
198
|
+
const common = {
|
|
199
|
+
id,
|
|
200
|
+
name,
|
|
201
|
+
required: !optional,
|
|
202
|
+
"aria-invalid": error ? true : void 0,
|
|
203
|
+
"aria-describedby": describedBy,
|
|
204
|
+
className: cx.input,
|
|
205
|
+
"data-sf-field-control": ""
|
|
206
|
+
};
|
|
207
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.root, "data-sf-field": true, "data-invalid": error ? "" : void 0, children: [
|
|
208
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: id, className: cx.label, "data-sf-label": label, children: [
|
|
209
|
+
label,
|
|
210
|
+
optional ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cx.optional, "data-sf-field-optional": true, children: [
|
|
211
|
+
" ",
|
|
212
|
+
m.optional
|
|
213
|
+
] }) : null
|
|
214
|
+
] }),
|
|
215
|
+
hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: hintId, className: cx.hint, "data-sf-field-hint": true, children: hint }) : null,
|
|
216
|
+
rest.as === "select" ? (() => {
|
|
217
|
+
const { as: _as, children, ...select } = rest;
|
|
218
|
+
return /* @__PURE__ */ jsxRuntime.jsx("select", { ...select, ...common, children });
|
|
219
|
+
})() : (() => {
|
|
220
|
+
const { as: _as, ...input } = rest;
|
|
221
|
+
return /* @__PURE__ */ jsxRuntime.jsx("input", { ...input, ...common });
|
|
222
|
+
})(),
|
|
223
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, className: cx.error, "data-sf-field-error": true, children: error }) : null
|
|
224
|
+
] });
|
|
225
|
+
}
|
|
226
|
+
var ES2 = {
|
|
227
|
+
email: "Correo",
|
|
228
|
+
phone: "Tel\xE9fono",
|
|
229
|
+
first_name: "Nombre",
|
|
230
|
+
last_name: "Apellidos",
|
|
231
|
+
zip: "C\xF3digo postal",
|
|
232
|
+
province: "Estado",
|
|
233
|
+
city: "Ciudad o municipio",
|
|
234
|
+
neighborhood: "Colonia",
|
|
235
|
+
address1: "Calle y n\xFAmero",
|
|
236
|
+
address2: "N\xFAmero interior o departamento",
|
|
237
|
+
reference: "Referencias para la entrega",
|
|
238
|
+
provincePlaceholder: "Elige tu estado",
|
|
239
|
+
address1Hint: "Por ejemplo: Av. Insurgentes Sur 1234",
|
|
240
|
+
referenceHint: "Entre qu\xE9 calles, color de la fachada\u2026",
|
|
241
|
+
emailHint: "Te enviamos aqu\xED la confirmaci\xF3n y el seguimiento.",
|
|
242
|
+
phoneHint: "Solo para la paqueter\xEDa, por si necesita contactarte.",
|
|
243
|
+
lookupFilled: "Completamos estado y ciudad con tu c\xF3digo postal."
|
|
244
|
+
};
|
|
245
|
+
var EN2 = {
|
|
246
|
+
email: "Email",
|
|
247
|
+
phone: "Phone",
|
|
248
|
+
first_name: "First name",
|
|
249
|
+
last_name: "Last name",
|
|
250
|
+
zip: "Postal code",
|
|
251
|
+
province: "State",
|
|
252
|
+
city: "City",
|
|
253
|
+
neighborhood: "Neighborhood",
|
|
254
|
+
address1: "Street and number",
|
|
255
|
+
address2: "Apartment, suite",
|
|
256
|
+
reference: "Delivery notes",
|
|
257
|
+
provincePlaceholder: "Choose your state",
|
|
258
|
+
address1Hint: "For example: 1234 Main St",
|
|
259
|
+
referenceHint: "Cross streets, building color\u2026",
|
|
260
|
+
emailHint: "We send the confirmation and tracking here.",
|
|
261
|
+
phoneHint: "Only for the carrier, in case they need to reach you.",
|
|
262
|
+
lookupFilled: "We filled in state and city from your postal code."
|
|
263
|
+
};
|
|
264
|
+
function addressFieldsMessages(locale, overrides) {
|
|
265
|
+
const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ? EN2 : ES2;
|
|
266
|
+
return overrides ? { ...base, ...overrides } : base;
|
|
267
|
+
}
|
|
268
|
+
var join = (...c) => c.filter(Boolean).join(" ") || void 0;
|
|
269
|
+
var field = (cx, span) => ({ ...cx, root: join(cx.root, cx[span]) });
|
|
270
|
+
function ContactFields({ defaults = {}, names = {}, errors = {}, phone, hints = true, locale, messages, fieldMessages: fm, classNames: cx = {} }) {
|
|
271
|
+
const m = addressFieldsMessages(locale, messages);
|
|
272
|
+
const n = (k) => names[k] ?? k;
|
|
273
|
+
const common = { ...locale ? { locale } : {}, ...fm ? { messages: fm } : {} };
|
|
274
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
275
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("email"), label: m.email, type: "email", autoComplete: "email", inputMode: "email", autoCapitalize: "none", spellCheck: false, defaultValue: defaults.email ?? "", error: errors[n("email")] ?? null, hint: hints ? m.emailHint : void 0, classNames: field(cx, "wide") }),
|
|
276
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("phone"), label: m.phone, type: "tel", autoComplete: "tel", inputMode: "tel", defaultValue: defaults.phone ?? "", error: errors[n("phone")] ?? null, hint: hints ? m.phoneHint : void 0, classNames: field(cx, "wide"), ...phone?.pattern ? { pattern: phone.pattern } : {}, ...phone?.title ? { title: phone.title } : {}, ...phone?.minLength ? { minLength: phone.minLength } : {} }),
|
|
277
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("first_name"), label: m.first_name, autoComplete: "given-name", defaultValue: defaults.first_name ?? "", error: errors[n("first_name")] ?? null, classNames: field(cx, "half") }),
|
|
278
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("last_name"), label: m.last_name, autoComplete: "family-name", defaultValue: defaults.last_name ?? "", error: errors[n("last_name")] ?? null, classNames: field(cx, "half") })
|
|
279
|
+
] });
|
|
280
|
+
}
|
|
281
|
+
function AddressFields(props) {
|
|
282
|
+
const { defaults, names = {}, errors = {}, countryCode, provinces, postalCode, lookupPostalCode, locale, messages, fieldMessages: fm, classNames: cx = {}, children } = props;
|
|
283
|
+
const showNeighborhood = props.neighborhood ?? true;
|
|
284
|
+
const showReference = props.reference ?? true;
|
|
285
|
+
const m = addressFieldsMessages(locale, messages);
|
|
286
|
+
const n = (k) => names[k] ?? k;
|
|
287
|
+
const common = { ...locale ? { locale } : {}, ...fm ? { messages: fm } : {} };
|
|
288
|
+
const listId = react.useId();
|
|
289
|
+
const [colonias, setColonias] = react.useState([]);
|
|
290
|
+
const [filled, setFilled] = react.useState(false);
|
|
291
|
+
const lastZip = react.useRef(null);
|
|
292
|
+
const zipRef = react.useRef(null);
|
|
293
|
+
const lookupRef = react.useRef(lookupPostalCode);
|
|
294
|
+
lookupRef.current = lookupPostalCode;
|
|
295
|
+
const runLookup = (zip) => {
|
|
296
|
+
const lookup = lookupRef.current;
|
|
297
|
+
if (!lookup || !zip || zip === lastZip.current) return;
|
|
298
|
+
if (postalCode?.pattern && !new RegExp(`^(?:${postalCode.pattern})$`).test(zip)) return;
|
|
299
|
+
lastZip.current = zip;
|
|
300
|
+
const form = zipRef.current?.closest("form");
|
|
301
|
+
void lookup(zip).then(
|
|
302
|
+
(info) => {
|
|
303
|
+
if (!info || lastZip.current !== zip) return;
|
|
304
|
+
const fill2 = (name, value) => {
|
|
305
|
+
const el = form?.elements.namedItem(name);
|
|
306
|
+
if (!el || !value || "length" in el && !(el instanceof HTMLSelectElement)) return false;
|
|
307
|
+
if (el.value && el.dataset.sfAutofilled !== "1") return false;
|
|
308
|
+
if (el instanceof HTMLSelectElement && ![...el.options].some((o) => o.value === value)) return false;
|
|
309
|
+
el.value = value;
|
|
310
|
+
el.dataset.sfAutofilled = "1";
|
|
311
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
312
|
+
return true;
|
|
313
|
+
};
|
|
314
|
+
const a = fill2(n("province"), info.province);
|
|
315
|
+
const b = fill2(n("city"), info.city);
|
|
316
|
+
setColonias(info.neighborhoods ?? []);
|
|
317
|
+
setFilled(a || b);
|
|
318
|
+
},
|
|
319
|
+
() => {
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
};
|
|
323
|
+
react.useEffect(() => {
|
|
324
|
+
const zip = defaults?.zip;
|
|
325
|
+
if (zip) runLookup(zip);
|
|
326
|
+
}, []);
|
|
327
|
+
const numericZip = postalCode?.inputMode === "numeric";
|
|
328
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
329
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: zipRef, className: join(cx.half), "data-sf-zip": true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
330
|
+
CheckoutField,
|
|
331
|
+
{
|
|
332
|
+
...common,
|
|
333
|
+
name: n("zip"),
|
|
334
|
+
label: m.zip,
|
|
335
|
+
autoComplete: "postal-code",
|
|
336
|
+
inputMode: postalCode?.inputMode ?? "text",
|
|
337
|
+
...postalCode?.pattern ? { pattern: postalCode.pattern } : {},
|
|
338
|
+
...postalCode?.maxLength ? { maxLength: postalCode.maxLength } : {},
|
|
339
|
+
...postalCode?.title ? { title: postalCode.title } : {},
|
|
340
|
+
...numericZip ? { autoCapitalize: "none" } : {},
|
|
341
|
+
defaultValue: defaults?.zip ?? "",
|
|
342
|
+
error: errors[n("zip")] ?? null,
|
|
343
|
+
classNames: { ...cx, root: cx.root },
|
|
344
|
+
onInput: (e) => {
|
|
345
|
+
const v = e.currentTarget.value.trim();
|
|
346
|
+
if (postalCode?.maxLength && v.length === postalCode.maxLength) runLookup(v);
|
|
347
|
+
},
|
|
348
|
+
onBlur: (e) => runLookup(e.currentTarget.value.trim())
|
|
349
|
+
}
|
|
350
|
+
) }),
|
|
351
|
+
provinces && provinces.length ? /* @__PURE__ */ jsxRuntime.jsxs(CheckoutField, { ...common, as: "select", name: n("province"), label: m.province, autoComplete: "address-level1", defaultValue: defaults?.province ?? "", error: errors[n("province")] ?? null, classNames: field(cx, "half"), children: [
|
|
352
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: m.provincePlaceholder }),
|
|
353
|
+
provinces.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.name, children: p.name }, p.code ?? p.name))
|
|
354
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("province"), label: m.province, autoComplete: "address-level1", defaultValue: defaults?.province ?? "", error: errors[n("province")] ?? null, classNames: field(cx, "half") }),
|
|
355
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("city"), label: m.city, autoComplete: "address-level2", defaultValue: defaults?.city ?? "", error: errors[n("city")] ?? null, classNames: field(cx, "half") }),
|
|
356
|
+
showNeighborhood ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
357
|
+
CheckoutField,
|
|
358
|
+
{
|
|
359
|
+
...common,
|
|
360
|
+
name: n("neighborhood"),
|
|
361
|
+
label: m.neighborhood,
|
|
362
|
+
autoComplete: "address-level3",
|
|
363
|
+
optional: showNeighborhood !== "required",
|
|
364
|
+
defaultValue: defaults?.neighborhood ?? "",
|
|
365
|
+
error: errors[n("neighborhood")] ?? null,
|
|
366
|
+
classNames: field(cx, "half"),
|
|
367
|
+
...colonias.length ? { list: listId } : {}
|
|
368
|
+
}
|
|
369
|
+
) : null,
|
|
370
|
+
colonias.length ? /* @__PURE__ */ jsxRuntime.jsx("datalist", { id: listId, children: colonias.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c }, c)) }) : null,
|
|
371
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", "aria-live": "polite", "data-sf-zip-status": true, style: filled ? void 0 : { position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)", whiteSpace: "nowrap" }, className: filled ? join(cx.hint, cx.wide) : void 0, children: filled ? m.lookupFilled : "" }),
|
|
372
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("address1"), label: m.address1, autoComplete: "address-line1", defaultValue: defaults?.address1 ?? "", error: errors[n("address1")] ?? null, hint: m.address1Hint, classNames: field(cx, "wide") }),
|
|
373
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("address2"), label: m.address2, autoComplete: "address-line2", optional: true, defaultValue: defaults?.address2 ?? "", error: errors[n("address2")] ?? null, classNames: field(cx, "half") }),
|
|
374
|
+
showReference ? /* @__PURE__ */ jsxRuntime.jsx(CheckoutField, { ...common, name: n("reference"), label: m.reference, optional: true, defaultValue: defaults?.reference ?? "", error: errors[n("reference")] ?? null, hint: m.referenceHint, classNames: field(cx, "wide"), maxLength: 200 }) : null,
|
|
375
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: "country_code", value: countryCode }),
|
|
376
|
+
children
|
|
377
|
+
] });
|
|
378
|
+
}
|
|
379
|
+
var StorefrontContext = react.createContext(null);
|
|
380
|
+
function useOptionalStorefront() {
|
|
381
|
+
return react.useContext(StorefrontContext);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/locale.ts
|
|
385
|
+
function useResolvedLocale(locale) {
|
|
386
|
+
const sf = useOptionalStorefront();
|
|
387
|
+
return locale ?? sf?.locale ?? "es-MX";
|
|
388
|
+
}
|
|
389
|
+
var ES3 = {
|
|
390
|
+
title: "Tu pedido",
|
|
391
|
+
subtotal: "Subtotal",
|
|
392
|
+
discount: "Descuento",
|
|
393
|
+
shipping: "Env\xEDo",
|
|
394
|
+
shippingPending: "Al elegir la entrega",
|
|
395
|
+
updating: "Actualizando\u2026",
|
|
396
|
+
free: "Gratis",
|
|
397
|
+
taxes: "Impuestos",
|
|
398
|
+
taxesIncluded: "Incluye {amount} de impuestos",
|
|
399
|
+
total: "Total",
|
|
400
|
+
quantity: "Cantidad: {n}",
|
|
401
|
+
show: "Ver resumen del pedido",
|
|
402
|
+
hide: "Ocultar resumen del pedido"
|
|
403
|
+
};
|
|
404
|
+
var EN3 = {
|
|
405
|
+
title: "Your order",
|
|
406
|
+
subtotal: "Subtotal",
|
|
407
|
+
discount: "Discount",
|
|
408
|
+
shipping: "Shipping",
|
|
409
|
+
shippingPending: "Calculated at delivery",
|
|
410
|
+
updating: "Updating\u2026",
|
|
411
|
+
free: "Free",
|
|
412
|
+
taxes: "Taxes",
|
|
413
|
+
taxesIncluded: "Includes {amount} in taxes",
|
|
414
|
+
total: "Total",
|
|
415
|
+
quantity: "Quantity: {n}",
|
|
416
|
+
show: "Show order summary",
|
|
417
|
+
hide: "Hide order summary"
|
|
418
|
+
};
|
|
419
|
+
function orderSummaryMessages(locale, overrides) {
|
|
420
|
+
const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ? EN3 : ES3;
|
|
421
|
+
return overrides ? { ...base, ...overrides } : base;
|
|
422
|
+
}
|
|
423
|
+
var isZero = (m) => !!m && Number(m.amount) === 0;
|
|
424
|
+
var positive = (m) => !!m && Number(m.amount) > 0;
|
|
425
|
+
function OrderSummary(props) {
|
|
426
|
+
const { lines, cost, updating = false, renderLineMedia, renderAmount, title, headingLevel = 2, classNames: cx = {}, children } = props;
|
|
427
|
+
const locale = useResolvedLocale(props.locale);
|
|
428
|
+
const m = orderSummaryMessages(locale, props.messages);
|
|
429
|
+
const money = (v) => renderAmount ? renderAmount(v) : storefront.formatMoney(v, locale);
|
|
430
|
+
const H = headingLevel === 3 ? "h3" : "h2";
|
|
431
|
+
const discounts = cost.discounts?.filter((d) => positive(d.amount)) ?? [];
|
|
432
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.root, "data-sf-summary": true, children: [
|
|
433
|
+
title === false ? null : /* @__PURE__ */ jsxRuntime.jsx(H, { className: cx.title, "data-sf-summary-title": true, children: title ?? m.title }),
|
|
434
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: cx.lines, "data-sf-summary-lines": true, children: lines.map((l) => {
|
|
435
|
+
const variant = l.merchandise.title && !/^default( title)?$/i.test(l.merchandise.title) ? l.merchandise.title : null;
|
|
436
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cx.line, "data-sf-summary-line": true, children: [
|
|
437
|
+
renderLineMedia ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cx.media, "data-sf-summary-media": true, children: [
|
|
438
|
+
renderLineMedia(l),
|
|
439
|
+
l.quantity > 1 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.qty, "data-sf-summary-qty": true, "aria-hidden": "true", children: l.quantity }) : null
|
|
440
|
+
] }) : null,
|
|
441
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { "data-sf-summary-line-body": true, children: [
|
|
442
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: cx.lineTitle, "data-sf-summary-line-title": true, children: [
|
|
443
|
+
!renderLineMedia && l.quantity > 1 ? `${l.quantity} \xD7 ` : null,
|
|
444
|
+
l.merchandise.product.title
|
|
445
|
+
] }),
|
|
446
|
+
variant ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.variant, "data-sf-summary-variant": true, children: variant }) : null,
|
|
447
|
+
renderLineMedia || l.quantity > 1 ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)", whiteSpace: "nowrap" }, children: m.quantity.replace("{n}", String(l.quantity)) }) : null
|
|
448
|
+
] }),
|
|
449
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.linePrice, "data-sf-summary-line-price": true, children: money(l.cost.total) })
|
|
450
|
+
] }, l.id);
|
|
451
|
+
}) }),
|
|
452
|
+
children,
|
|
453
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dl", { className: cx.totals, "data-sf-summary-totals": true, "aria-busy": updating || void 0, children: [
|
|
454
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.row, "data-sf-summary-row": "subtotal", children: [
|
|
455
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: m.subtotal }),
|
|
456
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: money(cost.subtotal) })
|
|
457
|
+
] }),
|
|
458
|
+
discounts.length ? discounts.map((d) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.row ? `${cx.row} ${cx.discount ?? ""}`.trim() : cx.discount, "data-sf-summary-row": "discount", children: [
|
|
459
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: d.code ? `${m.discount} (${d.code})` : d.title || m.discount }),
|
|
460
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dd", { children: [
|
|
461
|
+
"\u2212",
|
|
462
|
+
money(d.amount)
|
|
463
|
+
] })
|
|
464
|
+
] }, d.id)) : positive(cost.discount) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.row ? `${cx.row} ${cx.discount ?? ""}`.trim() : cx.discount, "data-sf-summary-row": "discount", children: [
|
|
465
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: m.discount }),
|
|
466
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dd", { children: [
|
|
467
|
+
"\u2212",
|
|
468
|
+
money(cost.discount)
|
|
469
|
+
] })
|
|
470
|
+
] }) : null,
|
|
471
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.row, "data-sf-summary-row": "shipping", children: [
|
|
472
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: m.shipping }),
|
|
473
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { className: updating || !cost.shipping ? cx.muted : void 0, children: updating ? m.updating : !cost.shipping ? m.shippingPending : isZero(cost.shipping) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.free, children: m.free }) : money(cost.shipping) })
|
|
474
|
+
] }),
|
|
475
|
+
positive(cost.tax) && !cost.tax_included ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.row, "data-sf-summary-row": "tax", children: [
|
|
476
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: m.taxes }),
|
|
477
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: money(cost.tax) })
|
|
478
|
+
] }) : null,
|
|
479
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.total, "data-sf-summary-row": "total", children: [
|
|
480
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: m.total }),
|
|
481
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { "aria-live": "polite", "data-updating": updating || void 0, children: money(cost.total) })
|
|
482
|
+
] })
|
|
483
|
+
] }),
|
|
484
|
+
positive(cost.tax) && cost.tax_included ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx.note, "data-sf-summary-tax-note": true, children: m.taxesIncluded.split("{amount}").flatMap((part, i) => i === 0 ? [part] : [/* @__PURE__ */ jsxRuntime.jsx("span", { children: money(cost.tax) }, i), part]) }) : null
|
|
485
|
+
] });
|
|
486
|
+
}
|
|
487
|
+
function OrderSummaryDisclosure({ total, updating, renderAmount, locale: loc, messages, defaultOpen = false, className, classNames: cx = {}, children }) {
|
|
488
|
+
const locale = useResolvedLocale(loc);
|
|
489
|
+
const m = orderSummaryMessages(locale, messages);
|
|
490
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("details", { className, "data-sf-summary-disclosure": true, ...defaultOpen ? { open: true } : {}, children: [
|
|
491
|
+
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: cx.summary, "data-sf-summary-toggle": true, children: [
|
|
492
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: cx.label, "data-sf-summary-toggle-label": true, children: [
|
|
493
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-sf-summary-show": true, children: m.show }),
|
|
494
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-sf-summary-hide": true, children: m.hide })
|
|
495
|
+
] }),
|
|
496
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.total, "data-sf-summary-toggle-total": true, "data-updating": updating || void 0, children: renderAmount ? renderAmount(total) : storefront.formatMoney(total, locale) })
|
|
497
|
+
] }),
|
|
498
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cx.panel, "data-sf-summary-panel": true, children })
|
|
499
|
+
] });
|
|
500
|
+
}
|
|
501
|
+
|
|
7
502
|
// src/checkout/brands/logos.generated.ts
|
|
8
503
|
var LOGOS = {
|
|
9
504
|
"7eleven": { src: "data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 xmlns:xlink=%22http://www.w3.org/1999/xlink%22 xml:space=%22preserve%22 viewBox=%220 0 45 59.89%22%3E%3Cdefs%3E%3Cpath id=%22a%22 d=%22M0 0h45v59.9H0z%22/%3E%3C/defs%3E%3CclipPath id=%22b%22%3E%3Cuse xlink:href=%22%23a%22 style=%22overflow:visible%22/%3E%3C/clipPath%3E%3Cpath d=%22M34.2 45c.9 0 1.7.8 1.7 1.7s-.7 1.7-1.7 1.7c-.9 0-1.6-.8-1.6-1.7s.7-1.7 1.6-1.7m0 3c.7 0 1.3-.6 1.3-1.3 0-.8-.6-1.3-1.3-1.3s-1.3.6-1.3 1.3c0 .8.6 1.3 1.3 1.3m-.2-.4h-.3v-1.8h.6q.6 0 .6.6c0 .3-.2.5-.4.5l.4.7h-.4l-.4-.7H34zm.2-1q.3 0 .3-.3t-.3-.3H34v.5h.2zm8-14.3c-.9 0-1.5.4-2.1.9l-.4.6-.1-.1.5-.8v-.5h-3.2V43h2.9v-6.7c0-1.1.7-1.4 1.2-1.5s1.1.2 1.1.8V43H45v-7.3c0-2.3-1-3.4-2.8-3.4M9.9 40.6h3v2.3H7V32.3h2.9zM0 42.9h5.9v-2.1h-3v-2.3h3v-2h-3v-2h3v-2.2H0zm13.9 0h6v-2.1h-3.1v-2.3h3.1v-2h-3.1v-2h3.1v-2.2h-6zm16 0h6v-2.1h-3.1v-2.3h3.1v-2h-3.1v-2h3.1v-2.2h-6zm-3.8-10.6L25 39l-.1 1.2v.1h-.1v-.1l-.1-1.2-1.1-6.7h-2.9l2.4 10.6h3.6l2.4-10.6z%22 style=%22clip-path:url(%23b);fill:%23147350%22/%3E%3Cpath d=%22M37.7 0H0v15h19.9C24.4 8.5 30.5 3.3 37.7 0%22 style=%22clip-path:url(%23b);fill:%23ff6c00%22/%3E%3Cpath d=%22M15 59.9h15v-15H15zM45 15V0a40.7 40.7 0 0 0-28.9 30h15.3A25.8 25.8 0 0 1 45 15%22 style=%22clip-path:url(%23b);fill:%23eb0f2a%22/%3E%3C/svg%3E", ar: 0.751, mono: false },
|
|
@@ -264,19 +759,83 @@ function BrandMark({ brand, logoUrl, size = 24, title, className }) {
|
|
|
264
759
|
lines.length > 1 ? lines.slice(0, 2).map((l, i) => /* @__PURE__ */ jsxRuntime.jsx("text", { x: "24", y: i === 0 ? 15 : 25.5, ...common, ...fit(l), children: l }, i)) : /* @__PURE__ */ jsxRuntime.jsx("text", { x: "24", y: "16", dominantBaseline: "central", letterSpacing: longest <= 4 ? 0.3 : 0, ...common, ...fit(text), children: text })
|
|
265
760
|
] });
|
|
266
761
|
}
|
|
267
|
-
var StorefrontContext = react.createContext(null);
|
|
268
|
-
function useOptionalStorefront() {
|
|
269
|
-
return react.useContext(StorefrontContext);
|
|
270
|
-
}
|
|
271
762
|
|
|
272
|
-
// src/
|
|
273
|
-
|
|
274
|
-
const
|
|
275
|
-
return
|
|
763
|
+
// src/checkout/recommend.ts
|
|
764
|
+
var costOf = (r) => {
|
|
765
|
+
const n = Number(r.cost.amount);
|
|
766
|
+
return Number.isFinite(n) ? n : null;
|
|
767
|
+
};
|
|
768
|
+
var daysOf = (r) => r.eta_days_max ?? r.eta_days_min ?? null;
|
|
769
|
+
var norm = (s) => (s ?? "").trim().toLowerCase();
|
|
770
|
+
var carrierKey = (r) => r.carrier ? brandKey(r.carrier) : r.provider ? brandKey(r.provider) : "";
|
|
771
|
+
function dedupeRates(rates) {
|
|
772
|
+
const best = /* @__PURE__ */ new Map();
|
|
773
|
+
const keyOf = (r) => `${carrierKey(r)}|${norm(r.service_code) || norm(r.title)}|${daysOf(r) ?? ""}|${r.cost.currency_code}`;
|
|
774
|
+
for (const r of rates) {
|
|
775
|
+
const k = keyOf(r);
|
|
776
|
+
const prev = best.get(k);
|
|
777
|
+
const c = costOf(r);
|
|
778
|
+
if (!prev || c !== null && (costOf(prev) === null || c < costOf(prev))) best.set(k, r);
|
|
779
|
+
}
|
|
780
|
+
const keep = new Set(best.values());
|
|
781
|
+
return rates.filter((r) => keep.has(r));
|
|
782
|
+
}
|
|
783
|
+
function recommendRates(input, options = {}) {
|
|
784
|
+
const count = Math.max(1, options.count ?? 3);
|
|
785
|
+
const rates = options.dedupe === false ? [...input] : dedupeRates(input);
|
|
786
|
+
const collapseAfter = options.collapseAfter ?? count + 1;
|
|
787
|
+
const sameCurrency = new Set(rates.map((r) => r.cost.currency_code)).size <= 1;
|
|
788
|
+
const byCost = (a, b) => (costOf(a) ?? Infinity) - (costOf(b) ?? Infinity);
|
|
789
|
+
const byDays = (a, b) => (daysOf(a) ?? Infinity) - (daysOf(b) ?? Infinity);
|
|
790
|
+
const tags = /* @__PURE__ */ new Map();
|
|
791
|
+
const tag = (r, t) => tags.set(r, [...tags.get(r) ?? [], t]);
|
|
792
|
+
const cheapest = sameCurrency && rates.length > 1 ? [...rates].sort((a, b) => byCost(a, b) || byDays(a, b))[0] : void 0;
|
|
793
|
+
if (cheapest && costOf(cheapest) !== null) tag(cheapest, "cheapest");
|
|
794
|
+
const fastest = rates.length > 1 ? [...rates].sort((a, b) => byDays(a, b) || byCost(a, b))[0] : void 0;
|
|
795
|
+
if (fastest && daysOf(fastest) !== null && (!cheapest || fastest === cheapest || (daysOf(cheapest) ?? Infinity) > daysOf(fastest))) tag(fastest, "fastest");
|
|
796
|
+
const chosen = [];
|
|
797
|
+
for (const r of [cheapest, fastest]) if (r && tags.has(r) && !chosen.includes(r)) chosen.push(r);
|
|
798
|
+
if (rates.length > collapseAfter) {
|
|
799
|
+
const rank = (sorted, val) => {
|
|
800
|
+
const out = /* @__PURE__ */ new Map();
|
|
801
|
+
let pos = 0;
|
|
802
|
+
let last;
|
|
803
|
+
sorted.forEach((r, i) => {
|
|
804
|
+
const v = val(r);
|
|
805
|
+
if (v !== last) pos = i;
|
|
806
|
+
last = v;
|
|
807
|
+
out.set(r, v === null ? sorted.length : pos);
|
|
808
|
+
});
|
|
809
|
+
return out;
|
|
810
|
+
};
|
|
811
|
+
const priceRank = rank([...rates].sort(byCost), costOf);
|
|
812
|
+
const timeRank = rank([...rates].sort(byDays), daysOf);
|
|
813
|
+
const rest = rates.filter((r) => !chosen.includes(r)).sort((a, b) => priceRank.get(a) + timeRank.get(a) - (priceRank.get(b) + timeRank.get(b)) || byCost(a, b));
|
|
814
|
+
let first = true;
|
|
815
|
+
for (const r of rest) {
|
|
816
|
+
if (chosen.length >= count) break;
|
|
817
|
+
chosen.push(r);
|
|
818
|
+
if (first) tag(r, "best_value");
|
|
819
|
+
first = false;
|
|
820
|
+
}
|
|
821
|
+
} else {
|
|
822
|
+
for (const r of rates) if (!chosen.includes(r)) chosen.push(r);
|
|
823
|
+
}
|
|
824
|
+
const recommended = chosen.sort(byCost).map((rate) => ({ rate, tags: tags.get(rate) ?? [] }));
|
|
825
|
+
const groups = /* @__PURE__ */ new Map();
|
|
826
|
+
for (const r of [...rates].sort(byCost)) {
|
|
827
|
+
if (chosen.includes(r)) continue;
|
|
828
|
+
const key = carrierKey(r);
|
|
829
|
+
const g = groups.get(key) ?? { key, carrier: r.carrier ?? r.provider ?? null, rates: [] };
|
|
830
|
+
g.rates.push(r);
|
|
831
|
+
groups.set(key, g);
|
|
832
|
+
}
|
|
833
|
+
const more = [...groups.values()];
|
|
834
|
+
return { recommended, more, moreCount: more.reduce((n, g) => n + g.rates.length, 0) };
|
|
276
835
|
}
|
|
277
836
|
|
|
278
837
|
// src/checkout/delivery.ts
|
|
279
|
-
var
|
|
838
|
+
var ES4 = {
|
|
280
839
|
etaOne: "Llega en 1 d\xEDa h\xE1bil",
|
|
281
840
|
etaMany: "Llega en {n} d\xEDas h\xE1biles",
|
|
282
841
|
etaRange: "Llega en {min} a {max} d\xEDas h\xE1biles",
|
|
@@ -290,11 +849,16 @@ var ES = {
|
|
|
290
849
|
quoteTomorrow: "Precios de env\xEDo vigentes hasta ma\xF1ana a las {time}.",
|
|
291
850
|
quoteLater: "Precios de env\xEDo vigentes hasta el {date}.",
|
|
292
851
|
quoteSoon: "Los precios de env\xEDo vencen pronto ({time}).",
|
|
293
|
-
partial: "
|
|
852
|
+
partial: "Algunas paqueter\xEDas no respondieron a tiempo; estas son las opciones disponibles.",
|
|
294
853
|
loading: "Buscando opciones de env\xEDo\u2026",
|
|
295
|
-
requoted: "Las tarifas de env\xEDo cambiaron y ya est\xE1n actualizadas. Revisa tu env\xEDo antes de pagar."
|
|
854
|
+
requoted: "Las tarifas de env\xEDo cambiaron y ya est\xE1n actualizadas. Revisa tu env\xEDo antes de pagar.",
|
|
855
|
+
bestValue: "Recomendado",
|
|
856
|
+
moreOptions: "Ver m\xE1s opciones ({n})",
|
|
857
|
+
otherCarriers: "Otras opciones",
|
|
858
|
+
error: "No pudimos consultar las opciones de env\xEDo en este momento.",
|
|
859
|
+
retry: "Intentar de nuevo"
|
|
296
860
|
};
|
|
297
|
-
var
|
|
861
|
+
var EN4 = {
|
|
298
862
|
etaOne: "Arrives in 1 business day",
|
|
299
863
|
etaMany: "Arrives in {n} business days",
|
|
300
864
|
etaRange: "Arrives in {min} to {max} business days",
|
|
@@ -310,10 +874,15 @@ var EN = {
|
|
|
310
874
|
quoteSoon: "Shipping prices expire soon ({time}).",
|
|
311
875
|
partial: "We couldn't reach every carrier. These are the options available now.",
|
|
312
876
|
loading: "Looking for delivery options\u2026",
|
|
313
|
-
requoted: "Shipping rates changed and are now up to date. Check your delivery before paying."
|
|
877
|
+
requoted: "Shipping rates changed and are now up to date. Check your delivery before paying.",
|
|
878
|
+
bestValue: "Recommended",
|
|
879
|
+
moreOptions: "Show more options ({n})",
|
|
880
|
+
otherCarriers: "Other options",
|
|
881
|
+
error: "We couldn't get delivery options right now.",
|
|
882
|
+
retry: "Try again"
|
|
314
883
|
};
|
|
315
884
|
function deliveryMessages(locale, overrides) {
|
|
316
|
-
const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ?
|
|
885
|
+
const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ? EN4 : ES4;
|
|
317
886
|
return overrides ? { ...base, ...overrides } : base;
|
|
318
887
|
}
|
|
319
888
|
var fill = (tpl, vars) => tpl.replace(/\{(\w+)\}/g, (_, k) => String(vars[k] ?? "")).replace(/\.\.$/, ".");
|
|
@@ -333,7 +902,7 @@ function rateService(rate) {
|
|
|
333
902
|
}
|
|
334
903
|
return title;
|
|
335
904
|
}
|
|
336
|
-
function rateEta(rate, messages =
|
|
905
|
+
function rateEta(rate, messages = ES4) {
|
|
337
906
|
const { eta_days_min: min, eta_days_max: max } = rate;
|
|
338
907
|
if (typeof min === "number" && typeof max === "number") {
|
|
339
908
|
if (min === max) return min === 1 ? messages.etaOne : fill(messages.etaMany, { n: min });
|
|
@@ -343,11 +912,11 @@ function rateEta(rate, messages = ES) {
|
|
|
343
912
|
if (typeof min === "number") return min === 1 ? messages.etaOne : fill(messages.etaFrom, { min });
|
|
344
913
|
return rate.eta ?? null;
|
|
345
914
|
}
|
|
346
|
-
var
|
|
915
|
+
var costOf2 = (r) => {
|
|
347
916
|
const n = Number(r.cost.amount);
|
|
348
917
|
return Number.isFinite(n) ? n : null;
|
|
349
918
|
};
|
|
350
|
-
var
|
|
919
|
+
var daysOf2 = (r) => r.eta_days_max ?? r.eta_days_min ?? null;
|
|
351
920
|
function rateBadges(rates) {
|
|
352
921
|
const out = /* @__PURE__ */ new Map();
|
|
353
922
|
if (rates.length < 2) return out;
|
|
@@ -361,10 +930,10 @@ function rateBadges(rates) {
|
|
|
361
930
|
};
|
|
362
931
|
const currencies = new Set(rates.map((r) => r.cost.currency_code));
|
|
363
932
|
if (currencies.size === 1) {
|
|
364
|
-
const id = unique(rates.map((r) => [r.id,
|
|
933
|
+
const id = unique(rates.map((r) => [r.id, costOf2(r)]));
|
|
365
934
|
if (id) add(id, "cheapest");
|
|
366
935
|
}
|
|
367
|
-
const fast = unique(rates.map((r) => [r.id,
|
|
936
|
+
const fast = unique(rates.map((r) => [r.id, daysOf2(r)]));
|
|
368
937
|
if (fast) add(fast, "fastest");
|
|
369
938
|
return out;
|
|
370
939
|
}
|
|
@@ -383,7 +952,7 @@ function quoteNote(deadline, opts = {}) {
|
|
|
383
952
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
384
953
|
const left = deadline.getTime() - now.getTime();
|
|
385
954
|
if (left <= 0) return null;
|
|
386
|
-
const m = opts.messages ??
|
|
955
|
+
const m = opts.messages ?? ES4;
|
|
387
956
|
const locale = opts.locale ?? "es-MX";
|
|
388
957
|
const tz = opts.timeZone ? { timeZone: opts.timeZone } : {};
|
|
389
958
|
const time = new Intl.DateTimeFormat(locale, { hour: "numeric", minute: "2-digit", ...tz }).format(deadline);
|
|
@@ -403,13 +972,13 @@ function isQuoteChange(err) {
|
|
|
403
972
|
}
|
|
404
973
|
function matchRate(previous, rates) {
|
|
405
974
|
if (!previous) return null;
|
|
406
|
-
const
|
|
407
|
-
const sameCarrier = (r) =>
|
|
975
|
+
const norm2 = (s) => (s ?? "").trim().toLowerCase();
|
|
976
|
+
const sameCarrier = (r) => norm2(r.carrier) === norm2(previous.carrier);
|
|
408
977
|
if (previous.service_code) {
|
|
409
|
-
const hit = rates.find((r) => sameCarrier(r) &&
|
|
978
|
+
const hit = rates.find((r) => sameCarrier(r) && norm2(r.service_code) === norm2(previous.service_code));
|
|
410
979
|
if (hit) return hit;
|
|
411
980
|
}
|
|
412
|
-
return rates.find((r) => sameCarrier(r) &&
|
|
981
|
+
return rates.find((r) => sameCarrier(r) && norm2(r.title) === norm2(previous.title)) ?? null;
|
|
413
982
|
}
|
|
414
983
|
var SR_ONLY = { position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)", whiteSpace: "nowrap" };
|
|
415
984
|
var useHydrated = () => react.useSyncExternalStore(
|
|
@@ -443,7 +1012,10 @@ function DeliveryOptions(props) {
|
|
|
443
1012
|
renderAmount,
|
|
444
1013
|
classNames: cx = {},
|
|
445
1014
|
testId,
|
|
446
|
-
children
|
|
1015
|
+
children,
|
|
1016
|
+
layout = "list",
|
|
1017
|
+
error,
|
|
1018
|
+
onRetry
|
|
447
1019
|
} = props;
|
|
448
1020
|
const locale = useResolvedLocale(props.locale);
|
|
449
1021
|
const m = react.useMemo(() => deliveryMessages(locale, props.messages), [locale, props.messages]);
|
|
@@ -456,7 +1028,13 @@ function DeliveryOptions(props) {
|
|
|
456
1028
|
const deadline = mode === "never" ? null : quoteDeadline(rates);
|
|
457
1029
|
const note = hydrated && deadline ? quoteNote(deadline, { locale, messages: m, ...timeZone ? { timeZone } : {} }) : null;
|
|
458
1030
|
const shownNote = note && (mode === "always" || note.soon) ? note : null;
|
|
459
|
-
const
|
|
1031
|
+
const current = value ?? defaultValue ?? null;
|
|
1032
|
+
const plan = react.useMemo(
|
|
1033
|
+
() => layout === "recommended" ? recommendRates(rates, { count: props.recommendedCount ?? 3 }) : null,
|
|
1034
|
+
[layout, rates, props.recommendedCount]
|
|
1035
|
+
);
|
|
1036
|
+
const inMore = plan ? plan.more.some((g) => g.rates.some((r) => rateValue(r) === current)) : false;
|
|
1037
|
+
const radio = (v, describedBy) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
460
1038
|
"input",
|
|
461
1039
|
{
|
|
462
1040
|
type: "radio",
|
|
@@ -464,36 +1042,66 @@ function DeliveryOptions(props) {
|
|
|
464
1042
|
value: v,
|
|
465
1043
|
required,
|
|
466
1044
|
className: cx.radio,
|
|
1045
|
+
...{},
|
|
467
1046
|
...value !== void 0 ? { checked: value === v, onChange: () => onValueChange?.(v) } : { defaultChecked: v === defaultValue, ...onValueChange ? { onChange: () => onValueChange(v) } : {} },
|
|
468
1047
|
...testId ? { "data-testid": testId } : {}
|
|
469
1048
|
}
|
|
470
1049
|
);
|
|
471
|
-
|
|
472
|
-
|
|
1050
|
+
const tagText = (t) => t === "cheapest" ? m.cheapest : t === "fastest" ? m.fastest : m.bestValue;
|
|
1051
|
+
const rateRow = (rate, opts) => {
|
|
1052
|
+
const carrier = rateCarrier(rate);
|
|
1053
|
+
const service = rateService(rate);
|
|
1054
|
+
const eta = rateEta(rate, m);
|
|
1055
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: cx.option, "data-sf-delivery-option": true, "data-loading": loading || void 0, "data-grouped": opts.grouped || void 0, children: [
|
|
1056
|
+
radio(rateValue(rate)),
|
|
1057
|
+
marks && !opts.grouped ? (
|
|
1058
|
+
// Fixed slot: logos of different widths do not push the text column out of line.
|
|
1059
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-sf-delivery-mark": true, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(BrandMark, { brand: rate.carrier ?? rate.provider ?? rate.title, size: 28, ...cx.mark ? { className: cx.mark } : {} }) })
|
|
1060
|
+
) : null,
|
|
1061
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: cx.body, "data-sf-delivery-body": true, children: [
|
|
1062
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.title, "data-sf-delivery-title": true, children: carrier ? opts.grouped ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1063
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: SR_ONLY, children: [
|
|
1064
|
+
carrier,
|
|
1065
|
+
" "
|
|
1066
|
+
] }),
|
|
1067
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.carrier, "data-sf-delivery-carrier": true, "data-sf-delivery-service-only": true, children: service })
|
|
1068
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1069
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.carrier, "data-sf-delivery-carrier": true, children: carrier }),
|
|
1070
|
+
" ",
|
|
1071
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.service, "data-sf-delivery-service": true, children: service })
|
|
1072
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.carrier, "data-sf-delivery-carrier": true, children: service }) }),
|
|
1073
|
+
eta ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.eta, "data-sf-delivery-eta": true, children: eta }) : null,
|
|
1074
|
+
opts.tags.length ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.badges, "data-sf-delivery-badges": true, children: opts.tags.map((b) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.badge, "data-sf-delivery-badge": b, children: tagText(b) }, b)) }) : null
|
|
1075
|
+
] }),
|
|
1076
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.price, "data-sf-delivery-price": true, children: amount(rate.cost) })
|
|
1077
|
+
] }, rate.id);
|
|
1078
|
+
};
|
|
1079
|
+
const errorText = error ? typeof error === "string" ? error : m.error : null;
|
|
1080
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.root, "data-sf-delivery": true, "data-layout": layout, "aria-busy": loading || void 0, children: [
|
|
1081
|
+
partial && !errorText ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", className: cx.partial, "data-sf-delivery-partial": true, children: m.partial }) : null,
|
|
473
1082
|
requoted ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", className: cx.partial, "data-sf-delivery-requoted": true, children: m.requoted }) : null,
|
|
474
1083
|
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: SR_ONLY, role: "status", "data-sf-delivery-loading": true, children: m.loading }) : null,
|
|
1084
|
+
errorText && rates.length === 0 && !loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: cx.error, "data-sf-delivery-error": true, children: [
|
|
1085
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: errorText }),
|
|
1086
|
+
onRetry ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: cx.retry, onClick: onRetry, "data-sf-delivery-retry": true, children: m.retry }) : null
|
|
1087
|
+
] }) : null,
|
|
475
1088
|
children,
|
|
476
1089
|
loading && rates.length === 0 ? [0, 1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx.skeleton, "data-sf-delivery-skeleton": true, "aria-hidden": "true" }, i)) : null,
|
|
477
|
-
rates.map((rate) => {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
own.length ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.badges, "data-sf-delivery-badges": true, children: own.map((b) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.badge, "data-sf-delivery-badge": b, children: b === "cheapest" ? m.cheapest : m.fastest }, b)) }) : null
|
|
493
|
-
] }),
|
|
494
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.price, "data-sf-delivery-price": true, children: amount(rate.cost) })
|
|
495
|
-
] }, rate.id);
|
|
496
|
-
}),
|
|
1090
|
+
plan ? plan.recommended.map(({ rate, tags }) => rateRow(rate, { tags: showBadges ? tags : [] })) : rates.map((rate) => rateRow(rate, { tags: badges.get(rate.id) ?? [] })),
|
|
1091
|
+
plan && plan.moreCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: cx.more, "data-sf-delivery-more": true, ...inMore ? { open: true } : {}, children: [
|
|
1092
|
+
/* @__PURE__ */ jsxRuntime.jsx("summary", { className: cx.moreSummary, "data-sf-delivery-more-summary": true, children: m.moreOptions.replace("{n}", String(plan.moreCount)) }),
|
|
1093
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-sf-delivery-groups": true, children: plan.more.map((g) => {
|
|
1094
|
+
const carrierName = g.carrier ? rateCarrier({ carrier: g.carrier }) : null;
|
|
1095
|
+
const id = `${name}-group-${g.key || "other"}`;
|
|
1096
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-labelledby": id, className: cx.group, "data-sf-delivery-group": g.key || "other", children: [
|
|
1097
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { id, className: cx.groupTitle, "data-sf-delivery-group-title": true, children: [
|
|
1098
|
+
marks && g.carrier ? /* @__PURE__ */ jsxRuntime.jsx(BrandMark, { brand: g.carrier, size: 22 }) : null,
|
|
1099
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: carrierName ?? m.otherCarriers })
|
|
1100
|
+
] }),
|
|
1101
|
+
g.rates.map((rate) => rateRow(rate, { tags: [], grouped: Boolean(carrierName) }))
|
|
1102
|
+
] }, g.key || "other");
|
|
1103
|
+
}) })
|
|
1104
|
+
] }) : null,
|
|
497
1105
|
pickup.map((b) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: cx.option, "data-sf-delivery-option": true, "data-sf-delivery-pickup": true, children: [
|
|
498
1106
|
radio(pickupValue(b)),
|
|
499
1107
|
marks ? /* @__PURE__ */ jsxRuntime.jsx(PickupGlyph, { size: 28 }) : null,
|
|
@@ -507,21 +1115,34 @@ function DeliveryOptions(props) {
|
|
|
507
1115
|
] });
|
|
508
1116
|
}
|
|
509
1117
|
|
|
1118
|
+
exports.AddressFields = AddressFields;
|
|
510
1119
|
exports.BrandMark = BrandMark;
|
|
1120
|
+
exports.CheckoutField = CheckoutField;
|
|
1121
|
+
exports.ContactFields = ContactFields;
|
|
511
1122
|
exports.DeliveryOptions = DeliveryOptions;
|
|
1123
|
+
exports.ErrorSummary = ErrorSummary;
|
|
1124
|
+
exports.OrderSummary = OrderSummary;
|
|
1125
|
+
exports.OrderSummaryDisclosure = OrderSummaryDisclosure;
|
|
1126
|
+
exports.addressFieldsMessages = addressFieldsMessages;
|
|
512
1127
|
exports.brandKey = brandKey;
|
|
513
1128
|
exports.brandLogo = brandLogo;
|
|
514
1129
|
exports.brandName = brandName;
|
|
1130
|
+
exports.dedupeRates = dedupeRates;
|
|
515
1131
|
exports.deliveryMessages = deliveryMessages;
|
|
1132
|
+
exports.fieldMessages = fieldMessages;
|
|
516
1133
|
exports.findBrand = findBrand;
|
|
517
1134
|
exports.isQuoteChange = isQuoteChange;
|
|
518
1135
|
exports.listBrands = listBrands;
|
|
519
1136
|
exports.matchRate = matchRate;
|
|
1137
|
+
exports.orderSummaryMessages = orderSummaryMessages;
|
|
520
1138
|
exports.quoteDeadline = quoteDeadline;
|
|
521
1139
|
exports.quoteNote = quoteNote;
|
|
522
1140
|
exports.rateBadges = rateBadges;
|
|
523
1141
|
exports.rateCarrier = rateCarrier;
|
|
524
1142
|
exports.rateEta = rateEta;
|
|
525
1143
|
exports.rateService = rateService;
|
|
1144
|
+
exports.recommendRates = recommendRates;
|
|
1145
|
+
exports.useFieldErrors = useFieldErrors;
|
|
1146
|
+
exports.validationMessage = validationMessage;
|
|
526
1147
|
//# sourceMappingURL=checkout.cjs.map
|
|
527
1148
|
//# sourceMappingURL=checkout.cjs.map
|