@nevios/storefront-kit 1.3.0 → 1.4.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.js CHANGED
@@ -1,14 +1,14 @@
1
- import * as React19 from 'react';
1
+ import * as React27 from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { imageSrcSet, StorefrontError } from '@nevios/storefront-js';
4
4
 
5
5
  // src/provider.tsx
6
- var StorefrontContext = React19.createContext(null);
6
+ var StorefrontContext = React27.createContext(null);
7
7
  function NeviosProvider({ client, children }) {
8
8
  return /* @__PURE__ */ jsx(StorefrontContext.Provider, { value: client, children });
9
9
  }
10
10
  function useStorefront() {
11
- const client = React19.useContext(StorefrontContext);
11
+ const client = React27.useContext(StorefrontContext);
12
12
  if (!client) {
13
13
  throw new Error(
14
14
  "useStorefront must be used inside <NeviosProvider>. Wrap your app root with it."
@@ -17,7 +17,7 @@ function useStorefront() {
17
17
  return client;
18
18
  }
19
19
  function useStorefrontOptional() {
20
- return React19.useContext(StorefrontContext);
20
+ return React27.useContext(StorefrontContext);
21
21
  }
22
22
  var DEFAULTS = {
23
23
  brand: "#111111",
@@ -53,7 +53,7 @@ function ThemeProvider({
53
53
  as: Tag = "div"
54
54
  }) {
55
55
  const style = themeToCssVars(theme);
56
- return React19.createElement(
56
+ return React27.createElement(
57
57
  Tag,
58
58
  { "data-nevios-theme": "", style },
59
59
  children
@@ -62,6 +62,16 @@ function ThemeProvider({
62
62
 
63
63
  // src/i18n/en.ts
64
64
  var en = {
65
+ "subscriptions.purchaseOption": "Purchase option",
66
+ "subscriptions.empty": "You have no subscriptions yet.",
67
+ "subscriptions.status.active": "Active",
68
+ "subscriptions.status.paused": "Paused",
69
+ "subscriptions.status.pending": "Awaiting payment",
70
+ "subscriptions.status.cancelled": "Cancelled",
71
+ "subscriptions.title": "Subscription",
72
+ "subscriptions.consent": "I agree to the recurring price, delivery schedule and terms shown above.",
73
+ "subscriptions.eachDelivery": "For each delivery",
74
+ "subscriptions.once": "One-time purchase",
65
75
  // common
66
76
  "common.free": "Free",
67
77
  "common.close": "Close",
@@ -278,6 +288,16 @@ var en = {
278
288
 
279
289
  // src/i18n/cs.ts
280
290
  var cs = {
291
+ "subscriptions.purchaseOption": "Zp\u016Fsob n\xE1kupu",
292
+ "subscriptions.empty": "Zat\xEDm nem\xE1te \u017E\xE1dn\xE9 p\u0159edplatn\xE9.",
293
+ "subscriptions.status.active": "Aktivn\xED",
294
+ "subscriptions.status.paused": "Pozastaveno",
295
+ "subscriptions.status.pending": "\u010Cek\xE1 na platbu",
296
+ "subscriptions.status.cancelled": "Zru\u0161eno",
297
+ "subscriptions.title": "P\u0159edplatn\xE9",
298
+ "subscriptions.consent": "Souhlas\xEDm s uvedenou opakovanou cenou, pl\xE1nem doru\u010Den\xED a podm\xEDnkami.",
299
+ "subscriptions.eachDelivery": "Za ka\u017Ed\xE9 doru\u010Den\xED",
300
+ "subscriptions.once": "Jednor\xE1zov\xFD n\xE1kup",
281
301
  "common.free": "Zdarma",
282
302
  "common.close": "Zav\u0159\xEDt",
283
303
  "common.loadingShort": "\u2026",
@@ -519,13 +539,13 @@ function makeI18n(locale, messages) {
519
539
  return { locale, messages, t };
520
540
  }
521
541
  var DEFAULT_I18N = makeI18n("en", en);
522
- var I18nContext = React19.createContext(null);
542
+ var I18nContext = React27.createContext(null);
523
543
  function I18nProvider({
524
544
  locale,
525
545
  messages,
526
546
  children
527
547
  }) {
528
- const value = React19.useMemo(() => {
548
+ const value = React27.useMemo(() => {
529
549
  const lang = langOf(locale);
530
550
  if (locale && !(lang in BUNDLED) && !messages) {
531
551
  devWarn(
@@ -539,7 +559,7 @@ function I18nProvider({
539
559
  return /* @__PURE__ */ jsx(I18nContext.Provider, { value, children });
540
560
  }
541
561
  function useI18n() {
542
- return React19.useContext(I18nContext) ?? DEFAULT_I18N;
562
+ return React27.useContext(I18nContext) ?? DEFAULT_I18N;
543
563
  }
544
564
  function useT() {
545
565
  return useI18n().t;
@@ -663,7 +683,7 @@ function ProductCard({ product, href, locale }) {
663
683
  var MAIN_WIDTHS = [600, 800, 1e3];
664
684
  var THUMB_WIDTHS = [56, 112];
665
685
  function ProductGallery({ media, alt }) {
666
- const [active, setActive] = React19.useState(0);
686
+ const [active, setActive] = React27.useState(0);
667
687
  const imageBase = useStorefrontOptional()?.imageBase;
668
688
  if (media.length === 0) {
669
689
  return /* @__PURE__ */ jsx(
@@ -751,10 +771,10 @@ function matchVariant(product, selected) {
751
771
  ) ?? null;
752
772
  }
753
773
  function VariantPicker({ product, onChange }) {
754
- const [selected, setSelected] = React19.useState(
774
+ const [selected, setSelected] = React27.useState(
755
775
  () => product.variants[0]?.options ?? []
756
776
  );
757
- React19.useEffect(() => {
777
+ React27.useEffect(() => {
758
778
  onChange?.(matchVariant(product, selected));
759
779
  }, [product, selected]);
760
780
  if (product.options.length === 0) return null;
@@ -795,8 +815,8 @@ function BackInStockForm({
795
815
  }) {
796
816
  const t = useT();
797
817
  const client = useStorefront();
798
- const [email, setEmail] = React19.useState(defaultEmail);
799
- const [state, setState] = React19.useState("idle");
818
+ const [email, setEmail] = React27.useState(defaultEmail);
819
+ const [state, setState] = React27.useState("idle");
800
820
  if (!variant || variant.availability?.status !== "out_of_stock") return null;
801
821
  async function submit(e) {
802
822
  e.preventDefault();
@@ -896,7 +916,7 @@ function ProductDetailPage({
896
916
  locale,
897
917
  addToCart
898
918
  }) {
899
- const [variant, setVariant] = React19.useState(
919
+ const [variant, setVariant] = React27.useState(
900
920
  product.variants[0] ?? null
901
921
  );
902
922
  return /* @__PURE__ */ jsxs(
@@ -1128,12 +1148,26 @@ function TagFilter({ tags, selected = [], onChange }) {
1128
1148
  }) })
1129
1149
  ] });
1130
1150
  }
1131
- var CartContext = React19.createContext(null);
1151
+ function PurchaseOptions({ plans, value, onChange, disabled, locale }) {
1152
+ const t = useT();
1153
+ const loc = useFormatLocale(locale);
1154
+ const name = React27.useId();
1155
+ const options = [{ id: null, name: t("subscriptions.once"), price: void 0 }, ...plans];
1156
+ return /* @__PURE__ */ jsxs("fieldset", { disabled, style: { border: 0, padding: 0, margin: 0, display: "grid", gap: "0.5rem" }, children: [
1157
+ /* @__PURE__ */ jsx("legend", { style: { marginBottom: "0.5rem", fontWeight: 500 }, children: t("subscriptions.purchaseOption") }),
1158
+ options.map((option) => /* @__PURE__ */ jsxs("label", { style: { display: "flex", gap: "0.6rem", alignItems: "center", padding: "0.75rem", border: `1px solid ${value === option.id ? "var(--nv-fg)" : "var(--nv-border)"}`, borderRadius: "var(--nv-radius)", cursor: "pointer" }, children: [
1159
+ /* @__PURE__ */ jsx("input", { type: "radio", name, checked: value === option.id, onChange: () => onChange(option.id) }),
1160
+ /* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: option.name }),
1161
+ option.price ? /* @__PURE__ */ jsx("span", { children: formatCents(option.price.amount_cents, option.price.currency, loc) }) : null
1162
+ ] }, option.id ?? "once"))
1163
+ ] });
1164
+ }
1165
+ var CartContext = React27.createContext(null);
1132
1166
  function CartProvider({ children }) {
1133
1167
  const client = useStorefront();
1134
- const [cart, setCart] = React19.useState(null);
1135
- const [loading, setLoading] = React19.useState(false);
1136
- const run = React19.useCallback(
1168
+ const [cart, setCart] = React27.useState(null);
1169
+ const [loading, setLoading] = React27.useState(false);
1170
+ const run = React27.useCallback(
1137
1171
  async (op) => {
1138
1172
  setLoading(true);
1139
1173
  try {
@@ -1146,7 +1180,7 @@ function CartProvider({ children }) {
1146
1180
  },
1147
1181
  []
1148
1182
  );
1149
- const refresh = React19.useCallback(async () => {
1183
+ const refresh = React27.useCallback(async () => {
1150
1184
  setLoading(true);
1151
1185
  try {
1152
1186
  setCart(await client.cart.get());
@@ -1154,16 +1188,17 @@ function CartProvider({ children }) {
1154
1188
  setLoading(false);
1155
1189
  }
1156
1190
  }, [client]);
1157
- React19.useEffect(() => {
1191
+ React27.useEffect(() => {
1158
1192
  void refresh();
1159
1193
  }, [refresh]);
1160
- const value = React19.useMemo(
1194
+ const value = React27.useMemo(
1161
1195
  () => ({
1162
1196
  cart,
1163
1197
  loading,
1164
1198
  itemCount: cart?.totals.item_count ?? 0,
1165
1199
  addLine: (input) => run(() => client.cart.addLine(input)),
1166
1200
  updateLine: (lineId, quantity) => run(() => client.cart.updateLine(lineId, quantity)),
1201
+ clearSubscription: () => run(() => client.cart.clearSubscription()),
1167
1202
  removeLine: (lineId) => run(() => client.cart.removeLine(lineId)),
1168
1203
  refresh
1169
1204
  }),
@@ -1172,7 +1207,7 @@ function CartProvider({ children }) {
1172
1207
  return /* @__PURE__ */ jsx(CartContext.Provider, { value, children });
1173
1208
  }
1174
1209
  function useCart() {
1175
- const ctx = React19.useContext(CartContext);
1210
+ const ctx = React27.useContext(CartContext);
1176
1211
  if (!ctx) {
1177
1212
  throw new Error("useCart must be used inside <CartProvider>.");
1178
1213
  }
@@ -1181,13 +1216,14 @@ function useCart() {
1181
1216
  function AddToCart({
1182
1217
  variant,
1183
1218
  quantity = 1,
1219
+ subscriptionPlanId,
1184
1220
  children,
1185
1221
  onAdded
1186
1222
  }) {
1187
1223
  const t = useT();
1188
1224
  const { addLine } = useCart();
1189
- const [busy, setBusy] = React19.useState(false);
1190
- const [error, setError] = React19.useState(null);
1225
+ const [busy, setBusy] = React27.useState(false);
1226
+ const [error, setError] = React27.useState(null);
1191
1227
  const disabled = variant == null || busy;
1192
1228
  return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
1193
1229
  /* @__PURE__ */ jsx(
@@ -1200,7 +1236,7 @@ function AddToCart({
1200
1236
  setBusy(true);
1201
1237
  setError(null);
1202
1238
  try {
1203
- await addLine({ variant_id: variant.id, quantity });
1239
+ await addLine({ variant_id: variant.id, quantity, ...subscriptionPlanId ? { subscription_plan_id: subscriptionPlanId } : {} });
1204
1240
  onAdded?.();
1205
1241
  } catch (err) {
1206
1242
  const code = err?.code;
@@ -1229,7 +1265,7 @@ function AddToCart({
1229
1265
  function CartLineItem({ line, locale }) {
1230
1266
  const t = useT();
1231
1267
  const loc = useFormatLocale(locale);
1232
- const { updateLine, removeLine } = useCart();
1268
+ const { cart, updateLine, removeLine } = useCart();
1233
1269
  return /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.85rem", alignItems: "flex-start", padding: "0.75rem 0" }, children: [
1234
1270
  /* @__PURE__ */ jsx(
1235
1271
  "div",
@@ -1258,6 +1294,7 @@ function CartLineItem({ line, locale }) {
1258
1294
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1259
1295
  /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, lineHeight: 1.3 }, children: line.title }),
1260
1296
  line.variant_title ? /* @__PURE__ */ jsx("div", { style: { color: "var(--nv-muted)", fontSize: "0.875em" }, children: line.variant_title }) : null,
1297
+ line.subscription_plan_id ? /* @__PURE__ */ jsx("div", { style: { color: "var(--nv-muted)", fontSize: "0.875em" }, children: cart?.subscription?.plan?.name ?? t("subscriptions.title") }) : null,
1261
1298
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", marginTop: "0.5rem" }, children: [
1262
1299
  /* @__PURE__ */ jsxs(
1263
1300
  "div",
@@ -1336,7 +1373,7 @@ function CartSummary({
1336
1373
  const { cart } = useCart();
1337
1374
  if (cart == null) return null;
1338
1375
  const t = cart.totals;
1339
- const empty = t.item_count === 0;
1376
+ const empty = t.item_count === 0 || cart.subscription?.available === false;
1340
1377
  const cta = checkoutLabel ?? tr("cart.checkout");
1341
1378
  const ctaStyle = {
1342
1379
  display: "block",
@@ -1357,6 +1394,7 @@ function CartSummary({
1357
1394
  t.tax_cents > 0 ? /* @__PURE__ */ jsx(Row, { label: tr("cart.tax"), value: formatCents(t.tax_cents, t.currency, loc), muted: true }) : null,
1358
1395
  /* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
1359
1396
  /* @__PURE__ */ jsx(Row, { label: tr("cart.total"), value: formatCents(t.total_cents, t.currency, loc), strong: true }),
1397
+ cart.subscription?.error ? /* @__PURE__ */ jsx("p", { role: "alert", style: { margin: 0 }, children: cart.subscription.error.message }) : null,
1360
1398
  checkoutHref && !empty ? /* @__PURE__ */ jsx("a", { href: checkoutHref, style: ctaStyle, children: cta }) : /* @__PURE__ */ jsx("button", { type: "button", disabled: empty, onClick: onCheckout, style: ctaStyle, children: cta })
1361
1399
  ] });
1362
1400
  }
@@ -1463,15 +1501,15 @@ function CartDrawer({
1463
1501
  }
1464
1502
  );
1465
1503
  }
1466
- var CheckoutContext = React19.createContext(null);
1504
+ var CheckoutContext = React27.createContext(null);
1467
1505
  function CheckoutProvider({
1468
1506
  children
1469
1507
  }) {
1470
1508
  const client = useStorefront();
1471
- const [checkout, setCheckout] = React19.useState(null);
1472
- const [loading, setLoading] = React19.useState(false);
1473
- const [error, setError] = React19.useState(null);
1474
- const run = React19.useCallback(
1509
+ const [checkout, setCheckout] = React27.useState(null);
1510
+ const [loading, setLoading] = React27.useState(false);
1511
+ const [error, setError] = React27.useState(null);
1512
+ const run = React27.useCallback(
1475
1513
  async (op, store) => {
1476
1514
  setLoading(true);
1477
1515
  try {
@@ -1489,23 +1527,36 @@ function CheckoutProvider({
1489
1527
  },
1490
1528
  []
1491
1529
  );
1492
- const refresh = React19.useCallback(async () => {
1530
+ const refresh = React27.useCallback(async () => {
1493
1531
  setLoading(true);
1494
1532
  try {
1495
1533
  setCheckout(await client.checkout.get());
1496
1534
  setError(null);
1535
+ } catch (err) {
1536
+ setError(err instanceof Error ? err : new Error(String(err)));
1497
1537
  } finally {
1498
1538
  setLoading(false);
1499
1539
  }
1500
1540
  }, [client]);
1501
- React19.useEffect(() => {
1541
+ React27.useEffect(() => {
1502
1542
  void refresh();
1503
1543
  }, [refresh]);
1504
- const pay = React19.useCallback(
1544
+ const pay = React27.useCallback(
1505
1545
  async (opts = {}) => {
1506
1546
  const co = checkout;
1507
1547
  if (!co) throw new Error("pay() called before a checkout exists");
1508
1548
  const idempotencyKey = opts.idempotencyKey ?? co.token;
1549
+ if (co.subscription) {
1550
+ if (co.subscription.subscription_id) {
1551
+ const payment = await run(() => client.checkout.subscriptionPayment(), () => null);
1552
+ setCheckout(await client.checkout.get());
1553
+ return { kind: "subscription_payment", payment };
1554
+ }
1555
+ if (!opts.subscription) throw new Error("Accept the current subscription terms before paying");
1556
+ const subscription = await run(() => client.checkout.enrollSubscription(opts.subscription), () => null);
1557
+ setCheckout(await client.checkout.get());
1558
+ return { kind: "subscription", subscription };
1559
+ }
1509
1560
  if (co.payment_category === "gateway") {
1510
1561
  const start = await run(
1511
1562
  () => client.checkout.startPayment({ return_url: opts.returnUrl, cancel_url: opts.cancelUrl }),
@@ -1524,11 +1575,18 @@ function CheckoutProvider({
1524
1575
  },
1525
1576
  [checkout, client, run]
1526
1577
  );
1527
- const value = React19.useMemo(
1578
+ const value = React27.useMemo(
1528
1579
  () => ({
1529
1580
  checkout,
1530
1581
  loading,
1531
1582
  error,
1583
+ selectSubscription: (selection) => run(async () => {
1584
+ const quote = await client.checkout.selectSubscription(selection);
1585
+ setCheckout(await client.checkout.get());
1586
+ return quote;
1587
+ }, () => null),
1588
+ clearSubscription: () => run(() => client.checkout.clearSubscription(), (r) => r),
1589
+ reviewSubscription: () => run(() => client.checkout.reviewSubscription(), () => null),
1532
1590
  create: (cartToken, input) => run(() => client.checkout.create(cartToken, input), (r) => r),
1533
1591
  setAddress: (input) => run(() => client.checkout.setAddress(input), (r) => r),
1534
1592
  shippingQuotes: () => run(() => client.checkout.shippingQuotes(), () => null),
@@ -1549,7 +1607,7 @@ function CheckoutProvider({
1549
1607
  return /* @__PURE__ */ jsx(CheckoutContext.Provider, { value, children });
1550
1608
  }
1551
1609
  function useCheckout() {
1552
- const ctx = React19.useContext(CheckoutContext);
1610
+ const ctx = React27.useContext(CheckoutContext);
1553
1611
  if (!ctx) {
1554
1612
  throw new Error("useCheckout must be used inside <CheckoutProvider>.");
1555
1613
  }
@@ -1708,11 +1766,11 @@ function AddressForm({
1708
1766
  }) {
1709
1767
  const t = useT();
1710
1768
  const { checkout, setAddress, loading } = useCheckout();
1711
- const [form, setForm] = React19.useState(
1769
+ const [form, setForm] = React27.useState(
1712
1770
  () => seed(checkout?.email ?? null, checkout?.shipping_address ?? null)
1713
1771
  );
1714
- const touched = React19.useRef(/* @__PURE__ */ new Set());
1715
- React19.useEffect(() => {
1772
+ const touched = React27.useRef(/* @__PURE__ */ new Set());
1773
+ React27.useEffect(() => {
1716
1774
  const prefill = checkout?.customer_prefill;
1717
1775
  const addresses = prefill?.addresses.filter((a) => !a.is_pickup);
1718
1776
  const saved = addresses?.find((a) => a.is_default) ?? addresses?.[0];
@@ -1777,11 +1835,11 @@ function ShippingPicker({
1777
1835
  const loc = useFormatLocale(locale);
1778
1836
  const { checkout, shippingQuotes, setShippingMethod, loading } = useCheckout();
1779
1837
  const heading = title ?? t("checkout.shippingMethod");
1780
- const [quotes, setQuotes] = React19.useState(null);
1781
- const [selected, setSelected] = React19.useState(null);
1782
- const [fetching, setFetching] = React19.useState(true);
1838
+ const [quotes, setQuotes] = React27.useState(null);
1839
+ const [selected, setSelected] = React27.useState(null);
1840
+ const [fetching, setFetching] = React27.useState(true);
1783
1841
  const addressKey = checkout?.shipping_address ? `${checkout.shipping_address.country_code}:${checkout.shipping_address.postal_code}` : null;
1784
- React19.useEffect(() => {
1842
+ React27.useEffect(() => {
1785
1843
  let live = true;
1786
1844
  setFetching(true);
1787
1845
  shippingQuotes().then((qs) => {
@@ -1856,20 +1914,45 @@ function PaymentMethodPicker({
1856
1914
  }
1857
1915
  );
1858
1916
  }
1917
+ function SubscriptionTerms({ quote, checked, onChange, locale }) {
1918
+ const t = useT();
1919
+ const loc = useFormatLocale(locale);
1920
+ return /* @__PURE__ */ jsxs("fieldset", { style: { margin: 0, padding: "1rem", border: "1px solid var(--nv-border)", borderRadius: "var(--nv-radius)" }, children: [
1921
+ /* @__PURE__ */ jsx("legend", { children: t("subscriptions.title") }),
1922
+ /* @__PURE__ */ jsxs("p", { style: { margin: "0 0 0.5rem", fontWeight: 500 }, children: [
1923
+ t("subscriptions.eachDelivery"),
1924
+ ": ",
1925
+ formatCents(quote.recurring_total_cents, quote.currency, loc)
1926
+ ] }),
1927
+ /* @__PURE__ */ jsx("p", { style: { margin: "0 0 0.75rem", whiteSpace: "pre-wrap" }, children: quote.terms_text }),
1928
+ /* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "flex-start", gap: "0.6rem", cursor: "pointer" }, children: [
1929
+ /* @__PURE__ */ jsx("input", { type: "checkbox", checked, onChange: (event) => onChange(event.target.checked) }),
1930
+ /* @__PURE__ */ jsx("span", { children: t("subscriptions.consent") })
1931
+ ] })
1932
+ ] });
1933
+ }
1859
1934
  function PaymentSection({
1860
1935
  title,
1861
1936
  returnUrl,
1862
1937
  cancelUrl,
1863
1938
  onOrderPlaced,
1864
- locale
1939
+ locale,
1940
+ onSubscriptionPayment
1865
1941
  }) {
1866
1942
  const t = useT();
1867
1943
  const heading = title ?? t("checkout.payment");
1868
- const { checkout, paymentMethods, setPaymentMethod, pay, loading } = useCheckout();
1869
- const [methods, setMethods] = React19.useState(null);
1870
- const [fetching, setFetching] = React19.useState(true);
1944
+ const { checkout, paymentMethods, setPaymentMethod, pay, loading, refresh } = useCheckout();
1945
+ const [methods, setMethods] = React27.useState(null);
1946
+ const [fetching, setFetching] = React27.useState(true);
1871
1947
  const selected = checkout?.payment_method ?? null;
1872
- React19.useEffect(() => {
1948
+ const [acceptedDigest, setAcceptedDigest] = React27.useState(null);
1949
+ const [actionBusy, setActionBusy] = React27.useState(false);
1950
+ const quote = checkout?.subscription?.quote;
1951
+ const needsConsent = Boolean(checkout?.subscription?.requires_consent);
1952
+ const clickInFlight = React27.useRef(false);
1953
+ const [actionError, setActionError] = React27.useState(null);
1954
+ const accepted = Boolean(quote && acceptedDigest === quote.quote_digest);
1955
+ React27.useEffect(() => {
1873
1956
  let live = true;
1874
1957
  setFetching(true);
1875
1958
  paymentMethods().then((ms) => {
@@ -1882,12 +1965,30 @@ function PaymentSection({
1882
1965
  return () => {
1883
1966
  live = false;
1884
1967
  };
1885
- }, []);
1968
+ }, [checkout?.token, checkout?.shipping_method_id, checkout?.subscription?.selection.plan_id]);
1886
1969
  const selectedMethod = methods?.find((m) => m.method === selected) ?? null;
1887
1970
  const isGateway = selectedMethod?.category === "gateway";
1888
1971
  async function placeOrder() {
1889
- const result = await pay({ returnUrl, cancelUrl });
1890
- if (result.kind === "order") onOrderPlaced?.(result.checkout);
1972
+ if (clickInFlight.current) return;
1973
+ clickInFlight.current = true;
1974
+ setActionBusy(true);
1975
+ setActionError(null);
1976
+ try {
1977
+ const result = await pay({
1978
+ returnUrl,
1979
+ cancelUrl,
1980
+ ...needsConsent && quote && accepted ? { subscription: { quote, consent: true } } : {}
1981
+ });
1982
+ if (result.kind === "subscription") await onSubscriptionPayment?.(result.subscription.payment);
1983
+ if (result.kind === "subscription_payment") await onSubscriptionPayment?.(result.payment);
1984
+ if (result.kind === "subscription" || result.kind === "subscription_payment") await refresh();
1985
+ if (result.kind === "order") onOrderPlaced?.(result.checkout);
1986
+ } catch (err) {
1987
+ setActionError(err instanceof Error ? err.message : String(err));
1988
+ } finally {
1989
+ clickInFlight.current = false;
1990
+ setActionBusy(false);
1991
+ }
1891
1992
  }
1892
1993
  if (fetching && methods == null) {
1893
1994
  return /* @__PURE__ */ jsx(Section, { title: heading, children: /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("checkout.loadingPayment") }) });
@@ -1907,9 +2008,12 @@ function PaymentSection({
1907
2008
  label: heading
1908
2009
  }
1909
2010
  ),
2011
+ quote && needsConsent ? /* @__PURE__ */ jsx(SubscriptionTerms, { locale, quote, checked: accepted, onChange: (value) => setAcceptedDigest(value && quote ? quote.quote_digest : null) }) : null,
2012
+ checkout?.subscription?.error ? /* @__PURE__ */ jsx("p", { role: "alert", children: checkout.subscription.error.message }) : null,
2013
+ actionError ? /* @__PURE__ */ jsx("p", { role: "alert", children: actionError }) : null,
1910
2014
  /* @__PURE__ */ jsxs("div", { children: [
1911
- /* @__PURE__ */ jsx(Button, { onClick: placeOrder, busy: loading, disabled: selected == null, children: isGateway ? t("checkout.payNow") : t("checkout.placeOrder") }),
1912
- isGateway ? /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)", marginTop: "0.6rem" }, children: t("checkout.gatewayRedirectNote") }) : null
2015
+ /* @__PURE__ */ jsx(Button, { onClick: placeOrder, busy: loading || actionBusy, disabled: selected == null || Boolean(checkout?.subscription) && (needsConsent && (!accepted || !quote) || !onSubscriptionPayment || !checkout?.subscription?.available), children: isGateway ? t("checkout.payNow") : t("checkout.placeOrder") }),
2016
+ isGateway && !checkout?.subscription ? /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)", marginTop: "0.6rem" }, children: t("checkout.gatewayRedirectNote") }) : null
1913
2017
  ] })
1914
2018
  ] });
1915
2019
  }
@@ -1997,6 +2101,7 @@ function reachedStep(checkout) {
1997
2101
  }
1998
2102
  function CheckoutFlow({
1999
2103
  cartToken,
2104
+ onSubscriptionPayment,
2000
2105
  onOrderPlaced,
2001
2106
  emptyState,
2002
2107
  renderConfirmation,
@@ -2006,19 +2111,19 @@ function CheckoutFlow({
2006
2111
  }) {
2007
2112
  const t = useT();
2008
2113
  const { checkout, loading, create } = useCheckout();
2009
- const [step, setStep] = React19.useState("address");
2010
- const [bootstrapped, setBootstrapped] = React19.useState(false);
2011
- React19.useEffect(() => {
2114
+ const [step, setStep] = React27.useState("address");
2115
+ const [bootstrapped, setBootstrapped] = React27.useState(false);
2116
+ React27.useEffect(() => {
2012
2117
  if (checkout || !cartToken || bootstrapped) return;
2013
2118
  setBootstrapped(true);
2014
2119
  void create(cartToken).catch(() => {
2015
2120
  });
2016
2121
  }, [checkout, cartToken, bootstrapped, create]);
2017
2122
  const serverStep = reachedStep(checkout);
2018
- React19.useEffect(() => {
2123
+ React27.useEffect(() => {
2019
2124
  setStep((cur) => rank(serverStep) > rank(cur) ? serverStep : cur);
2020
2125
  }, [serverStep]);
2021
- if (checkout?.order_id) {
2126
+ if (checkout?.order_id && (!checkout.subscription || checkout.phase === "success")) {
2022
2127
  return /* @__PURE__ */ jsx(Shell, { summary: /* @__PURE__ */ jsx(OrderSummary, { locale }), children: renderConfirmation ? renderConfirmation(checkout) : /* @__PURE__ */ jsx(DefaultConfirmation, { checkout }) });
2023
2128
  }
2024
2129
  if (!checkout) {
@@ -2032,6 +2137,7 @@ function CheckoutFlow({
2032
2137
  step === "address" ? /* @__PURE__ */ jsx(AddressForm, { onComplete: () => setStep("shipping") }) : step === "shipping" ? /* @__PURE__ */ jsx(ShippingPicker, { onComplete: () => setStep("payment"), locale }) : /* @__PURE__ */ jsx(
2033
2138
  PaymentSection,
2034
2139
  {
2140
+ onSubscriptionPayment,
2035
2141
  returnUrl,
2036
2142
  cancelUrl,
2037
2143
  onOrderPlaced,
@@ -2136,10 +2242,10 @@ function DefaultConfirmation({ checkout }) {
2136
2242
  }
2137
2243
  function useOrderStatus(statusToken, initial) {
2138
2244
  const client = useStorefront();
2139
- const [order, setOrder] = React19.useState(initial ?? null);
2140
- const [loading, setLoading] = React19.useState(false);
2141
- const [error, setError] = React19.useState(null);
2142
- const load = React19.useCallback(async () => {
2245
+ const [order, setOrder] = React27.useState(initial ?? null);
2246
+ const [loading, setLoading] = React27.useState(false);
2247
+ const [error, setError] = React27.useState(null);
2248
+ const load = React27.useCallback(async () => {
2143
2249
  if (!statusToken) return;
2144
2250
  setLoading(true);
2145
2251
  try {
@@ -2151,7 +2257,7 @@ function useOrderStatus(statusToken, initial) {
2151
2257
  setLoading(false);
2152
2258
  }
2153
2259
  }, [client, statusToken]);
2154
- React19.useEffect(() => {
2260
+ React27.useEffect(() => {
2155
2261
  if (initial) return;
2156
2262
  void load();
2157
2263
  }, [load, initial]);
@@ -2159,12 +2265,12 @@ function useOrderStatus(statusToken, initial) {
2159
2265
  }
2160
2266
  function usePayment(token, initial) {
2161
2267
  const client = useStorefront();
2162
- const [payment, setPayment] = React19.useState(initial ?? null);
2163
- const [methods, setMethods] = React19.useState([]);
2164
- const [loading, setLoading] = React19.useState(false);
2165
- const [busy, setBusy] = React19.useState(false);
2166
- const [error, setError] = React19.useState(null);
2167
- const load = React19.useCallback(async () => {
2268
+ const [payment, setPayment] = React27.useState(initial ?? null);
2269
+ const [methods, setMethods] = React27.useState([]);
2270
+ const [loading, setLoading] = React27.useState(false);
2271
+ const [busy, setBusy] = React27.useState(false);
2272
+ const [error, setError] = React27.useState(null);
2273
+ const load = React27.useCallback(async () => {
2168
2274
  if (!token) return;
2169
2275
  setLoading(true);
2170
2276
  try {
@@ -2181,7 +2287,7 @@ function usePayment(token, initial) {
2181
2287
  setLoading(false);
2182
2288
  }
2183
2289
  }, [client, token]);
2184
- React19.useEffect(() => {
2290
+ React27.useEffect(() => {
2185
2291
  if (!token) return;
2186
2292
  if (initial && initial.token === token) {
2187
2293
  setPayment(initial);
@@ -2190,7 +2296,7 @@ function usePayment(token, initial) {
2190
2296
  }
2191
2297
  void load();
2192
2298
  }, [token, load]);
2193
- const selectMethod = React19.useCallback(
2299
+ const selectMethod = React27.useCallback(
2194
2300
  async (method) => {
2195
2301
  if (!token) return null;
2196
2302
  setBusy(true);
@@ -2208,7 +2314,7 @@ function usePayment(token, initial) {
2208
2314
  },
2209
2315
  [client, token]
2210
2316
  );
2211
- const startPayment = React19.useCallback(
2317
+ const startPayment = React27.useCallback(
2212
2318
  async (input) => {
2213
2319
  if (!token) return null;
2214
2320
  setBusy(true);
@@ -2645,8 +2751,8 @@ function Row4({
2645
2751
  }
2646
2752
  function CopyRow({ label, value }) {
2647
2753
  const t = useT();
2648
- const [copied, setCopied] = React19.useState(false);
2649
- React19.useEffect(() => {
2754
+ const [copied, setCopied] = React27.useState(false);
2755
+ React27.useEffect(() => {
2650
2756
  if (!copied) return;
2651
2757
  const id = setTimeout(() => setCopied(false), 1800);
2652
2758
  return () => clearTimeout(id);
@@ -2730,12 +2836,12 @@ function PaymentPage({
2730
2836
  const t = useT();
2731
2837
  const loc = useFormatLocale(locale);
2732
2838
  const { payment, methods, loading, busy, error, reload, selectMethod, startPayment } = usePayment(token, initial);
2733
- const [verifying, setVerifying] = React19.useState(false);
2734
- React19.useEffect(() => {
2839
+ const [verifying, setVerifying] = React27.useState(false);
2840
+ React27.useEffect(() => {
2735
2841
  if (token) setVerifying(consumeHandoff(token));
2736
2842
  }, [token]);
2737
2843
  const settled = payment != null && !payment.can_pay && payment.blocked_reason === "already_paid";
2738
- React19.useEffect(() => {
2844
+ React27.useEffect(() => {
2739
2845
  if (!verifying || !token || settled) return;
2740
2846
  let attempts = 0;
2741
2847
  const id = setInterval(() => {
@@ -2750,7 +2856,7 @@ function PaymentPage({
2750
2856
  }, POLL_MS);
2751
2857
  return () => clearInterval(id);
2752
2858
  }, [verifying, token, settled, reload]);
2753
- React19.useEffect(() => {
2859
+ React27.useEffect(() => {
2754
2860
  if (!settled || !token || !payment) return;
2755
2861
  setVerifying(false);
2756
2862
  forgetHandoff(token);
@@ -2831,13 +2937,13 @@ function Amount({ label, value }) {
2831
2937
  function Link({ href, children }) {
2832
2938
  return /* @__PURE__ */ jsx("a", { href, style: { color: "var(--nv-brand)", fontSize: "0.875rem" }, children });
2833
2939
  }
2834
- var AccountContext = React19.createContext(null);
2940
+ var AccountContext = React27.createContext(null);
2835
2941
  function AccountProvider({ children }) {
2836
2942
  const client = useStorefront();
2837
- const [customer, setCustomer] = React19.useState(null);
2838
- const [loading, setLoading] = React19.useState(true);
2839
- const [error, setError] = React19.useState(false);
2840
- const refresh = React19.useCallback(async () => {
2943
+ const [customer, setCustomer] = React27.useState(null);
2944
+ const [loading, setLoading] = React27.useState(true);
2945
+ const [error, setError] = React27.useState(false);
2946
+ const refresh = React27.useCallback(async () => {
2841
2947
  setLoading(true);
2842
2948
  setError(false);
2843
2949
  try {
@@ -2848,10 +2954,10 @@ function AccountProvider({ children }) {
2848
2954
  setLoading(false);
2849
2955
  }
2850
2956
  }, [client]);
2851
- React19.useEffect(() => {
2957
+ React27.useEffect(() => {
2852
2958
  void refresh();
2853
2959
  }, [refresh]);
2854
- const value = React19.useMemo(
2960
+ const value = React27.useMemo(
2855
2961
  () => ({
2856
2962
  customer,
2857
2963
  signedIn: customer != null,
@@ -2874,7 +2980,7 @@ function AccountProvider({ children }) {
2874
2980
  return /* @__PURE__ */ jsx(AccountContext.Provider, { value, children });
2875
2981
  }
2876
2982
  function useAccount() {
2877
- const ctx = React19.useContext(AccountContext);
2983
+ const ctx = React27.useContext(AccountContext);
2878
2984
  if (!ctx) {
2879
2985
  throw new Error("useAccount must be used inside <AccountProvider>.");
2880
2986
  }
@@ -2882,9 +2988,9 @@ function useAccount() {
2882
2988
  }
2883
2989
  function useMagicLinkVerify(token) {
2884
2990
  const { verify } = useAccount();
2885
- const [status, setStatus] = React19.useState("idle");
2886
- const done = React19.useRef(false);
2887
- React19.useEffect(() => {
2991
+ const [status, setStatus] = React27.useState("idle");
2992
+ const done = React27.useRef(false);
2993
+ React27.useEffect(() => {
2888
2994
  if (!token || done.current) return;
2889
2995
  done.current = true;
2890
2996
  setStatus("verifying");
@@ -2895,11 +3001,11 @@ function useMagicLinkVerify(token) {
2895
3001
  function LoginForm({ verifyPath = "/account/verify", onSent }) {
2896
3002
  const t = useT();
2897
3003
  const { requestMagicLink } = useAccount();
2898
- const [email, setEmail] = React19.useState("");
2899
- const [busy, setBusy] = React19.useState(false);
2900
- const [sent, setSent] = React19.useState(false);
2901
- const [error, setError] = React19.useState(false);
2902
- const [devLink, setDevLink] = React19.useState(null);
3004
+ const [email, setEmail] = React27.useState("");
3005
+ const [busy, setBusy] = React27.useState(false);
3006
+ const [sent, setSent] = React27.useState(false);
3007
+ const [error, setError] = React27.useState(false);
3008
+ const [devLink, setDevLink] = React27.useState(null);
2903
3009
  async function submit(e) {
2904
3010
  e.preventDefault();
2905
3011
  setBusy(true);
@@ -3011,14 +3117,14 @@ function OrderHistory({
3011
3117
  const loc = useFormatLocale(locale);
3012
3118
  const { signedIn } = useAccount();
3013
3119
  const client = useStorefront();
3014
- const [orders, setOrders] = React19.useState(null);
3015
- const [error, setError] = React19.useState(false);
3016
- const [nextCursor, setNextCursor] = React19.useState(null);
3017
- const [pageLoading, setPageLoading] = React19.useState(false);
3018
- const [reload, setReload] = React19.useState(0);
3019
- const [reordering, setReordering] = React19.useState(null);
3020
- const [notice, setNotice] = React19.useState(null);
3021
- React19.useEffect(() => {
3120
+ const [orders, setOrders] = React27.useState(null);
3121
+ const [error, setError] = React27.useState(false);
3122
+ const [nextCursor, setNextCursor] = React27.useState(null);
3123
+ const [pageLoading, setPageLoading] = React27.useState(false);
3124
+ const [reload, setReload] = React27.useState(0);
3125
+ const [reordering, setReordering] = React27.useState(null);
3126
+ const [notice, setNotice] = React27.useState(null);
3127
+ React27.useEffect(() => {
3022
3128
  let live = true;
3023
3129
  if (!signedIn) {
3024
3130
  setOrders([]);
@@ -3129,7 +3235,7 @@ function OrderHistory({
3129
3235
  }
3130
3236
  function AddressForm2({ initial, onSubmit, onCancel, busy }) {
3131
3237
  const t = useT();
3132
- const [form, setForm] = React19.useState(() => ({
3238
+ const [form, setForm] = React27.useState(() => ({
3133
3239
  first_name: initial?.first_name ?? "",
3134
3240
  last_name: initial?.last_name ?? "",
3135
3241
  company: initial?.company ?? "",
@@ -3227,17 +3333,17 @@ function AddressBook() {
3227
3333
  const t = useT();
3228
3334
  const { signedIn } = useAccount();
3229
3335
  const client = useStorefront();
3230
- const [addresses, setAddresses] = React19.useState(null);
3231
- const [mode, setMode] = React19.useState({ kind: "list" });
3232
- const [busy, setBusy] = React19.useState(false);
3233
- const load = React19.useCallback(() => {
3336
+ const [addresses, setAddresses] = React27.useState(null);
3337
+ const [mode, setMode] = React27.useState({ kind: "list" });
3338
+ const [busy, setBusy] = React27.useState(false);
3339
+ const load = React27.useCallback(() => {
3234
3340
  if (!signedIn) {
3235
3341
  setAddresses([]);
3236
3342
  return;
3237
3343
  }
3238
3344
  client.account.addresses().then(setAddresses).catch(() => setAddresses([]));
3239
3345
  }, [signedIn, client]);
3240
- React19.useEffect(() => {
3346
+ React27.useEffect(() => {
3241
3347
  load();
3242
3348
  }, [load]);
3243
3349
  async function run(fn) {
@@ -3291,10 +3397,10 @@ function ProfileEditor() {
3291
3397
  const t = useT();
3292
3398
  const client = useStorefront();
3293
3399
  const { customer, refresh } = useAccount();
3294
- const [editing, setEditing] = React19.useState(false);
3295
- const [busy, setBusy] = React19.useState(false);
3296
- const [error, setError] = React19.useState(false);
3297
- const [form, setForm] = React19.useState({});
3400
+ const [editing, setEditing] = React27.useState(false);
3401
+ const [busy, setBusy] = React27.useState(false);
3402
+ const [error, setError] = React27.useState(false);
3403
+ const [form, setForm] = React27.useState({});
3298
3404
  if (!customer) return null;
3299
3405
  function startEdit() {
3300
3406
  setForm({
@@ -3375,13 +3481,13 @@ function AccountSecurity() {
3375
3481
  const client = useStorefront();
3376
3482
  const account = useAccount();
3377
3483
  const t = useT();
3378
- const [sessions, setSessions] = React19.useState(null);
3379
- const [email, setEmail] = React19.useState("");
3380
- const [busy, setBusy] = React19.useState(false);
3381
- const [notice, setNotice] = React19.useState(null);
3382
- const [confirmClose, setConfirmClose] = React19.useState(false);
3383
- const [retry, setRetry] = React19.useState(0);
3384
- React19.useEffect(() => {
3484
+ const [sessions, setSessions] = React27.useState(null);
3485
+ const [email, setEmail] = React27.useState("");
3486
+ const [busy, setBusy] = React27.useState(false);
3487
+ const [notice, setNotice] = React27.useState(null);
3488
+ const [confirmClose, setConfirmClose] = React27.useState(false);
3489
+ const [retry, setRetry] = React27.useState(0);
3490
+ React27.useEffect(() => {
3385
3491
  let live = true;
3386
3492
  if (account.signedIn) client.account.sessions().then((s) => {
3387
3493
  if (live) setSessions(s);
@@ -3444,6 +3550,103 @@ function AccountSecurity() {
3444
3550
  ] }) : /* @__PURE__ */ jsx(Button, { disabled: busy, onClick: () => setConfirmClose(true), children: t("account.closeAccount") })
3445
3551
  ] });
3446
3552
  }
3553
+ function useCustomerSubscriptions() {
3554
+ const client = useStorefront();
3555
+ const { customer } = useAccount();
3556
+ const [dataOwner, setDataOwner] = React27.useState(void 0);
3557
+ const [subscriptions, setSubscriptions] = React27.useState([]);
3558
+ const [loading, setLoading] = React27.useState(false);
3559
+ const [error, setError] = React27.useState(null);
3560
+ const generation = React27.useRef(0);
3561
+ const owner = customer?.id;
3562
+ const api = client.account.subscriptions;
3563
+ const refresh = React27.useCallback(async () => {
3564
+ const current = ++generation.current;
3565
+ setError(null);
3566
+ if (!owner) {
3567
+ setSubscriptions([]);
3568
+ setLoading(false);
3569
+ return;
3570
+ }
3571
+ setLoading(true);
3572
+ try {
3573
+ const rows = await api.list();
3574
+ if (current === generation.current) {
3575
+ setSubscriptions(rows);
3576
+ setDataOwner(owner);
3577
+ setError(null);
3578
+ }
3579
+ } catch (err) {
3580
+ if (current === generation.current) setError(err instanceof Error ? err : new Error(String(err)));
3581
+ } finally {
3582
+ if (current === generation.current) setLoading(false);
3583
+ }
3584
+ }, [owner, api]);
3585
+ React27.useEffect(() => {
3586
+ setSubscriptions([]);
3587
+ void refresh();
3588
+ return () => {
3589
+ generation.current++;
3590
+ };
3591
+ }, [refresh]);
3592
+ return { subscriptions: dataOwner === owner ? subscriptions : [], loading, error, refresh, api };
3593
+ }
3594
+ function useCustomerSubscription(id) {
3595
+ const client = useStorefront();
3596
+ const { customer } = useAccount();
3597
+ const [dataKey, setDataKey] = React27.useState("");
3598
+ const [subscription, setSubscription] = React27.useState(null);
3599
+ const [loading, setLoading] = React27.useState(false);
3600
+ const [error, setError] = React27.useState(null);
3601
+ const generation = React27.useRef(0);
3602
+ const owner = customer?.id;
3603
+ const api = client.account.subscriptions;
3604
+ const refresh = React27.useCallback(async () => {
3605
+ const current = ++generation.current;
3606
+ setError(null);
3607
+ if (!owner || !id) {
3608
+ setSubscription(null);
3609
+ setLoading(false);
3610
+ return;
3611
+ }
3612
+ setLoading(true);
3613
+ try {
3614
+ const row = await api.management(id);
3615
+ if (current === generation.current) {
3616
+ setSubscription(row);
3617
+ setDataKey(`${owner}:${id}`);
3618
+ setError(null);
3619
+ }
3620
+ } catch (err) {
3621
+ if (current === generation.current) setError(err instanceof Error ? err : new Error(String(err)));
3622
+ } finally {
3623
+ if (current === generation.current) setLoading(false);
3624
+ }
3625
+ }, [owner, id, api]);
3626
+ React27.useEffect(() => {
3627
+ setSubscription(null);
3628
+ void refresh();
3629
+ return () => {
3630
+ generation.current++;
3631
+ };
3632
+ }, [refresh]);
3633
+ return { subscription: dataKey === `${owner}:${id}` ? subscription : null, loading, error, refresh, api };
3634
+ }
3635
+ function SubscriptionList({ href, locale }) {
3636
+ const t = useT();
3637
+ const { subscriptions, loading, error } = useCustomerSubscriptions();
3638
+ return /* @__PURE__ */ jsxs("section", { style: { fontFamily: "var(--nv-font)", color: "var(--nv-fg)" }, children: [
3639
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: "1.125rem", fontWeight: 500 }, children: t("subscriptions.title") }),
3640
+ loading ? /* @__PURE__ */ jsx("p", { children: t("checkout.loading") }) : error ? /* @__PURE__ */ jsx("p", { role: "alert", children: error.message }) : subscriptions.length === 0 ? /* @__PURE__ */ jsx("p", { children: t("subscriptions.empty") }) : /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: subscriptions.map((sub) => /* @__PURE__ */ jsx("li", { style: { borderBottom: "1px solid var(--nv-border)", padding: "0.8rem 0" }, children: /* @__PURE__ */ jsxs("a", { href: href(sub.id), style: { color: "inherit", display: "flex", justifyContent: "space-between", gap: "1rem", flexWrap: "wrap" }, children: [
3641
+ /* @__PURE__ */ jsxs("span", { children: [
3642
+ "#",
3643
+ sub.id
3644
+ ] }),
3645
+ /* @__PURE__ */ jsx("span", { children: t(`subscriptions.status.${sub.status}`) }),
3646
+ sub.status === "active" && sub.next_at ? /* @__PURE__ */ jsx("time", { dateTime: sub.next_at, children: new Date(sub.next_at).toLocaleDateString(locale) }) : null
3647
+ ] }) }, sub.id)) })
3648
+ ] });
3649
+ }
3447
3650
  function serializeJsonLd(data) {
3448
3651
  return JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
3449
3652
  }
@@ -3548,6 +3751,6 @@ function OrganizationJsonLd({
3548
3751
  return /* @__PURE__ */ jsx(JsonLd, { data });
3549
3752
  }
3550
3753
 
3551
- export { AccountDashboard, AccountProvider, AccountSecurity, 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 };
3754
+ export { AccountDashboard, AccountProvider, AccountSecurity, 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, PurchaseOptions, ShippingPicker, SortSelect, StatusBanner, StockBadge, SubscriptionList, SubscriptionTerms, TagFilter, ThemeProvider, TransferInstructions, VariantPicker, absoluteUrl, bundledMessages, cs, en, formatCents, formatMoney, isTerminal, serializeJsonLd, stripHtml, themeToCssVars, useAccount, useCart, useCheckout, useCustomerSubscription, useCustomerSubscriptions, useI18n, useMagicLinkVerify, useOrderStatus, usePayment, useStorefront, useStorefrontOptional, useT };
3552
3755
  //# sourceMappingURL=index.js.map
3553
3756
  //# sourceMappingURL=index.js.map