@nevios/storefront-kit 1.2.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/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React10 = require('react');
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 React10__namespace = /*#__PURE__*/_interopNamespace(React10);
25
+ var React19__namespace = /*#__PURE__*/_interopNamespace(React19);
26
26
 
27
27
  // src/provider.tsx
28
- var StorefrontContext = React10__namespace.createContext(null);
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 = React10__namespace.useContext(StorefrontContext);
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 React10__namespace.useContext(StorefrontContext);
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 React10__namespace.createElement(
78
+ return React19__namespace.createElement(
79
79
  Tag,
80
80
  { "data-nevios-theme": "", style },
81
81
  children
@@ -248,6 +248,20 @@ var en = {
248
248
  "account.signOut": "Sign out",
249
249
  "account.greeting": "Signed in as {email}",
250
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",
251
265
  "account.noOrders": "No orders yet.",
252
266
  "account.addresses": "Saved addresses",
253
267
  "account.noAddresses": "No saved addresses yet.",
@@ -429,6 +443,20 @@ var cs = {
429
443
  "account.signOut": "Odhl\xE1sit se",
430
444
  "account.greeting": "P\u0159ihl\xE1\u0161en jako {email}",
431
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",
432
460
  "account.noOrders": "Zat\xEDm \u017E\xE1dn\xE9 objedn\xE1vky.",
433
461
  "account.addresses": "Ulo\u017Een\xE9 adresy",
434
462
  "account.noAddresses": "Zat\xEDm \u017E\xE1dn\xE9 ulo\u017Een\xE9 adresy.",
@@ -513,13 +541,13 @@ function makeI18n(locale, messages) {
513
541
  return { locale, messages, t };
514
542
  }
515
543
  var DEFAULT_I18N = makeI18n("en", en);
516
- var I18nContext = React10__namespace.createContext(null);
544
+ var I18nContext = React19__namespace.createContext(null);
517
545
  function I18nProvider({
518
546
  locale,
519
547
  messages,
520
548
  children
521
549
  }) {
522
- const value = React10__namespace.useMemo(() => {
550
+ const value = React19__namespace.useMemo(() => {
523
551
  const lang = langOf(locale);
524
552
  if (locale && !(lang in BUNDLED) && !messages) {
525
553
  devWarn(
@@ -533,7 +561,7 @@ function I18nProvider({
533
561
  return /* @__PURE__ */ jsxRuntime.jsx(I18nContext.Provider, { value, children });
534
562
  }
535
563
  function useI18n() {
536
- return React10__namespace.useContext(I18nContext) ?? DEFAULT_I18N;
564
+ return React19__namespace.useContext(I18nContext) ?? DEFAULT_I18N;
537
565
  }
538
566
  function useT() {
539
567
  return useI18n().t;
@@ -657,7 +685,7 @@ function ProductCard({ product, href, locale }) {
657
685
  var MAIN_WIDTHS = [600, 800, 1e3];
658
686
  var THUMB_WIDTHS = [56, 112];
659
687
  function ProductGallery({ media, alt }) {
660
- const [active, setActive] = React10__namespace.useState(0);
688
+ const [active, setActive] = React19__namespace.useState(0);
661
689
  const imageBase = useStorefrontOptional()?.imageBase;
662
690
  if (media.length === 0) {
663
691
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -745,10 +773,10 @@ function matchVariant(product, selected) {
745
773
  ) ?? null;
746
774
  }
747
775
  function VariantPicker({ product, onChange }) {
748
- const [selected, setSelected] = React10__namespace.useState(
776
+ const [selected, setSelected] = React19__namespace.useState(
749
777
  () => product.variants[0]?.options ?? []
750
778
  );
751
- React10__namespace.useEffect(() => {
779
+ React19__namespace.useEffect(() => {
752
780
  onChange?.(matchVariant(product, selected));
753
781
  }, [product, selected]);
754
782
  if (product.options.length === 0) return null;
@@ -789,8 +817,8 @@ function BackInStockForm({
789
817
  }) {
790
818
  const t = useT();
791
819
  const client = useStorefront();
792
- const [email, setEmail] = React10__namespace.useState(defaultEmail);
793
- const [state, setState] = React10__namespace.useState("idle");
820
+ const [email, setEmail] = React19__namespace.useState(defaultEmail);
821
+ const [state, setState] = React19__namespace.useState("idle");
794
822
  if (!variant || variant.availability?.status !== "out_of_stock") return null;
795
823
  async function submit(e) {
796
824
  e.preventDefault();
@@ -890,7 +918,7 @@ function ProductDetailPage({
890
918
  locale,
891
919
  addToCart
892
920
  }) {
893
- const [variant, setVariant] = React10__namespace.useState(
921
+ const [variant, setVariant] = React19__namespace.useState(
894
922
  product.variants[0] ?? null
895
923
  );
896
924
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1122,12 +1150,12 @@ function TagFilter({ tags, selected = [], onChange }) {
1122
1150
  }) })
1123
1151
  ] });
1124
1152
  }
1125
- var CartContext = React10__namespace.createContext(null);
1153
+ var CartContext = React19__namespace.createContext(null);
1126
1154
  function CartProvider({ children }) {
1127
1155
  const client = useStorefront();
1128
- const [cart, setCart] = React10__namespace.useState(null);
1129
- const [loading, setLoading] = React10__namespace.useState(false);
1130
- const run = React10__namespace.useCallback(
1156
+ const [cart, setCart] = React19__namespace.useState(null);
1157
+ const [loading, setLoading] = React19__namespace.useState(false);
1158
+ const run = React19__namespace.useCallback(
1131
1159
  async (op) => {
1132
1160
  setLoading(true);
1133
1161
  try {
@@ -1140,7 +1168,7 @@ function CartProvider({ children }) {
1140
1168
  },
1141
1169
  []
1142
1170
  );
1143
- const refresh = React10__namespace.useCallback(async () => {
1171
+ const refresh = React19__namespace.useCallback(async () => {
1144
1172
  setLoading(true);
1145
1173
  try {
1146
1174
  setCart(await client.cart.get());
@@ -1148,10 +1176,10 @@ function CartProvider({ children }) {
1148
1176
  setLoading(false);
1149
1177
  }
1150
1178
  }, [client]);
1151
- React10__namespace.useEffect(() => {
1179
+ React19__namespace.useEffect(() => {
1152
1180
  void refresh();
1153
1181
  }, [refresh]);
1154
- const value = React10__namespace.useMemo(
1182
+ const value = React19__namespace.useMemo(
1155
1183
  () => ({
1156
1184
  cart,
1157
1185
  loading,
@@ -1166,7 +1194,7 @@ function CartProvider({ children }) {
1166
1194
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
1167
1195
  }
1168
1196
  function useCart() {
1169
- const ctx = React10__namespace.useContext(CartContext);
1197
+ const ctx = React19__namespace.useContext(CartContext);
1170
1198
  if (!ctx) {
1171
1199
  throw new Error("useCart must be used inside <CartProvider>.");
1172
1200
  }
@@ -1180,8 +1208,8 @@ function AddToCart({
1180
1208
  }) {
1181
1209
  const t = useT();
1182
1210
  const { addLine } = useCart();
1183
- const [busy, setBusy] = React10__namespace.useState(false);
1184
- const [error, setError] = React10__namespace.useState(null);
1211
+ const [busy, setBusy] = React19__namespace.useState(false);
1212
+ const [error, setError] = React19__namespace.useState(null);
1185
1213
  const disabled = variant == null || busy;
1186
1214
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
1187
1215
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1457,15 +1485,15 @@ function CartDrawer({
1457
1485
  }
1458
1486
  );
1459
1487
  }
1460
- var CheckoutContext = React10__namespace.createContext(null);
1488
+ var CheckoutContext = React19__namespace.createContext(null);
1461
1489
  function CheckoutProvider({
1462
1490
  children
1463
1491
  }) {
1464
1492
  const client = useStorefront();
1465
- const [checkout, setCheckout] = React10__namespace.useState(null);
1466
- const [loading, setLoading] = React10__namespace.useState(false);
1467
- const [error, setError] = React10__namespace.useState(null);
1468
- const run = React10__namespace.useCallback(
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(
1469
1497
  async (op, store) => {
1470
1498
  setLoading(true);
1471
1499
  try {
@@ -1483,7 +1511,7 @@ function CheckoutProvider({
1483
1511
  },
1484
1512
  []
1485
1513
  );
1486
- const refresh = React10__namespace.useCallback(async () => {
1514
+ const refresh = React19__namespace.useCallback(async () => {
1487
1515
  setLoading(true);
1488
1516
  try {
1489
1517
  setCheckout(await client.checkout.get());
@@ -1492,10 +1520,10 @@ function CheckoutProvider({
1492
1520
  setLoading(false);
1493
1521
  }
1494
1522
  }, [client]);
1495
- React10__namespace.useEffect(() => {
1523
+ React19__namespace.useEffect(() => {
1496
1524
  void refresh();
1497
1525
  }, [refresh]);
1498
- const pay = React10__namespace.useCallback(
1526
+ const pay = React19__namespace.useCallback(
1499
1527
  async (opts = {}) => {
1500
1528
  const co = checkout;
1501
1529
  if (!co) throw new Error("pay() called before a checkout exists");
@@ -1518,7 +1546,7 @@ function CheckoutProvider({
1518
1546
  },
1519
1547
  [checkout, client, run]
1520
1548
  );
1521
- const value = React10__namespace.useMemo(
1549
+ const value = React19__namespace.useMemo(
1522
1550
  () => ({
1523
1551
  checkout,
1524
1552
  loading,
@@ -1543,7 +1571,7 @@ function CheckoutProvider({
1543
1571
  return /* @__PURE__ */ jsxRuntime.jsx(CheckoutContext.Provider, { value, children });
1544
1572
  }
1545
1573
  function useCheckout() {
1546
- const ctx = React10__namespace.useContext(CheckoutContext);
1574
+ const ctx = React19__namespace.useContext(CheckoutContext);
1547
1575
  if (!ctx) {
1548
1576
  throw new Error("useCheckout must be used inside <CheckoutProvider>.");
1549
1577
  }
@@ -1702,10 +1730,25 @@ function AddressForm({
1702
1730
  }) {
1703
1731
  const t = useT();
1704
1732
  const { checkout, setAddress, loading } = useCheckout();
1705
- const [form, setForm] = React10__namespace.useState(
1733
+ const [form, setForm] = React19__namespace.useState(
1706
1734
  () => seed(checkout?.email ?? null, checkout?.shipping_address ?? null)
1707
1735
  );
1708
- const set = (key) => (e) => setForm((f) => ({ ...f, [key]: e.target.value }));
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
+ };
1709
1752
  async function submit(e) {
1710
1753
  e.preventDefault();
1711
1754
  const { email, ...rest } = form;
@@ -1756,11 +1799,11 @@ function ShippingPicker({
1756
1799
  const loc = useFormatLocale(locale);
1757
1800
  const { checkout, shippingQuotes, setShippingMethod, loading } = useCheckout();
1758
1801
  const heading = title ?? t("checkout.shippingMethod");
1759
- const [quotes, setQuotes] = React10__namespace.useState(null);
1760
- const [selected, setSelected] = React10__namespace.useState(null);
1761
- const [fetching, setFetching] = React10__namespace.useState(true);
1802
+ const [quotes, setQuotes] = React19__namespace.useState(null);
1803
+ const [selected, setSelected] = React19__namespace.useState(null);
1804
+ const [fetching, setFetching] = React19__namespace.useState(true);
1762
1805
  const addressKey = checkout?.shipping_address ? `${checkout.shipping_address.country_code}:${checkout.shipping_address.postal_code}` : null;
1763
- React10__namespace.useEffect(() => {
1806
+ React19__namespace.useEffect(() => {
1764
1807
  let live = true;
1765
1808
  setFetching(true);
1766
1809
  shippingQuotes().then((qs) => {
@@ -1788,17 +1831,13 @@ function ShippingPicker({
1788
1831
  }
1789
1832
  return /* @__PURE__ */ jsxRuntime.jsxs(Section, { title: heading, children: [
1790
1833
  /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", style: { display: "flex", flexDirection: "column", gap: "0.6rem" }, children: quotes.map((q) => {
1791
- const days = estDays(q, t);
1792
1834
  return /* @__PURE__ */ jsxRuntime.jsx(
1793
1835
  SelectRow,
1794
1836
  {
1795
1837
  selected: selected === q.rate_id,
1796
1838
  onSelect: () => setSelected(q.rate_id),
1797
1839
  trailing: q.is_free ? t("common.free") : formatCents(q.price_cents, q.currency, loc),
1798
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", flexDirection: "column" }, children: [
1799
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: q.label }),
1800
- days ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: days }) : null
1801
- ] })
1840
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: q.label }) })
1802
1841
  },
1803
1842
  q.rate_id
1804
1843
  );
@@ -1806,15 +1845,6 @@ function ShippingPicker({
1806
1845
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: submit, busy: loading, disabled: selected == null, children: submitLabel ?? t("checkout.continueToPayment") }) })
1807
1846
  ] });
1808
1847
  }
1809
- function estDays(q, t) {
1810
- const { estimated_days_min: lo, estimated_days_max: hi } = q;
1811
- if (lo == null && hi == null) return null;
1812
- if (lo != null && hi != null) {
1813
- return lo === hi ? t("shipping.days", { count: lo }) : t("shipping.daysRange", { min: lo, max: hi });
1814
- }
1815
- const n = lo ?? hi;
1816
- return t("shipping.days", { count: n });
1817
- }
1818
1848
  function PaymentMethodPicker({
1819
1849
  methods,
1820
1850
  value,
@@ -1858,10 +1888,10 @@ function PaymentSection({
1858
1888
  const t = useT();
1859
1889
  const heading = title ?? t("checkout.payment");
1860
1890
  const { checkout, paymentMethods, setPaymentMethod, pay, loading } = useCheckout();
1861
- const [methods, setMethods] = React10__namespace.useState(null);
1862
- const [fetching, setFetching] = React10__namespace.useState(true);
1891
+ const [methods, setMethods] = React19__namespace.useState(null);
1892
+ const [fetching, setFetching] = React19__namespace.useState(true);
1863
1893
  const selected = checkout?.payment_method ?? null;
1864
- React10__namespace.useEffect(() => {
1894
+ React19__namespace.useEffect(() => {
1865
1895
  let live = true;
1866
1896
  setFetching(true);
1867
1897
  paymentMethods().then((ms) => {
@@ -1998,16 +2028,16 @@ function CheckoutFlow({
1998
2028
  }) {
1999
2029
  const t = useT();
2000
2030
  const { checkout, loading, create } = useCheckout();
2001
- const [step, setStep] = React10__namespace.useState("address");
2002
- const [bootstrapped, setBootstrapped] = React10__namespace.useState(false);
2003
- React10__namespace.useEffect(() => {
2031
+ const [step, setStep] = React19__namespace.useState("address");
2032
+ const [bootstrapped, setBootstrapped] = React19__namespace.useState(false);
2033
+ React19__namespace.useEffect(() => {
2004
2034
  if (checkout || !cartToken || bootstrapped) return;
2005
2035
  setBootstrapped(true);
2006
2036
  void create(cartToken).catch(() => {
2007
2037
  });
2008
2038
  }, [checkout, cartToken, bootstrapped, create]);
2009
2039
  const serverStep = reachedStep(checkout);
2010
- React10__namespace.useEffect(() => {
2040
+ React19__namespace.useEffect(() => {
2011
2041
  setStep((cur) => rank(serverStep) > rank(cur) ? serverStep : cur);
2012
2042
  }, [serverStep]);
2013
2043
  if (checkout?.order_id) {
@@ -2128,10 +2158,10 @@ function DefaultConfirmation({ checkout }) {
2128
2158
  }
2129
2159
  function useOrderStatus(statusToken, initial) {
2130
2160
  const client = useStorefront();
2131
- const [order, setOrder] = React10__namespace.useState(initial ?? null);
2132
- const [loading, setLoading] = React10__namespace.useState(false);
2133
- const [error, setError] = React10__namespace.useState(null);
2134
- const load = React10__namespace.useCallback(async () => {
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 () => {
2135
2165
  if (!statusToken) return;
2136
2166
  setLoading(true);
2137
2167
  try {
@@ -2143,7 +2173,7 @@ function useOrderStatus(statusToken, initial) {
2143
2173
  setLoading(false);
2144
2174
  }
2145
2175
  }, [client, statusToken]);
2146
- React10__namespace.useEffect(() => {
2176
+ React19__namespace.useEffect(() => {
2147
2177
  if (initial) return;
2148
2178
  void load();
2149
2179
  }, [load, initial]);
@@ -2151,12 +2181,12 @@ function useOrderStatus(statusToken, initial) {
2151
2181
  }
2152
2182
  function usePayment(token, initial) {
2153
2183
  const client = useStorefront();
2154
- const [payment, setPayment] = React10__namespace.useState(initial ?? null);
2155
- const [methods, setMethods] = React10__namespace.useState([]);
2156
- const [loading, setLoading] = React10__namespace.useState(false);
2157
- const [busy, setBusy] = React10__namespace.useState(false);
2158
- const [error, setError] = React10__namespace.useState(null);
2159
- const load = React10__namespace.useCallback(async () => {
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 () => {
2160
2190
  if (!token) return;
2161
2191
  setLoading(true);
2162
2192
  try {
@@ -2173,7 +2203,7 @@ function usePayment(token, initial) {
2173
2203
  setLoading(false);
2174
2204
  }
2175
2205
  }, [client, token]);
2176
- React10__namespace.useEffect(() => {
2206
+ React19__namespace.useEffect(() => {
2177
2207
  if (!token) return;
2178
2208
  if (initial && initial.token === token) {
2179
2209
  setPayment(initial);
@@ -2182,7 +2212,7 @@ function usePayment(token, initial) {
2182
2212
  }
2183
2213
  void load();
2184
2214
  }, [token, load]);
2185
- const selectMethod = React10__namespace.useCallback(
2215
+ const selectMethod = React19__namespace.useCallback(
2186
2216
  async (method) => {
2187
2217
  if (!token) return null;
2188
2218
  setBusy(true);
@@ -2200,7 +2230,7 @@ function usePayment(token, initial) {
2200
2230
  },
2201
2231
  [client, token]
2202
2232
  );
2203
- const startPayment = React10__namespace.useCallback(
2233
+ const startPayment = React19__namespace.useCallback(
2204
2234
  async (input) => {
2205
2235
  if (!token) return null;
2206
2236
  setBusy(true);
@@ -2637,8 +2667,8 @@ function Row4({
2637
2667
  }
2638
2668
  function CopyRow({ label, value }) {
2639
2669
  const t = useT();
2640
- const [copied, setCopied] = React10__namespace.useState(false);
2641
- React10__namespace.useEffect(() => {
2670
+ const [copied, setCopied] = React19__namespace.useState(false);
2671
+ React19__namespace.useEffect(() => {
2642
2672
  if (!copied) return;
2643
2673
  const id = setTimeout(() => setCopied(false), 1800);
2644
2674
  return () => clearTimeout(id);
@@ -2722,12 +2752,12 @@ function PaymentPage({
2722
2752
  const t = useT();
2723
2753
  const loc = useFormatLocale(locale);
2724
2754
  const { payment, methods, loading, busy, error, reload, selectMethod, startPayment } = usePayment(token, initial);
2725
- const [verifying, setVerifying] = React10__namespace.useState(false);
2726
- React10__namespace.useEffect(() => {
2755
+ const [verifying, setVerifying] = React19__namespace.useState(false);
2756
+ React19__namespace.useEffect(() => {
2727
2757
  if (token) setVerifying(consumeHandoff(token));
2728
2758
  }, [token]);
2729
2759
  const settled = payment != null && !payment.can_pay && payment.blocked_reason === "already_paid";
2730
- React10__namespace.useEffect(() => {
2760
+ React19__namespace.useEffect(() => {
2731
2761
  if (!verifying || !token || settled) return;
2732
2762
  let attempts = 0;
2733
2763
  const id = setInterval(() => {
@@ -2742,7 +2772,7 @@ function PaymentPage({
2742
2772
  }, POLL_MS);
2743
2773
  return () => clearInterval(id);
2744
2774
  }, [verifying, token, settled, reload]);
2745
- React10__namespace.useEffect(() => {
2775
+ React19__namespace.useEffect(() => {
2746
2776
  if (!settled || !token || !payment) return;
2747
2777
  setVerifying(false);
2748
2778
  forgetHandoff(token);
@@ -2823,27 +2853,32 @@ function Amount({ label, value }) {
2823
2853
  function Link({ href, children }) {
2824
2854
  return /* @__PURE__ */ jsxRuntime.jsx("a", { href, style: { color: "var(--nv-brand)", fontSize: "0.875rem" }, children });
2825
2855
  }
2826
- var AccountContext = React10__namespace.createContext(null);
2856
+ var AccountContext = React19__namespace.createContext(null);
2827
2857
  function AccountProvider({ children }) {
2828
2858
  const client = useStorefront();
2829
- const [customer, setCustomer] = React10__namespace.useState(null);
2830
- const [loading, setLoading] = React10__namespace.useState(true);
2831
- const refresh = React10__namespace.useCallback(async () => {
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 () => {
2832
2863
  setLoading(true);
2864
+ setError(false);
2833
2865
  try {
2834
2866
  setCustomer(await client.account.me());
2867
+ } catch {
2868
+ setError(true);
2835
2869
  } finally {
2836
2870
  setLoading(false);
2837
2871
  }
2838
2872
  }, [client]);
2839
- React10__namespace.useEffect(() => {
2873
+ React19__namespace.useEffect(() => {
2840
2874
  void refresh();
2841
2875
  }, [refresh]);
2842
- const value = React10__namespace.useMemo(
2876
+ const value = React19__namespace.useMemo(
2843
2877
  () => ({
2844
2878
  customer,
2845
2879
  signedIn: customer != null,
2846
2880
  loading,
2881
+ error,
2847
2882
  requestMagicLink: (email) => client.account.requestMagicLink(email),
2848
2883
  verify: async (token) => {
2849
2884
  const c = await client.account.verify(token);
@@ -2856,12 +2891,12 @@ function AccountProvider({ children }) {
2856
2891
  },
2857
2892
  refresh
2858
2893
  }),
2859
- [customer, loading, client, refresh]
2894
+ [customer, loading, error, client, refresh]
2860
2895
  );
2861
2896
  return /* @__PURE__ */ jsxRuntime.jsx(AccountContext.Provider, { value, children });
2862
2897
  }
2863
2898
  function useAccount() {
2864
- const ctx = React10__namespace.useContext(AccountContext);
2899
+ const ctx = React19__namespace.useContext(AccountContext);
2865
2900
  if (!ctx) {
2866
2901
  throw new Error("useAccount must be used inside <AccountProvider>.");
2867
2902
  }
@@ -2869,9 +2904,9 @@ function useAccount() {
2869
2904
  }
2870
2905
  function useMagicLinkVerify(token) {
2871
2906
  const { verify } = useAccount();
2872
- const [status, setStatus] = React10__namespace.useState("idle");
2873
- const done = React10__namespace.useRef(false);
2874
- React10__namespace.useEffect(() => {
2907
+ const [status, setStatus] = React19__namespace.useState("idle");
2908
+ const done = React19__namespace.useRef(false);
2909
+ React19__namespace.useEffect(() => {
2875
2910
  if (!token || done.current) return;
2876
2911
  done.current = true;
2877
2912
  setStatus("verifying");
@@ -2882,18 +2917,22 @@ function useMagicLinkVerify(token) {
2882
2917
  function LoginForm({ verifyPath = "/account/verify", onSent }) {
2883
2918
  const t = useT();
2884
2919
  const { requestMagicLink } = useAccount();
2885
- const [email, setEmail] = React10__namespace.useState("");
2886
- const [busy, setBusy] = React10__namespace.useState(false);
2887
- const [sent, setSent] = React10__namespace.useState(false);
2888
- const [devLink, setDevLink] = React10__namespace.useState(null);
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);
2889
2925
  async function submit(e) {
2890
2926
  e.preventDefault();
2891
2927
  setBusy(true);
2928
+ setError(false);
2892
2929
  try {
2893
2930
  const r = await requestMagicLink(email);
2894
2931
  setSent(true);
2895
2932
  if (r.devToken) setDevLink(`${verifyPath}?token=${encodeURIComponent(r.devToken)}`);
2896
2933
  onSent?.(email);
2934
+ } catch {
2935
+ setError(true);
2897
2936
  } finally {
2898
2937
  setBusy(false);
2899
2938
  }
@@ -2932,6 +2971,7 @@ function LoginForm({ verifyPath = "/account/verify", onSent }) {
2932
2971
  }
2933
2972
  )
2934
2973
  ] }),
2974
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: t("account.signInError") }) : null,
2935
2975
  /* @__PURE__ */ jsxRuntime.jsx(
2936
2976
  "button",
2937
2977
  {
@@ -2993,20 +3033,47 @@ function OrderHistory({
2993
3033
  const loc = useFormatLocale(locale);
2994
3034
  const { signedIn } = useAccount();
2995
3035
  const client = useStorefront();
2996
- const [orders, setOrders] = React10__namespace.useState(null);
2997
- const [reordering, setReordering] = React10__namespace.useState(null);
2998
- const [notice, setNotice] = React10__namespace.useState(null);
2999
- React10__namespace.useEffect(() => {
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(() => {
3000
3044
  let live = true;
3001
3045
  if (!signedIn) {
3002
3046
  setOrders([]);
3003
3047
  return;
3004
3048
  }
3005
- client.account.orders().then((o) => live && setOrders(o)).catch(() => live && setOrders([]));
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
+ });
3006
3059
  return () => {
3007
3060
  live = false;
3008
3061
  };
3009
- }, [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
+ }
3010
3077
  async function reorder(statusToken) {
3011
3078
  setReordering(statusToken);
3012
3079
  setNotice(null);
@@ -3027,7 +3094,11 @@ function OrderHistory({
3027
3094
  }
3028
3095
  return /* @__PURE__ */ jsxRuntime.jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
3029
3096
  /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.1rem", fontWeight: 600 }, children: t("account.orders") }),
3030
- orders == 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(
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(
3031
3102
  "li",
3032
3103
  {
3033
3104
  style: {
@@ -3074,12 +3145,13 @@ function OrderHistory({
3074
3145
  ]
3075
3146
  },
3076
3147
  o.status_token
3077
- )) })
3148
+ )) }),
3149
+ nextCursor ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", disabled: pageLoading, onClick: () => void loadMore(), children: pageLoading ? t("common.loadingShort") : t("account.loadMore") }) : null
3078
3150
  ] });
3079
3151
  }
3080
3152
  function AddressForm2({ initial, onSubmit, onCancel, busy }) {
3081
3153
  const t = useT();
3082
- const [form, setForm] = React10__namespace.useState(() => ({
3154
+ const [form, setForm] = React19__namespace.useState(() => ({
3083
3155
  first_name: initial?.first_name ?? "",
3084
3156
  last_name: initial?.last_name ?? "",
3085
3157
  company: initial?.company ?? "",
@@ -3177,17 +3249,17 @@ function AddressBook() {
3177
3249
  const t = useT();
3178
3250
  const { signedIn } = useAccount();
3179
3251
  const client = useStorefront();
3180
- const [addresses, setAddresses] = React10__namespace.useState(null);
3181
- const [mode, setMode] = React10__namespace.useState({ kind: "list" });
3182
- const [busy, setBusy] = React10__namespace.useState(false);
3183
- const load = React10__namespace.useCallback(() => {
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(() => {
3184
3256
  if (!signedIn) {
3185
3257
  setAddresses([]);
3186
3258
  return;
3187
3259
  }
3188
3260
  client.account.addresses().then(setAddresses).catch(() => setAddresses([]));
3189
3261
  }, [signedIn, client]);
3190
- React10__namespace.useEffect(() => {
3262
+ React19__namespace.useEffect(() => {
3191
3263
  load();
3192
3264
  }, [load]);
3193
3265
  async function run(fn) {
@@ -3241,10 +3313,10 @@ function ProfileEditor() {
3241
3313
  const t = useT();
3242
3314
  const client = useStorefront();
3243
3315
  const { customer, refresh } = useAccount();
3244
- const [editing, setEditing] = React10__namespace.useState(false);
3245
- const [busy, setBusy] = React10__namespace.useState(false);
3246
- const [error, setError] = React10__namespace.useState(false);
3247
- const [form, setForm] = React10__namespace.useState({});
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({});
3248
3320
  if (!customer) return null;
3249
3321
  function startEdit() {
3250
3322
  setForm({
@@ -3321,6 +3393,79 @@ function ProfileEditor() {
3321
3393
  ] })
3322
3394
  ] });
3323
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
+ }
3324
3469
  function serializeJsonLd(data) {
3325
3470
  return JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
3326
3471
  }
@@ -3427,6 +3572,7 @@ function OrganizationJsonLd({
3427
3572
 
3428
3573
  exports.AccountDashboard = AccountDashboard;
3429
3574
  exports.AccountProvider = AccountProvider;
3575
+ exports.AccountSecurity = AccountSecurity;
3430
3576
  exports.AddToCart = AddToCart;
3431
3577
  exports.AddressBook = AddressBook;
3432
3578
  exports.AddressForm = AddressForm;