@nevios/storefront-kit 1.4.0 → 1.5.1
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 +1 -1
- package/dist/index.cjs +764 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -2
- package/dist/index.d.ts +93 -2
- package/dist/index.js +763 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -248,6 +248,45 @@ var en = {
|
|
|
248
248
|
"error.generic.title": "Something went wrong",
|
|
249
249
|
"error.generic.body": "Please try again in a moment.",
|
|
250
250
|
"error.home": "Back to home",
|
|
251
|
+
"subscriptions.mixPrice": "Fixed box price; shipping is separate",
|
|
252
|
+
"subscriptions.locked.inactive": "This subscription is not active",
|
|
253
|
+
"subscriptions.locked.cutoff": "The edit cutoff has passed",
|
|
254
|
+
"subscriptions.locked.in_flight": "This shipment or payment is already being processed",
|
|
255
|
+
"subscriptions.quantity": "Quantity",
|
|
256
|
+
"subscriptions.back": "Back",
|
|
257
|
+
"subscriptions.loading": "Loading subscription\u2026",
|
|
258
|
+
"subscriptions.loadingProducts": "Loading products\u2026",
|
|
259
|
+
"subscriptions.chargeDate": "Scheduled charge",
|
|
260
|
+
"subscriptions.noticeHeld": "The charge is waiting for a confirmed advance notice.",
|
|
261
|
+
"subscriptions.nextDelivery": "Next shipment",
|
|
262
|
+
"subscriptions.onlyNext": "Only in this shipment",
|
|
263
|
+
"subscriptions.toCharge": "Amount to charge",
|
|
264
|
+
"subscriptions.noticeStatus": "Renewal notice",
|
|
265
|
+
"subscriptions.notice.pending": "Pending",
|
|
266
|
+
"subscriptions.notice.queued": "Queued",
|
|
267
|
+
"subscriptions.notice.sent": "Sent",
|
|
268
|
+
"subscriptions.notice.failed": "Needs attention",
|
|
269
|
+
"subscriptions.notice.superseded": "Updated notice pending",
|
|
270
|
+
"subscriptions.editUntil": "Changes available until",
|
|
271
|
+
"subscriptions.changeInterval": "Change delivery frequency",
|
|
272
|
+
"subscriptions.addNext": "Add to next shipment",
|
|
273
|
+
"subscriptions.changeMix": "Change my mix",
|
|
274
|
+
"subscriptions.skip": "Skip next shipment",
|
|
275
|
+
"subscriptions.skipWarning": "This shipment and its one-time additions will be skipped. Following shipments keep their regular contents.",
|
|
276
|
+
"subscriptions.futureOnly": "Applies to future shipments. Existing orders stay unchanged.",
|
|
277
|
+
"subscriptions.nextUnchanged": "Next date",
|
|
278
|
+
"subscriptions.reviewTotal": "Reviewed amount",
|
|
279
|
+
"subscriptions.acceptChange": "I agree to the displayed contents, schedule and price.",
|
|
280
|
+
"subscriptions.reloadBeforeRetry": "Reload before another attempt",
|
|
281
|
+
"subscriptions.confirmChange": "Confirm change",
|
|
282
|
+
"subscriptions.reviewChange": "Review change",
|
|
283
|
+
"subscriptions.unit.week": "Every {count} week(s)",
|
|
284
|
+
"subscriptions.unit.month": "Every {count} month(s)",
|
|
285
|
+
"subscriptions.unit.year": "Every {count} year(s)",
|
|
286
|
+
"subscriptions.searchProducts": "Search products",
|
|
287
|
+
"subscriptions.addProduct": "Add product",
|
|
288
|
+
"subscriptions.mixCount": "{count} selected \xB7 choose {min}\u2013{max} units",
|
|
289
|
+
"subscriptions.addMix": "Add mix to cart",
|
|
251
290
|
// account
|
|
252
291
|
"account.title": "Your account",
|
|
253
292
|
"account.signIn": "Sign in",
|
|
@@ -454,6 +493,45 @@ var cs = {
|
|
|
454
493
|
"error.generic.title": "N\u011Bco se pokazilo",
|
|
455
494
|
"error.generic.body": "Zkuste to pros\xEDm za chv\xEDli znovu.",
|
|
456
495
|
"error.home": "Zp\u011Bt na \xFAvod",
|
|
496
|
+
"subscriptions.mixPrice": "Pevn\xE1 cena mixu; doprava se po\u010D\xEDt\xE1 zvl\xE1\u0161\u0165",
|
|
497
|
+
"subscriptions.locked.inactive": "P\u0159edplatn\xE9 nen\xED aktivn\xED.",
|
|
498
|
+
"subscriptions.locked.cutoff": "Term\xEDn pro \xFApravy t\xE9to z\xE1silky ji\u017E uplynul.",
|
|
499
|
+
"subscriptions.locked.in_flight": "Z\xE1silka nebo jej\xED platba se ji\u017E zpracov\xE1v\xE1.",
|
|
500
|
+
"subscriptions.quantity": "Mno\u017Estv\xED",
|
|
501
|
+
"subscriptions.back": "Zp\u011Bt",
|
|
502
|
+
"subscriptions.loading": "Na\u010D\xEDt\xE1n\xED p\u0159edplatn\xE9ho\u2026",
|
|
503
|
+
"subscriptions.loadingProducts": "Na\u010D\xEDt\xE1n\xED produkt\u016F\u2026",
|
|
504
|
+
"subscriptions.chargeDate": "Pl\xE1novan\xE9 str\u017Een\xED",
|
|
505
|
+
"subscriptions.noticeHeld": "Platba \u010Dek\xE1 na potvrzen\xE9 odesl\xE1n\xED upozorn\u011Bn\xED a sjednan\xFD p\u0159edstih.",
|
|
506
|
+
"subscriptions.nextDelivery": "P\u0159\xED\u0161t\xED z\xE1silka",
|
|
507
|
+
"subscriptions.onlyNext": "Jen v t\xE9to z\xE1silce",
|
|
508
|
+
"subscriptions.toCharge": "\u010C\xE1stka ke str\u017Een\xED",
|
|
509
|
+
"subscriptions.noticeStatus": "Upozorn\u011Bn\xED p\u0159ed platbou",
|
|
510
|
+
"subscriptions.notice.pending": "\u010Cek\xE1 na odesl\xE1n\xED",
|
|
511
|
+
"subscriptions.notice.queued": "Ve front\u011B",
|
|
512
|
+
"subscriptions.notice.sent": "Odesl\xE1no",
|
|
513
|
+
"subscriptions.notice.failed": "Vy\u017Eaduje pozornost",
|
|
514
|
+
"subscriptions.notice.superseded": "\u010Cek\xE1 na aktualizovan\xE9 upozorn\u011Bn\xED",
|
|
515
|
+
"subscriptions.editUntil": "\xDApravy mo\u017En\xE9 do",
|
|
516
|
+
"subscriptions.changeInterval": "Zm\u011Bnit interval doru\u010Den\xED",
|
|
517
|
+
"subscriptions.addNext": "P\u0159idat k p\u0159\xED\u0161t\xED z\xE1silce",
|
|
518
|
+
"subscriptions.changeMix": "Zm\u011Bnit vlastn\xED mix",
|
|
519
|
+
"subscriptions.skip": "P\u0159esko\u010Dit p\u0159\xED\u0161t\xED z\xE1silku",
|
|
520
|
+
"subscriptions.skipWarning": "Tato z\xE1silka se p\u0159esko\u010D\xED v\u010Detn\u011B jednor\xE1zov\u011B p\u0159idan\xFDch produkt\u016F. Dal\u0161\xED z\xE1silky budou m\xEDt b\u011B\u017En\xFD obsah p\u0159edplatn\xE9ho.",
|
|
521
|
+
"subscriptions.futureOnly": "Plat\xED pro budouc\xED z\xE1silky. Existuj\xEDc\xED objedn\xE1vky se nezm\u011Bn\xED.",
|
|
522
|
+
"subscriptions.nextUnchanged": "Nejbli\u017E\u0161\xED term\xEDn",
|
|
523
|
+
"subscriptions.reviewTotal": "Potvrzovan\xE1 \u010D\xE1stka",
|
|
524
|
+
"subscriptions.acceptChange": "Souhlas\xEDm se zobrazen\xFDm obsahem, term\xEDny a cenou.",
|
|
525
|
+
"subscriptions.reloadBeforeRetry": "Obnovit p\u0159ed dal\u0161\xEDm pokusem",
|
|
526
|
+
"subscriptions.confirmChange": "Potvrdit zm\u011Bnu",
|
|
527
|
+
"subscriptions.reviewChange": "Zkontrolovat zm\u011Bnu",
|
|
528
|
+
"subscriptions.unit.week": "Ka\u017Ed\xFDch {count} t\xFDdn\u016F",
|
|
529
|
+
"subscriptions.unit.month": "Ka\u017Ed\xFDch {count} m\u011Bs\xEDc\u016F",
|
|
530
|
+
"subscriptions.unit.year": "Ka\u017Ed\xFDch {count} let",
|
|
531
|
+
"subscriptions.searchProducts": "Hledat produkty",
|
|
532
|
+
"subscriptions.addProduct": "P\u0159idat produkt",
|
|
533
|
+
"subscriptions.mixCount": "Vybr\xE1no {count} \xB7 zvolte {min}\u2013{max} kus\u016F",
|
|
534
|
+
"subscriptions.addMix": "P\u0159idat mix do ko\u0161\xEDku",
|
|
457
535
|
"account.title": "V\xE1\u0161 \xFA\u010Det",
|
|
458
536
|
"account.signIn": "P\u0159ihl\xE1sit se",
|
|
459
537
|
"account.signInBlurb": "Zadejte e-mail a po\u0161leme v\xE1m p\u0159ihla\u0161ovac\xED odkaz.",
|
|
@@ -1185,7 +1263,9 @@ function PurchaseOptions({ plans, value, onChange, disabled, locale }) {
|
|
|
1185
1263
|
] });
|
|
1186
1264
|
}
|
|
1187
1265
|
var CartContext = React27__namespace.createContext(null);
|
|
1188
|
-
function CartProvider({
|
|
1266
|
+
function CartProvider({
|
|
1267
|
+
children
|
|
1268
|
+
}) {
|
|
1189
1269
|
const client = useStorefront();
|
|
1190
1270
|
const [cart, setCart] = React27__namespace.useState(null);
|
|
1191
1271
|
const [loading, setLoading] = React27__namespace.useState(false);
|
|
@@ -1219,6 +1299,11 @@ function CartProvider({ children }) {
|
|
|
1219
1299
|
loading,
|
|
1220
1300
|
itemCount: cart?.totals.item_count ?? 0,
|
|
1221
1301
|
addLine: (input) => run(() => client.cart.addLine(input)),
|
|
1302
|
+
setSubscriptionMix: (planId, lines, expectedLineIds) => run(
|
|
1303
|
+
() => client.cart.setSubscriptionMix(planId, lines, expectedLineIds, {
|
|
1304
|
+
expectedRevision: cart?.subscription?.revision
|
|
1305
|
+
})
|
|
1306
|
+
),
|
|
1222
1307
|
updateLine: (lineId, quantity) => run(() => client.cart.updateLine(lineId, quantity)),
|
|
1223
1308
|
clearSubscription: () => run(() => client.cart.clearSubscription()),
|
|
1224
1309
|
removeLine: (lineId) => run(() => client.cart.removeLine(lineId)),
|
|
@@ -3575,7 +3660,9 @@ function AccountSecurity() {
|
|
|
3575
3660
|
function useCustomerSubscriptions() {
|
|
3576
3661
|
const client = useStorefront();
|
|
3577
3662
|
const { customer } = useAccount();
|
|
3578
|
-
const [dataOwner, setDataOwner] = React27__namespace.useState(
|
|
3663
|
+
const [dataOwner, setDataOwner] = React27__namespace.useState(
|
|
3664
|
+
void 0
|
|
3665
|
+
);
|
|
3579
3666
|
const [subscriptions, setSubscriptions] = React27__namespace.useState([]);
|
|
3580
3667
|
const [loading, setLoading] = React27__namespace.useState(false);
|
|
3581
3668
|
const [error, setError] = React27__namespace.useState(null);
|
|
@@ -3599,7 +3686,8 @@ function useCustomerSubscriptions() {
|
|
|
3599
3686
|
setError(null);
|
|
3600
3687
|
}
|
|
3601
3688
|
} catch (err) {
|
|
3602
|
-
if (current === generation.current)
|
|
3689
|
+
if (current === generation.current)
|
|
3690
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3603
3691
|
} finally {
|
|
3604
3692
|
if (current === generation.current) setLoading(false);
|
|
3605
3693
|
}
|
|
@@ -3611,11 +3699,18 @@ function useCustomerSubscriptions() {
|
|
|
3611
3699
|
generation.current++;
|
|
3612
3700
|
};
|
|
3613
3701
|
}, [refresh]);
|
|
3614
|
-
return {
|
|
3702
|
+
return {
|
|
3703
|
+
subscriptions: dataOwner === owner ? subscriptions : [],
|
|
3704
|
+
loading,
|
|
3705
|
+
error,
|
|
3706
|
+
refresh,
|
|
3707
|
+
api
|
|
3708
|
+
};
|
|
3615
3709
|
}
|
|
3616
3710
|
function useCustomerSubscription(id) {
|
|
3617
3711
|
const client = useStorefront();
|
|
3618
3712
|
const { customer } = useAccount();
|
|
3713
|
+
const [readRevision, setReadRevision] = React27__namespace.useState(0);
|
|
3619
3714
|
const [dataKey, setDataKey] = React27__namespace.useState("");
|
|
3620
3715
|
const [subscription, setSubscription] = React27__namespace.useState(null);
|
|
3621
3716
|
const [loading, setLoading] = React27__namespace.useState(false);
|
|
@@ -3636,11 +3731,13 @@ function useCustomerSubscription(id) {
|
|
|
3636
3731
|
const row = await api.management(id);
|
|
3637
3732
|
if (current === generation.current) {
|
|
3638
3733
|
setSubscription(row);
|
|
3734
|
+
setReadRevision((n) => n + 1);
|
|
3639
3735
|
setDataKey(`${owner}:${id}`);
|
|
3640
3736
|
setError(null);
|
|
3641
3737
|
}
|
|
3642
3738
|
} catch (err) {
|
|
3643
|
-
if (current === generation.current)
|
|
3739
|
+
if (current === generation.current)
|
|
3740
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3644
3741
|
} finally {
|
|
3645
3742
|
if (current === generation.current) setLoading(false);
|
|
3646
3743
|
}
|
|
@@ -3652,7 +3749,14 @@ function useCustomerSubscription(id) {
|
|
|
3652
3749
|
generation.current++;
|
|
3653
3750
|
};
|
|
3654
3751
|
}, [refresh]);
|
|
3655
|
-
return {
|
|
3752
|
+
return {
|
|
3753
|
+
subscription: dataKey === `${owner}:${id}` ? subscription : null,
|
|
3754
|
+
loading,
|
|
3755
|
+
error,
|
|
3756
|
+
refresh,
|
|
3757
|
+
api,
|
|
3758
|
+
readRevision
|
|
3759
|
+
};
|
|
3656
3760
|
}
|
|
3657
3761
|
function SubscriptionList({ href, locale }) {
|
|
3658
3762
|
const t = useT();
|
|
@@ -3669,6 +3773,546 @@ function SubscriptionList({ href, locale }) {
|
|
|
3669
3773
|
] }) }, sub.id)) })
|
|
3670
3774
|
] });
|
|
3671
3775
|
}
|
|
3776
|
+
var subscriptionPanel = {
|
|
3777
|
+
fontFamily: "var(--nv-font)",
|
|
3778
|
+
color: "var(--nv-fg)",
|
|
3779
|
+
background: "var(--nv-bg)",
|
|
3780
|
+
border: "1px solid var(--nv-border)",
|
|
3781
|
+
borderRadius: "var(--nv-radius)",
|
|
3782
|
+
padding: "1rem"
|
|
3783
|
+
};
|
|
3784
|
+
function SubscriptionButton({
|
|
3785
|
+
primary = false,
|
|
3786
|
+
style,
|
|
3787
|
+
...props
|
|
3788
|
+
}) {
|
|
3789
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3790
|
+
"button",
|
|
3791
|
+
{
|
|
3792
|
+
type: "button",
|
|
3793
|
+
...props,
|
|
3794
|
+
style: {
|
|
3795
|
+
font: "inherit",
|
|
3796
|
+
fontWeight: 500,
|
|
3797
|
+
padding: ".5rem .85rem",
|
|
3798
|
+
borderRadius: "var(--nv-radius)",
|
|
3799
|
+
border: "1px solid var(--nv-border)",
|
|
3800
|
+
background: primary ? "var(--nv-brand)" : "var(--nv-bg)",
|
|
3801
|
+
color: primary ? "var(--nv-brand-foreground)" : "var(--nv-fg)",
|
|
3802
|
+
cursor: props.disabled ? "default" : "pointer",
|
|
3803
|
+
opacity: props.disabled ? 0.55 : 1,
|
|
3804
|
+
...style
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
);
|
|
3808
|
+
}
|
|
3809
|
+
function ProductSelection({
|
|
3810
|
+
load,
|
|
3811
|
+
value,
|
|
3812
|
+
onChange,
|
|
3813
|
+
initialItems = [],
|
|
3814
|
+
locale,
|
|
3815
|
+
maxQuantity = 99
|
|
3816
|
+
}) {
|
|
3817
|
+
const t = useT(), loc = useFormatLocale(locale), [query, setQuery] = React27__namespace.useState(""), [page, setPage] = React27__namespace.useState(0), [items, setItems] = React27__namespace.useState([]), [more, setMore] = React27__namespace.useState(false), [busy, setBusy] = React27__namespace.useState(false), [error, setError] = React27__namespace.useState("");
|
|
3818
|
+
const known = React27__namespace.useRef({});
|
|
3819
|
+
for (const item of initialItems) known.current[item.variant_id] = item;
|
|
3820
|
+
React27__namespace.useEffect(() => {
|
|
3821
|
+
const controller = new AbortController();
|
|
3822
|
+
setBusy(true);
|
|
3823
|
+
setError("");
|
|
3824
|
+
const timer = setTimeout(() => {
|
|
3825
|
+
void load(query, page * 50, controller.signal).then((result) => {
|
|
3826
|
+
if (controller.signal.aborted) return;
|
|
3827
|
+
for (const item of result.items)
|
|
3828
|
+
known.current[item.variant_id] = item;
|
|
3829
|
+
setItems((old) => page ? [...old, ...result.items] : result.items);
|
|
3830
|
+
setMore(result.more);
|
|
3831
|
+
}).catch((err) => {
|
|
3832
|
+
if (!controller.signal.aborted)
|
|
3833
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3834
|
+
}).finally(() => {
|
|
3835
|
+
if (!controller.signal.aborted) setBusy(false);
|
|
3836
|
+
});
|
|
3837
|
+
}, 180);
|
|
3838
|
+
return () => {
|
|
3839
|
+
clearTimeout(timer);
|
|
3840
|
+
controller.abort();
|
|
3841
|
+
};
|
|
3842
|
+
}, [load, query, page]);
|
|
3843
|
+
const selected = Object.keys(value).filter((id) => value[id] > 0).map((id) => known.current[id]).filter(Boolean);
|
|
3844
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gap: ".75rem" }, children: [
|
|
3845
|
+
selected.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3846
|
+
"label",
|
|
3847
|
+
{
|
|
3848
|
+
style: {
|
|
3849
|
+
display: "flex",
|
|
3850
|
+
justifyContent: "space-between",
|
|
3851
|
+
gap: "1rem",
|
|
3852
|
+
alignItems: "center"
|
|
3853
|
+
},
|
|
3854
|
+
children: [
|
|
3855
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3856
|
+
p.title,
|
|
3857
|
+
" ",
|
|
3858
|
+
p.variant_title,
|
|
3859
|
+
/* @__PURE__ */ jsxRuntime.jsx("small", { style: { display: "block", color: "var(--nv-muted)" }, children: p.sku })
|
|
3860
|
+
] }),
|
|
3861
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3862
|
+
"input",
|
|
3863
|
+
{
|
|
3864
|
+
"aria-label": `${t("subscriptions.quantity")}: ${p.title}`,
|
|
3865
|
+
type: "number",
|
|
3866
|
+
min: 0,
|
|
3867
|
+
max: maxQuantity,
|
|
3868
|
+
value: value[p.variant_id] ?? 0,
|
|
3869
|
+
onChange: (e) => onChange({ ...value, [p.variant_id]: Number(e.target.value) }),
|
|
3870
|
+
style: {
|
|
3871
|
+
font: "inherit",
|
|
3872
|
+
width: "4.5rem",
|
|
3873
|
+
padding: ".5rem",
|
|
3874
|
+
border: "1px solid var(--nv-border)",
|
|
3875
|
+
borderRadius: "var(--nv-radius)",
|
|
3876
|
+
color: "var(--nv-fg)",
|
|
3877
|
+
background: "var(--nv-bg)"
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
)
|
|
3881
|
+
]
|
|
3882
|
+
},
|
|
3883
|
+
p.variant_id
|
|
3884
|
+
)),
|
|
3885
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3886
|
+
"input",
|
|
3887
|
+
{
|
|
3888
|
+
"aria-label": t("subscriptions.searchProducts"),
|
|
3889
|
+
placeholder: t("subscriptions.searchProducts"),
|
|
3890
|
+
value: query,
|
|
3891
|
+
onChange: (e) => {
|
|
3892
|
+
setQuery(e.target.value);
|
|
3893
|
+
setPage(0);
|
|
3894
|
+
setItems([]);
|
|
3895
|
+
},
|
|
3896
|
+
style: {
|
|
3897
|
+
font: "inherit",
|
|
3898
|
+
padding: ".65rem",
|
|
3899
|
+
border: "1px solid var(--nv-border)",
|
|
3900
|
+
borderRadius: "var(--nv-radius)",
|
|
3901
|
+
background: "var(--nv-bg)",
|
|
3902
|
+
color: "var(--nv-fg)"
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
),
|
|
3906
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3907
|
+
"ul",
|
|
3908
|
+
{
|
|
3909
|
+
style: {
|
|
3910
|
+
listStyle: "none",
|
|
3911
|
+
padding: 0,
|
|
3912
|
+
margin: 0,
|
|
3913
|
+
maxHeight: "18rem",
|
|
3914
|
+
overflowY: "auto"
|
|
3915
|
+
},
|
|
3916
|
+
children: items.filter((p) => !value[p.variant_id]).map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3917
|
+
"li",
|
|
3918
|
+
{
|
|
3919
|
+
style: {
|
|
3920
|
+
display: "flex",
|
|
3921
|
+
alignItems: "center",
|
|
3922
|
+
justifyContent: "space-between",
|
|
3923
|
+
gap: "1rem",
|
|
3924
|
+
padding: ".5rem 0",
|
|
3925
|
+
borderBottom: "1px solid var(--nv-border)"
|
|
3926
|
+
},
|
|
3927
|
+
children: [
|
|
3928
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3929
|
+
p.title,
|
|
3930
|
+
" ",
|
|
3931
|
+
p.variant_title,
|
|
3932
|
+
/* @__PURE__ */ jsxRuntime.jsx("small", { style: { display: "block", color: "var(--nv-muted)" }, children: formatCents(p.unit_gross, p.currency, loc) })
|
|
3933
|
+
] }),
|
|
3934
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3935
|
+
SubscriptionButton,
|
|
3936
|
+
{
|
|
3937
|
+
"aria-label": `${t("subscriptions.addProduct")}: ${p.title}`,
|
|
3938
|
+
onClick: () => onChange({ ...value, [p.variant_id]: 1 }),
|
|
3939
|
+
children: "+"
|
|
3940
|
+
}
|
|
3941
|
+
)
|
|
3942
|
+
]
|
|
3943
|
+
},
|
|
3944
|
+
p.variant_id
|
|
3945
|
+
))
|
|
3946
|
+
}
|
|
3947
|
+
),
|
|
3948
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: t("subscriptions.loadingProducts") }) : more ? /* @__PURE__ */ jsxRuntime.jsx(SubscriptionButton, { onClick: () => setPage((p) => p + 1), children: t("account.loadMore") }) : null,
|
|
3949
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error })
|
|
3950
|
+
] });
|
|
3951
|
+
}
|
|
3952
|
+
function SubscriptionManager({
|
|
3953
|
+
subscriptionId,
|
|
3954
|
+
locale
|
|
3955
|
+
}) {
|
|
3956
|
+
const state = useCustomerSubscription(subscriptionId), { customer } = useAccount(), t = useT();
|
|
3957
|
+
if (!customer) return null;
|
|
3958
|
+
if (state.error)
|
|
3959
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("p", { role: "alert", children: [
|
|
3960
|
+
state.error.message,
|
|
3961
|
+
" ",
|
|
3962
|
+
/* @__PURE__ */ jsxRuntime.jsx(SubscriptionButton, { onClick: () => void state.refresh(), children: t("account.retry") })
|
|
3963
|
+
] });
|
|
3964
|
+
if (!state.subscription)
|
|
3965
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: t("subscriptions.loading") });
|
|
3966
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3967
|
+
Manager,
|
|
3968
|
+
{
|
|
3969
|
+
state,
|
|
3970
|
+
locale
|
|
3971
|
+
},
|
|
3972
|
+
`${customer.id}:${subscriptionId}:${state.subscription.version}:${state.readRevision}`
|
|
3973
|
+
);
|
|
3974
|
+
}
|
|
3975
|
+
function Manager({
|
|
3976
|
+
state,
|
|
3977
|
+
locale
|
|
3978
|
+
}) {
|
|
3979
|
+
const { subscription: s, api, refresh } = state, t = useT(), loc = useFormatLocale(locale);
|
|
3980
|
+
const [mode, setMode] = React27__namespace.useState(null);
|
|
3981
|
+
const [option, setOption] = React27__namespace.useState("");
|
|
3982
|
+
const [quantities, setQuantities] = React27__namespace.useState(
|
|
3983
|
+
{}
|
|
3984
|
+
);
|
|
3985
|
+
const [quote, setQuote] = React27__namespace.useState(null);
|
|
3986
|
+
const [busy, setBusy] = React27__namespace.useState(false), [locked, setLocked] = React27__namespace.useState(false), [error, setError] = React27__namespace.useState("");
|
|
3987
|
+
const [consent, setConsent] = React27__namespace.useState(false);
|
|
3988
|
+
const upcoming = s?.upcoming, heading = React27__namespace.useRef(null);
|
|
3989
|
+
const loader = React27__namespace.useCallback(
|
|
3990
|
+
(q, offset, signal) => api.products(s.id, {
|
|
3991
|
+
q,
|
|
3992
|
+
offset,
|
|
3993
|
+
signal,
|
|
3994
|
+
scope: mode === "mix" ? "mix" : "one_time"
|
|
3995
|
+
}),
|
|
3996
|
+
[api, s?.id, mode]
|
|
3997
|
+
);
|
|
3998
|
+
React27__namespace.useEffect(() => {
|
|
3999
|
+
if (mode) heading.current?.focus();
|
|
4000
|
+
}, [mode]);
|
|
4001
|
+
if (!s || !upcoming) return null;
|
|
4002
|
+
if (s.status !== "active")
|
|
4003
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { style: subscriptionPanel, children: /* @__PURE__ */ jsxRuntime.jsx("h2", { children: t(`subscriptions.status.${s.status}`) }) });
|
|
4004
|
+
const money = (n) => formatCents(n, s.currency, loc);
|
|
4005
|
+
const scope = mode === "mix" ? "recurring" : "one_time";
|
|
4006
|
+
const selected = Object.entries(quantities).filter(([, quantity]) => quantity > 0).map(([variant_id, quantity]) => ({ variant_id, quantity }));
|
|
4007
|
+
const changes = mode === "cadence" ? { cadence_option_id: option } : { lines: selected };
|
|
4008
|
+
const amount = quote ? "recurring_total_cents" in quote ? quote.recurring_total_cents : quote.after.total_cents : upcoming.total_cents;
|
|
4009
|
+
const enter = (next) => {
|
|
4010
|
+
setMode(next);
|
|
4011
|
+
setQuote(null);
|
|
4012
|
+
setConsent(false);
|
|
4013
|
+
setError("");
|
|
4014
|
+
setOption("");
|
|
4015
|
+
setQuantities(
|
|
4016
|
+
Object.fromEntries(
|
|
4017
|
+
upcoming.lines.filter(
|
|
4018
|
+
(li) => li.scope === (next === "mix" ? "recurring" : "one_time")
|
|
4019
|
+
).map((li) => [li.variant_id, li.quantity])
|
|
4020
|
+
)
|
|
4021
|
+
);
|
|
4022
|
+
};
|
|
4023
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4024
|
+
"section",
|
|
4025
|
+
{
|
|
4026
|
+
style: { ...subscriptionPanel, display: "grid", gap: "1rem" },
|
|
4027
|
+
"aria-busy": busy,
|
|
4028
|
+
children: [
|
|
4029
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { children: [
|
|
4030
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontWeight: 500 }, children: t("subscriptions.nextDelivery") }),
|
|
4031
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
4032
|
+
t("subscriptions.chargeDate"),
|
|
4033
|
+
":",
|
|
4034
|
+
" ",
|
|
4035
|
+
/* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: upcoming.due_at, children: new Date(upcoming.due_at).toLocaleString(loc) })
|
|
4036
|
+
] })
|
|
4037
|
+
] }),
|
|
4038
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: upcoming.lines.map((li) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4039
|
+
"li",
|
|
4040
|
+
{
|
|
4041
|
+
style: {
|
|
4042
|
+
display: "flex",
|
|
4043
|
+
justifyContent: "space-between",
|
|
4044
|
+
gap: "1rem",
|
|
4045
|
+
padding: ".65rem 0",
|
|
4046
|
+
borderBottom: "1px solid var(--nv-border)"
|
|
4047
|
+
},
|
|
4048
|
+
children: [
|
|
4049
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4050
|
+
li.title ?? li.sku,
|
|
4051
|
+
" \xD7 ",
|
|
4052
|
+
li.quantity,
|
|
4053
|
+
li.scope === "one_time" ? /* @__PURE__ */ jsxRuntime.jsx("small", { style: { display: "block", color: "var(--nv-muted)" }, children: t("subscriptions.onlyNext") }) : null
|
|
4054
|
+
] }),
|
|
4055
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: money(li.unit_gross * li.quantity - (li.discount_cents ?? 0)) })
|
|
4056
|
+
]
|
|
4057
|
+
},
|
|
4058
|
+
li.line_id
|
|
4059
|
+
)) }),
|
|
4060
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
4061
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t("totals.shipping") }),
|
|
4062
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: money(upcoming.shipping_cents) })
|
|
4063
|
+
] }),
|
|
4064
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4065
|
+
"div",
|
|
4066
|
+
{
|
|
4067
|
+
style: {
|
|
4068
|
+
display: "flex",
|
|
4069
|
+
justifyContent: "space-between",
|
|
4070
|
+
fontWeight: 500
|
|
4071
|
+
},
|
|
4072
|
+
children: [
|
|
4073
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t("subscriptions.toCharge") }),
|
|
4074
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: money(upcoming.total_cents) })
|
|
4075
|
+
]
|
|
4076
|
+
}
|
|
4077
|
+
),
|
|
4078
|
+
upcoming.capabilities.reminder?.enabled ? /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: [
|
|
4079
|
+
t("subscriptions.noticeStatus"),
|
|
4080
|
+
":",
|
|
4081
|
+
" ",
|
|
4082
|
+
t(`subscriptions.notice.${upcoming.reminder?.status ?? "pending"}`)
|
|
4083
|
+
] }) : null,
|
|
4084
|
+
upcoming.charge_held_for_notice && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: t("subscriptions.noticeHeld") }),
|
|
4085
|
+
!upcoming.editable ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: t(
|
|
4086
|
+
`subscriptions.locked.${upcoming.locked_reason_code ?? "in_flight"}`
|
|
4087
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: [
|
|
4088
|
+
t("subscriptions.editUntil"),
|
|
4089
|
+
":",
|
|
4090
|
+
" ",
|
|
4091
|
+
new Date(upcoming.edit_cutoff_at).toLocaleString(loc)
|
|
4092
|
+
] }),
|
|
4093
|
+
!mode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: ".5rem", flexWrap: "wrap" }, children: [
|
|
4094
|
+
!!upcoming.capabilities.cadence_options?.length && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4095
|
+
SubscriptionButton,
|
|
4096
|
+
{
|
|
4097
|
+
disabled: !upcoming.editable,
|
|
4098
|
+
onClick: () => enter("cadence"),
|
|
4099
|
+
children: t("subscriptions.changeInterval")
|
|
4100
|
+
}
|
|
4101
|
+
),
|
|
4102
|
+
upcoming.capabilities.one_time_addons && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4103
|
+
SubscriptionButton,
|
|
4104
|
+
{
|
|
4105
|
+
disabled: !upcoming.editable,
|
|
4106
|
+
onClick: () => enter("addons"),
|
|
4107
|
+
children: t("subscriptions.addNext")
|
|
4108
|
+
}
|
|
4109
|
+
),
|
|
4110
|
+
upcoming.capabilities.mix && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4111
|
+
SubscriptionButton,
|
|
4112
|
+
{
|
|
4113
|
+
disabled: !upcoming.editable,
|
|
4114
|
+
onClick: () => enter("mix"),
|
|
4115
|
+
children: t("subscriptions.changeMix")
|
|
4116
|
+
}
|
|
4117
|
+
),
|
|
4118
|
+
s.allowed_actions.skip && /* @__PURE__ */ jsxRuntime.jsx(SubscriptionButton, { onClick: () => enter("skip"), children: t("subscriptions.skip") })
|
|
4119
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4120
|
+
"form",
|
|
4121
|
+
{
|
|
4122
|
+
noValidate: true,
|
|
4123
|
+
onSubmit: async (event) => {
|
|
4124
|
+
event.preventDefault();
|
|
4125
|
+
if (busy || locked) return;
|
|
4126
|
+
setBusy(true);
|
|
4127
|
+
setError("");
|
|
4128
|
+
try {
|
|
4129
|
+
if (mode === "skip") {
|
|
4130
|
+
if (!consent) return;
|
|
4131
|
+
try {
|
|
4132
|
+
await api.skipNext(s.id, s.version);
|
|
4133
|
+
await refresh();
|
|
4134
|
+
} catch (err) {
|
|
4135
|
+
setLocked(true);
|
|
4136
|
+
throw err;
|
|
4137
|
+
}
|
|
4138
|
+
} else if (!quote) {
|
|
4139
|
+
const q = mode === "addons" ? await api.previewNextItems(s.id, { addons: selected }) : await api.previewChanges(s.id, changes);
|
|
4140
|
+
setQuote(q);
|
|
4141
|
+
setConsent(false);
|
|
4142
|
+
} else {
|
|
4143
|
+
if (!consent) return;
|
|
4144
|
+
try {
|
|
4145
|
+
if (mode === "addons")
|
|
4146
|
+
await api.commitNextItems(
|
|
4147
|
+
s.id,
|
|
4148
|
+
{ addons: selected },
|
|
4149
|
+
quote,
|
|
4150
|
+
"Customer explicitly accepted the displayed next-delivery contents and total"
|
|
4151
|
+
);
|
|
4152
|
+
else
|
|
4153
|
+
await api.commitChanges(
|
|
4154
|
+
s.id,
|
|
4155
|
+
changes,
|
|
4156
|
+
quote,
|
|
4157
|
+
"Customer explicitly accepted the displayed future terms, dates and price"
|
|
4158
|
+
);
|
|
4159
|
+
await refresh();
|
|
4160
|
+
} catch (err) {
|
|
4161
|
+
setLocked(true);
|
|
4162
|
+
throw err;
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
} catch (err) {
|
|
4166
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4167
|
+
} finally {
|
|
4168
|
+
setBusy(false);
|
|
4169
|
+
}
|
|
4170
|
+
},
|
|
4171
|
+
style: {
|
|
4172
|
+
borderTop: "1px solid var(--nv-border)",
|
|
4173
|
+
paddingTop: "1rem",
|
|
4174
|
+
display: "grid",
|
|
4175
|
+
gap: "1rem"
|
|
4176
|
+
},
|
|
4177
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4178
|
+
"fieldset",
|
|
4179
|
+
{
|
|
4180
|
+
disabled: busy,
|
|
4181
|
+
style: {
|
|
4182
|
+
border: 0,
|
|
4183
|
+
margin: 0,
|
|
4184
|
+
padding: 0,
|
|
4185
|
+
display: "grid",
|
|
4186
|
+
gap: "1rem",
|
|
4187
|
+
minWidth: 0
|
|
4188
|
+
},
|
|
4189
|
+
children: [
|
|
4190
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4191
|
+
"h3",
|
|
4192
|
+
{
|
|
4193
|
+
ref: heading,
|
|
4194
|
+
tabIndex: -1,
|
|
4195
|
+
style: { margin: 0, fontWeight: 500 },
|
|
4196
|
+
children: t(
|
|
4197
|
+
mode === "cadence" ? "subscriptions.changeInterval" : mode === "mix" ? "subscriptions.changeMix" : mode === "skip" ? "subscriptions.skip" : "subscriptions.addNext"
|
|
4198
|
+
)
|
|
4199
|
+
}
|
|
4200
|
+
),
|
|
4201
|
+
mode === "skip" ? /* @__PURE__ */ jsxRuntime.jsx("p", { children: t("subscriptions.skipWarning") }) : quote ? /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "status", children: [
|
|
4202
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: t(
|
|
4203
|
+
mode === "addons" ? "subscriptions.onlyNext" : "subscriptions.futureOnly"
|
|
4204
|
+
) }),
|
|
4205
|
+
mode === "cadence" ? /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
4206
|
+
t("subscriptions.nextUnchanged"),
|
|
4207
|
+
":",
|
|
4208
|
+
" ",
|
|
4209
|
+
new Date(
|
|
4210
|
+
String(quote.after.next_at)
|
|
4211
|
+
).toLocaleString(loc)
|
|
4212
|
+
] }) : null,
|
|
4213
|
+
"upcoming_dates" in quote && quote.upcoming_dates?.map((date) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: new Date(date).toLocaleString(loc) }, date)),
|
|
4214
|
+
mode === "addons" && "addons" in quote.after && quote.after.addons.map(
|
|
4215
|
+
(li) => /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
4216
|
+
li.title ?? li.sku ?? li.variant_id,
|
|
4217
|
+
" \xD7 ",
|
|
4218
|
+
li.quantity
|
|
4219
|
+
] }, li.variant_id)
|
|
4220
|
+
),
|
|
4221
|
+
"display_items" in quote && quote.display_items?.map((li) => /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
4222
|
+
li.title,
|
|
4223
|
+
" \xD7 ",
|
|
4224
|
+
li.quantity
|
|
4225
|
+
] }, li.variant_id)),
|
|
4226
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
4227
|
+
t("subscriptions.reviewTotal"),
|
|
4228
|
+
": ",
|
|
4229
|
+
money(amount)
|
|
4230
|
+
] })
|
|
4231
|
+
] }) : mode === "cadence" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4232
|
+
"div",
|
|
4233
|
+
{
|
|
4234
|
+
role: "group",
|
|
4235
|
+
"aria-label": t("subscriptions.changeInterval"),
|
|
4236
|
+
style: { display: "flex", gap: ".5rem", flexWrap: "wrap" },
|
|
4237
|
+
children: upcoming.capabilities.cadence_options?.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4238
|
+
SubscriptionButton,
|
|
4239
|
+
{
|
|
4240
|
+
"aria-pressed": option === o.id,
|
|
4241
|
+
onClick: () => setOption(o.id),
|
|
4242
|
+
children: t(`subscriptions.unit.${o.unit}`, { count: o.count })
|
|
4243
|
+
},
|
|
4244
|
+
o.id
|
|
4245
|
+
))
|
|
4246
|
+
}
|
|
4247
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4248
|
+
ProductSelection,
|
|
4249
|
+
{
|
|
4250
|
+
maxQuantity: mode === "mix" ? upcoming.capabilities.mix?.per_sku_max ?? 99 : 99,
|
|
4251
|
+
load: loader,
|
|
4252
|
+
value: quantities,
|
|
4253
|
+
onChange: setQuantities,
|
|
4254
|
+
initialItems: upcoming.lines.filter((li) => li.scope === scope).map((li) => ({
|
|
4255
|
+
...li,
|
|
4256
|
+
title: li.title ?? li.sku ?? li.variant_id,
|
|
4257
|
+
currency: s.currency,
|
|
4258
|
+
variant_title: li.variant_title ?? null,
|
|
4259
|
+
sku: li.sku ?? null
|
|
4260
|
+
})),
|
|
4261
|
+
locale: loc
|
|
4262
|
+
}
|
|
4263
|
+
),
|
|
4264
|
+
(quote || mode === "skip") && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4265
|
+
"label",
|
|
4266
|
+
{
|
|
4267
|
+
style: {
|
|
4268
|
+
display: "flex",
|
|
4269
|
+
gap: ".5rem",
|
|
4270
|
+
alignItems: "flex-start"
|
|
4271
|
+
},
|
|
4272
|
+
children: [
|
|
4273
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4274
|
+
"input",
|
|
4275
|
+
{
|
|
4276
|
+
type: "checkbox",
|
|
4277
|
+
checked: consent,
|
|
4278
|
+
onChange: (e) => setConsent(e.target.checked)
|
|
4279
|
+
}
|
|
4280
|
+
),
|
|
4281
|
+
t("subscriptions.acceptChange")
|
|
4282
|
+
]
|
|
4283
|
+
}
|
|
4284
|
+
),
|
|
4285
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
|
|
4286
|
+
locked ? /* @__PURE__ */ jsxRuntime.jsx(SubscriptionButton, { onClick: () => void refresh(), children: t("subscriptions.reloadBeforeRetry") }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: ".5rem", flexWrap: "wrap" }, children: [
|
|
4287
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4288
|
+
SubscriptionButton,
|
|
4289
|
+
{
|
|
4290
|
+
disabled: busy,
|
|
4291
|
+
onClick: () => quote ? (setQuote(null), setConsent(false)) : enter(null),
|
|
4292
|
+
children: t(quote ? "subscriptions.back" : "account.cancel")
|
|
4293
|
+
}
|
|
4294
|
+
),
|
|
4295
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4296
|
+
SubscriptionButton,
|
|
4297
|
+
{
|
|
4298
|
+
type: "submit",
|
|
4299
|
+
primary: true,
|
|
4300
|
+
disabled: busy || (quote || mode === "skip" ? !consent : mode === "cadence" ? !option : mode === "mix" ? !selected.length : false),
|
|
4301
|
+
children: busy ? t("subscriptions.loading") : t(
|
|
4302
|
+
quote || mode === "skip" ? "subscriptions.confirmChange" : "subscriptions.reviewChange"
|
|
4303
|
+
)
|
|
4304
|
+
}
|
|
4305
|
+
)
|
|
4306
|
+
] })
|
|
4307
|
+
]
|
|
4308
|
+
}
|
|
4309
|
+
)
|
|
4310
|
+
}
|
|
4311
|
+
)
|
|
4312
|
+
]
|
|
4313
|
+
}
|
|
4314
|
+
);
|
|
4315
|
+
}
|
|
3672
4316
|
function serializeJsonLd(data) {
|
|
3673
4317
|
return JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
|
|
3674
4318
|
}
|
|
@@ -3772,6 +4416,118 @@ function OrganizationJsonLd({
|
|
|
3772
4416
|
});
|
|
3773
4417
|
return /* @__PURE__ */ jsxRuntime.jsx(JsonLd, { data });
|
|
3774
4418
|
}
|
|
4419
|
+
function Mix({
|
|
4420
|
+
plan,
|
|
4421
|
+
marketId,
|
|
4422
|
+
locale,
|
|
4423
|
+
onAdded
|
|
4424
|
+
}) {
|
|
4425
|
+
const client = useStorefront(), cart = useCart(), t = useT(), [value, setValue] = React27__namespace.useState({}), [busy, setBusy] = React27__namespace.useState(false), [error, setError] = React27__namespace.useState(""), [locked, setLocked] = React27__namespace.useState(false);
|
|
4426
|
+
const load = React27__namespace.useCallback(
|
|
4427
|
+
(q, offset, signal) => client.subscriptions.mixProducts(plan.id, {
|
|
4428
|
+
q,
|
|
4429
|
+
offset,
|
|
4430
|
+
marketId,
|
|
4431
|
+
signal
|
|
4432
|
+
}),
|
|
4433
|
+
[client, plan.id, marketId]
|
|
4434
|
+
);
|
|
4435
|
+
const loc = useFormatLocale(locale);
|
|
4436
|
+
const mix = plan.capabilities?.mix;
|
|
4437
|
+
if (!mix) return null;
|
|
4438
|
+
const units = Object.values(value).reduce((a, b) => a + b, 0), lines = Object.entries(value).filter(([, q]) => q > 0).map(([variant_id, quantity]) => ({ variant_id, quantity }));
|
|
4439
|
+
const valid = units >= mix.min_units && units <= mix.max_units && lines.every(
|
|
4440
|
+
(li) => Number.isInteger(li.quantity) && li.quantity <= (mix.per_sku_max ?? 99)
|
|
4441
|
+
) && (mix.groups ?? []).every((g) => {
|
|
4442
|
+
const n = lines.filter((li) => g.variant_ids.includes(li.variant_id)).reduce((a, li) => a + li.quantity, 0);
|
|
4443
|
+
return n >= g.min_units && n <= g.max_units;
|
|
4444
|
+
});
|
|
4445
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { style: { ...subscriptionPanel, display: "grid", gap: "1rem" }, children: [
|
|
4446
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { fontWeight: 500, margin: 0 }, children: plan.name }),
|
|
4447
|
+
plan.price && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
4448
|
+
formatCents(plan.price.amount_cents, plan.price.currency, loc),
|
|
4449
|
+
" \xB7",
|
|
4450
|
+
" ",
|
|
4451
|
+
t("subscriptions.mixPrice")
|
|
4452
|
+
] }),
|
|
4453
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: t("subscriptions.mixCount", {
|
|
4454
|
+
count: units,
|
|
4455
|
+
min: mix.min_units,
|
|
4456
|
+
max: mix.max_units
|
|
4457
|
+
}) }),
|
|
4458
|
+
mix.groups?.map((g) => /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
4459
|
+
g.name,
|
|
4460
|
+
": ",
|
|
4461
|
+
g.min_units,
|
|
4462
|
+
"\u2013",
|
|
4463
|
+
g.max_units
|
|
4464
|
+
] }, g.name)),
|
|
4465
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4466
|
+
"fieldset",
|
|
4467
|
+
{
|
|
4468
|
+
disabled: busy || locked,
|
|
4469
|
+
style: { border: 0, padding: 0, margin: 0, minWidth: 0 },
|
|
4470
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4471
|
+
ProductSelection,
|
|
4472
|
+
{
|
|
4473
|
+
maxQuantity: mix.per_sku_max ?? 99,
|
|
4474
|
+
load,
|
|
4475
|
+
value,
|
|
4476
|
+
onChange: (v) => {
|
|
4477
|
+
setValue(v);
|
|
4478
|
+
setError("");
|
|
4479
|
+
},
|
|
4480
|
+
locale
|
|
4481
|
+
}
|
|
4482
|
+
)
|
|
4483
|
+
}
|
|
4484
|
+
),
|
|
4485
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
|
|
4486
|
+
locked ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4487
|
+
SubscriptionButton,
|
|
4488
|
+
{
|
|
4489
|
+
onClick: async () => {
|
|
4490
|
+
await cart.refresh();
|
|
4491
|
+
setLocked(false);
|
|
4492
|
+
},
|
|
4493
|
+
children: t("subscriptions.reloadBeforeRetry")
|
|
4494
|
+
}
|
|
4495
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4496
|
+
SubscriptionButton,
|
|
4497
|
+
{
|
|
4498
|
+
primary: true,
|
|
4499
|
+
disabled: !valid || busy || cart.loading,
|
|
4500
|
+
onClick: async () => {
|
|
4501
|
+
setBusy(true);
|
|
4502
|
+
setError("");
|
|
4503
|
+
try {
|
|
4504
|
+
await cart.setSubscriptionMix(
|
|
4505
|
+
plan.id,
|
|
4506
|
+
lines,
|
|
4507
|
+
cart.cart?.line_items.filter((li) => li.subscription_plan_id).map((li) => li.id) ?? []
|
|
4508
|
+
);
|
|
4509
|
+
onAdded?.();
|
|
4510
|
+
} catch (err) {
|
|
4511
|
+
setLocked(true);
|
|
4512
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4513
|
+
} finally {
|
|
4514
|
+
setBusy(false);
|
|
4515
|
+
}
|
|
4516
|
+
},
|
|
4517
|
+
children: t("subscriptions.addMix")
|
|
4518
|
+
}
|
|
4519
|
+
)
|
|
4520
|
+
] });
|
|
4521
|
+
}
|
|
4522
|
+
function SubscriptionMix(props) {
|
|
4523
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4524
|
+
Mix,
|
|
4525
|
+
{
|
|
4526
|
+
...props
|
|
4527
|
+
},
|
|
4528
|
+
`${props.plan.id}:${props.plan.version}:${props.marketId ?? ""}`
|
|
4529
|
+
);
|
|
4530
|
+
}
|
|
3775
4531
|
|
|
3776
4532
|
exports.AccountDashboard = AccountDashboard;
|
|
3777
4533
|
exports.AccountProvider = AccountProvider;
|
|
@@ -3818,6 +4574,8 @@ exports.SortSelect = SortSelect;
|
|
|
3818
4574
|
exports.StatusBanner = StatusBanner;
|
|
3819
4575
|
exports.StockBadge = StockBadge;
|
|
3820
4576
|
exports.SubscriptionList = SubscriptionList;
|
|
4577
|
+
exports.SubscriptionManager = SubscriptionManager;
|
|
4578
|
+
exports.SubscriptionMix = SubscriptionMix;
|
|
3821
4579
|
exports.SubscriptionTerms = SubscriptionTerms;
|
|
3822
4580
|
exports.TagFilter = TagFilter;
|
|
3823
4581
|
exports.ThemeProvider = ThemeProvider;
|