@nevios/storefront-kit 1.0.0 → 1.2.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 +459 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +184 -3
- package/dist/index.d.ts +184 -3
- package/dist/index.js +451 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -179,6 +179,37 @@ var en = {
|
|
|
179
179
|
"order.terminal.cancelled": "This order was cancelled.",
|
|
180
180
|
"order.terminal.refunded": "This order was refunded.",
|
|
181
181
|
"order.terminal.returned": "This order was returned.",
|
|
182
|
+
// payment page — the four situations it can be in
|
|
183
|
+
"payment.title": "Pay for order {order}",
|
|
184
|
+
"payment.amountDue": "Amount due",
|
|
185
|
+
"payment.methodLabel": "Payment method",
|
|
186
|
+
"payment.payNow": "Pay now",
|
|
187
|
+
"payment.finish": "Finish payment",
|
|
188
|
+
"payment.loading": "Loading payment\u2026",
|
|
189
|
+
"payment.loadError": "Couldn't load this payment.",
|
|
190
|
+
"payment.actionError": "That didn't go through. Please try again.",
|
|
191
|
+
// …paid
|
|
192
|
+
"payment.paidTitle": "Paid",
|
|
193
|
+
"payment.paidBody": "Order {order} is paid. Nothing further is needed.",
|
|
194
|
+
"payment.paidAmount": "Paid",
|
|
195
|
+
// …returning from a gateway, callback still in flight
|
|
196
|
+
"payment.verifyingTitle": "Checking your payment\u2026",
|
|
197
|
+
"payment.verifyingBody": "This takes a few seconds. Don't pay again \u2014 we'll update this page.",
|
|
198
|
+
// …locked, one sentence per reason
|
|
199
|
+
"payment.blockedTitle": "This order can't be paid",
|
|
200
|
+
"payment.blocked.orderCancelled": "This order was cancelled, so there is nothing to pay.",
|
|
201
|
+
"payment.blocked.alreadyPaid": "This order is already paid.",
|
|
202
|
+
"payment.blocked.authorizationHeld": "Your bank is holding the funds for this order. Once the payment settles this page will show it as paid.",
|
|
203
|
+
"payment.blocked.documentIssued": "An invoice has been issued for this order, so the amount is fixed. Contact us to change how you pay.",
|
|
204
|
+
// …bank transfer
|
|
205
|
+
"payment.account": "Account",
|
|
206
|
+
"payment.beneficiary": "Beneficiary",
|
|
207
|
+
"payment.variableSymbol": "Variable symbol",
|
|
208
|
+
"payment.amount": "Amount",
|
|
209
|
+
"payment.copy": "Copy",
|
|
210
|
+
"payment.copied": "Copied",
|
|
211
|
+
"payment.qrAlt": "QR code for the payment",
|
|
212
|
+
"payment.qrCaption": "Scan in your banking app",
|
|
182
213
|
// error pages
|
|
183
214
|
"error.notFound.title": "Page not found",
|
|
184
215
|
"error.notFound.body": "This page doesn't exist or isn't available in your region.",
|
|
@@ -335,6 +366,33 @@ var cs = {
|
|
|
335
366
|
"order.terminal.cancelled": "Tato objedn\xE1vka byla zru\u0161ena.",
|
|
336
367
|
"order.terminal.refunded": "Tato objedn\xE1vka byla refundov\xE1na.",
|
|
337
368
|
"order.terminal.returned": "Tato objedn\xE1vka byla vr\xE1cena.",
|
|
369
|
+
// platební stránka — čtyři situace, ve kterých může být
|
|
370
|
+
"payment.title": "Zaplatit objedn\xE1vku {order}",
|
|
371
|
+
"payment.amountDue": "K \xFAhrad\u011B",
|
|
372
|
+
"payment.methodLabel": "Zp\u016Fsob platby",
|
|
373
|
+
"payment.payNow": "Zaplatit",
|
|
374
|
+
"payment.finish": "Dokon\u010Dit platbu",
|
|
375
|
+
"payment.loading": "Na\u010D\xEDt\xE1n\xED platby\u2026",
|
|
376
|
+
"payment.loadError": "Platbu se nepoda\u0159ilo na\u010D\xEDst.",
|
|
377
|
+
"payment.actionError": "Nepovedlo se to. Zkuste to pros\xEDm znovu.",
|
|
378
|
+
"payment.paidTitle": "Zaplaceno",
|
|
379
|
+
"payment.paidBody": "Objedn\xE1vka {order} je zaplacen\xE1. Nic dal\u0161\xEDho d\u011Blat nemus\xEDte.",
|
|
380
|
+
"payment.paidAmount": "Uhrazeno",
|
|
381
|
+
"payment.verifyingTitle": "Ov\u011B\u0159ujeme platbu\u2026",
|
|
382
|
+
"payment.verifyingBody": "Chvilku to trv\xE1. Nepla\u0165te pros\xEDm znovu \u2014 str\xE1nka se sama aktualizuje.",
|
|
383
|
+
"payment.blockedTitle": "Tuhle objedn\xE1vku te\u010F zaplatit nejde",
|
|
384
|
+
"payment.blocked.orderCancelled": "Objedn\xE1vka byla zru\u0161en\xE1, tak\u017Ee nen\xED co platit.",
|
|
385
|
+
"payment.blocked.alreadyPaid": "Objedn\xE1vka je u\u017E zaplacen\xE1.",
|
|
386
|
+
"payment.blocked.authorizationHeld": "Banka na tuhle objedn\xE1vku dr\u017E\xED pen\xEDze. Jakmile se platba dokon\u010D\xED, uvid\xEDte to tady.",
|
|
387
|
+
"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.",
|
|
388
|
+
"payment.account": "\xDA\u010Det",
|
|
389
|
+
"payment.beneficiary": "P\u0159\xEDjemce",
|
|
390
|
+
"payment.variableSymbol": "Variabiln\xED symbol",
|
|
391
|
+
"payment.amount": "\u010C\xE1stka",
|
|
392
|
+
"payment.copy": "Kop\xEDrovat",
|
|
393
|
+
"payment.copied": "Zkop\xEDrov\xE1no",
|
|
394
|
+
"payment.qrAlt": "QR k\xF3d k platb\u011B",
|
|
395
|
+
"payment.qrCaption": "Na\u010Dt\u011Bte v bankovn\xED aplikaci",
|
|
338
396
|
"error.notFound.title": "Str\xE1nka nenalezena",
|
|
339
397
|
"error.notFound.body": "Tato str\xE1nka neexistuje nebo nen\xED ve va\u0161em regionu dostupn\xE1.",
|
|
340
398
|
"error.generic.title": "N\u011Bco se pokazilo",
|
|
@@ -1142,6 +1200,7 @@ function AddToCart({
|
|
|
1142
1200
|
}
|
|
1143
1201
|
function CartLineItem({ line, locale }) {
|
|
1144
1202
|
const t = useT();
|
|
1203
|
+
const loc = useFormatLocale(locale);
|
|
1145
1204
|
const { updateLine, removeLine } = useCart();
|
|
1146
1205
|
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.85rem", alignItems: "flex-start", padding: "0.75rem 0" }, children: [
|
|
1147
1206
|
/* @__PURE__ */ jsx(
|
|
@@ -1213,7 +1272,7 @@ function CartLineItem({ line, locale }) {
|
|
|
1213
1272
|
)
|
|
1214
1273
|
] })
|
|
1215
1274
|
] }),
|
|
1216
|
-
/* @__PURE__ */ jsx("div", { style: { fontWeight: 500, whiteSpace: "nowrap" }, children: formatCents(line.line_total_cents, line.unit_price.currency,
|
|
1275
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 500, whiteSpace: "nowrap" }, children: formatCents(line.line_total_cents, line.unit_price.currency, loc) })
|
|
1217
1276
|
] });
|
|
1218
1277
|
}
|
|
1219
1278
|
function StepBtn({ label, onClick }) {
|
|
@@ -1245,6 +1304,7 @@ function CartSummary({
|
|
|
1245
1304
|
locale
|
|
1246
1305
|
}) {
|
|
1247
1306
|
const tr = useT();
|
|
1307
|
+
const loc = useFormatLocale(locale);
|
|
1248
1308
|
const { cart } = useCart();
|
|
1249
1309
|
if (cart == null) return null;
|
|
1250
1310
|
const t = cart.totals;
|
|
@@ -1265,10 +1325,10 @@ function CartSummary({
|
|
|
1265
1325
|
opacity: empty ? 0.55 : 1
|
|
1266
1326
|
};
|
|
1267
1327
|
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
1268
|
-
/* @__PURE__ */ jsx(Row, { label: tr("cart.subtotal"), value: formatCents(t.subtotal_with_tax_cents, t.currency,
|
|
1269
|
-
t.tax_cents > 0 ? /* @__PURE__ */ jsx(Row, { label: tr("cart.tax"), value: formatCents(t.tax_cents, t.currency,
|
|
1328
|
+
/* @__PURE__ */ jsx(Row, { label: tr("cart.subtotal"), value: formatCents(t.subtotal_with_tax_cents, t.currency, loc) }),
|
|
1329
|
+
t.tax_cents > 0 ? /* @__PURE__ */ jsx(Row, { label: tr("cart.tax"), value: formatCents(t.tax_cents, t.currency, loc), muted: true }) : null,
|
|
1270
1330
|
/* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
|
|
1271
|
-
/* @__PURE__ */ jsx(Row, { label: tr("cart.total"), value: formatCents(t.total_cents, t.currency,
|
|
1331
|
+
/* @__PURE__ */ jsx(Row, { label: tr("cart.total"), value: formatCents(t.total_cents, t.currency, loc), strong: true }),
|
|
1272
1332
|
checkoutHref && !empty ? /* @__PURE__ */ jsx("a", { href: checkoutHref, style: ctaStyle, children: cta }) : /* @__PURE__ */ jsx("button", { type: "button", disabled: empty, onClick: onCheckout, style: ctaStyle, children: cta })
|
|
1273
1333
|
] });
|
|
1274
1334
|
}
|
|
@@ -1671,6 +1731,7 @@ function ShippingPicker({
|
|
|
1671
1731
|
locale
|
|
1672
1732
|
}) {
|
|
1673
1733
|
const t = useT();
|
|
1734
|
+
const loc = useFormatLocale(locale);
|
|
1674
1735
|
const { checkout, shippingQuotes, setShippingMethod, loading } = useCheckout();
|
|
1675
1736
|
const heading = title ?? t("checkout.shippingMethod");
|
|
1676
1737
|
const [quotes, setQuotes] = React10.useState(null);
|
|
@@ -1711,7 +1772,7 @@ function ShippingPicker({
|
|
|
1711
1772
|
{
|
|
1712
1773
|
selected: selected === q.rate_id,
|
|
1713
1774
|
onSelect: () => setSelected(q.rate_id),
|
|
1714
|
-
trailing: q.is_free ? t("common.free") : formatCents(q.price_cents, q.currency,
|
|
1775
|
+
trailing: q.is_free ? t("common.free") : formatCents(q.price_cents, q.currency, loc),
|
|
1715
1776
|
children: /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexDirection: "column" }, children: [
|
|
1716
1777
|
/* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: q.label }),
|
|
1717
1778
|
days ? /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: days }) : null
|
|
@@ -1732,6 +1793,39 @@ function estDays(q, t) {
|
|
|
1732
1793
|
const n = lo ?? hi;
|
|
1733
1794
|
return t("shipping.days", { count: n });
|
|
1734
1795
|
}
|
|
1796
|
+
function PaymentMethodPicker({
|
|
1797
|
+
methods,
|
|
1798
|
+
value,
|
|
1799
|
+
onSelect,
|
|
1800
|
+
currency,
|
|
1801
|
+
locale,
|
|
1802
|
+
disabled,
|
|
1803
|
+
label
|
|
1804
|
+
}) {
|
|
1805
|
+
const loc = useFormatLocale(locale);
|
|
1806
|
+
return /* @__PURE__ */ jsx(
|
|
1807
|
+
"div",
|
|
1808
|
+
{
|
|
1809
|
+
role: "radiogroup",
|
|
1810
|
+
"aria-label": label,
|
|
1811
|
+
style: { display: "flex", flexDirection: "column", gap: "0.6rem" },
|
|
1812
|
+
children: methods.map((m) => /* @__PURE__ */ jsx(
|
|
1813
|
+
SelectRow,
|
|
1814
|
+
{
|
|
1815
|
+
selected: value === m.method,
|
|
1816
|
+
disabled,
|
|
1817
|
+
onSelect: () => onSelect(m.method),
|
|
1818
|
+
trailing: m.surcharge_cents > 0 ? `+${formatCents(m.surcharge_cents, currency, loc)}` : void 0,
|
|
1819
|
+
children: /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexDirection: "column" }, children: [
|
|
1820
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: m.display_label }),
|
|
1821
|
+
m.display_description ? /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: m.display_description }) : null
|
|
1822
|
+
] })
|
|
1823
|
+
},
|
|
1824
|
+
m.method
|
|
1825
|
+
))
|
|
1826
|
+
}
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1735
1829
|
function PaymentSection({
|
|
1736
1830
|
title,
|
|
1737
1831
|
returnUrl,
|
|
@@ -1772,19 +1866,17 @@ function PaymentSection({
|
|
|
1772
1866
|
return /* @__PURE__ */ jsx(Section, { title: heading, children: /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("checkout.noPayment") }) });
|
|
1773
1867
|
}
|
|
1774
1868
|
return /* @__PURE__ */ jsxs(Section, { title: heading, children: [
|
|
1775
|
-
/* @__PURE__ */ jsx(
|
|
1776
|
-
|
|
1869
|
+
/* @__PURE__ */ jsx(
|
|
1870
|
+
PaymentMethodPicker,
|
|
1777
1871
|
{
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
m.method
|
|
1787
|
-
)) }),
|
|
1872
|
+
methods,
|
|
1873
|
+
value: selected,
|
|
1874
|
+
onSelect: (method) => void setPaymentMethod(method),
|
|
1875
|
+
currency: checkout?.totals.currency ?? "CZK",
|
|
1876
|
+
locale,
|
|
1877
|
+
label: heading
|
|
1878
|
+
}
|
|
1879
|
+
),
|
|
1788
1880
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1789
1881
|
/* @__PURE__ */ jsx(Button, { onClick: placeOrder, busy: loading, disabled: selected == null, children: isGateway ? t("checkout.payNow") : t("checkout.placeOrder") }),
|
|
1790
1882
|
isGateway ? /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)", marginTop: "0.6rem" }, children: t("checkout.gatewayRedirectNote") }) : null
|
|
@@ -1797,12 +1889,13 @@ function OrderSummary({
|
|
|
1797
1889
|
locale
|
|
1798
1890
|
}) {
|
|
1799
1891
|
const tr = useT();
|
|
1892
|
+
const loc = useFormatLocale(locale);
|
|
1800
1893
|
const ctx = useCheckout();
|
|
1801
1894
|
const checkout = override ?? ctx.checkout;
|
|
1802
1895
|
if (checkout == null) return null;
|
|
1803
1896
|
const t = checkout.totals;
|
|
1804
1897
|
const c = t.currency;
|
|
1805
|
-
const money = (cents) => formatCents(cents, c,
|
|
1898
|
+
const money = (cents) => formatCents(cents, c, loc);
|
|
1806
1899
|
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
|
|
1807
1900
|
!totalsOnly && checkout.line_items.length > 0 ? /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.75rem" }, children: checkout.line_items.map((li) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1808
1901
|
li.image_url ? /* @__PURE__ */ jsx(
|
|
@@ -2034,6 +2127,79 @@ function useOrderStatus(statusToken, initial) {
|
|
|
2034
2127
|
}, [load, initial]);
|
|
2035
2128
|
return { order, loading, error, reload: () => void load() };
|
|
2036
2129
|
}
|
|
2130
|
+
function usePayment(token, initial) {
|
|
2131
|
+
const client = useStorefront();
|
|
2132
|
+
const [payment, setPayment] = React10.useState(initial ?? null);
|
|
2133
|
+
const [methods, setMethods] = React10.useState([]);
|
|
2134
|
+
const [loading, setLoading] = React10.useState(false);
|
|
2135
|
+
const [busy, setBusy] = React10.useState(false);
|
|
2136
|
+
const [error, setError] = React10.useState(null);
|
|
2137
|
+
const load = React10.useCallback(async () => {
|
|
2138
|
+
if (!token) return;
|
|
2139
|
+
setLoading(true);
|
|
2140
|
+
try {
|
|
2141
|
+
const [state, list] = await Promise.all([
|
|
2142
|
+
client.payment.get(token),
|
|
2143
|
+
client.payment.methods(token)
|
|
2144
|
+
]);
|
|
2145
|
+
setPayment(state);
|
|
2146
|
+
setMethods(list);
|
|
2147
|
+
setError(null);
|
|
2148
|
+
} catch (e) {
|
|
2149
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
2150
|
+
} finally {
|
|
2151
|
+
setLoading(false);
|
|
2152
|
+
}
|
|
2153
|
+
}, [client, token]);
|
|
2154
|
+
React10.useEffect(() => {
|
|
2155
|
+
if (!token) return;
|
|
2156
|
+
if (initial && initial.token === token) {
|
|
2157
|
+
setPayment(initial);
|
|
2158
|
+
client.payment.methods(token).then(setMethods).catch(() => setMethods([]));
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
void load();
|
|
2162
|
+
}, [token, load]);
|
|
2163
|
+
const selectMethod = React10.useCallback(
|
|
2164
|
+
async (method) => {
|
|
2165
|
+
if (!token) return null;
|
|
2166
|
+
setBusy(true);
|
|
2167
|
+
try {
|
|
2168
|
+
const next = await client.payment.selectMethod(token, method);
|
|
2169
|
+
setPayment(next);
|
|
2170
|
+
setError(null);
|
|
2171
|
+
return next;
|
|
2172
|
+
} catch (e) {
|
|
2173
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
2174
|
+
return null;
|
|
2175
|
+
} finally {
|
|
2176
|
+
setBusy(false);
|
|
2177
|
+
}
|
|
2178
|
+
},
|
|
2179
|
+
[client, token]
|
|
2180
|
+
);
|
|
2181
|
+
const startPayment = React10.useCallback(
|
|
2182
|
+
async (input) => {
|
|
2183
|
+
if (!token) return null;
|
|
2184
|
+
setBusy(true);
|
|
2185
|
+
try {
|
|
2186
|
+
const result = await client.payment.start(token, {
|
|
2187
|
+
return_url: input?.returnUrl,
|
|
2188
|
+
cancel_url: input?.cancelUrl
|
|
2189
|
+
});
|
|
2190
|
+
setError(null);
|
|
2191
|
+
return result.redirect_url;
|
|
2192
|
+
} catch (e) {
|
|
2193
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
2194
|
+
return null;
|
|
2195
|
+
} finally {
|
|
2196
|
+
setBusy(false);
|
|
2197
|
+
}
|
|
2198
|
+
},
|
|
2199
|
+
[client, token]
|
|
2200
|
+
);
|
|
2201
|
+
return { payment, methods, loading, busy, error, reload: load, selectMethod, startPayment };
|
|
2202
|
+
}
|
|
2037
2203
|
var PHASE_RANK = {
|
|
2038
2204
|
placed: 0,
|
|
2039
2205
|
paid: 1,
|
|
@@ -2129,6 +2295,7 @@ function OrderLines({
|
|
|
2129
2295
|
order,
|
|
2130
2296
|
locale
|
|
2131
2297
|
}) {
|
|
2298
|
+
const loc = useFormatLocale(locale);
|
|
2132
2299
|
return /* @__PURE__ */ jsxs("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
2133
2300
|
order.line_items.map((li) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
|
|
2134
2301
|
li.image_url ? /* @__PURE__ */ jsx(
|
|
@@ -2149,11 +2316,11 @@ function OrderLines({
|
|
|
2149
2316
|
li.quantity
|
|
2150
2317
|
] })
|
|
2151
2318
|
] }),
|
|
2152
|
-
/* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(li.total_with_tax_cents, order.currency,
|
|
2319
|
+
/* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(li.total_with_tax_cents, order.currency, loc) })
|
|
2153
2320
|
] }, li.id)),
|
|
2154
2321
|
order.fee_lines.map((f, i) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
|
|
2155
2322
|
/* @__PURE__ */ jsx("span", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx("span", { style: { display: "block", fontWeight: 500 }, children: f.title }) }),
|
|
2156
|
-
/* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(f.total_with_tax_cents, order.currency,
|
|
2323
|
+
/* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(f.total_with_tax_cents, order.currency, loc) })
|
|
2157
2324
|
] }, `fee-${i}`))
|
|
2158
2325
|
] });
|
|
2159
2326
|
}
|
|
@@ -2162,9 +2329,10 @@ function OrderTotals({
|
|
|
2162
2329
|
locale
|
|
2163
2330
|
}) {
|
|
2164
2331
|
const tr = useT();
|
|
2332
|
+
const loc = useFormatLocale(locale);
|
|
2165
2333
|
const t = order.totals;
|
|
2166
2334
|
const c = order.currency;
|
|
2167
|
-
const money = (cents) => formatCents(cents, c,
|
|
2335
|
+
const money = (cents) => formatCents(cents, c, loc);
|
|
2168
2336
|
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
2169
2337
|
/* @__PURE__ */ jsx(Row3, { label: tr("totals.subtotal"), value: money(t.subtotal_cents) }),
|
|
2170
2338
|
t.discount_cents > 0 ? /* @__PURE__ */ jsx(Row3, { label: tr("totals.discount"), value: `\u2212${money(t.discount_cents)}`, muted: true }) : null,
|
|
@@ -2270,6 +2438,7 @@ function OrderStatusPage({
|
|
|
2270
2438
|
statusToken,
|
|
2271
2439
|
order: initial,
|
|
2272
2440
|
onContactSupport,
|
|
2441
|
+
payHref,
|
|
2273
2442
|
locale
|
|
2274
2443
|
}) {
|
|
2275
2444
|
const t = useT();
|
|
@@ -2321,6 +2490,7 @@ function OrderStatusPage({
|
|
|
2321
2490
|
/* @__PURE__ */ jsxs(Card, { title: t("order.payment"), children: [
|
|
2322
2491
|
/* @__PURE__ */ jsx(Line, { label: t("order.method"), value: order.payment.method ?? "\u2014" }),
|
|
2323
2492
|
/* @__PURE__ */ jsx(Line, { label: t("order.status"), value: order.payment.status }),
|
|
2493
|
+
order.payment.token && payHref ? /* @__PURE__ */ jsx("a", { href: payHref(order.payment.token), style: { color: "var(--nv-brand)", fontWeight: 500 }, children: t("payment.finish") }) : null,
|
|
2324
2494
|
order.payment.invoice_available && order.payment.invoice_url ? /* @__PURE__ */ jsx("a", { href: order.payment.invoice_url, style: { color: "var(--nv-brand)" }, children: t("order.downloadInvoice") }) : null
|
|
2325
2495
|
] }),
|
|
2326
2496
|
order.actions.can_contact_support && onContactSupport ? /* @__PURE__ */ jsx(
|
|
@@ -2372,6 +2542,265 @@ function Line({ label, value }) {
|
|
|
2372
2542
|
/* @__PURE__ */ jsx("span", { style: { textAlign: "right" }, children: value })
|
|
2373
2543
|
] });
|
|
2374
2544
|
}
|
|
2545
|
+
function TransferInstructions({
|
|
2546
|
+
instructions: i,
|
|
2547
|
+
locale
|
|
2548
|
+
}) {
|
|
2549
|
+
const t = useT();
|
|
2550
|
+
const loc = useFormatLocale(locale);
|
|
2551
|
+
const account = i.iban || i.account_number;
|
|
2552
|
+
return /* @__PURE__ */ jsxs(
|
|
2553
|
+
"div",
|
|
2554
|
+
{
|
|
2555
|
+
style: {
|
|
2556
|
+
display: "flex",
|
|
2557
|
+
flexWrap: "wrap",
|
|
2558
|
+
gap: "1.25rem",
|
|
2559
|
+
alignItems: "flex-start",
|
|
2560
|
+
padding: "1rem",
|
|
2561
|
+
borderRadius: "var(--nv-radius)",
|
|
2562
|
+
border: "1px solid var(--nv-border)"
|
|
2563
|
+
},
|
|
2564
|
+
children: [
|
|
2565
|
+
/* @__PURE__ */ jsxs("dl", { style: { flex: "1 1 15rem", margin: 0, display: "flex", flexDirection: "column", gap: "0.7rem" }, children: [
|
|
2566
|
+
account ? /* @__PURE__ */ jsx(CopyRow, { label: t("payment.account"), value: account }) : null,
|
|
2567
|
+
i.beneficiary_name ? /* @__PURE__ */ jsx(Row4, { label: t("payment.beneficiary"), value: i.beneficiary_name }) : null,
|
|
2568
|
+
/* @__PURE__ */ jsx(CopyRow, { label: t("payment.variableSymbol"), value: i.variable_symbol }),
|
|
2569
|
+
/* @__PURE__ */ jsx(
|
|
2570
|
+
Row4,
|
|
2571
|
+
{
|
|
2572
|
+
label: t("payment.amount"),
|
|
2573
|
+
value: formatCents(i.amount_cents, i.currency, loc),
|
|
2574
|
+
strong: true
|
|
2575
|
+
}
|
|
2576
|
+
)
|
|
2577
|
+
] }),
|
|
2578
|
+
i.qr_svg_data_uri ? /* @__PURE__ */ jsxs("figure", { style: { margin: 0, textAlign: "center" }, children: [
|
|
2579
|
+
/* @__PURE__ */ jsx(
|
|
2580
|
+
"img",
|
|
2581
|
+
{
|
|
2582
|
+
src: i.qr_svg_data_uri,
|
|
2583
|
+
alt: t("payment.qrAlt"),
|
|
2584
|
+
width: 148,
|
|
2585
|
+
height: 148,
|
|
2586
|
+
style: { display: "block", borderRadius: "var(--nv-radius)" }
|
|
2587
|
+
}
|
|
2588
|
+
),
|
|
2589
|
+
/* @__PURE__ */ jsx("figcaption", { style: { fontSize: "0.75rem", color: "var(--nv-muted)", marginTop: "0.4rem" }, children: t("payment.qrCaption") })
|
|
2590
|
+
] }) : null,
|
|
2591
|
+
i.instructions ? /* @__PURE__ */ jsx("p", { style: { flexBasis: "100%", margin: 0, fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: i.instructions }) : null
|
|
2592
|
+
]
|
|
2593
|
+
}
|
|
2594
|
+
);
|
|
2595
|
+
}
|
|
2596
|
+
function Row4({
|
|
2597
|
+
label,
|
|
2598
|
+
value,
|
|
2599
|
+
strong
|
|
2600
|
+
}) {
|
|
2601
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.1rem" }, children: [
|
|
2602
|
+
/* @__PURE__ */ jsx("dt", { style: { fontSize: "0.75rem", color: "var(--nv-muted)" }, children: label }),
|
|
2603
|
+
/* @__PURE__ */ jsx(
|
|
2604
|
+
"dd",
|
|
2605
|
+
{
|
|
2606
|
+
style: {
|
|
2607
|
+
margin: 0,
|
|
2608
|
+
fontWeight: strong ? 600 : 500,
|
|
2609
|
+
fontVariantNumeric: "tabular-nums"
|
|
2610
|
+
},
|
|
2611
|
+
children: value
|
|
2612
|
+
}
|
|
2613
|
+
)
|
|
2614
|
+
] });
|
|
2615
|
+
}
|
|
2616
|
+
function CopyRow({ label, value }) {
|
|
2617
|
+
const t = useT();
|
|
2618
|
+
const [copied, setCopied] = React10.useState(false);
|
|
2619
|
+
React10.useEffect(() => {
|
|
2620
|
+
if (!copied) return;
|
|
2621
|
+
const id = setTimeout(() => setCopied(false), 1800);
|
|
2622
|
+
return () => clearTimeout(id);
|
|
2623
|
+
}, [copied]);
|
|
2624
|
+
async function copy() {
|
|
2625
|
+
try {
|
|
2626
|
+
await navigator.clipboard.writeText(value);
|
|
2627
|
+
setCopied(true);
|
|
2628
|
+
} catch {
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.1rem" }, children: [
|
|
2632
|
+
/* @__PURE__ */ jsx("dt", { style: { fontSize: "0.75rem", color: "var(--nv-muted)" }, children: label }),
|
|
2633
|
+
/* @__PURE__ */ jsxs("dd", { style: { margin: 0, display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
2634
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 500, fontVariantNumeric: "tabular-nums" }, children: value }),
|
|
2635
|
+
/* @__PURE__ */ jsx(
|
|
2636
|
+
"button",
|
|
2637
|
+
{
|
|
2638
|
+
type: "button",
|
|
2639
|
+
onClick: () => void copy(),
|
|
2640
|
+
style: {
|
|
2641
|
+
font: "inherit",
|
|
2642
|
+
fontSize: "0.75rem",
|
|
2643
|
+
cursor: "pointer",
|
|
2644
|
+
padding: "0.15rem 0.5rem",
|
|
2645
|
+
borderRadius: "var(--nv-radius)",
|
|
2646
|
+
border: "1px solid var(--nv-border)",
|
|
2647
|
+
background: "transparent",
|
|
2648
|
+
color: "var(--nv-muted)"
|
|
2649
|
+
},
|
|
2650
|
+
children: copied ? t("payment.copied") : t("payment.copy")
|
|
2651
|
+
}
|
|
2652
|
+
)
|
|
2653
|
+
] })
|
|
2654
|
+
] });
|
|
2655
|
+
}
|
|
2656
|
+
var HANDOFF_TTL_MS = 30 * 60 * 1e3;
|
|
2657
|
+
var POLL_MS = 2e3;
|
|
2658
|
+
var POLL_ATTEMPTS = 6;
|
|
2659
|
+
var BLOCKED_MESSAGE = {
|
|
2660
|
+
order_cancelled: "payment.blocked.orderCancelled",
|
|
2661
|
+
already_paid: "payment.blocked.alreadyPaid",
|
|
2662
|
+
authorization_held: "payment.blocked.authorizationHeld",
|
|
2663
|
+
document_issued: "payment.blocked.documentIssued"
|
|
2664
|
+
};
|
|
2665
|
+
function handoffKey(token) {
|
|
2666
|
+
return `nv_payment_handoff_${token}`;
|
|
2667
|
+
}
|
|
2668
|
+
function rememberHandoff(token) {
|
|
2669
|
+
try {
|
|
2670
|
+
sessionStorage.setItem(handoffKey(token), String(Date.now()));
|
|
2671
|
+
} catch {
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
function consumeHandoff(token) {
|
|
2675
|
+
try {
|
|
2676
|
+
const raw = sessionStorage.getItem(handoffKey(token));
|
|
2677
|
+
if (!raw) return false;
|
|
2678
|
+
const fresh = Date.now() - Number(raw) < HANDOFF_TTL_MS;
|
|
2679
|
+
if (!fresh) sessionStorage.removeItem(handoffKey(token));
|
|
2680
|
+
return fresh;
|
|
2681
|
+
} catch {
|
|
2682
|
+
return false;
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
function forgetHandoff(token) {
|
|
2686
|
+
try {
|
|
2687
|
+
sessionStorage.removeItem(handoffKey(token));
|
|
2688
|
+
} catch {
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
function PaymentPage({
|
|
2692
|
+
token,
|
|
2693
|
+
payment: initial,
|
|
2694
|
+
returnUrl,
|
|
2695
|
+
cancelUrl,
|
|
2696
|
+
statusHref,
|
|
2697
|
+
locale,
|
|
2698
|
+
onPaid
|
|
2699
|
+
}) {
|
|
2700
|
+
const t = useT();
|
|
2701
|
+
const loc = useFormatLocale(locale);
|
|
2702
|
+
const { payment, methods, loading, busy, error, reload, selectMethod, startPayment } = usePayment(token, initial);
|
|
2703
|
+
const [verifying, setVerifying] = React10.useState(false);
|
|
2704
|
+
React10.useEffect(() => {
|
|
2705
|
+
if (token) setVerifying(consumeHandoff(token));
|
|
2706
|
+
}, [token]);
|
|
2707
|
+
const settled = payment != null && !payment.can_pay && payment.blocked_reason === "already_paid";
|
|
2708
|
+
React10.useEffect(() => {
|
|
2709
|
+
if (!verifying || !token || settled) return;
|
|
2710
|
+
let attempts = 0;
|
|
2711
|
+
const id = setInterval(() => {
|
|
2712
|
+
attempts += 1;
|
|
2713
|
+
if (attempts > POLL_ATTEMPTS) {
|
|
2714
|
+
setVerifying(false);
|
|
2715
|
+
forgetHandoff(token);
|
|
2716
|
+
clearInterval(id);
|
|
2717
|
+
return;
|
|
2718
|
+
}
|
|
2719
|
+
void reload();
|
|
2720
|
+
}, POLL_MS);
|
|
2721
|
+
return () => clearInterval(id);
|
|
2722
|
+
}, [verifying, token, settled, reload]);
|
|
2723
|
+
React10.useEffect(() => {
|
|
2724
|
+
if (!settled || !token || !payment) return;
|
|
2725
|
+
setVerifying(false);
|
|
2726
|
+
forgetHandoff(token);
|
|
2727
|
+
onPaid?.(payment);
|
|
2728
|
+
}, [settled, token, payment, onPaid]);
|
|
2729
|
+
if (!token) return null;
|
|
2730
|
+
if (payment == null) {
|
|
2731
|
+
return /* @__PURE__ */ jsx(Shell2, { children: /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: loading ? t("payment.loading") : t("payment.loadError") }) });
|
|
2732
|
+
}
|
|
2733
|
+
const money = (cents) => formatCents(cents, payment.currency, loc);
|
|
2734
|
+
if (settled) {
|
|
2735
|
+
return /* @__PURE__ */ jsxs(Shell2, { title: t("payment.paidTitle"), children: [
|
|
2736
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0 }, children: t("payment.paidBody", { order: payment.order_name ?? payment.order_number }) }),
|
|
2737
|
+
/* @__PURE__ */ jsx(Amount, { label: t("payment.paidAmount"), value: money(payment.total_cents) }),
|
|
2738
|
+
statusHref ? /* @__PURE__ */ jsx(Link, { href: statusHref, children: t("order.trackOrder") }) : null
|
|
2739
|
+
] });
|
|
2740
|
+
}
|
|
2741
|
+
if (payment.blocked_reason) {
|
|
2742
|
+
return /* @__PURE__ */ jsxs(Shell2, { title: t("payment.blockedTitle"), children: [
|
|
2743
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0 }, children: t(BLOCKED_MESSAGE[payment.blocked_reason]) }),
|
|
2744
|
+
statusHref ? /* @__PURE__ */ jsx(Link, { href: statusHref, children: t("order.trackOrder") }) : null
|
|
2745
|
+
] });
|
|
2746
|
+
}
|
|
2747
|
+
if (verifying) {
|
|
2748
|
+
return /* @__PURE__ */ jsx(Shell2, { title: t("payment.verifyingTitle"), children: /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: t("payment.verifyingBody") }) });
|
|
2749
|
+
}
|
|
2750
|
+
const isBank = payment.category === "bank";
|
|
2751
|
+
const isGateway = payment.category === "gateway";
|
|
2752
|
+
async function pay() {
|
|
2753
|
+
if (!token) return;
|
|
2754
|
+
rememberHandoff(token);
|
|
2755
|
+
const url = await startPayment({ returnUrl, cancelUrl });
|
|
2756
|
+
if (url) {
|
|
2757
|
+
window.location.assign(url);
|
|
2758
|
+
return;
|
|
2759
|
+
}
|
|
2760
|
+
forgetHandoff(token);
|
|
2761
|
+
await reload();
|
|
2762
|
+
}
|
|
2763
|
+
return /* @__PURE__ */ jsxs(Shell2, { title: t("payment.title", { order: payment.order_name ?? payment.order_number }), children: [
|
|
2764
|
+
/* @__PURE__ */ jsx(Amount, { label: t("payment.amountDue"), value: money(payment.amount_due_cents) }),
|
|
2765
|
+
methods.length > 0 ? /* @__PURE__ */ jsx(
|
|
2766
|
+
PaymentMethodPicker,
|
|
2767
|
+
{
|
|
2768
|
+
methods,
|
|
2769
|
+
value: payment.method,
|
|
2770
|
+
onSelect: (method) => void selectMethod(method),
|
|
2771
|
+
currency: payment.currency,
|
|
2772
|
+
locale: loc,
|
|
2773
|
+
disabled: busy,
|
|
2774
|
+
label: t("payment.methodLabel")
|
|
2775
|
+
}
|
|
2776
|
+
) : null,
|
|
2777
|
+
isBank && payment.instructions ? /* @__PURE__ */ jsx(TransferInstructions, { instructions: payment.instructions, locale: loc }) : null,
|
|
2778
|
+
!isBank ? /* @__PURE__ */ jsxs("div", { children: [
|
|
2779
|
+
/* @__PURE__ */ jsx(Button, { onClick: () => void pay(), busy, children: t("payment.payNow") }),
|
|
2780
|
+
isGateway ? /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)", marginTop: "0.6rem" }, children: t("checkout.gatewayRedirectNote") }) : null
|
|
2781
|
+
] }) : null,
|
|
2782
|
+
error ? /* @__PURE__ */ jsx("p", { role: "alert", style: { margin: 0, color: "var(--nv-danger, #b3261e)" }, children: t("payment.actionError") }) : null,
|
|
2783
|
+
statusHref ? /* @__PURE__ */ jsx(Link, { href: statusHref, children: t("order.trackOrder") }) : null
|
|
2784
|
+
] });
|
|
2785
|
+
}
|
|
2786
|
+
function Shell2({
|
|
2787
|
+
title,
|
|
2788
|
+
children
|
|
2789
|
+
}) {
|
|
2790
|
+
return /* @__PURE__ */ jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "1rem", maxWidth: "34rem" }, children: [
|
|
2791
|
+
title ? /* @__PURE__ */ jsx("h1", { style: { margin: 0, fontSize: "1.25rem", fontWeight: 600 }, children: title }) : null,
|
|
2792
|
+
children
|
|
2793
|
+
] });
|
|
2794
|
+
}
|
|
2795
|
+
function Amount({ label, value }) {
|
|
2796
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "baseline" }, children: [
|
|
2797
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--nv-muted)" }, children: label }),
|
|
2798
|
+
/* @__PURE__ */ jsx("strong", { style: { fontSize: "1.35rem", fontVariantNumeric: "tabular-nums" }, children: value })
|
|
2799
|
+
] });
|
|
2800
|
+
}
|
|
2801
|
+
function Link({ href, children }) {
|
|
2802
|
+
return /* @__PURE__ */ jsx("a", { href, style: { color: "var(--nv-brand)", fontSize: "0.875rem" }, children });
|
|
2803
|
+
}
|
|
2375
2804
|
var AccountContext = React10.createContext(null);
|
|
2376
2805
|
function AccountProvider({ children }) {
|
|
2377
2806
|
const client = useStorefront();
|
|
@@ -2974,6 +3403,6 @@ function OrganizationJsonLd({
|
|
|
2974
3403
|
return /* @__PURE__ */ jsx(JsonLd, { data });
|
|
2975
3404
|
}
|
|
2976
3405
|
|
|
2977
|
-
export { AccountDashboard, AccountProvider, AddToCart, AddressBook, AddressForm, AvailabilityFilter, BackInStockForm, BreadcrumbJsonLd, CartDrawer, CartLineItem, CartProvider, CartSummary, CheckoutFlow, CheckoutProvider, CollectionPage, I18nProvider, JsonLd, LoginForm, MarketSwitcher, NeviosProvider, OrderConfirmation, OrderHistory, OrderStatusPage, OrderSummary, OrganizationJsonLd, PaymentSection, PriceMoney, PriceRangeFilter, ProductCard, ProductDetailPage, ProductGallery, ProductJsonLd, ProfileEditor, ShippingPicker, SortSelect, StockBadge, TagFilter, ThemeProvider, VariantPicker, absoluteUrl, bundledMessages, cs, en, formatCents, formatMoney, serializeJsonLd, stripHtml, themeToCssVars, useAccount, useCart, useCheckout, useI18n, useMagicLinkVerify, useOrderStatus, useStorefront, useStorefrontOptional, useT };
|
|
3406
|
+
export { AccountDashboard, AccountProvider, AddToCart, AddressBook, AddressForm, AvailabilityFilter, BackInStockForm, BreadcrumbJsonLd, CartDrawer, CartLineItem, CartProvider, CartSummary, CheckoutFlow, CheckoutProvider, CollectionPage, I18nProvider, JsonLd, LoginForm, MarketSwitcher, NeviosProvider, OrderConfirmation, OrderHistory, OrderLines, OrderStatusPage, OrderSummary, OrderTotals, OrganizationJsonLd, PaymentMethodPicker, PaymentPage, PaymentSection, PhaseTimeline, PriceMoney, PriceRangeFilter, ProductCard, ProductDetailPage, ProductGallery, ProductJsonLd, ProfileEditor, ShippingPicker, SortSelect, StatusBanner, StockBadge, TagFilter, ThemeProvider, TransferInstructions, VariantPicker, absoluteUrl, bundledMessages, cs, en, formatCents, formatMoney, isTerminal, serializeJsonLd, stripHtml, themeToCssVars, useAccount, useCart, useCheckout, useI18n, useMagicLinkVerify, useOrderStatus, usePayment, useStorefront, useStorefrontOptional, useT };
|
|
2978
3407
|
//# sourceMappingURL=index.js.map
|
|
2979
3408
|
//# sourceMappingURL=index.js.map
|