@fluid-app/portal-sdk 0.1.483 → 0.1.485
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/{SubscriptionsScreen-DoyP5YBP.cjs → SubscriptionsScreen-9NJY-K63.cjs} +180 -101
- package/dist/SubscriptionsScreen-9NJY-K63.cjs.map +1 -0
- package/dist/{SubscriptionsScreen-0Giqwkng.mjs → SubscriptionsScreen-C44-Ft7P.mjs} +180 -101
- package/dist/SubscriptionsScreen-C44-Ft7P.mjs.map +1 -0
- package/dist/{SubscriptionsScreen-ClSfyR6N.cjs → SubscriptionsScreen-CKbJgV4Y.cjs} +1 -1
- package/dist/{SubscriptionsScreen-BHy5B_66.mjs → SubscriptionsScreen-Duigd4Qu.mjs} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +12 -12
- package/dist/SubscriptionsScreen-0Giqwkng.mjs.map +0 -1
- package/dist/SubscriptionsScreen-DoyP5YBP.cjs.map +0 -1
|
@@ -2600,6 +2600,19 @@ function getMaxEditableBillDate(billingInterval = 1, billingIntervalUnit = "mont
|
|
|
2600
2600
|
if (maxDate.getDate() !== day) maxDate.setDate(0);
|
|
2601
2601
|
return maxDate;
|
|
2602
2602
|
}
|
|
2603
|
+
/**
|
|
2604
|
+
* Latest date a whole bundle's bill date may be edited to. Every member moves
|
|
2605
|
+
* to one shared date, so the strictest member binds: a bundle holding one
|
|
2606
|
+
* monthly plan is capped at 12 months even if its other members are yearly.
|
|
2607
|
+
*
|
|
2608
|
+
* An empty list falls back to the 12-month cap, which is also what a member of
|
|
2609
|
+
* unknown cadence resolves to via getMaxEditableBillDate's own default.
|
|
2610
|
+
*/
|
|
2611
|
+
function getMaxEditableBillDateForBundle(members, from = /* @__PURE__ */ new Date()) {
|
|
2612
|
+
const [first, ...rest] = members.map((member) => getMaxEditableBillDate(member.billingInterval, member.billingIntervalUnit, from));
|
|
2613
|
+
if (!first) return getMaxEditableBillDate(1, "month", from);
|
|
2614
|
+
return rest.reduce((strictest, current) => current < strictest ? current : strictest, first);
|
|
2615
|
+
}
|
|
2603
2616
|
function calculateNextBillDate(billingInterval = 1, billingIntervalUnit = "month") {
|
|
2604
2617
|
const now = /* @__PURE__ */ new Date();
|
|
2605
2618
|
const nextBillDate = new Date(now);
|
|
@@ -2620,6 +2633,36 @@ function calculateNextBillDate(billingInterval = 1, billingIntervalUnit = "month
|
|
|
2620
2633
|
}
|
|
2621
2634
|
return nextBillDate.toISOString().split("T")[0] || "";
|
|
2622
2635
|
}
|
|
2636
|
+
/** Longest pause the dialogs have ever offered, before the cap narrows it. */
|
|
2637
|
+
const MAX_SKIPPABLE_ORDERS = 99;
|
|
2638
|
+
/**
|
|
2639
|
+
* How many upcoming orders a pause may skip: the largest count whose resume
|
|
2640
|
+
* date still lands inside the bill-date cap.
|
|
2641
|
+
*
|
|
2642
|
+
* Pausing for a number of orders sets a bill date like any other edit, so the
|
|
2643
|
+
* API caps the date it derives from that count, 2 years out for a yearly cadence
|
|
2644
|
+
* and 12 months for everything else, and rejects the request naming
|
|
2645
|
+
* number_of_orders. Offering counts past that offers a pause the API refuses.
|
|
2646
|
+
*
|
|
2647
|
+
* Returns 0 when even a single skip overshoots, which happens on a subscription
|
|
2648
|
+
* whose next bill date already sits near the cap. Callers should read that as
|
|
2649
|
+
* "pausing by order count is unavailable here" and leave the indefinite pause.
|
|
2650
|
+
*
|
|
2651
|
+
* The two ends deliberately measure from different places: the resume date
|
|
2652
|
+
* counts forward from the current bill date, the cap counts forward from today.
|
|
2653
|
+
* The API stays the backstop, so the exact boundary count depends on its
|
|
2654
|
+
* resume-date arithmetic agreeing with calculateResumeDate.
|
|
2655
|
+
*/
|
|
2656
|
+
function getMaxSkippableOrders(billingInterval = 1, billingIntervalUnit = "month", currentNextBillDate, from = /* @__PURE__ */ new Date()) {
|
|
2657
|
+
const cap = getMaxEditableBillDate(billingInterval, billingIntervalUnit, from);
|
|
2658
|
+
let allowed = 0;
|
|
2659
|
+
for (let count = 1; count <= MAX_SKIPPABLE_ORDERS; count += 1) {
|
|
2660
|
+
const resume = calculateResumeDate(billingInterval, billingIntervalUnit, count, currentNextBillDate ?? from);
|
|
2661
|
+
if (new Date(resume.getUTCFullYear(), resume.getUTCMonth(), resume.getUTCDate()) > cap) break;
|
|
2662
|
+
allowed = count;
|
|
2663
|
+
}
|
|
2664
|
+
return allowed;
|
|
2665
|
+
}
|
|
2623
2666
|
function formatDate(dateString, locale = "en-US") {
|
|
2624
2667
|
if (!dateString) return "";
|
|
2625
2668
|
const parts = (dateString.split("T")[0] ?? dateString).split("-");
|
|
@@ -2680,22 +2723,30 @@ function formatTime(dateString, timezone, locale = "en-US") {
|
|
|
2680
2723
|
return "";
|
|
2681
2724
|
}
|
|
2682
2725
|
}
|
|
2683
|
-
function getNextBillDisplay(
|
|
2726
|
+
function getNextBillDisplay(nextBillDate, displayStatus, labels = {
|
|
2684
2727
|
cancelled: "Cancelled",
|
|
2685
2728
|
completed: "Completed",
|
|
2686
2729
|
paused: "Paused",
|
|
2687
2730
|
notAvailable: "N/A"
|
|
2688
2731
|
}, locale = "en-US") {
|
|
2689
|
-
if (
|
|
2690
|
-
if (
|
|
2691
|
-
if (
|
|
2692
|
-
if (
|
|
2732
|
+
if (displayStatus === "completed") return labels.completed;
|
|
2733
|
+
if (displayStatus === "cancelled") return labels.cancelled;
|
|
2734
|
+
if (nextBillDate) return formatDate(nextBillDate, locale);
|
|
2735
|
+
if (displayStatus === "paused") return labels.paused;
|
|
2693
2736
|
return labels.notAvailable;
|
|
2694
2737
|
}
|
|
2695
2738
|
//#endregion
|
|
2696
2739
|
//#region ../../subscriptions/core/src/utils/subscription-actions.ts
|
|
2740
|
+
/**
|
|
2741
|
+
* The one rule for a completed subscription: its current plan's
|
|
2742
|
+
* billing-cycle limit is reached. Every "completed" presentation and
|
|
2743
|
+
* gate reads this, so a new terminal condition lands here once.
|
|
2744
|
+
*/
|
|
2745
|
+
function isSubscriptionCompleted(subscription) {
|
|
2746
|
+
return subscription?.billing_cycle_limit_reached === true;
|
|
2747
|
+
}
|
|
2697
2748
|
function getSubscriptionDisplayStatus(subscription) {
|
|
2698
|
-
return subscription
|
|
2749
|
+
return isSubscriptionCompleted(subscription) ? "completed" : subscription.status;
|
|
2699
2750
|
}
|
|
2700
2751
|
function hasPendingSubscriptionSkip(skips, today = /* @__PURE__ */ new Date()) {
|
|
2701
2752
|
if (!skips?.length) return false;
|
|
@@ -2707,13 +2758,11 @@ function hasPendingSubscriptionSkip(skips, today = /* @__PURE__ */ new Date()) {
|
|
|
2707
2758
|
});
|
|
2708
2759
|
}
|
|
2709
2760
|
function getSubscriptionActionPolicy(subscription) {
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
};
|
|
2716
|
-
if (subscription.status === "active") {
|
|
2761
|
+
const status = getSubscriptionDisplayStatus({
|
|
2762
|
+
status: subscription.status,
|
|
2763
|
+
billing_cycle_limit_reached: subscription.billingCycleLimitReached
|
|
2764
|
+
});
|
|
2765
|
+
if (status === "active") {
|
|
2717
2766
|
const skipAllowanceAvailable = subscription.maxSkips == null || (subscription.skippedCount ?? 0) < subscription.maxSkips;
|
|
2718
2767
|
const canSkip = subscription.allowSkipping === true && subscription.nextBillDate != null && skipAllowanceAvailable;
|
|
2719
2768
|
const order = [];
|
|
@@ -2728,19 +2777,19 @@ function getSubscriptionActionPolicy(subscription) {
|
|
|
2728
2777
|
recovery: null
|
|
2729
2778
|
};
|
|
2730
2779
|
}
|
|
2731
|
-
if (
|
|
2780
|
+
if (status === "paused") return {
|
|
2732
2781
|
primary: "resume_subscription",
|
|
2733
2782
|
order: [],
|
|
2734
2783
|
menu: ["cancel_subscription"],
|
|
2735
2784
|
recovery: null
|
|
2736
2785
|
};
|
|
2737
|
-
if (
|
|
2786
|
+
if (status === "cancelled") return {
|
|
2738
2787
|
primary: "reactivate_subscription",
|
|
2739
2788
|
order: [],
|
|
2740
2789
|
menu: [],
|
|
2741
2790
|
recovery: null
|
|
2742
2791
|
};
|
|
2743
|
-
if (
|
|
2792
|
+
if (status === "past_due") {
|
|
2744
2793
|
const isExhausted = subscription.nextRetryAt == null;
|
|
2745
2794
|
const secondary = subscription.canChangePaymentMethod ? "change_payment_method" : null;
|
|
2746
2795
|
return {
|
|
@@ -2756,13 +2805,13 @@ function getSubscriptionActionPolicy(subscription) {
|
|
|
2756
2805
|
}
|
|
2757
2806
|
};
|
|
2758
2807
|
}
|
|
2759
|
-
if (
|
|
2808
|
+
if (status === "completed") return {
|
|
2760
2809
|
primary: null,
|
|
2761
2810
|
order: [],
|
|
2762
2811
|
menu: [],
|
|
2763
2812
|
recovery: null
|
|
2764
2813
|
};
|
|
2765
|
-
if (["pending", "trial"].includes(
|
|
2814
|
+
if (["pending", "trial"].includes(status)) return {
|
|
2766
2815
|
primary: null,
|
|
2767
2816
|
order: [],
|
|
2768
2817
|
menu: ["cancel_subscription"],
|
|
@@ -4188,6 +4237,30 @@ function isPaymentMethodUsable(pm) {
|
|
|
4188
4237
|
return Boolean(addr.address1 && addr.city && addr.state && addr.zip && addr.country_code);
|
|
4189
4238
|
}
|
|
4190
4239
|
//#endregion
|
|
4240
|
+
//#region src/screens/subscriptions/bundle-drawer/bill-date-bounds.ts
|
|
4241
|
+
function getDaysInMonth(year, month) {
|
|
4242
|
+
return new Date(year, month + 1, 0).getDate();
|
|
4243
|
+
}
|
|
4244
|
+
function isYearOutOfRange(year, { today, maxDate }) {
|
|
4245
|
+
return year < today.getFullYear() || year > maxDate.getFullYear();
|
|
4246
|
+
}
|
|
4247
|
+
function isMonthOutOfRange(year, month, bounds) {
|
|
4248
|
+
const { today, maxDate } = bounds;
|
|
4249
|
+
if (isYearOutOfRange(year, bounds)) return true;
|
|
4250
|
+
if (year === maxDate.getFullYear() && month > maxDate.getMonth()) return true;
|
|
4251
|
+
if (year > today.getFullYear()) return false;
|
|
4252
|
+
return month < today.getMonth();
|
|
4253
|
+
}
|
|
4254
|
+
function isDayOutOfRange(year, month, day, bounds) {
|
|
4255
|
+
const { today, maxDate } = bounds;
|
|
4256
|
+
if (day > getDaysInMonth(year, month)) return true;
|
|
4257
|
+
if (isMonthOutOfRange(year, month, bounds)) return true;
|
|
4258
|
+
if (year === maxDate.getFullYear() && month === maxDate.getMonth() && day > maxDate.getDate()) return true;
|
|
4259
|
+
if (year > today.getFullYear()) return false;
|
|
4260
|
+
if (month > today.getMonth()) return false;
|
|
4261
|
+
return day < today.getDate();
|
|
4262
|
+
}
|
|
4263
|
+
//#endregion
|
|
4191
4264
|
//#region src/screens/subscriptions/bundle-drawer/use-bundle-form.ts
|
|
4192
4265
|
function pickDefaultAddressId(addresses, defaultAddressId) {
|
|
4193
4266
|
if (defaultAddressId != null) {
|
|
@@ -4208,11 +4281,11 @@ function pickDefaultPaymentMethodId(paymentMethods, defaultPaymentMethodId) {
|
|
|
4208
4281
|
if (flagged) return flagged.id;
|
|
4209
4282
|
return usable[0]?.id ?? null;
|
|
4210
4283
|
}
|
|
4211
|
-
function useBundleForm({ addresses, paymentMethods, defaultAddressId, defaultPaymentMethodId }) {
|
|
4284
|
+
function useBundleForm({ subscriptions: subscriptionList, addresses, paymentMethods, defaultAddressId, defaultPaymentMethodId }) {
|
|
4212
4285
|
const [step, setStep] = (0, react.useState)(1);
|
|
4213
4286
|
const [selectedTokens, setSelectedTokens] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
4214
4287
|
const today = (0, react.useMemo)(() => /* @__PURE__ */ new Date(), []);
|
|
4215
|
-
const [selectedYear, setYearState] = (0, react.useState)(today.
|
|
4288
|
+
const [selectedYear, setYearState] = (0, react.useState)(today.getFullYear());
|
|
4216
4289
|
const [selectedMonth, setMonthState] = (0, react.useState)(null);
|
|
4217
4290
|
const [selectedDay, setDayState] = (0, react.useState)(null);
|
|
4218
4291
|
const [selectedAddressId, setSelectedAddressId] = (0, react.useState)(() => pickDefaultAddressId(addresses, defaultAddressId));
|
|
@@ -4231,55 +4304,73 @@ function useBundleForm({ addresses, paymentMethods, defaultAddressId, defaultPay
|
|
|
4231
4304
|
paymentMethods,
|
|
4232
4305
|
defaultPaymentMethodId
|
|
4233
4306
|
]);
|
|
4307
|
+
const toggleToken = (0, react.useCallback)((token) => {
|
|
4308
|
+
setSelectedTokens((prev) => {
|
|
4309
|
+
const next = new Set(prev);
|
|
4310
|
+
if (next.has(token)) next.delete(token);
|
|
4311
|
+
else next.add(token);
|
|
4312
|
+
return next;
|
|
4313
|
+
});
|
|
4314
|
+
}, []);
|
|
4315
|
+
const bounds = (0, react.useMemo)(() => {
|
|
4316
|
+
return {
|
|
4317
|
+
today,
|
|
4318
|
+
maxDate: getMaxEditableBillDateForBundle(Array.from(selectedTokens).map((token) => {
|
|
4319
|
+
const plan = subscriptionList.find((sub) => sub.subscription_token === token)?.subscription_plan;
|
|
4320
|
+
return {
|
|
4321
|
+
billingInterval: plan?.billing_interval,
|
|
4322
|
+
billingIntervalUnit: plan?.billing_interval_unit
|
|
4323
|
+
};
|
|
4324
|
+
}), today)
|
|
4325
|
+
};
|
|
4326
|
+
}, [
|
|
4327
|
+
selectedTokens,
|
|
4328
|
+
subscriptionList,
|
|
4329
|
+
today
|
|
4330
|
+
]);
|
|
4331
|
+
const setYear = (0, react.useCallback)((y) => {
|
|
4332
|
+
setYearState(y);
|
|
4333
|
+
if (selectedMonth == null) return;
|
|
4334
|
+
if (isMonthOutOfRange(y, selectedMonth, bounds)) {
|
|
4335
|
+
setMonthState(null);
|
|
4336
|
+
setDayState(null);
|
|
4337
|
+
return;
|
|
4338
|
+
}
|
|
4339
|
+
if (selectedDay != null && isDayOutOfRange(y, selectedMonth, selectedDay, bounds)) setDayState(null);
|
|
4340
|
+
}, [
|
|
4341
|
+
selectedMonth,
|
|
4342
|
+
selectedDay,
|
|
4343
|
+
bounds
|
|
4344
|
+
]);
|
|
4345
|
+
const setMonth = (0, react.useCallback)((m) => {
|
|
4346
|
+
setMonthState(m);
|
|
4347
|
+
if (selectedDay != null && isDayOutOfRange(selectedYear, m, selectedDay, bounds)) setDayState(null);
|
|
4348
|
+
}, [
|
|
4349
|
+
selectedDay,
|
|
4350
|
+
selectedYear,
|
|
4351
|
+
bounds
|
|
4352
|
+
]);
|
|
4353
|
+
const setDay = (0, react.useCallback)((d) => setDayState(d), []);
|
|
4354
|
+
const canProceedFromStep1 = selectedTokens.size >= 2;
|
|
4355
|
+
const selectedDateOutOfRange = selectedMonth !== null && selectedDay !== null && isDayOutOfRange(selectedYear, selectedMonth, selectedDay, bounds);
|
|
4234
4356
|
return {
|
|
4235
4357
|
step,
|
|
4236
4358
|
setStep,
|
|
4237
4359
|
selectedTokens,
|
|
4238
|
-
toggleToken
|
|
4239
|
-
setSelectedTokens((prev) => {
|
|
4240
|
-
const next = new Set(prev);
|
|
4241
|
-
if (next.has(token)) next.delete(token);
|
|
4242
|
-
else next.add(token);
|
|
4243
|
-
return next;
|
|
4244
|
-
});
|
|
4245
|
-
}, []),
|
|
4360
|
+
toggleToken,
|
|
4246
4361
|
selectedYear,
|
|
4247
4362
|
selectedMonth,
|
|
4248
4363
|
selectedDay,
|
|
4249
|
-
setYear
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
const isPastMonth = y < today.getUTCFullYear() || y === today.getUTCFullYear() && selectedMonth < today.getUTCMonth();
|
|
4253
|
-
const isPastDay = y === today.getUTCFullYear() && selectedMonth === today.getUTCMonth() && selectedDay != null && selectedDay < today.getUTCDate();
|
|
4254
|
-
if (isPastMonth) {
|
|
4255
|
-
setMonthState(null);
|
|
4256
|
-
setDayState(null);
|
|
4257
|
-
} else if (isPastDay) setDayState(null);
|
|
4258
|
-
}
|
|
4259
|
-
}, [
|
|
4260
|
-
selectedMonth,
|
|
4261
|
-
selectedDay,
|
|
4262
|
-
today
|
|
4263
|
-
]),
|
|
4264
|
-
setMonth: (0, react.useCallback)((m) => {
|
|
4265
|
-
setMonthState(m);
|
|
4266
|
-
if (selectedDay != null) {
|
|
4267
|
-
const daysInNewMonth = new Date(Date.UTC(selectedYear, m + 1, 0)).getUTCDate();
|
|
4268
|
-
const isPastDay = selectedYear === today.getUTCFullYear() && m === today.getUTCMonth() && selectedDay < today.getUTCDate();
|
|
4269
|
-
if (selectedDay > daysInNewMonth || isPastDay) setDayState(null);
|
|
4270
|
-
}
|
|
4271
|
-
}, [
|
|
4272
|
-
selectedDay,
|
|
4273
|
-
selectedYear,
|
|
4274
|
-
today
|
|
4275
|
-
]),
|
|
4276
|
-
setDay: (0, react.useCallback)((d) => setDayState(d), []),
|
|
4364
|
+
setYear,
|
|
4365
|
+
setMonth,
|
|
4366
|
+
setDay,
|
|
4277
4367
|
selectedAddressId,
|
|
4278
4368
|
setSelectedAddressId,
|
|
4279
4369
|
selectedPaymentMethodId,
|
|
4280
4370
|
setSelectedPaymentMethodId,
|
|
4281
|
-
|
|
4282
|
-
|
|
4371
|
+
bounds,
|
|
4372
|
+
canProceedFromStep1,
|
|
4373
|
+
canProceedFromStep2: selectedMonth !== null && selectedDay !== null && !selectedDateOutOfRange,
|
|
4283
4374
|
canProceedFromStep3: selectedAddressId != null,
|
|
4284
4375
|
canProceedFromStep4: selectedPaymentMethodId != null,
|
|
4285
4376
|
formattedDate: (0, react.useMemo)(() => {
|
|
@@ -4508,34 +4599,20 @@ const MONTHS = [
|
|
|
4508
4599
|
"Nov",
|
|
4509
4600
|
"Dec"
|
|
4510
4601
|
];
|
|
4511
|
-
function
|
|
4512
|
-
return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
|
4513
|
-
}
|
|
4514
|
-
function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange, onMonthChange, onDayChange }) {
|
|
4602
|
+
function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange, onMonthChange, onDayChange, bounds }) {
|
|
4515
4603
|
const { t } = useSubscriptionsTranslation();
|
|
4516
|
-
const
|
|
4517
|
-
const currentYear = today.getUTCFullYear();
|
|
4518
|
-
const currentMonth = today.getUTCMonth();
|
|
4519
|
-
const currentDay = today.getUTCDate();
|
|
4604
|
+
const currentYear = bounds.today.getFullYear();
|
|
4520
4605
|
const availableYears = (0, react.useMemo)(() => [
|
|
4521
4606
|
currentYear,
|
|
4522
4607
|
currentYear + 1,
|
|
4523
4608
|
currentYear + 2
|
|
4524
4609
|
], [currentYear]);
|
|
4525
|
-
const
|
|
4526
|
-
|
|
4527
|
-
if (selectedYear > currentYear) return false;
|
|
4528
|
-
return monthIndex < currentMonth;
|
|
4529
|
-
};
|
|
4610
|
+
const isYearDisabled = (year) => isYearOutOfRange(year, bounds);
|
|
4611
|
+
const isMonthDisabled = (monthIndex) => isMonthOutOfRange(selectedYear, monthIndex, bounds);
|
|
4530
4612
|
const daysInSelectedMonth = selectedMonth == null ? 31 : getDaysInMonth(selectedYear, selectedMonth);
|
|
4531
4613
|
const isDayDisabled = (day) => {
|
|
4532
4614
|
if (selectedMonth == null) return true;
|
|
4533
|
-
|
|
4534
|
-
if (selectedYear < currentYear) return true;
|
|
4535
|
-
if (selectedYear > currentYear) return false;
|
|
4536
|
-
if (selectedMonth > currentMonth) return false;
|
|
4537
|
-
if (selectedMonth < currentMonth) return true;
|
|
4538
|
-
return day < currentDay;
|
|
4615
|
+
return isDayOutOfRange(selectedYear, selectedMonth, day, bounds);
|
|
4539
4616
|
};
|
|
4540
4617
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4541
4618
|
className: "flex-1 overflow-y-auto px-6 py-4",
|
|
@@ -4558,10 +4635,13 @@ function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange
|
|
|
4558
4635
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4559
4636
|
className: "grid grid-cols-3 gap-2",
|
|
4560
4637
|
children: availableYears.map((year) => {
|
|
4638
|
+
const isActive = selectedYear === year;
|
|
4639
|
+
const disabled = isYearDisabled(year);
|
|
4561
4640
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4562
4641
|
type: "button",
|
|
4642
|
+
disabled,
|
|
4563
4643
|
onClick: () => onYearChange(year),
|
|
4564
|
-
className: `rounded-lg px-3 py-2.5 text-xs font-semibold transition-all ${
|
|
4644
|
+
className: `rounded-lg px-3 py-2.5 text-xs font-semibold transition-all ${isActive ? "bg-primary text-primary-foreground" : "text-foreground ring-border hover:ring-foreground/20 bg-transparent ring-1"} ${disabled ? "cursor-not-allowed opacity-40" : ""}`,
|
|
4565
4645
|
children: year
|
|
4566
4646
|
}, year);
|
|
4567
4647
|
})
|
|
@@ -4805,6 +4885,7 @@ function BundleSubscriptionsDrawer({ open, onOpenChange, subscriptions: subscrip
|
|
|
4805
4885
|
const { t } = useSubscriptionsTranslation();
|
|
4806
4886
|
const { isMobile } = require_sidebar.useSidebar();
|
|
4807
4887
|
const form = useBundleForm({
|
|
4888
|
+
subscriptions: subscriptionList,
|
|
4808
4889
|
addresses,
|
|
4809
4890
|
paymentMethods,
|
|
4810
4891
|
defaultAddressId,
|
|
@@ -4849,7 +4930,8 @@ function BundleSubscriptionsDrawer({ open, onOpenChange, subscriptions: subscrip
|
|
|
4849
4930
|
selectedDay: form.selectedDay,
|
|
4850
4931
|
onYearChange: form.setYear,
|
|
4851
4932
|
onMonthChange: form.setMonth,
|
|
4852
|
-
onDayChange: form.setDay
|
|
4933
|
+
onDayChange: form.setDay,
|
|
4934
|
+
bounds: form.bounds
|
|
4853
4935
|
}),
|
|
4854
4936
|
form.step === 3 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DrawerStepAddress, {
|
|
4855
4937
|
addresses,
|
|
@@ -5410,7 +5492,8 @@ function PauseSubscriptionDialog({ open, onOpenChange, onConfirm, isLoading, err
|
|
|
5410
5492
|
const { t, locale } = useSubscriptionsTranslation();
|
|
5411
5493
|
const [pauseType, setPauseType] = (0, react.useState)("indefinite");
|
|
5412
5494
|
const [selectedOrderCount, setSelectedOrderCount] = (0, react.useState)(null);
|
|
5413
|
-
const
|
|
5495
|
+
const maxSkippableOrders = getMaxSkippableOrders(billingInterval, billingIntervalUnit, currentNextBillDate);
|
|
5496
|
+
const orderCountOptions = Array.from({ length: maxSkippableOrders }, (_, i) => i + 1);
|
|
5414
5497
|
const calculatedResumeDate = selectedOrderCount && currentNextBillDate ? calculateResumeDate(billingInterval, billingIntervalUnit, selectedOrderCount, currentNextBillDate) : null;
|
|
5415
5498
|
(0, react.useEffect)(() => {
|
|
5416
5499
|
if (!open) return;
|
|
@@ -5490,10 +5573,11 @@ function PauseSubscriptionDialog({ open, onOpenChange, onConfirm, isLoading, err
|
|
|
5490
5573
|
type: "radio",
|
|
5491
5574
|
checked: pauseType === "order_count",
|
|
5492
5575
|
onChange: () => setPauseType("order_count"),
|
|
5493
|
-
|
|
5576
|
+
disabled: maxSkippableOrders === 0,
|
|
5577
|
+
className: "border-border accent-primary size-4 focus:ring-0 disabled:opacity-40"
|
|
5494
5578
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Label, {
|
|
5495
5579
|
htmlFor: "pause-order-count",
|
|
5496
|
-
className: "text-foreground cursor-
|
|
5580
|
+
className: `text-sm font-medium ${maxSkippableOrders === 0 ? "text-muted-foreground cursor-not-allowed" : "text-foreground cursor-pointer"}`,
|
|
5497
5581
|
children: t("pause_for_orders")
|
|
5498
5582
|
})]
|
|
5499
5583
|
}), pauseType === "order_count" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -6487,12 +6571,14 @@ function SubscriptionItemsSection({ subscription, displayQuantity, displayNextBi
|
|
|
6487
6571
|
const variant = subscription.variant;
|
|
6488
6572
|
const product = variant?.product;
|
|
6489
6573
|
const quantity = displayQuantity ?? subscription.quantity;
|
|
6574
|
+
const displayStatus = getSubscriptionDisplayStatus(subscription);
|
|
6575
|
+
const paymentFailed = displayStatus === "past_due";
|
|
6490
6576
|
const quantityInputId = `subscription-${subscription.subscription_token}-quantity`;
|
|
6491
6577
|
const pricing = computeSubscriptionPricing(subscription);
|
|
6492
6578
|
const subtotal = formatCurrency(pricing.subtotalUnit * quantity);
|
|
6493
6579
|
const totalPrice = formatCurrency(pricing.totalUnit * quantity);
|
|
6494
6580
|
const effectiveNextBillDate = displayNextBillDate ?? subscription.next_bill_date;
|
|
6495
|
-
const nextOrderTimeOfDay =
|
|
6581
|
+
const nextOrderTimeOfDay = displayStatus === "completed" ? "" : formatTime(effectiveNextBillDate, subscription.timezone, locale);
|
|
6496
6582
|
const nextBillDisplayLabels = {
|
|
6497
6583
|
cancelled: t("date_cancelled"),
|
|
6498
6584
|
completed: t("list_status_completed"),
|
|
@@ -6516,14 +6602,11 @@ function SubscriptionItemsSection({ subscription, displayQuantity, displayNextBi
|
|
|
6516
6602
|
children: [
|
|
6517
6603
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6518
6604
|
className: "text-muted-foreground mb-1 text-sm",
|
|
6519
|
-
children:
|
|
6605
|
+
children: paymentFailed ? t("payment_failed_on") : t("next_order_date")
|
|
6520
6606
|
}),
|
|
6521
6607
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6522
6608
|
className: "text-foreground text-2xl font-bold",
|
|
6523
|
-
children:
|
|
6524
|
-
...subscription,
|
|
6525
|
-
next_bill_date: displayNextBillDate
|
|
6526
|
-
} : subscription, nextBillDisplayLabels, locale)
|
|
6609
|
+
children: paymentFailed ? subscription.last_failed_at ? formatOptionalDate(subscription.last_failed_at, locale) : "—" : getNextBillDisplay(effectiveNextBillDate, displayStatus, nextBillDisplayLabels, locale)
|
|
6527
6610
|
}),
|
|
6528
6611
|
nextOrderTimeOfDay && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6529
6612
|
className: "text-muted-foreground mt-1 text-xs",
|
|
@@ -6654,10 +6737,7 @@ function SubscriptionManagementSection({ subscription, actionPolicy, isMutating,
|
|
|
6654
6737
|
const plan = subscription.subscription_plan;
|
|
6655
6738
|
const quantity = subscription.quantity;
|
|
6656
6739
|
const totalPrice = formatCurrency(subscription.price * quantity);
|
|
6657
|
-
const displayStatus = getSubscriptionDisplayStatus(
|
|
6658
|
-
status: subscription.status,
|
|
6659
|
-
billingCycleLimitReached: subscription.billing_cycle_limit_reached
|
|
6660
|
-
});
|
|
6740
|
+
const displayStatus = getSubscriptionDisplayStatus(subscription);
|
|
6661
6741
|
const cadenceKey = getCadenceKey(plan.billing_interval_unit);
|
|
6662
6742
|
const interval = plan.billing_interval;
|
|
6663
6743
|
const unitKeys = UNIT_KEYS[plan.billing_interval_unit.toLowerCase()];
|
|
@@ -6852,7 +6932,7 @@ function SubscriptionManagementSection({ subscription, actionPolicy, isMutating,
|
|
|
6852
6932
|
subscriptionToken: subscription.subscription_token,
|
|
6853
6933
|
customerId: subscription.customer?.id ?? 0,
|
|
6854
6934
|
countryCode: subscription.address?.country_code ?? "US",
|
|
6855
|
-
disabled: subscription
|
|
6935
|
+
disabled: isSubscriptionCompleted(subscription)
|
|
6856
6936
|
}) : subscription.address && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6857
6937
|
className: "border-border mb-6 border-b pb-4",
|
|
6858
6938
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -6989,7 +7069,7 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
6989
7069
|
const { data, isLoading, error } = useSubscription(token);
|
|
6990
7070
|
const subscription = data?.subscription;
|
|
6991
7071
|
const customerId = subscription?.customer?.id ?? 0;
|
|
6992
|
-
const waiverPreviewEnabled = subscription?.status === "past_due" && subscription
|
|
7072
|
+
const waiverPreviewEnabled = subscription?.status === "past_due" && !isSubscriptionCompleted(subscription) && subscription.next_retry_at == null;
|
|
6993
7073
|
const waiverPreviewQuery = useFailedCycleWaiverPreview(token, { enabled: waiverPreviewEnabled });
|
|
6994
7074
|
const isWaiverPreviewLoading = waiverPreviewEnabled && waiverPreviewQuery.isFetching;
|
|
6995
7075
|
const waiverPreview = waiverPreviewQuery.data?.failed_cycle_waiver;
|
|
@@ -7149,7 +7229,8 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
7149
7229
|
if (isLoading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SubscriptionDetailSkeleton, {});
|
|
7150
7230
|
if (!subscription) return null;
|
|
7151
7231
|
const plan = subscription.subscription_plan;
|
|
7152
|
-
const
|
|
7232
|
+
const displayStatus = getSubscriptionDisplayStatus(subscription);
|
|
7233
|
+
const isActive = displayStatus === "active";
|
|
7153
7234
|
const actionPolicy = getSubscriptionActionPolicy({
|
|
7154
7235
|
status: subscription.status,
|
|
7155
7236
|
billingCycleLimitReached: subscription.billing_cycle_limit_reached,
|
|
@@ -7168,7 +7249,7 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
7168
7249
|
const childPaymentRecoveryDisabled = childPaymentRecoveryToken === token;
|
|
7169
7250
|
const waiverMutationPending = waiverMutation.isPending && waiverMutation.variables?.subscriptionToken === token;
|
|
7170
7251
|
const aggregateRecoveryDisabled = directParentRecoveryDisabled || childPaymentRecoveryDisabled || waiverMutationPending;
|
|
7171
|
-
const paymentMethodDisabled = subscription
|
|
7252
|
+
const paymentMethodDisabled = isSubscriptionCompleted(subscription) || directParentRecoveryDisabled || waiverMutationPending || independentParentMutationDisabled;
|
|
7172
7253
|
const isMutating = independentParentMutationDisabled || aggregateRecoveryDisabled;
|
|
7173
7254
|
const handlePauseConfirm = (selection) => {
|
|
7174
7255
|
const pauseParams = { customerId };
|
|
@@ -7225,7 +7306,7 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
7225
7306
|
}, { onSuccess: () => setShowReactivateModal(false) });
|
|
7226
7307
|
};
|
|
7227
7308
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
7228
|
-
|
|
7309
|
+
displayStatus === "past_due" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7229
7310
|
className: "mb-4 px-2 sm:px-0 lg:mb-6",
|
|
7230
7311
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PastDueBanner, {
|
|
7231
7312
|
productTitle: subscription.variant?.product?.title ?? null,
|
|
@@ -7545,7 +7626,7 @@ async function invalidateSubscriptionPaymentRecoveryCache(queryClient, subscript
|
|
|
7545
7626
|
}
|
|
7546
7627
|
async function completeSubscriptionPaymentUpdate(args) {
|
|
7547
7628
|
const cached = args.queryClient.getQueryData(subscriptionsKeys.detail(args.updatedSubscriptionToken));
|
|
7548
|
-
if (cached?.subscription.status === "past_due" && cached.subscription
|
|
7629
|
+
if (cached?.subscription.status === "past_due" && !isSubscriptionCompleted(cached.subscription)) {
|
|
7549
7630
|
args.queueRetry(args.updatedSubscriptionToken);
|
|
7550
7631
|
return;
|
|
7551
7632
|
}
|
|
@@ -8336,7 +8417,6 @@ function PortalSubscriptionShippingAddressSectionInner({ addressId, address: cur
|
|
|
8336
8417
|
addressList: addresses,
|
|
8337
8418
|
selectedAddressId: addressId ?? 0,
|
|
8338
8419
|
onSelectAddress: (addr) => {
|
|
8339
|
-
if (disabled) return;
|
|
8340
8420
|
if (addr.id === addressId) return;
|
|
8341
8421
|
updateSubscription.mutate({
|
|
8342
8422
|
subscriptionToken,
|
|
@@ -8344,7 +8424,6 @@ function PortalSubscriptionShippingAddressSectionInner({ addressId, address: cur
|
|
|
8344
8424
|
});
|
|
8345
8425
|
},
|
|
8346
8426
|
onAddAddressClick: () => {
|
|
8347
|
-
if (disabled) return;
|
|
8348
8427
|
setEditingAddress(null);
|
|
8349
8428
|
setIsFormDialogOpen(true);
|
|
8350
8429
|
},
|
|
@@ -8614,4 +8693,4 @@ Object.defineProperty(exports, "subscriptionsScreenPropertySchema", {
|
|
|
8614
8693
|
}
|
|
8615
8694
|
});
|
|
8616
8695
|
|
|
8617
|
-
//# sourceMappingURL=SubscriptionsScreen-
|
|
8696
|
+
//# sourceMappingURL=SubscriptionsScreen-9NJY-K63.cjs.map
|