@nevios/storefront-kit 1.0.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/index.cjs +704 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +202 -3
- package/dist/index.d.ts +202 -3
- package/dist/index.js +695 -121
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React19 = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var storefrontJs = require('@nevios/storefront-js');
|
|
6
6
|
|
|
@@ -22,15 +22,15 @@ function _interopNamespace(e) {
|
|
|
22
22
|
return Object.freeze(n);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
var
|
|
25
|
+
var React19__namespace = /*#__PURE__*/_interopNamespace(React19);
|
|
26
26
|
|
|
27
27
|
// src/provider.tsx
|
|
28
|
-
var StorefrontContext =
|
|
28
|
+
var StorefrontContext = React19__namespace.createContext(null);
|
|
29
29
|
function NeviosProvider({ client, children }) {
|
|
30
30
|
return /* @__PURE__ */ jsxRuntime.jsx(StorefrontContext.Provider, { value: client, children });
|
|
31
31
|
}
|
|
32
32
|
function useStorefront() {
|
|
33
|
-
const client =
|
|
33
|
+
const client = React19__namespace.useContext(StorefrontContext);
|
|
34
34
|
if (!client) {
|
|
35
35
|
throw new Error(
|
|
36
36
|
"useStorefront must be used inside <NeviosProvider>. Wrap your app root with it."
|
|
@@ -39,7 +39,7 @@ function useStorefront() {
|
|
|
39
39
|
return client;
|
|
40
40
|
}
|
|
41
41
|
function useStorefrontOptional() {
|
|
42
|
-
return
|
|
42
|
+
return React19__namespace.useContext(StorefrontContext);
|
|
43
43
|
}
|
|
44
44
|
var DEFAULTS = {
|
|
45
45
|
brand: "#111111",
|
|
@@ -75,7 +75,7 @@ function ThemeProvider({
|
|
|
75
75
|
as: Tag = "div"
|
|
76
76
|
}) {
|
|
77
77
|
const style = themeToCssVars(theme);
|
|
78
|
-
return
|
|
78
|
+
return React19__namespace.createElement(
|
|
79
79
|
Tag,
|
|
80
80
|
{ "data-nevios-theme": "", style },
|
|
81
81
|
children
|
|
@@ -201,6 +201,37 @@ var en = {
|
|
|
201
201
|
"order.terminal.cancelled": "This order was cancelled.",
|
|
202
202
|
"order.terminal.refunded": "This order was refunded.",
|
|
203
203
|
"order.terminal.returned": "This order was returned.",
|
|
204
|
+
// payment page — the four situations it can be in
|
|
205
|
+
"payment.title": "Pay for order {order}",
|
|
206
|
+
"payment.amountDue": "Amount due",
|
|
207
|
+
"payment.methodLabel": "Payment method",
|
|
208
|
+
"payment.payNow": "Pay now",
|
|
209
|
+
"payment.finish": "Finish payment",
|
|
210
|
+
"payment.loading": "Loading payment\u2026",
|
|
211
|
+
"payment.loadError": "Couldn't load this payment.",
|
|
212
|
+
"payment.actionError": "That didn't go through. Please try again.",
|
|
213
|
+
// …paid
|
|
214
|
+
"payment.paidTitle": "Paid",
|
|
215
|
+
"payment.paidBody": "Order {order} is paid. Nothing further is needed.",
|
|
216
|
+
"payment.paidAmount": "Paid",
|
|
217
|
+
// …returning from a gateway, callback still in flight
|
|
218
|
+
"payment.verifyingTitle": "Checking your payment\u2026",
|
|
219
|
+
"payment.verifyingBody": "This takes a few seconds. Don't pay again \u2014 we'll update this page.",
|
|
220
|
+
// …locked, one sentence per reason
|
|
221
|
+
"payment.blockedTitle": "This order can't be paid",
|
|
222
|
+
"payment.blocked.orderCancelled": "This order was cancelled, so there is nothing to pay.",
|
|
223
|
+
"payment.blocked.alreadyPaid": "This order is already paid.",
|
|
224
|
+
"payment.blocked.authorizationHeld": "Your bank is holding the funds for this order. Once the payment settles this page will show it as paid.",
|
|
225
|
+
"payment.blocked.documentIssued": "An invoice has been issued for this order, so the amount is fixed. Contact us to change how you pay.",
|
|
226
|
+
// …bank transfer
|
|
227
|
+
"payment.account": "Account",
|
|
228
|
+
"payment.beneficiary": "Beneficiary",
|
|
229
|
+
"payment.variableSymbol": "Variable symbol",
|
|
230
|
+
"payment.amount": "Amount",
|
|
231
|
+
"payment.copy": "Copy",
|
|
232
|
+
"payment.copied": "Copied",
|
|
233
|
+
"payment.qrAlt": "QR code for the payment",
|
|
234
|
+
"payment.qrCaption": "Scan in your banking app",
|
|
204
235
|
// error pages
|
|
205
236
|
"error.notFound.title": "Page not found",
|
|
206
237
|
"error.notFound.body": "This page doesn't exist or isn't available in your region.",
|
|
@@ -217,6 +248,20 @@ var en = {
|
|
|
217
248
|
"account.signOut": "Sign out",
|
|
218
249
|
"account.greeting": "Signed in as {email}",
|
|
219
250
|
"account.orders": "Your orders",
|
|
251
|
+
"account.loadError": "Could not load your account. Please try again.",
|
|
252
|
+
"account.retry": "Try again",
|
|
253
|
+
"account.loadMore": "Load more",
|
|
254
|
+
"account.signInError": "Could not request a sign-in link. Please try again shortly.",
|
|
255
|
+
"account.security": "Account security",
|
|
256
|
+
"account.newEmail": "New email",
|
|
257
|
+
"account.changeEmail": "Verify new email",
|
|
258
|
+
"account.recentLogin": "Sign in again by email before making this change.",
|
|
259
|
+
"account.sessions": "Sessions",
|
|
260
|
+
"account.currentSession": "Current session",
|
|
261
|
+
"account.revokeSession": "Sign out",
|
|
262
|
+
"account.closeAccount": "Close account",
|
|
263
|
+
"account.closeWarning": "Closing your account signs out all devices and disables account access. Orders and invoices are retained. Contact the shop to restore access.",
|
|
264
|
+
"account.confirmClose": "Confirm account closure",
|
|
220
265
|
"account.noOrders": "No orders yet.",
|
|
221
266
|
"account.addresses": "Saved addresses",
|
|
222
267
|
"account.noAddresses": "No saved addresses yet.",
|
|
@@ -357,6 +402,33 @@ var cs = {
|
|
|
357
402
|
"order.terminal.cancelled": "Tato objedn\xE1vka byla zru\u0161ena.",
|
|
358
403
|
"order.terminal.refunded": "Tato objedn\xE1vka byla refundov\xE1na.",
|
|
359
404
|
"order.terminal.returned": "Tato objedn\xE1vka byla vr\xE1cena.",
|
|
405
|
+
// platební stránka — čtyři situace, ve kterých může být
|
|
406
|
+
"payment.title": "Zaplatit objedn\xE1vku {order}",
|
|
407
|
+
"payment.amountDue": "K \xFAhrad\u011B",
|
|
408
|
+
"payment.methodLabel": "Zp\u016Fsob platby",
|
|
409
|
+
"payment.payNow": "Zaplatit",
|
|
410
|
+
"payment.finish": "Dokon\u010Dit platbu",
|
|
411
|
+
"payment.loading": "Na\u010D\xEDt\xE1n\xED platby\u2026",
|
|
412
|
+
"payment.loadError": "Platbu se nepoda\u0159ilo na\u010D\xEDst.",
|
|
413
|
+
"payment.actionError": "Nepovedlo se to. Zkuste to pros\xEDm znovu.",
|
|
414
|
+
"payment.paidTitle": "Zaplaceno",
|
|
415
|
+
"payment.paidBody": "Objedn\xE1vka {order} je zaplacen\xE1. Nic dal\u0161\xEDho d\u011Blat nemus\xEDte.",
|
|
416
|
+
"payment.paidAmount": "Uhrazeno",
|
|
417
|
+
"payment.verifyingTitle": "Ov\u011B\u0159ujeme platbu\u2026",
|
|
418
|
+
"payment.verifyingBody": "Chvilku to trv\xE1. Nepla\u0165te pros\xEDm znovu \u2014 str\xE1nka se sama aktualizuje.",
|
|
419
|
+
"payment.blockedTitle": "Tuhle objedn\xE1vku te\u010F zaplatit nejde",
|
|
420
|
+
"payment.blocked.orderCancelled": "Objedn\xE1vka byla zru\u0161en\xE1, tak\u017Ee nen\xED co platit.",
|
|
421
|
+
"payment.blocked.alreadyPaid": "Objedn\xE1vka je u\u017E zaplacen\xE1.",
|
|
422
|
+
"payment.blocked.authorizationHeld": "Banka na tuhle objedn\xE1vku dr\u017E\xED pen\xEDze. Jakmile se platba dokon\u010D\xED, uvid\xEDte to tady.",
|
|
423
|
+
"payment.blocked.documentIssued": "K objedn\xE1vce je vystaven\xE1 faktura, tak\u017Ee je \u010D\xE1stka pevn\xE1. Pokud chcete platit jinak, ozv\u011Bte se n\xE1m.",
|
|
424
|
+
"payment.account": "\xDA\u010Det",
|
|
425
|
+
"payment.beneficiary": "P\u0159\xEDjemce",
|
|
426
|
+
"payment.variableSymbol": "Variabiln\xED symbol",
|
|
427
|
+
"payment.amount": "\u010C\xE1stka",
|
|
428
|
+
"payment.copy": "Kop\xEDrovat",
|
|
429
|
+
"payment.copied": "Zkop\xEDrov\xE1no",
|
|
430
|
+
"payment.qrAlt": "QR k\xF3d k platb\u011B",
|
|
431
|
+
"payment.qrCaption": "Na\u010Dt\u011Bte v bankovn\xED aplikaci",
|
|
360
432
|
"error.notFound.title": "Str\xE1nka nenalezena",
|
|
361
433
|
"error.notFound.body": "Tato str\xE1nka neexistuje nebo nen\xED ve va\u0161em regionu dostupn\xE1.",
|
|
362
434
|
"error.generic.title": "N\u011Bco se pokazilo",
|
|
@@ -371,6 +443,20 @@ var cs = {
|
|
|
371
443
|
"account.signOut": "Odhl\xE1sit se",
|
|
372
444
|
"account.greeting": "P\u0159ihl\xE1\u0161en jako {email}",
|
|
373
445
|
"account.orders": "Va\u0161e objedn\xE1vky",
|
|
446
|
+
"account.loadError": "\xDAdaje se nepoda\u0159ilo na\u010D\xEDst. Zkuste to znovu.",
|
|
447
|
+
"account.retry": "Zkusit znovu",
|
|
448
|
+
"account.loadMore": "Na\u010D\xEDst dal\u0161\xED",
|
|
449
|
+
"account.signInError": "P\u0159ihl\xE1\u0161en\xED se nepoda\u0159ilo zah\xE1jit. Zkuste to za chv\xEDli znovu.",
|
|
450
|
+
"account.security": "Zabezpe\u010Den\xED \xFA\u010Dtu",
|
|
451
|
+
"account.newEmail": "Nov\xFD e-mail",
|
|
452
|
+
"account.changeEmail": "Ov\u011B\u0159it nov\xFD e-mail",
|
|
453
|
+
"account.recentLogin": "Pro tuto zm\u011Bnu se nejprve znovu p\u0159ihlaste p\u0159es e-mail.",
|
|
454
|
+
"account.sessions": "P\u0159ihl\xE1\u0161en\xED",
|
|
455
|
+
"account.currentSession": "Toto p\u0159ihl\xE1\u0161en\xED",
|
|
456
|
+
"account.revokeSession": "Odhl\xE1sit",
|
|
457
|
+
"account.closeAccount": "Uzav\u0159\xEDt \xFA\u010Det",
|
|
458
|
+
"account.closeWarning": "Uzav\u0159en\xEDm \xFA\u010Dtu ukon\u010D\xEDte p\u0159\xEDstup a odhl\xE1s\xEDte v\u0161echna za\u0159\xEDzen\xED. Objedn\xE1vky a doklady z\u016Fstanou zachov\xE1ny. Obnoven\xED p\u0159\xEDstupu \u0159e\u0161\xED podpora obchodu.",
|
|
459
|
+
"account.confirmClose": "Potvrdit uzav\u0159en\xED \xFA\u010Dtu",
|
|
374
460
|
"account.noOrders": "Zat\xEDm \u017E\xE1dn\xE9 objedn\xE1vky.",
|
|
375
461
|
"account.addresses": "Ulo\u017Een\xE9 adresy",
|
|
376
462
|
"account.noAddresses": "Zat\xEDm \u017E\xE1dn\xE9 ulo\u017Een\xE9 adresy.",
|
|
@@ -455,13 +541,13 @@ function makeI18n(locale, messages) {
|
|
|
455
541
|
return { locale, messages, t };
|
|
456
542
|
}
|
|
457
543
|
var DEFAULT_I18N = makeI18n("en", en);
|
|
458
|
-
var I18nContext =
|
|
544
|
+
var I18nContext = React19__namespace.createContext(null);
|
|
459
545
|
function I18nProvider({
|
|
460
546
|
locale,
|
|
461
547
|
messages,
|
|
462
548
|
children
|
|
463
549
|
}) {
|
|
464
|
-
const value =
|
|
550
|
+
const value = React19__namespace.useMemo(() => {
|
|
465
551
|
const lang = langOf(locale);
|
|
466
552
|
if (locale && !(lang in BUNDLED) && !messages) {
|
|
467
553
|
devWarn(
|
|
@@ -475,7 +561,7 @@ function I18nProvider({
|
|
|
475
561
|
return /* @__PURE__ */ jsxRuntime.jsx(I18nContext.Provider, { value, children });
|
|
476
562
|
}
|
|
477
563
|
function useI18n() {
|
|
478
|
-
return
|
|
564
|
+
return React19__namespace.useContext(I18nContext) ?? DEFAULT_I18N;
|
|
479
565
|
}
|
|
480
566
|
function useT() {
|
|
481
567
|
return useI18n().t;
|
|
@@ -599,7 +685,7 @@ function ProductCard({ product, href, locale }) {
|
|
|
599
685
|
var MAIN_WIDTHS = [600, 800, 1e3];
|
|
600
686
|
var THUMB_WIDTHS = [56, 112];
|
|
601
687
|
function ProductGallery({ media, alt }) {
|
|
602
|
-
const [active, setActive] =
|
|
688
|
+
const [active, setActive] = React19__namespace.useState(0);
|
|
603
689
|
const imageBase = useStorefrontOptional()?.imageBase;
|
|
604
690
|
if (media.length === 0) {
|
|
605
691
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -687,10 +773,10 @@ function matchVariant(product, selected) {
|
|
|
687
773
|
) ?? null;
|
|
688
774
|
}
|
|
689
775
|
function VariantPicker({ product, onChange }) {
|
|
690
|
-
const [selected, setSelected] =
|
|
776
|
+
const [selected, setSelected] = React19__namespace.useState(
|
|
691
777
|
() => product.variants[0]?.options ?? []
|
|
692
778
|
);
|
|
693
|
-
|
|
779
|
+
React19__namespace.useEffect(() => {
|
|
694
780
|
onChange?.(matchVariant(product, selected));
|
|
695
781
|
}, [product, selected]);
|
|
696
782
|
if (product.options.length === 0) return null;
|
|
@@ -731,8 +817,8 @@ function BackInStockForm({
|
|
|
731
817
|
}) {
|
|
732
818
|
const t = useT();
|
|
733
819
|
const client = useStorefront();
|
|
734
|
-
const [email, setEmail] =
|
|
735
|
-
const [state, setState] =
|
|
820
|
+
const [email, setEmail] = React19__namespace.useState(defaultEmail);
|
|
821
|
+
const [state, setState] = React19__namespace.useState("idle");
|
|
736
822
|
if (!variant || variant.availability?.status !== "out_of_stock") return null;
|
|
737
823
|
async function submit(e) {
|
|
738
824
|
e.preventDefault();
|
|
@@ -832,7 +918,7 @@ function ProductDetailPage({
|
|
|
832
918
|
locale,
|
|
833
919
|
addToCart
|
|
834
920
|
}) {
|
|
835
|
-
const [variant, setVariant] =
|
|
921
|
+
const [variant, setVariant] = React19__namespace.useState(
|
|
836
922
|
product.variants[0] ?? null
|
|
837
923
|
);
|
|
838
924
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1064,12 +1150,12 @@ function TagFilter({ tags, selected = [], onChange }) {
|
|
|
1064
1150
|
}) })
|
|
1065
1151
|
] });
|
|
1066
1152
|
}
|
|
1067
|
-
var CartContext =
|
|
1153
|
+
var CartContext = React19__namespace.createContext(null);
|
|
1068
1154
|
function CartProvider({ children }) {
|
|
1069
1155
|
const client = useStorefront();
|
|
1070
|
-
const [cart, setCart] =
|
|
1071
|
-
const [loading, setLoading] =
|
|
1072
|
-
const run =
|
|
1156
|
+
const [cart, setCart] = React19__namespace.useState(null);
|
|
1157
|
+
const [loading, setLoading] = React19__namespace.useState(false);
|
|
1158
|
+
const run = React19__namespace.useCallback(
|
|
1073
1159
|
async (op) => {
|
|
1074
1160
|
setLoading(true);
|
|
1075
1161
|
try {
|
|
@@ -1082,7 +1168,7 @@ function CartProvider({ children }) {
|
|
|
1082
1168
|
},
|
|
1083
1169
|
[]
|
|
1084
1170
|
);
|
|
1085
|
-
const refresh =
|
|
1171
|
+
const refresh = React19__namespace.useCallback(async () => {
|
|
1086
1172
|
setLoading(true);
|
|
1087
1173
|
try {
|
|
1088
1174
|
setCart(await client.cart.get());
|
|
@@ -1090,10 +1176,10 @@ function CartProvider({ children }) {
|
|
|
1090
1176
|
setLoading(false);
|
|
1091
1177
|
}
|
|
1092
1178
|
}, [client]);
|
|
1093
|
-
|
|
1179
|
+
React19__namespace.useEffect(() => {
|
|
1094
1180
|
void refresh();
|
|
1095
1181
|
}, [refresh]);
|
|
1096
|
-
const value =
|
|
1182
|
+
const value = React19__namespace.useMemo(
|
|
1097
1183
|
() => ({
|
|
1098
1184
|
cart,
|
|
1099
1185
|
loading,
|
|
@@ -1108,7 +1194,7 @@ function CartProvider({ children }) {
|
|
|
1108
1194
|
return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
|
|
1109
1195
|
}
|
|
1110
1196
|
function useCart() {
|
|
1111
|
-
const ctx =
|
|
1197
|
+
const ctx = React19__namespace.useContext(CartContext);
|
|
1112
1198
|
if (!ctx) {
|
|
1113
1199
|
throw new Error("useCart must be used inside <CartProvider>.");
|
|
1114
1200
|
}
|
|
@@ -1122,8 +1208,8 @@ function AddToCart({
|
|
|
1122
1208
|
}) {
|
|
1123
1209
|
const t = useT();
|
|
1124
1210
|
const { addLine } = useCart();
|
|
1125
|
-
const [busy, setBusy] =
|
|
1126
|
-
const [error, setError] =
|
|
1211
|
+
const [busy, setBusy] = React19__namespace.useState(false);
|
|
1212
|
+
const [error, setError] = React19__namespace.useState(null);
|
|
1127
1213
|
const disabled = variant == null || busy;
|
|
1128
1214
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
1129
1215
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1164,6 +1250,7 @@ function AddToCart({
|
|
|
1164
1250
|
}
|
|
1165
1251
|
function CartLineItem({ line, locale }) {
|
|
1166
1252
|
const t = useT();
|
|
1253
|
+
const loc = useFormatLocale(locale);
|
|
1167
1254
|
const { updateLine, removeLine } = useCart();
|
|
1168
1255
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "0.85rem", alignItems: "flex-start", padding: "0.75rem 0" }, children: [
|
|
1169
1256
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1235,7 +1322,7 @@ function CartLineItem({ line, locale }) {
|
|
|
1235
1322
|
)
|
|
1236
1323
|
] })
|
|
1237
1324
|
] }),
|
|
1238
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 500, whiteSpace: "nowrap" }, children: formatCents(line.line_total_cents, line.unit_price.currency,
|
|
1325
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 500, whiteSpace: "nowrap" }, children: formatCents(line.line_total_cents, line.unit_price.currency, loc) })
|
|
1239
1326
|
] });
|
|
1240
1327
|
}
|
|
1241
1328
|
function StepBtn({ label, onClick }) {
|
|
@@ -1267,6 +1354,7 @@ function CartSummary({
|
|
|
1267
1354
|
locale
|
|
1268
1355
|
}) {
|
|
1269
1356
|
const tr = useT();
|
|
1357
|
+
const loc = useFormatLocale(locale);
|
|
1270
1358
|
const { cart } = useCart();
|
|
1271
1359
|
if (cart == null) return null;
|
|
1272
1360
|
const t = cart.totals;
|
|
@@ -1287,10 +1375,10 @@ function CartSummary({
|
|
|
1287
1375
|
opacity: empty ? 0.55 : 1
|
|
1288
1376
|
};
|
|
1289
1377
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
1290
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: tr("cart.subtotal"), value: formatCents(t.subtotal_with_tax_cents, t.currency,
|
|
1291
|
-
t.tax_cents > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Row, { label: tr("cart.tax"), value: formatCents(t.tax_cents, t.currency,
|
|
1378
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: tr("cart.subtotal"), value: formatCents(t.subtotal_with_tax_cents, t.currency, loc) }),
|
|
1379
|
+
t.tax_cents > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Row, { label: tr("cart.tax"), value: formatCents(t.tax_cents, t.currency, loc), muted: true }) : null,
|
|
1292
1380
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
|
|
1293
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: tr("cart.total"), value: formatCents(t.total_cents, t.currency,
|
|
1381
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: tr("cart.total"), value: formatCents(t.total_cents, t.currency, loc), strong: true }),
|
|
1294
1382
|
checkoutHref && !empty ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: checkoutHref, style: ctaStyle, children: cta }) : /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", disabled: empty, onClick: onCheckout, style: ctaStyle, children: cta })
|
|
1295
1383
|
] });
|
|
1296
1384
|
}
|
|
@@ -1397,15 +1485,15 @@ function CartDrawer({
|
|
|
1397
1485
|
}
|
|
1398
1486
|
);
|
|
1399
1487
|
}
|
|
1400
|
-
var CheckoutContext =
|
|
1488
|
+
var CheckoutContext = React19__namespace.createContext(null);
|
|
1401
1489
|
function CheckoutProvider({
|
|
1402
1490
|
children
|
|
1403
1491
|
}) {
|
|
1404
1492
|
const client = useStorefront();
|
|
1405
|
-
const [checkout, setCheckout] =
|
|
1406
|
-
const [loading, setLoading] =
|
|
1407
|
-
const [error, setError] =
|
|
1408
|
-
const run =
|
|
1493
|
+
const [checkout, setCheckout] = React19__namespace.useState(null);
|
|
1494
|
+
const [loading, setLoading] = React19__namespace.useState(false);
|
|
1495
|
+
const [error, setError] = React19__namespace.useState(null);
|
|
1496
|
+
const run = React19__namespace.useCallback(
|
|
1409
1497
|
async (op, store) => {
|
|
1410
1498
|
setLoading(true);
|
|
1411
1499
|
try {
|
|
@@ -1423,7 +1511,7 @@ function CheckoutProvider({
|
|
|
1423
1511
|
},
|
|
1424
1512
|
[]
|
|
1425
1513
|
);
|
|
1426
|
-
const refresh =
|
|
1514
|
+
const refresh = React19__namespace.useCallback(async () => {
|
|
1427
1515
|
setLoading(true);
|
|
1428
1516
|
try {
|
|
1429
1517
|
setCheckout(await client.checkout.get());
|
|
@@ -1432,10 +1520,10 @@ function CheckoutProvider({
|
|
|
1432
1520
|
setLoading(false);
|
|
1433
1521
|
}
|
|
1434
1522
|
}, [client]);
|
|
1435
|
-
|
|
1523
|
+
React19__namespace.useEffect(() => {
|
|
1436
1524
|
void refresh();
|
|
1437
1525
|
}, [refresh]);
|
|
1438
|
-
const pay =
|
|
1526
|
+
const pay = React19__namespace.useCallback(
|
|
1439
1527
|
async (opts = {}) => {
|
|
1440
1528
|
const co = checkout;
|
|
1441
1529
|
if (!co) throw new Error("pay() called before a checkout exists");
|
|
@@ -1458,7 +1546,7 @@ function CheckoutProvider({
|
|
|
1458
1546
|
},
|
|
1459
1547
|
[checkout, client, run]
|
|
1460
1548
|
);
|
|
1461
|
-
const value =
|
|
1549
|
+
const value = React19__namespace.useMemo(
|
|
1462
1550
|
() => ({
|
|
1463
1551
|
checkout,
|
|
1464
1552
|
loading,
|
|
@@ -1483,7 +1571,7 @@ function CheckoutProvider({
|
|
|
1483
1571
|
return /* @__PURE__ */ jsxRuntime.jsx(CheckoutContext.Provider, { value, children });
|
|
1484
1572
|
}
|
|
1485
1573
|
function useCheckout() {
|
|
1486
|
-
const ctx =
|
|
1574
|
+
const ctx = React19__namespace.useContext(CheckoutContext);
|
|
1487
1575
|
if (!ctx) {
|
|
1488
1576
|
throw new Error("useCheckout must be used inside <CheckoutProvider>.");
|
|
1489
1577
|
}
|
|
@@ -1642,10 +1730,25 @@ function AddressForm({
|
|
|
1642
1730
|
}) {
|
|
1643
1731
|
const t = useT();
|
|
1644
1732
|
const { checkout, setAddress, loading } = useCheckout();
|
|
1645
|
-
const [form, setForm] =
|
|
1733
|
+
const [form, setForm] = React19__namespace.useState(
|
|
1646
1734
|
() => seed(checkout?.email ?? null, checkout?.shipping_address ?? null)
|
|
1647
1735
|
);
|
|
1648
|
-
const
|
|
1736
|
+
const touched = React19__namespace.useRef(/* @__PURE__ */ new Set());
|
|
1737
|
+
React19__namespace.useEffect(() => {
|
|
1738
|
+
const prefill = checkout?.customer_prefill;
|
|
1739
|
+
const addresses = prefill?.addresses.filter((a) => !a.is_pickup);
|
|
1740
|
+
const saved = addresses?.find((a) => a.is_default) ?? addresses?.[0];
|
|
1741
|
+
const address = checkout?.shipping_address ?? (saved ? { ...saved, postal_code: saved.zip } : null);
|
|
1742
|
+
const defaults = seed(checkout?.email ?? prefill?.email ?? null, address);
|
|
1743
|
+
defaults.first_name || (defaults.first_name = prefill?.first_name ?? "");
|
|
1744
|
+
defaults.last_name || (defaults.last_name = prefill?.last_name ?? "");
|
|
1745
|
+
defaults.phone || (defaults.phone = prefill?.phone ?? "");
|
|
1746
|
+
setForm((current) => Object.fromEntries(Object.entries(current).map(([key, value]) => [key, touched.current.has(key) ? value : value || defaults[key]])));
|
|
1747
|
+
}, [checkout?.token]);
|
|
1748
|
+
const set = (key) => (e) => {
|
|
1749
|
+
touched.current.add(key);
|
|
1750
|
+
setForm((f) => ({ ...f, [key]: e.target.value }));
|
|
1751
|
+
};
|
|
1649
1752
|
async function submit(e) {
|
|
1650
1753
|
e.preventDefault();
|
|
1651
1754
|
const { email, ...rest } = form;
|
|
@@ -1693,13 +1796,14 @@ function ShippingPicker({
|
|
|
1693
1796
|
locale
|
|
1694
1797
|
}) {
|
|
1695
1798
|
const t = useT();
|
|
1799
|
+
const loc = useFormatLocale(locale);
|
|
1696
1800
|
const { checkout, shippingQuotes, setShippingMethod, loading } = useCheckout();
|
|
1697
1801
|
const heading = title ?? t("checkout.shippingMethod");
|
|
1698
|
-
const [quotes, setQuotes] =
|
|
1699
|
-
const [selected, setSelected] =
|
|
1700
|
-
const [fetching, setFetching] =
|
|
1802
|
+
const [quotes, setQuotes] = React19__namespace.useState(null);
|
|
1803
|
+
const [selected, setSelected] = React19__namespace.useState(null);
|
|
1804
|
+
const [fetching, setFetching] = React19__namespace.useState(true);
|
|
1701
1805
|
const addressKey = checkout?.shipping_address ? `${checkout.shipping_address.country_code}:${checkout.shipping_address.postal_code}` : null;
|
|
1702
|
-
|
|
1806
|
+
React19__namespace.useEffect(() => {
|
|
1703
1807
|
let live = true;
|
|
1704
1808
|
setFetching(true);
|
|
1705
1809
|
shippingQuotes().then((qs) => {
|
|
@@ -1727,17 +1831,13 @@ function ShippingPicker({
|
|
|
1727
1831
|
}
|
|
1728
1832
|
return /* @__PURE__ */ jsxRuntime.jsxs(Section, { title: heading, children: [
|
|
1729
1833
|
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", style: { display: "flex", flexDirection: "column", gap: "0.6rem" }, children: quotes.map((q) => {
|
|
1730
|
-
const days = estDays(q, t);
|
|
1731
1834
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1732
1835
|
SelectRow,
|
|
1733
1836
|
{
|
|
1734
1837
|
selected: selected === q.rate_id,
|
|
1735
1838
|
onSelect: () => setSelected(q.rate_id),
|
|
1736
|
-
trailing: q.is_free ? t("common.free") : formatCents(q.price_cents, q.currency,
|
|
1737
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
1738
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: q.label }),
|
|
1739
|
-
days ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: days }) : null
|
|
1740
|
-
] })
|
|
1839
|
+
trailing: q.is_free ? t("common.free") : formatCents(q.price_cents, q.currency, loc),
|
|
1840
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: q.label }) })
|
|
1741
1841
|
},
|
|
1742
1842
|
q.rate_id
|
|
1743
1843
|
);
|
|
@@ -1745,14 +1845,38 @@ function ShippingPicker({
|
|
|
1745
1845
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: submit, busy: loading, disabled: selected == null, children: submitLabel ?? t("checkout.continueToPayment") }) })
|
|
1746
1846
|
] });
|
|
1747
1847
|
}
|
|
1748
|
-
function
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1848
|
+
function PaymentMethodPicker({
|
|
1849
|
+
methods,
|
|
1850
|
+
value,
|
|
1851
|
+
onSelect,
|
|
1852
|
+
currency,
|
|
1853
|
+
locale,
|
|
1854
|
+
disabled,
|
|
1855
|
+
label
|
|
1856
|
+
}) {
|
|
1857
|
+
const loc = useFormatLocale(locale);
|
|
1858
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1859
|
+
"div",
|
|
1860
|
+
{
|
|
1861
|
+
role: "radiogroup",
|
|
1862
|
+
"aria-label": label,
|
|
1863
|
+
style: { display: "flex", flexDirection: "column", gap: "0.6rem" },
|
|
1864
|
+
children: methods.map((m) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1865
|
+
SelectRow,
|
|
1866
|
+
{
|
|
1867
|
+
selected: value === m.method,
|
|
1868
|
+
disabled,
|
|
1869
|
+
onSelect: () => onSelect(m.method),
|
|
1870
|
+
trailing: m.surcharge_cents > 0 ? `+${formatCents(m.surcharge_cents, currency, loc)}` : void 0,
|
|
1871
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", flexDirection: "column" }, children: [
|
|
1872
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: m.display_label }),
|
|
1873
|
+
m.display_description ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: m.display_description }) : null
|
|
1874
|
+
] })
|
|
1875
|
+
},
|
|
1876
|
+
m.method
|
|
1877
|
+
))
|
|
1878
|
+
}
|
|
1879
|
+
);
|
|
1756
1880
|
}
|
|
1757
1881
|
function PaymentSection({
|
|
1758
1882
|
title,
|
|
@@ -1764,10 +1888,10 @@ function PaymentSection({
|
|
|
1764
1888
|
const t = useT();
|
|
1765
1889
|
const heading = title ?? t("checkout.payment");
|
|
1766
1890
|
const { checkout, paymentMethods, setPaymentMethod, pay, loading } = useCheckout();
|
|
1767
|
-
const [methods, setMethods] =
|
|
1768
|
-
const [fetching, setFetching] =
|
|
1891
|
+
const [methods, setMethods] = React19__namespace.useState(null);
|
|
1892
|
+
const [fetching, setFetching] = React19__namespace.useState(true);
|
|
1769
1893
|
const selected = checkout?.payment_method ?? null;
|
|
1770
|
-
|
|
1894
|
+
React19__namespace.useEffect(() => {
|
|
1771
1895
|
let live = true;
|
|
1772
1896
|
setFetching(true);
|
|
1773
1897
|
paymentMethods().then((ms) => {
|
|
@@ -1794,19 +1918,17 @@ function PaymentSection({
|
|
|
1794
1918
|
return /* @__PURE__ */ jsxRuntime.jsx(Section, { title: heading, children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("checkout.noPayment") }) });
|
|
1795
1919
|
}
|
|
1796
1920
|
return /* @__PURE__ */ jsxRuntime.jsxs(Section, { title: heading, children: [
|
|
1797
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1798
|
-
|
|
1921
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1922
|
+
PaymentMethodPicker,
|
|
1799
1923
|
{
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
m.method
|
|
1809
|
-
)) }),
|
|
1924
|
+
methods,
|
|
1925
|
+
value: selected,
|
|
1926
|
+
onSelect: (method) => void setPaymentMethod(method),
|
|
1927
|
+
currency: checkout?.totals.currency ?? "CZK",
|
|
1928
|
+
locale,
|
|
1929
|
+
label: heading
|
|
1930
|
+
}
|
|
1931
|
+
),
|
|
1810
1932
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1811
1933
|
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: placeOrder, busy: loading, disabled: selected == null, children: isGateway ? t("checkout.payNow") : t("checkout.placeOrder") }),
|
|
1812
1934
|
isGateway ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)", marginTop: "0.6rem" }, children: t("checkout.gatewayRedirectNote") }) : null
|
|
@@ -1819,12 +1941,13 @@ function OrderSummary({
|
|
|
1819
1941
|
locale
|
|
1820
1942
|
}) {
|
|
1821
1943
|
const tr = useT();
|
|
1944
|
+
const loc = useFormatLocale(locale);
|
|
1822
1945
|
const ctx = useCheckout();
|
|
1823
1946
|
const checkout = override ?? ctx.checkout;
|
|
1824
1947
|
if (checkout == null) return null;
|
|
1825
1948
|
const t = checkout.totals;
|
|
1826
1949
|
const c = t.currency;
|
|
1827
|
-
const money = (cents) => formatCents(cents, c,
|
|
1950
|
+
const money = (cents) => formatCents(cents, c, loc);
|
|
1828
1951
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
|
|
1829
1952
|
!totalsOnly && checkout.line_items.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.75rem" }, children: checkout.line_items.map((li) => /* @__PURE__ */ jsxRuntime.jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1830
1953
|
li.image_url ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1905,16 +2028,16 @@ function CheckoutFlow({
|
|
|
1905
2028
|
}) {
|
|
1906
2029
|
const t = useT();
|
|
1907
2030
|
const { checkout, loading, create } = useCheckout();
|
|
1908
|
-
const [step, setStep] =
|
|
1909
|
-
const [bootstrapped, setBootstrapped] =
|
|
1910
|
-
|
|
2031
|
+
const [step, setStep] = React19__namespace.useState("address");
|
|
2032
|
+
const [bootstrapped, setBootstrapped] = React19__namespace.useState(false);
|
|
2033
|
+
React19__namespace.useEffect(() => {
|
|
1911
2034
|
if (checkout || !cartToken || bootstrapped) return;
|
|
1912
2035
|
setBootstrapped(true);
|
|
1913
2036
|
void create(cartToken).catch(() => {
|
|
1914
2037
|
});
|
|
1915
2038
|
}, [checkout, cartToken, bootstrapped, create]);
|
|
1916
2039
|
const serverStep = reachedStep(checkout);
|
|
1917
|
-
|
|
2040
|
+
React19__namespace.useEffect(() => {
|
|
1918
2041
|
setStep((cur) => rank(serverStep) > rank(cur) ? serverStep : cur);
|
|
1919
2042
|
}, [serverStep]);
|
|
1920
2043
|
if (checkout?.order_id) {
|
|
@@ -2035,10 +2158,10 @@ function DefaultConfirmation({ checkout }) {
|
|
|
2035
2158
|
}
|
|
2036
2159
|
function useOrderStatus(statusToken, initial) {
|
|
2037
2160
|
const client = useStorefront();
|
|
2038
|
-
const [order, setOrder] =
|
|
2039
|
-
const [loading, setLoading] =
|
|
2040
|
-
const [error, setError] =
|
|
2041
|
-
const load =
|
|
2161
|
+
const [order, setOrder] = React19__namespace.useState(initial ?? null);
|
|
2162
|
+
const [loading, setLoading] = React19__namespace.useState(false);
|
|
2163
|
+
const [error, setError] = React19__namespace.useState(null);
|
|
2164
|
+
const load = React19__namespace.useCallback(async () => {
|
|
2042
2165
|
if (!statusToken) return;
|
|
2043
2166
|
setLoading(true);
|
|
2044
2167
|
try {
|
|
@@ -2050,12 +2173,85 @@ function useOrderStatus(statusToken, initial) {
|
|
|
2050
2173
|
setLoading(false);
|
|
2051
2174
|
}
|
|
2052
2175
|
}, [client, statusToken]);
|
|
2053
|
-
|
|
2176
|
+
React19__namespace.useEffect(() => {
|
|
2054
2177
|
if (initial) return;
|
|
2055
2178
|
void load();
|
|
2056
2179
|
}, [load, initial]);
|
|
2057
2180
|
return { order, loading, error, reload: () => void load() };
|
|
2058
2181
|
}
|
|
2182
|
+
function usePayment(token, initial) {
|
|
2183
|
+
const client = useStorefront();
|
|
2184
|
+
const [payment, setPayment] = React19__namespace.useState(initial ?? null);
|
|
2185
|
+
const [methods, setMethods] = React19__namespace.useState([]);
|
|
2186
|
+
const [loading, setLoading] = React19__namespace.useState(false);
|
|
2187
|
+
const [busy, setBusy] = React19__namespace.useState(false);
|
|
2188
|
+
const [error, setError] = React19__namespace.useState(null);
|
|
2189
|
+
const load = React19__namespace.useCallback(async () => {
|
|
2190
|
+
if (!token) return;
|
|
2191
|
+
setLoading(true);
|
|
2192
|
+
try {
|
|
2193
|
+
const [state, list] = await Promise.all([
|
|
2194
|
+
client.payment.get(token),
|
|
2195
|
+
client.payment.methods(token)
|
|
2196
|
+
]);
|
|
2197
|
+
setPayment(state);
|
|
2198
|
+
setMethods(list);
|
|
2199
|
+
setError(null);
|
|
2200
|
+
} catch (e) {
|
|
2201
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
2202
|
+
} finally {
|
|
2203
|
+
setLoading(false);
|
|
2204
|
+
}
|
|
2205
|
+
}, [client, token]);
|
|
2206
|
+
React19__namespace.useEffect(() => {
|
|
2207
|
+
if (!token) return;
|
|
2208
|
+
if (initial && initial.token === token) {
|
|
2209
|
+
setPayment(initial);
|
|
2210
|
+
client.payment.methods(token).then(setMethods).catch(() => setMethods([]));
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
void load();
|
|
2214
|
+
}, [token, load]);
|
|
2215
|
+
const selectMethod = React19__namespace.useCallback(
|
|
2216
|
+
async (method) => {
|
|
2217
|
+
if (!token) return null;
|
|
2218
|
+
setBusy(true);
|
|
2219
|
+
try {
|
|
2220
|
+
const next = await client.payment.selectMethod(token, method);
|
|
2221
|
+
setPayment(next);
|
|
2222
|
+
setError(null);
|
|
2223
|
+
return next;
|
|
2224
|
+
} catch (e) {
|
|
2225
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
2226
|
+
return null;
|
|
2227
|
+
} finally {
|
|
2228
|
+
setBusy(false);
|
|
2229
|
+
}
|
|
2230
|
+
},
|
|
2231
|
+
[client, token]
|
|
2232
|
+
);
|
|
2233
|
+
const startPayment = React19__namespace.useCallback(
|
|
2234
|
+
async (input) => {
|
|
2235
|
+
if (!token) return null;
|
|
2236
|
+
setBusy(true);
|
|
2237
|
+
try {
|
|
2238
|
+
const result = await client.payment.start(token, {
|
|
2239
|
+
return_url: input?.returnUrl,
|
|
2240
|
+
cancel_url: input?.cancelUrl
|
|
2241
|
+
});
|
|
2242
|
+
setError(null);
|
|
2243
|
+
return result.redirect_url;
|
|
2244
|
+
} catch (e) {
|
|
2245
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
2246
|
+
return null;
|
|
2247
|
+
} finally {
|
|
2248
|
+
setBusy(false);
|
|
2249
|
+
}
|
|
2250
|
+
},
|
|
2251
|
+
[client, token]
|
|
2252
|
+
);
|
|
2253
|
+
return { payment, methods, loading, busy, error, reload: load, selectMethod, startPayment };
|
|
2254
|
+
}
|
|
2059
2255
|
var PHASE_RANK = {
|
|
2060
2256
|
placed: 0,
|
|
2061
2257
|
paid: 1,
|
|
@@ -2151,6 +2347,7 @@ function OrderLines({
|
|
|
2151
2347
|
order,
|
|
2152
2348
|
locale
|
|
2153
2349
|
}) {
|
|
2350
|
+
const loc = useFormatLocale(locale);
|
|
2154
2351
|
return /* @__PURE__ */ jsxRuntime.jsxs("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
2155
2352
|
order.line_items.map((li) => /* @__PURE__ */ jsxRuntime.jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
|
|
2156
2353
|
li.image_url ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2171,11 +2368,11 @@ function OrderLines({
|
|
|
2171
2368
|
li.quantity
|
|
2172
2369
|
] })
|
|
2173
2370
|
] }),
|
|
2174
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(li.total_with_tax_cents, order.currency,
|
|
2371
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(li.total_with_tax_cents, order.currency, loc) })
|
|
2175
2372
|
] }, li.id)),
|
|
2176
2373
|
order.fee_lines.map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
|
|
2177
2374
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "block", fontWeight: 500 }, children: f.title }) }),
|
|
2178
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(f.total_with_tax_cents, order.currency,
|
|
2375
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(f.total_with_tax_cents, order.currency, loc) })
|
|
2179
2376
|
] }, `fee-${i}`))
|
|
2180
2377
|
] });
|
|
2181
2378
|
}
|
|
@@ -2184,9 +2381,10 @@ function OrderTotals({
|
|
|
2184
2381
|
locale
|
|
2185
2382
|
}) {
|
|
2186
2383
|
const tr = useT();
|
|
2384
|
+
const loc = useFormatLocale(locale);
|
|
2187
2385
|
const t = order.totals;
|
|
2188
2386
|
const c = order.currency;
|
|
2189
|
-
const money = (cents) => formatCents(cents, c,
|
|
2387
|
+
const money = (cents) => formatCents(cents, c, loc);
|
|
2190
2388
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2191
2389
|
/* @__PURE__ */ jsxRuntime.jsx(Row3, { label: tr("totals.subtotal"), value: money(t.subtotal_cents) }),
|
|
2192
2390
|
t.discount_cents > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Row3, { label: tr("totals.discount"), value: `\u2212${money(t.discount_cents)}`, muted: true }) : null,
|
|
@@ -2292,6 +2490,7 @@ function OrderStatusPage({
|
|
|
2292
2490
|
statusToken,
|
|
2293
2491
|
order: initial,
|
|
2294
2492
|
onContactSupport,
|
|
2493
|
+
payHref,
|
|
2295
2494
|
locale
|
|
2296
2495
|
}) {
|
|
2297
2496
|
const t = useT();
|
|
@@ -2343,6 +2542,7 @@ function OrderStatusPage({
|
|
|
2343
2542
|
/* @__PURE__ */ jsxRuntime.jsxs(Card, { title: t("order.payment"), children: [
|
|
2344
2543
|
/* @__PURE__ */ jsxRuntime.jsx(Line, { label: t("order.method"), value: order.payment.method ?? "\u2014" }),
|
|
2345
2544
|
/* @__PURE__ */ jsxRuntime.jsx(Line, { label: t("order.status"), value: order.payment.status }),
|
|
2545
|
+
order.payment.token && payHref ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: payHref(order.payment.token), style: { color: "var(--nv-brand)", fontWeight: 500 }, children: t("payment.finish") }) : null,
|
|
2346
2546
|
order.payment.invoice_available && order.payment.invoice_url ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: order.payment.invoice_url, style: { color: "var(--nv-brand)" }, children: t("order.downloadInvoice") }) : null
|
|
2347
2547
|
] }),
|
|
2348
2548
|
order.actions.can_contact_support && onContactSupport ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2394,27 +2594,291 @@ function Line({ label, value }) {
|
|
|
2394
2594
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { textAlign: "right" }, children: value })
|
|
2395
2595
|
] });
|
|
2396
2596
|
}
|
|
2397
|
-
|
|
2597
|
+
function TransferInstructions({
|
|
2598
|
+
instructions: i,
|
|
2599
|
+
locale
|
|
2600
|
+
}) {
|
|
2601
|
+
const t = useT();
|
|
2602
|
+
const loc = useFormatLocale(locale);
|
|
2603
|
+
const account = i.iban || i.account_number;
|
|
2604
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2605
|
+
"div",
|
|
2606
|
+
{
|
|
2607
|
+
style: {
|
|
2608
|
+
display: "flex",
|
|
2609
|
+
flexWrap: "wrap",
|
|
2610
|
+
gap: "1.25rem",
|
|
2611
|
+
alignItems: "flex-start",
|
|
2612
|
+
padding: "1rem",
|
|
2613
|
+
borderRadius: "var(--nv-radius)",
|
|
2614
|
+
border: "1px solid var(--nv-border)"
|
|
2615
|
+
},
|
|
2616
|
+
children: [
|
|
2617
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dl", { style: { flex: "1 1 15rem", margin: 0, display: "flex", flexDirection: "column", gap: "0.7rem" }, children: [
|
|
2618
|
+
account ? /* @__PURE__ */ jsxRuntime.jsx(CopyRow, { label: t("payment.account"), value: account }) : null,
|
|
2619
|
+
i.beneficiary_name ? /* @__PURE__ */ jsxRuntime.jsx(Row4, { label: t("payment.beneficiary"), value: i.beneficiary_name }) : null,
|
|
2620
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyRow, { label: t("payment.variableSymbol"), value: i.variable_symbol }),
|
|
2621
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2622
|
+
Row4,
|
|
2623
|
+
{
|
|
2624
|
+
label: t("payment.amount"),
|
|
2625
|
+
value: formatCents(i.amount_cents, i.currency, loc),
|
|
2626
|
+
strong: true
|
|
2627
|
+
}
|
|
2628
|
+
)
|
|
2629
|
+
] }),
|
|
2630
|
+
i.qr_svg_data_uri ? /* @__PURE__ */ jsxRuntime.jsxs("figure", { style: { margin: 0, textAlign: "center" }, children: [
|
|
2631
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2632
|
+
"img",
|
|
2633
|
+
{
|
|
2634
|
+
src: i.qr_svg_data_uri,
|
|
2635
|
+
alt: t("payment.qrAlt"),
|
|
2636
|
+
width: 148,
|
|
2637
|
+
height: 148,
|
|
2638
|
+
style: { display: "block", borderRadius: "var(--nv-radius)" }
|
|
2639
|
+
}
|
|
2640
|
+
),
|
|
2641
|
+
/* @__PURE__ */ jsxRuntime.jsx("figcaption", { style: { fontSize: "0.75rem", color: "var(--nv-muted)", marginTop: "0.4rem" }, children: t("payment.qrCaption") })
|
|
2642
|
+
] }) : null,
|
|
2643
|
+
i.instructions ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { flexBasis: "100%", margin: 0, fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: i.instructions }) : null
|
|
2644
|
+
]
|
|
2645
|
+
}
|
|
2646
|
+
);
|
|
2647
|
+
}
|
|
2648
|
+
function Row4({
|
|
2649
|
+
label,
|
|
2650
|
+
value,
|
|
2651
|
+
strong
|
|
2652
|
+
}) {
|
|
2653
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.1rem" }, children: [
|
|
2654
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { style: { fontSize: "0.75rem", color: "var(--nv-muted)" }, children: label }),
|
|
2655
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2656
|
+
"dd",
|
|
2657
|
+
{
|
|
2658
|
+
style: {
|
|
2659
|
+
margin: 0,
|
|
2660
|
+
fontWeight: strong ? 600 : 500,
|
|
2661
|
+
fontVariantNumeric: "tabular-nums"
|
|
2662
|
+
},
|
|
2663
|
+
children: value
|
|
2664
|
+
}
|
|
2665
|
+
)
|
|
2666
|
+
] });
|
|
2667
|
+
}
|
|
2668
|
+
function CopyRow({ label, value }) {
|
|
2669
|
+
const t = useT();
|
|
2670
|
+
const [copied, setCopied] = React19__namespace.useState(false);
|
|
2671
|
+
React19__namespace.useEffect(() => {
|
|
2672
|
+
if (!copied) return;
|
|
2673
|
+
const id = setTimeout(() => setCopied(false), 1800);
|
|
2674
|
+
return () => clearTimeout(id);
|
|
2675
|
+
}, [copied]);
|
|
2676
|
+
async function copy() {
|
|
2677
|
+
try {
|
|
2678
|
+
await navigator.clipboard.writeText(value);
|
|
2679
|
+
setCopied(true);
|
|
2680
|
+
} catch {
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.1rem" }, children: [
|
|
2684
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { style: { fontSize: "0.75rem", color: "var(--nv-muted)" }, children: label }),
|
|
2685
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dd", { style: { margin: 0, display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
2686
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500, fontVariantNumeric: "tabular-nums" }, children: value }),
|
|
2687
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2688
|
+
"button",
|
|
2689
|
+
{
|
|
2690
|
+
type: "button",
|
|
2691
|
+
onClick: () => void copy(),
|
|
2692
|
+
style: {
|
|
2693
|
+
font: "inherit",
|
|
2694
|
+
fontSize: "0.75rem",
|
|
2695
|
+
cursor: "pointer",
|
|
2696
|
+
padding: "0.15rem 0.5rem",
|
|
2697
|
+
borderRadius: "var(--nv-radius)",
|
|
2698
|
+
border: "1px solid var(--nv-border)",
|
|
2699
|
+
background: "transparent",
|
|
2700
|
+
color: "var(--nv-muted)"
|
|
2701
|
+
},
|
|
2702
|
+
children: copied ? t("payment.copied") : t("payment.copy")
|
|
2703
|
+
}
|
|
2704
|
+
)
|
|
2705
|
+
] })
|
|
2706
|
+
] });
|
|
2707
|
+
}
|
|
2708
|
+
var HANDOFF_TTL_MS = 30 * 60 * 1e3;
|
|
2709
|
+
var POLL_MS = 2e3;
|
|
2710
|
+
var POLL_ATTEMPTS = 6;
|
|
2711
|
+
var BLOCKED_MESSAGE = {
|
|
2712
|
+
order_cancelled: "payment.blocked.orderCancelled",
|
|
2713
|
+
already_paid: "payment.blocked.alreadyPaid",
|
|
2714
|
+
authorization_held: "payment.blocked.authorizationHeld",
|
|
2715
|
+
document_issued: "payment.blocked.documentIssued"
|
|
2716
|
+
};
|
|
2717
|
+
function handoffKey(token) {
|
|
2718
|
+
return `nv_payment_handoff_${token}`;
|
|
2719
|
+
}
|
|
2720
|
+
function rememberHandoff(token) {
|
|
2721
|
+
try {
|
|
2722
|
+
sessionStorage.setItem(handoffKey(token), String(Date.now()));
|
|
2723
|
+
} catch {
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
function consumeHandoff(token) {
|
|
2727
|
+
try {
|
|
2728
|
+
const raw = sessionStorage.getItem(handoffKey(token));
|
|
2729
|
+
if (!raw) return false;
|
|
2730
|
+
const fresh = Date.now() - Number(raw) < HANDOFF_TTL_MS;
|
|
2731
|
+
if (!fresh) sessionStorage.removeItem(handoffKey(token));
|
|
2732
|
+
return fresh;
|
|
2733
|
+
} catch {
|
|
2734
|
+
return false;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
function forgetHandoff(token) {
|
|
2738
|
+
try {
|
|
2739
|
+
sessionStorage.removeItem(handoffKey(token));
|
|
2740
|
+
} catch {
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
function PaymentPage({
|
|
2744
|
+
token,
|
|
2745
|
+
payment: initial,
|
|
2746
|
+
returnUrl,
|
|
2747
|
+
cancelUrl,
|
|
2748
|
+
statusHref,
|
|
2749
|
+
locale,
|
|
2750
|
+
onPaid
|
|
2751
|
+
}) {
|
|
2752
|
+
const t = useT();
|
|
2753
|
+
const loc = useFormatLocale(locale);
|
|
2754
|
+
const { payment, methods, loading, busy, error, reload, selectMethod, startPayment } = usePayment(token, initial);
|
|
2755
|
+
const [verifying, setVerifying] = React19__namespace.useState(false);
|
|
2756
|
+
React19__namespace.useEffect(() => {
|
|
2757
|
+
if (token) setVerifying(consumeHandoff(token));
|
|
2758
|
+
}, [token]);
|
|
2759
|
+
const settled = payment != null && !payment.can_pay && payment.blocked_reason === "already_paid";
|
|
2760
|
+
React19__namespace.useEffect(() => {
|
|
2761
|
+
if (!verifying || !token || settled) return;
|
|
2762
|
+
let attempts = 0;
|
|
2763
|
+
const id = setInterval(() => {
|
|
2764
|
+
attempts += 1;
|
|
2765
|
+
if (attempts > POLL_ATTEMPTS) {
|
|
2766
|
+
setVerifying(false);
|
|
2767
|
+
forgetHandoff(token);
|
|
2768
|
+
clearInterval(id);
|
|
2769
|
+
return;
|
|
2770
|
+
}
|
|
2771
|
+
void reload();
|
|
2772
|
+
}, POLL_MS);
|
|
2773
|
+
return () => clearInterval(id);
|
|
2774
|
+
}, [verifying, token, settled, reload]);
|
|
2775
|
+
React19__namespace.useEffect(() => {
|
|
2776
|
+
if (!settled || !token || !payment) return;
|
|
2777
|
+
setVerifying(false);
|
|
2778
|
+
forgetHandoff(token);
|
|
2779
|
+
onPaid?.(payment);
|
|
2780
|
+
}, [settled, token, payment, onPaid]);
|
|
2781
|
+
if (!token) return null;
|
|
2782
|
+
if (payment == null) {
|
|
2783
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Shell2, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: loading ? t("payment.loading") : t("payment.loadError") }) });
|
|
2784
|
+
}
|
|
2785
|
+
const money = (cents) => formatCents(cents, payment.currency, loc);
|
|
2786
|
+
if (settled) {
|
|
2787
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Shell2, { title: t("payment.paidTitle"), children: [
|
|
2788
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0 }, children: t("payment.paidBody", { order: payment.order_name ?? payment.order_number }) }),
|
|
2789
|
+
/* @__PURE__ */ jsxRuntime.jsx(Amount, { label: t("payment.paidAmount"), value: money(payment.total_cents) }),
|
|
2790
|
+
statusHref ? /* @__PURE__ */ jsxRuntime.jsx(Link, { href: statusHref, children: t("order.trackOrder") }) : null
|
|
2791
|
+
] });
|
|
2792
|
+
}
|
|
2793
|
+
if (payment.blocked_reason) {
|
|
2794
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Shell2, { title: t("payment.blockedTitle"), children: [
|
|
2795
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0 }, children: t(BLOCKED_MESSAGE[payment.blocked_reason]) }),
|
|
2796
|
+
statusHref ? /* @__PURE__ */ jsxRuntime.jsx(Link, { href: statusHref, children: t("order.trackOrder") }) : null
|
|
2797
|
+
] });
|
|
2798
|
+
}
|
|
2799
|
+
if (verifying) {
|
|
2800
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Shell2, { title: t("payment.verifyingTitle"), children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: t("payment.verifyingBody") }) });
|
|
2801
|
+
}
|
|
2802
|
+
const isBank = payment.category === "bank";
|
|
2803
|
+
const isGateway = payment.category === "gateway";
|
|
2804
|
+
async function pay() {
|
|
2805
|
+
if (!token) return;
|
|
2806
|
+
rememberHandoff(token);
|
|
2807
|
+
const url = await startPayment({ returnUrl, cancelUrl });
|
|
2808
|
+
if (url) {
|
|
2809
|
+
window.location.assign(url);
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
forgetHandoff(token);
|
|
2813
|
+
await reload();
|
|
2814
|
+
}
|
|
2815
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Shell2, { title: t("payment.title", { order: payment.order_name ?? payment.order_number }), children: [
|
|
2816
|
+
/* @__PURE__ */ jsxRuntime.jsx(Amount, { label: t("payment.amountDue"), value: money(payment.amount_due_cents) }),
|
|
2817
|
+
methods.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2818
|
+
PaymentMethodPicker,
|
|
2819
|
+
{
|
|
2820
|
+
methods,
|
|
2821
|
+
value: payment.method,
|
|
2822
|
+
onSelect: (method) => void selectMethod(method),
|
|
2823
|
+
currency: payment.currency,
|
|
2824
|
+
locale: loc,
|
|
2825
|
+
disabled: busy,
|
|
2826
|
+
label: t("payment.methodLabel")
|
|
2827
|
+
}
|
|
2828
|
+
) : null,
|
|
2829
|
+
isBank && payment.instructions ? /* @__PURE__ */ jsxRuntime.jsx(TransferInstructions, { instructions: payment.instructions, locale: loc }) : null,
|
|
2830
|
+
!isBank ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2831
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => void pay(), busy, children: t("payment.payNow") }),
|
|
2832
|
+
isGateway ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)", marginTop: "0.6rem" }, children: t("checkout.gatewayRedirectNote") }) : null
|
|
2833
|
+
] }) : null,
|
|
2834
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", style: { margin: 0, color: "var(--nv-danger, #b3261e)" }, children: t("payment.actionError") }) : null,
|
|
2835
|
+
statusHref ? /* @__PURE__ */ jsxRuntime.jsx(Link, { href: statusHref, children: t("order.trackOrder") }) : null
|
|
2836
|
+
] });
|
|
2837
|
+
}
|
|
2838
|
+
function Shell2({
|
|
2839
|
+
title,
|
|
2840
|
+
children
|
|
2841
|
+
}) {
|
|
2842
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "1rem", maxWidth: "34rem" }, children: [
|
|
2843
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx("h1", { style: { margin: 0, fontSize: "1.25rem", fontWeight: 600 }, children: title }) : null,
|
|
2844
|
+
children
|
|
2845
|
+
] });
|
|
2846
|
+
}
|
|
2847
|
+
function Amount({ label, value }) {
|
|
2848
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "baseline" }, children: [
|
|
2849
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--nv-muted)" }, children: label }),
|
|
2850
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontSize: "1.35rem", fontVariantNumeric: "tabular-nums" }, children: value })
|
|
2851
|
+
] });
|
|
2852
|
+
}
|
|
2853
|
+
function Link({ href, children }) {
|
|
2854
|
+
return /* @__PURE__ */ jsxRuntime.jsx("a", { href, style: { color: "var(--nv-brand)", fontSize: "0.875rem" }, children });
|
|
2855
|
+
}
|
|
2856
|
+
var AccountContext = React19__namespace.createContext(null);
|
|
2398
2857
|
function AccountProvider({ children }) {
|
|
2399
2858
|
const client = useStorefront();
|
|
2400
|
-
const [customer, setCustomer] =
|
|
2401
|
-
const [loading, setLoading] =
|
|
2402
|
-
const
|
|
2859
|
+
const [customer, setCustomer] = React19__namespace.useState(null);
|
|
2860
|
+
const [loading, setLoading] = React19__namespace.useState(true);
|
|
2861
|
+
const [error, setError] = React19__namespace.useState(false);
|
|
2862
|
+
const refresh = React19__namespace.useCallback(async () => {
|
|
2403
2863
|
setLoading(true);
|
|
2864
|
+
setError(false);
|
|
2404
2865
|
try {
|
|
2405
2866
|
setCustomer(await client.account.me());
|
|
2867
|
+
} catch {
|
|
2868
|
+
setError(true);
|
|
2406
2869
|
} finally {
|
|
2407
2870
|
setLoading(false);
|
|
2408
2871
|
}
|
|
2409
2872
|
}, [client]);
|
|
2410
|
-
|
|
2873
|
+
React19__namespace.useEffect(() => {
|
|
2411
2874
|
void refresh();
|
|
2412
2875
|
}, [refresh]);
|
|
2413
|
-
const value =
|
|
2876
|
+
const value = React19__namespace.useMemo(
|
|
2414
2877
|
() => ({
|
|
2415
2878
|
customer,
|
|
2416
2879
|
signedIn: customer != null,
|
|
2417
2880
|
loading,
|
|
2881
|
+
error,
|
|
2418
2882
|
requestMagicLink: (email) => client.account.requestMagicLink(email),
|
|
2419
2883
|
verify: async (token) => {
|
|
2420
2884
|
const c = await client.account.verify(token);
|
|
@@ -2427,12 +2891,12 @@ function AccountProvider({ children }) {
|
|
|
2427
2891
|
},
|
|
2428
2892
|
refresh
|
|
2429
2893
|
}),
|
|
2430
|
-
[customer, loading, client, refresh]
|
|
2894
|
+
[customer, loading, error, client, refresh]
|
|
2431
2895
|
);
|
|
2432
2896
|
return /* @__PURE__ */ jsxRuntime.jsx(AccountContext.Provider, { value, children });
|
|
2433
2897
|
}
|
|
2434
2898
|
function useAccount() {
|
|
2435
|
-
const ctx =
|
|
2899
|
+
const ctx = React19__namespace.useContext(AccountContext);
|
|
2436
2900
|
if (!ctx) {
|
|
2437
2901
|
throw new Error("useAccount must be used inside <AccountProvider>.");
|
|
2438
2902
|
}
|
|
@@ -2440,9 +2904,9 @@ function useAccount() {
|
|
|
2440
2904
|
}
|
|
2441
2905
|
function useMagicLinkVerify(token) {
|
|
2442
2906
|
const { verify } = useAccount();
|
|
2443
|
-
const [status, setStatus] =
|
|
2444
|
-
const done =
|
|
2445
|
-
|
|
2907
|
+
const [status, setStatus] = React19__namespace.useState("idle");
|
|
2908
|
+
const done = React19__namespace.useRef(false);
|
|
2909
|
+
React19__namespace.useEffect(() => {
|
|
2446
2910
|
if (!token || done.current) return;
|
|
2447
2911
|
done.current = true;
|
|
2448
2912
|
setStatus("verifying");
|
|
@@ -2453,18 +2917,22 @@ function useMagicLinkVerify(token) {
|
|
|
2453
2917
|
function LoginForm({ verifyPath = "/account/verify", onSent }) {
|
|
2454
2918
|
const t = useT();
|
|
2455
2919
|
const { requestMagicLink } = useAccount();
|
|
2456
|
-
const [email, setEmail] =
|
|
2457
|
-
const [busy, setBusy] =
|
|
2458
|
-
const [sent, setSent] =
|
|
2459
|
-
const [
|
|
2920
|
+
const [email, setEmail] = React19__namespace.useState("");
|
|
2921
|
+
const [busy, setBusy] = React19__namespace.useState(false);
|
|
2922
|
+
const [sent, setSent] = React19__namespace.useState(false);
|
|
2923
|
+
const [error, setError] = React19__namespace.useState(false);
|
|
2924
|
+
const [devLink, setDevLink] = React19__namespace.useState(null);
|
|
2460
2925
|
async function submit(e) {
|
|
2461
2926
|
e.preventDefault();
|
|
2462
2927
|
setBusy(true);
|
|
2928
|
+
setError(false);
|
|
2463
2929
|
try {
|
|
2464
2930
|
const r = await requestMagicLink(email);
|
|
2465
2931
|
setSent(true);
|
|
2466
2932
|
if (r.devToken) setDevLink(`${verifyPath}?token=${encodeURIComponent(r.devToken)}`);
|
|
2467
2933
|
onSent?.(email);
|
|
2934
|
+
} catch {
|
|
2935
|
+
setError(true);
|
|
2468
2936
|
} finally {
|
|
2469
2937
|
setBusy(false);
|
|
2470
2938
|
}
|
|
@@ -2503,6 +2971,7 @@ function LoginForm({ verifyPath = "/account/verify", onSent }) {
|
|
|
2503
2971
|
}
|
|
2504
2972
|
)
|
|
2505
2973
|
] }),
|
|
2974
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: t("account.signInError") }) : null,
|
|
2506
2975
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2507
2976
|
"button",
|
|
2508
2977
|
{
|
|
@@ -2564,20 +3033,47 @@ function OrderHistory({
|
|
|
2564
3033
|
const loc = useFormatLocale(locale);
|
|
2565
3034
|
const { signedIn } = useAccount();
|
|
2566
3035
|
const client = useStorefront();
|
|
2567
|
-
const [orders, setOrders] =
|
|
2568
|
-
const [
|
|
2569
|
-
const [
|
|
2570
|
-
|
|
3036
|
+
const [orders, setOrders] = React19__namespace.useState(null);
|
|
3037
|
+
const [error, setError] = React19__namespace.useState(false);
|
|
3038
|
+
const [nextCursor, setNextCursor] = React19__namespace.useState(null);
|
|
3039
|
+
const [pageLoading, setPageLoading] = React19__namespace.useState(false);
|
|
3040
|
+
const [reload, setReload] = React19__namespace.useState(0);
|
|
3041
|
+
const [reordering, setReordering] = React19__namespace.useState(null);
|
|
3042
|
+
const [notice, setNotice] = React19__namespace.useState(null);
|
|
3043
|
+
React19__namespace.useEffect(() => {
|
|
2571
3044
|
let live = true;
|
|
2572
3045
|
if (!signedIn) {
|
|
2573
3046
|
setOrders([]);
|
|
2574
3047
|
return;
|
|
2575
3048
|
}
|
|
2576
|
-
|
|
3049
|
+
setError(false);
|
|
3050
|
+
setOrders(null);
|
|
3051
|
+
client.account.ordersPage().then((page) => {
|
|
3052
|
+
if (live) {
|
|
3053
|
+
setOrders(page.orders);
|
|
3054
|
+
setNextCursor(page.nextCursor);
|
|
3055
|
+
}
|
|
3056
|
+
}).catch(() => {
|
|
3057
|
+
if (live) setError(true);
|
|
3058
|
+
});
|
|
2577
3059
|
return () => {
|
|
2578
3060
|
live = false;
|
|
2579
3061
|
};
|
|
2580
|
-
}, [signedIn, client]);
|
|
3062
|
+
}, [signedIn, client, reload]);
|
|
3063
|
+
async function loadMore() {
|
|
3064
|
+
if (!nextCursor || pageLoading) return;
|
|
3065
|
+
setPageLoading(true);
|
|
3066
|
+
setError(false);
|
|
3067
|
+
try {
|
|
3068
|
+
const page = await client.account.ordersPage({ beforeId: nextCursor });
|
|
3069
|
+
setOrders((previous) => [...previous ?? [], ...page.orders]);
|
|
3070
|
+
setNextCursor(page.nextCursor);
|
|
3071
|
+
} catch {
|
|
3072
|
+
setError(true);
|
|
3073
|
+
} finally {
|
|
3074
|
+
setPageLoading(false);
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
2581
3077
|
async function reorder(statusToken) {
|
|
2582
3078
|
setReordering(statusToken);
|
|
2583
3079
|
setNotice(null);
|
|
@@ -2598,7 +3094,11 @@ function OrderHistory({
|
|
|
2598
3094
|
}
|
|
2599
3095
|
return /* @__PURE__ */ jsxRuntime.jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
2600
3096
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.1rem", fontWeight: 600 }, children: t("account.orders") }),
|
|
2601
|
-
|
|
3097
|
+
error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", children: [
|
|
3098
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: t("account.loadError") }),
|
|
3099
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => orders ? void loadMore() : setReload((x) => x + 1), children: t("account.retry") })
|
|
3100
|
+
] }) : null,
|
|
3101
|
+
orders == null ? error ? null : /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("common.loadingShort") }) : orders.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("account.noOrders") }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.5rem" }, children: orders.map((o) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2602
3102
|
"li",
|
|
2603
3103
|
{
|
|
2604
3104
|
style: {
|
|
@@ -2645,12 +3145,13 @@ function OrderHistory({
|
|
|
2645
3145
|
]
|
|
2646
3146
|
},
|
|
2647
3147
|
o.status_token
|
|
2648
|
-
)) })
|
|
3148
|
+
)) }),
|
|
3149
|
+
nextCursor ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", disabled: pageLoading, onClick: () => void loadMore(), children: pageLoading ? t("common.loadingShort") : t("account.loadMore") }) : null
|
|
2649
3150
|
] });
|
|
2650
3151
|
}
|
|
2651
3152
|
function AddressForm2({ initial, onSubmit, onCancel, busy }) {
|
|
2652
3153
|
const t = useT();
|
|
2653
|
-
const [form, setForm] =
|
|
3154
|
+
const [form, setForm] = React19__namespace.useState(() => ({
|
|
2654
3155
|
first_name: initial?.first_name ?? "",
|
|
2655
3156
|
last_name: initial?.last_name ?? "",
|
|
2656
3157
|
company: initial?.company ?? "",
|
|
@@ -2748,17 +3249,17 @@ function AddressBook() {
|
|
|
2748
3249
|
const t = useT();
|
|
2749
3250
|
const { signedIn } = useAccount();
|
|
2750
3251
|
const client = useStorefront();
|
|
2751
|
-
const [addresses, setAddresses] =
|
|
2752
|
-
const [mode, setMode] =
|
|
2753
|
-
const [busy, setBusy] =
|
|
2754
|
-
const load =
|
|
3252
|
+
const [addresses, setAddresses] = React19__namespace.useState(null);
|
|
3253
|
+
const [mode, setMode] = React19__namespace.useState({ kind: "list" });
|
|
3254
|
+
const [busy, setBusy] = React19__namespace.useState(false);
|
|
3255
|
+
const load = React19__namespace.useCallback(() => {
|
|
2755
3256
|
if (!signedIn) {
|
|
2756
3257
|
setAddresses([]);
|
|
2757
3258
|
return;
|
|
2758
3259
|
}
|
|
2759
3260
|
client.account.addresses().then(setAddresses).catch(() => setAddresses([]));
|
|
2760
3261
|
}, [signedIn, client]);
|
|
2761
|
-
|
|
3262
|
+
React19__namespace.useEffect(() => {
|
|
2762
3263
|
load();
|
|
2763
3264
|
}, [load]);
|
|
2764
3265
|
async function run(fn) {
|
|
@@ -2812,10 +3313,10 @@ function ProfileEditor() {
|
|
|
2812
3313
|
const t = useT();
|
|
2813
3314
|
const client = useStorefront();
|
|
2814
3315
|
const { customer, refresh } = useAccount();
|
|
2815
|
-
const [editing, setEditing] =
|
|
2816
|
-
const [busy, setBusy] =
|
|
2817
|
-
const [error, setError] =
|
|
2818
|
-
const [form, setForm] =
|
|
3316
|
+
const [editing, setEditing] = React19__namespace.useState(false);
|
|
3317
|
+
const [busy, setBusy] = React19__namespace.useState(false);
|
|
3318
|
+
const [error, setError] = React19__namespace.useState(false);
|
|
3319
|
+
const [form, setForm] = React19__namespace.useState({});
|
|
2819
3320
|
if (!customer) return null;
|
|
2820
3321
|
function startEdit() {
|
|
2821
3322
|
setForm({
|
|
@@ -2892,6 +3393,79 @@ function ProfileEditor() {
|
|
|
2892
3393
|
] })
|
|
2893
3394
|
] });
|
|
2894
3395
|
}
|
|
3396
|
+
function AccountSecurity() {
|
|
3397
|
+
const client = useStorefront();
|
|
3398
|
+
const account = useAccount();
|
|
3399
|
+
const t = useT();
|
|
3400
|
+
const [sessions, setSessions] = React19__namespace.useState(null);
|
|
3401
|
+
const [email, setEmail] = React19__namespace.useState("");
|
|
3402
|
+
const [busy, setBusy] = React19__namespace.useState(false);
|
|
3403
|
+
const [notice, setNotice] = React19__namespace.useState(null);
|
|
3404
|
+
const [confirmClose, setConfirmClose] = React19__namespace.useState(false);
|
|
3405
|
+
const [retry, setRetry] = React19__namespace.useState(0);
|
|
3406
|
+
React19__namespace.useEffect(() => {
|
|
3407
|
+
let live = true;
|
|
3408
|
+
if (account.signedIn) client.account.sessions().then((s) => {
|
|
3409
|
+
if (live) setSessions(s);
|
|
3410
|
+
}).catch(() => {
|
|
3411
|
+
if (live) setNotice(t("account.loadError"));
|
|
3412
|
+
});
|
|
3413
|
+
return () => {
|
|
3414
|
+
live = false;
|
|
3415
|
+
};
|
|
3416
|
+
}, [client, account.signedIn, retry, t]);
|
|
3417
|
+
async function act(operation) {
|
|
3418
|
+
setBusy(true);
|
|
3419
|
+
setNotice(null);
|
|
3420
|
+
try {
|
|
3421
|
+
await operation();
|
|
3422
|
+
} catch (e) {
|
|
3423
|
+
setNotice(e instanceof storefrontJs.StorefrontError && e.status === 401 ? t("account.recentLogin") : t("account.loadError"));
|
|
3424
|
+
} finally {
|
|
3425
|
+
setBusy(false);
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
if (!account.signedIn) return null;
|
|
3429
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { style: { display: "grid", gap: "0.75rem" }, children: [
|
|
3430
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.1rem", fontWeight: 600 }, children: t("account.security") }),
|
|
3431
|
+
notice ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: notice }) : null,
|
|
3432
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3433
|
+
"form",
|
|
3434
|
+
{
|
|
3435
|
+
style: { display: "flex", gap: "0.75rem", flexWrap: "wrap", alignItems: "end" },
|
|
3436
|
+
onSubmit: (e) => {
|
|
3437
|
+
e.preventDefault();
|
|
3438
|
+
void act(async () => {
|
|
3439
|
+
await client.account.requestEmailChange(email);
|
|
3440
|
+
setNotice(t("account.checkEmail"));
|
|
3441
|
+
});
|
|
3442
|
+
},
|
|
3443
|
+
children: [
|
|
3444
|
+
/* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("account.newEmail"), type: "email", required: true, value: email, onChange: (e) => setEmail(e.target.value) }),
|
|
3445
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", busy, children: t("account.changeEmail") })
|
|
3446
|
+
]
|
|
3447
|
+
}
|
|
3448
|
+
),
|
|
3449
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: t("account.sessions") }),
|
|
3450
|
+
sessions ? sessions.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", justifyContent: "space-between" }, children: [
|
|
3451
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: s.current ? t("account.currentSession") : /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: s.created_at, children: s.created_at.slice(0, 10) }) }),
|
|
3452
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy, onClick: () => void act(async () => {
|
|
3453
|
+
await client.account.revokeSession(s.id);
|
|
3454
|
+
if (s.current) await account.logout();
|
|
3455
|
+
else setSessions((old) => old?.filter((row) => row.id !== s.id) ?? null);
|
|
3456
|
+
}), children: t("account.revokeSession") })
|
|
3457
|
+
] }, s.id)) : /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => setRetry((x) => x + 1), children: t("account.retry") }),
|
|
3458
|
+
confirmClose ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3459
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: t("account.closeWarning") }),
|
|
3460
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy, onClick: () => void act(async () => {
|
|
3461
|
+
await client.account.close();
|
|
3462
|
+
await account.refresh();
|
|
3463
|
+
}), children: t("account.confirmClose") }),
|
|
3464
|
+
" ",
|
|
3465
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { disabled: busy, onClick: () => setConfirmClose(false), children: t("account.cancel") })
|
|
3466
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(Button, { disabled: busy, onClick: () => setConfirmClose(true), children: t("account.closeAccount") })
|
|
3467
|
+
] });
|
|
3468
|
+
}
|
|
2895
3469
|
function serializeJsonLd(data) {
|
|
2896
3470
|
return JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
|
|
2897
3471
|
}
|
|
@@ -2998,6 +3572,7 @@ function OrganizationJsonLd({
|
|
|
2998
3572
|
|
|
2999
3573
|
exports.AccountDashboard = AccountDashboard;
|
|
3000
3574
|
exports.AccountProvider = AccountProvider;
|
|
3575
|
+
exports.AccountSecurity = AccountSecurity;
|
|
3001
3576
|
exports.AddToCart = AddToCart;
|
|
3002
3577
|
exports.AddressBook = AddressBook;
|
|
3003
3578
|
exports.AddressForm = AddressForm;
|
|
@@ -3018,10 +3593,15 @@ exports.MarketSwitcher = MarketSwitcher;
|
|
|
3018
3593
|
exports.NeviosProvider = NeviosProvider;
|
|
3019
3594
|
exports.OrderConfirmation = OrderConfirmation;
|
|
3020
3595
|
exports.OrderHistory = OrderHistory;
|
|
3596
|
+
exports.OrderLines = OrderLines;
|
|
3021
3597
|
exports.OrderStatusPage = OrderStatusPage;
|
|
3022
3598
|
exports.OrderSummary = OrderSummary;
|
|
3599
|
+
exports.OrderTotals = OrderTotals;
|
|
3023
3600
|
exports.OrganizationJsonLd = OrganizationJsonLd;
|
|
3601
|
+
exports.PaymentMethodPicker = PaymentMethodPicker;
|
|
3602
|
+
exports.PaymentPage = PaymentPage;
|
|
3024
3603
|
exports.PaymentSection = PaymentSection;
|
|
3604
|
+
exports.PhaseTimeline = PhaseTimeline;
|
|
3025
3605
|
exports.PriceMoney = PriceMoney;
|
|
3026
3606
|
exports.PriceRangeFilter = PriceRangeFilter;
|
|
3027
3607
|
exports.ProductCard = ProductCard;
|
|
@@ -3031,9 +3611,11 @@ exports.ProductJsonLd = ProductJsonLd;
|
|
|
3031
3611
|
exports.ProfileEditor = ProfileEditor;
|
|
3032
3612
|
exports.ShippingPicker = ShippingPicker;
|
|
3033
3613
|
exports.SortSelect = SortSelect;
|
|
3614
|
+
exports.StatusBanner = StatusBanner;
|
|
3034
3615
|
exports.StockBadge = StockBadge;
|
|
3035
3616
|
exports.TagFilter = TagFilter;
|
|
3036
3617
|
exports.ThemeProvider = ThemeProvider;
|
|
3618
|
+
exports.TransferInstructions = TransferInstructions;
|
|
3037
3619
|
exports.VariantPicker = VariantPicker;
|
|
3038
3620
|
exports.absoluteUrl = absoluteUrl;
|
|
3039
3621
|
exports.bundledMessages = bundledMessages;
|
|
@@ -3041,6 +3623,7 @@ exports.cs = cs;
|
|
|
3041
3623
|
exports.en = en;
|
|
3042
3624
|
exports.formatCents = formatCents;
|
|
3043
3625
|
exports.formatMoney = formatMoney;
|
|
3626
|
+
exports.isTerminal = isTerminal;
|
|
3044
3627
|
exports.serializeJsonLd = serializeJsonLd;
|
|
3045
3628
|
exports.stripHtml = stripHtml;
|
|
3046
3629
|
exports.themeToCssVars = themeToCssVars;
|
|
@@ -3050,6 +3633,7 @@ exports.useCheckout = useCheckout;
|
|
|
3050
3633
|
exports.useI18n = useI18n;
|
|
3051
3634
|
exports.useMagicLinkVerify = useMagicLinkVerify;
|
|
3052
3635
|
exports.useOrderStatus = useOrderStatus;
|
|
3636
|
+
exports.usePayment = usePayment;
|
|
3053
3637
|
exports.useStorefront = useStorefront;
|
|
3054
3638
|
exports.useStorefrontOptional = useStorefrontOptional;
|
|
3055
3639
|
exports.useT = useT;
|