@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
|
@@ -2538,6 +2538,19 @@ function getMaxEditableBillDate(billingInterval = 1, billingIntervalUnit = "mont
|
|
|
2538
2538
|
if (maxDate.getDate() !== day) maxDate.setDate(0);
|
|
2539
2539
|
return maxDate;
|
|
2540
2540
|
}
|
|
2541
|
+
/**
|
|
2542
|
+
* Latest date a whole bundle's bill date may be edited to. Every member moves
|
|
2543
|
+
* to one shared date, so the strictest member binds: a bundle holding one
|
|
2544
|
+
* monthly plan is capped at 12 months even if its other members are yearly.
|
|
2545
|
+
*
|
|
2546
|
+
* An empty list falls back to the 12-month cap, which is also what a member of
|
|
2547
|
+
* unknown cadence resolves to via getMaxEditableBillDate's own default.
|
|
2548
|
+
*/
|
|
2549
|
+
function getMaxEditableBillDateForBundle(members, from = /* @__PURE__ */ new Date()) {
|
|
2550
|
+
const [first, ...rest] = members.map((member) => getMaxEditableBillDate(member.billingInterval, member.billingIntervalUnit, from));
|
|
2551
|
+
if (!first) return getMaxEditableBillDate(1, "month", from);
|
|
2552
|
+
return rest.reduce((strictest, current) => current < strictest ? current : strictest, first);
|
|
2553
|
+
}
|
|
2541
2554
|
function calculateNextBillDate(billingInterval = 1, billingIntervalUnit = "month") {
|
|
2542
2555
|
const now = /* @__PURE__ */ new Date();
|
|
2543
2556
|
const nextBillDate = new Date(now);
|
|
@@ -2558,6 +2571,36 @@ function calculateNextBillDate(billingInterval = 1, billingIntervalUnit = "month
|
|
|
2558
2571
|
}
|
|
2559
2572
|
return nextBillDate.toISOString().split("T")[0] || "";
|
|
2560
2573
|
}
|
|
2574
|
+
/** Longest pause the dialogs have ever offered, before the cap narrows it. */
|
|
2575
|
+
const MAX_SKIPPABLE_ORDERS = 99;
|
|
2576
|
+
/**
|
|
2577
|
+
* How many upcoming orders a pause may skip: the largest count whose resume
|
|
2578
|
+
* date still lands inside the bill-date cap.
|
|
2579
|
+
*
|
|
2580
|
+
* Pausing for a number of orders sets a bill date like any other edit, so the
|
|
2581
|
+
* API caps the date it derives from that count, 2 years out for a yearly cadence
|
|
2582
|
+
* and 12 months for everything else, and rejects the request naming
|
|
2583
|
+
* number_of_orders. Offering counts past that offers a pause the API refuses.
|
|
2584
|
+
*
|
|
2585
|
+
* Returns 0 when even a single skip overshoots, which happens on a subscription
|
|
2586
|
+
* whose next bill date already sits near the cap. Callers should read that as
|
|
2587
|
+
* "pausing by order count is unavailable here" and leave the indefinite pause.
|
|
2588
|
+
*
|
|
2589
|
+
* The two ends deliberately measure from different places: the resume date
|
|
2590
|
+
* counts forward from the current bill date, the cap counts forward from today.
|
|
2591
|
+
* The API stays the backstop, so the exact boundary count depends on its
|
|
2592
|
+
* resume-date arithmetic agreeing with calculateResumeDate.
|
|
2593
|
+
*/
|
|
2594
|
+
function getMaxSkippableOrders(billingInterval = 1, billingIntervalUnit = "month", currentNextBillDate, from = /* @__PURE__ */ new Date()) {
|
|
2595
|
+
const cap = getMaxEditableBillDate(billingInterval, billingIntervalUnit, from);
|
|
2596
|
+
let allowed = 0;
|
|
2597
|
+
for (let count = 1; count <= MAX_SKIPPABLE_ORDERS; count += 1) {
|
|
2598
|
+
const resume = calculateResumeDate(billingInterval, billingIntervalUnit, count, currentNextBillDate ?? from);
|
|
2599
|
+
if (new Date(resume.getUTCFullYear(), resume.getUTCMonth(), resume.getUTCDate()) > cap) break;
|
|
2600
|
+
allowed = count;
|
|
2601
|
+
}
|
|
2602
|
+
return allowed;
|
|
2603
|
+
}
|
|
2561
2604
|
function formatDate(dateString, locale = "en-US") {
|
|
2562
2605
|
if (!dateString) return "";
|
|
2563
2606
|
const parts = (dateString.split("T")[0] ?? dateString).split("-");
|
|
@@ -2618,22 +2661,30 @@ function formatTime(dateString, timezone, locale = "en-US") {
|
|
|
2618
2661
|
return "";
|
|
2619
2662
|
}
|
|
2620
2663
|
}
|
|
2621
|
-
function getNextBillDisplay(
|
|
2664
|
+
function getNextBillDisplay(nextBillDate, displayStatus, labels = {
|
|
2622
2665
|
cancelled: "Cancelled",
|
|
2623
2666
|
completed: "Completed",
|
|
2624
2667
|
paused: "Paused",
|
|
2625
2668
|
notAvailable: "N/A"
|
|
2626
2669
|
}, locale = "en-US") {
|
|
2627
|
-
if (
|
|
2628
|
-
if (
|
|
2629
|
-
if (
|
|
2630
|
-
if (
|
|
2670
|
+
if (displayStatus === "completed") return labels.completed;
|
|
2671
|
+
if (displayStatus === "cancelled") return labels.cancelled;
|
|
2672
|
+
if (nextBillDate) return formatDate(nextBillDate, locale);
|
|
2673
|
+
if (displayStatus === "paused") return labels.paused;
|
|
2631
2674
|
return labels.notAvailable;
|
|
2632
2675
|
}
|
|
2633
2676
|
//#endregion
|
|
2634
2677
|
//#region ../../subscriptions/core/src/utils/subscription-actions.ts
|
|
2678
|
+
/**
|
|
2679
|
+
* The one rule for a completed subscription: its current plan's
|
|
2680
|
+
* billing-cycle limit is reached. Every "completed" presentation and
|
|
2681
|
+
* gate reads this, so a new terminal condition lands here once.
|
|
2682
|
+
*/
|
|
2683
|
+
function isSubscriptionCompleted(subscription) {
|
|
2684
|
+
return subscription?.billing_cycle_limit_reached === true;
|
|
2685
|
+
}
|
|
2635
2686
|
function getSubscriptionDisplayStatus(subscription) {
|
|
2636
|
-
return subscription
|
|
2687
|
+
return isSubscriptionCompleted(subscription) ? "completed" : subscription.status;
|
|
2637
2688
|
}
|
|
2638
2689
|
function hasPendingSubscriptionSkip(skips, today = /* @__PURE__ */ new Date()) {
|
|
2639
2690
|
if (!skips?.length) return false;
|
|
@@ -2645,13 +2696,11 @@ function hasPendingSubscriptionSkip(skips, today = /* @__PURE__ */ new Date()) {
|
|
|
2645
2696
|
});
|
|
2646
2697
|
}
|
|
2647
2698
|
function getSubscriptionActionPolicy(subscription) {
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
};
|
|
2654
|
-
if (subscription.status === "active") {
|
|
2699
|
+
const status = getSubscriptionDisplayStatus({
|
|
2700
|
+
status: subscription.status,
|
|
2701
|
+
billing_cycle_limit_reached: subscription.billingCycleLimitReached
|
|
2702
|
+
});
|
|
2703
|
+
if (status === "active") {
|
|
2655
2704
|
const skipAllowanceAvailable = subscription.maxSkips == null || (subscription.skippedCount ?? 0) < subscription.maxSkips;
|
|
2656
2705
|
const canSkip = subscription.allowSkipping === true && subscription.nextBillDate != null && skipAllowanceAvailable;
|
|
2657
2706
|
const order = [];
|
|
@@ -2666,19 +2715,19 @@ function getSubscriptionActionPolicy(subscription) {
|
|
|
2666
2715
|
recovery: null
|
|
2667
2716
|
};
|
|
2668
2717
|
}
|
|
2669
|
-
if (
|
|
2718
|
+
if (status === "paused") return {
|
|
2670
2719
|
primary: "resume_subscription",
|
|
2671
2720
|
order: [],
|
|
2672
2721
|
menu: ["cancel_subscription"],
|
|
2673
2722
|
recovery: null
|
|
2674
2723
|
};
|
|
2675
|
-
if (
|
|
2724
|
+
if (status === "cancelled") return {
|
|
2676
2725
|
primary: "reactivate_subscription",
|
|
2677
2726
|
order: [],
|
|
2678
2727
|
menu: [],
|
|
2679
2728
|
recovery: null
|
|
2680
2729
|
};
|
|
2681
|
-
if (
|
|
2730
|
+
if (status === "past_due") {
|
|
2682
2731
|
const isExhausted = subscription.nextRetryAt == null;
|
|
2683
2732
|
const secondary = subscription.canChangePaymentMethod ? "change_payment_method" : null;
|
|
2684
2733
|
return {
|
|
@@ -2694,13 +2743,13 @@ function getSubscriptionActionPolicy(subscription) {
|
|
|
2694
2743
|
}
|
|
2695
2744
|
};
|
|
2696
2745
|
}
|
|
2697
|
-
if (
|
|
2746
|
+
if (status === "completed") return {
|
|
2698
2747
|
primary: null,
|
|
2699
2748
|
order: [],
|
|
2700
2749
|
menu: [],
|
|
2701
2750
|
recovery: null
|
|
2702
2751
|
};
|
|
2703
|
-
if (["pending", "trial"].includes(
|
|
2752
|
+
if (["pending", "trial"].includes(status)) return {
|
|
2704
2753
|
primary: null,
|
|
2705
2754
|
order: [],
|
|
2706
2755
|
menu: ["cancel_subscription"],
|
|
@@ -4126,6 +4175,30 @@ function isPaymentMethodUsable(pm) {
|
|
|
4126
4175
|
return Boolean(addr.address1 && addr.city && addr.state && addr.zip && addr.country_code);
|
|
4127
4176
|
}
|
|
4128
4177
|
//#endregion
|
|
4178
|
+
//#region src/screens/subscriptions/bundle-drawer/bill-date-bounds.ts
|
|
4179
|
+
function getDaysInMonth(year, month) {
|
|
4180
|
+
return new Date(year, month + 1, 0).getDate();
|
|
4181
|
+
}
|
|
4182
|
+
function isYearOutOfRange(year, { today, maxDate }) {
|
|
4183
|
+
return year < today.getFullYear() || year > maxDate.getFullYear();
|
|
4184
|
+
}
|
|
4185
|
+
function isMonthOutOfRange(year, month, bounds) {
|
|
4186
|
+
const { today, maxDate } = bounds;
|
|
4187
|
+
if (isYearOutOfRange(year, bounds)) return true;
|
|
4188
|
+
if (year === maxDate.getFullYear() && month > maxDate.getMonth()) return true;
|
|
4189
|
+
if (year > today.getFullYear()) return false;
|
|
4190
|
+
return month < today.getMonth();
|
|
4191
|
+
}
|
|
4192
|
+
function isDayOutOfRange(year, month, day, bounds) {
|
|
4193
|
+
const { today, maxDate } = bounds;
|
|
4194
|
+
if (day > getDaysInMonth(year, month)) return true;
|
|
4195
|
+
if (isMonthOutOfRange(year, month, bounds)) return true;
|
|
4196
|
+
if (year === maxDate.getFullYear() && month === maxDate.getMonth() && day > maxDate.getDate()) return true;
|
|
4197
|
+
if (year > today.getFullYear()) return false;
|
|
4198
|
+
if (month > today.getMonth()) return false;
|
|
4199
|
+
return day < today.getDate();
|
|
4200
|
+
}
|
|
4201
|
+
//#endregion
|
|
4129
4202
|
//#region src/screens/subscriptions/bundle-drawer/use-bundle-form.ts
|
|
4130
4203
|
function pickDefaultAddressId(addresses, defaultAddressId) {
|
|
4131
4204
|
if (defaultAddressId != null) {
|
|
@@ -4146,11 +4219,11 @@ function pickDefaultPaymentMethodId(paymentMethods, defaultPaymentMethodId) {
|
|
|
4146
4219
|
if (flagged) return flagged.id;
|
|
4147
4220
|
return usable[0]?.id ?? null;
|
|
4148
4221
|
}
|
|
4149
|
-
function useBundleForm({ addresses, paymentMethods, defaultAddressId, defaultPaymentMethodId }) {
|
|
4222
|
+
function useBundleForm({ subscriptions: subscriptionList, addresses, paymentMethods, defaultAddressId, defaultPaymentMethodId }) {
|
|
4150
4223
|
const [step, setStep] = useState(1);
|
|
4151
4224
|
const [selectedTokens, setSelectedTokens] = useState(() => /* @__PURE__ */ new Set());
|
|
4152
4225
|
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
4153
|
-
const [selectedYear, setYearState] = useState(today.
|
|
4226
|
+
const [selectedYear, setYearState] = useState(today.getFullYear());
|
|
4154
4227
|
const [selectedMonth, setMonthState] = useState(null);
|
|
4155
4228
|
const [selectedDay, setDayState] = useState(null);
|
|
4156
4229
|
const [selectedAddressId, setSelectedAddressId] = useState(() => pickDefaultAddressId(addresses, defaultAddressId));
|
|
@@ -4169,55 +4242,73 @@ function useBundleForm({ addresses, paymentMethods, defaultAddressId, defaultPay
|
|
|
4169
4242
|
paymentMethods,
|
|
4170
4243
|
defaultPaymentMethodId
|
|
4171
4244
|
]);
|
|
4245
|
+
const toggleToken = useCallback((token) => {
|
|
4246
|
+
setSelectedTokens((prev) => {
|
|
4247
|
+
const next = new Set(prev);
|
|
4248
|
+
if (next.has(token)) next.delete(token);
|
|
4249
|
+
else next.add(token);
|
|
4250
|
+
return next;
|
|
4251
|
+
});
|
|
4252
|
+
}, []);
|
|
4253
|
+
const bounds = useMemo(() => {
|
|
4254
|
+
return {
|
|
4255
|
+
today,
|
|
4256
|
+
maxDate: getMaxEditableBillDateForBundle(Array.from(selectedTokens).map((token) => {
|
|
4257
|
+
const plan = subscriptionList.find((sub) => sub.subscription_token === token)?.subscription_plan;
|
|
4258
|
+
return {
|
|
4259
|
+
billingInterval: plan?.billing_interval,
|
|
4260
|
+
billingIntervalUnit: plan?.billing_interval_unit
|
|
4261
|
+
};
|
|
4262
|
+
}), today)
|
|
4263
|
+
};
|
|
4264
|
+
}, [
|
|
4265
|
+
selectedTokens,
|
|
4266
|
+
subscriptionList,
|
|
4267
|
+
today
|
|
4268
|
+
]);
|
|
4269
|
+
const setYear = useCallback((y) => {
|
|
4270
|
+
setYearState(y);
|
|
4271
|
+
if (selectedMonth == null) return;
|
|
4272
|
+
if (isMonthOutOfRange(y, selectedMonth, bounds)) {
|
|
4273
|
+
setMonthState(null);
|
|
4274
|
+
setDayState(null);
|
|
4275
|
+
return;
|
|
4276
|
+
}
|
|
4277
|
+
if (selectedDay != null && isDayOutOfRange(y, selectedMonth, selectedDay, bounds)) setDayState(null);
|
|
4278
|
+
}, [
|
|
4279
|
+
selectedMonth,
|
|
4280
|
+
selectedDay,
|
|
4281
|
+
bounds
|
|
4282
|
+
]);
|
|
4283
|
+
const setMonth = useCallback((m) => {
|
|
4284
|
+
setMonthState(m);
|
|
4285
|
+
if (selectedDay != null && isDayOutOfRange(selectedYear, m, selectedDay, bounds)) setDayState(null);
|
|
4286
|
+
}, [
|
|
4287
|
+
selectedDay,
|
|
4288
|
+
selectedYear,
|
|
4289
|
+
bounds
|
|
4290
|
+
]);
|
|
4291
|
+
const setDay = useCallback((d) => setDayState(d), []);
|
|
4292
|
+
const canProceedFromStep1 = selectedTokens.size >= 2;
|
|
4293
|
+
const selectedDateOutOfRange = selectedMonth !== null && selectedDay !== null && isDayOutOfRange(selectedYear, selectedMonth, selectedDay, bounds);
|
|
4172
4294
|
return {
|
|
4173
4295
|
step,
|
|
4174
4296
|
setStep,
|
|
4175
4297
|
selectedTokens,
|
|
4176
|
-
toggleToken
|
|
4177
|
-
setSelectedTokens((prev) => {
|
|
4178
|
-
const next = new Set(prev);
|
|
4179
|
-
if (next.has(token)) next.delete(token);
|
|
4180
|
-
else next.add(token);
|
|
4181
|
-
return next;
|
|
4182
|
-
});
|
|
4183
|
-
}, []),
|
|
4298
|
+
toggleToken,
|
|
4184
4299
|
selectedYear,
|
|
4185
4300
|
selectedMonth,
|
|
4186
4301
|
selectedDay,
|
|
4187
|
-
setYear
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
const isPastMonth = y < today.getUTCFullYear() || y === today.getUTCFullYear() && selectedMonth < today.getUTCMonth();
|
|
4191
|
-
const isPastDay = y === today.getUTCFullYear() && selectedMonth === today.getUTCMonth() && selectedDay != null && selectedDay < today.getUTCDate();
|
|
4192
|
-
if (isPastMonth) {
|
|
4193
|
-
setMonthState(null);
|
|
4194
|
-
setDayState(null);
|
|
4195
|
-
} else if (isPastDay) setDayState(null);
|
|
4196
|
-
}
|
|
4197
|
-
}, [
|
|
4198
|
-
selectedMonth,
|
|
4199
|
-
selectedDay,
|
|
4200
|
-
today
|
|
4201
|
-
]),
|
|
4202
|
-
setMonth: useCallback((m) => {
|
|
4203
|
-
setMonthState(m);
|
|
4204
|
-
if (selectedDay != null) {
|
|
4205
|
-
const daysInNewMonth = new Date(Date.UTC(selectedYear, m + 1, 0)).getUTCDate();
|
|
4206
|
-
const isPastDay = selectedYear === today.getUTCFullYear() && m === today.getUTCMonth() && selectedDay < today.getUTCDate();
|
|
4207
|
-
if (selectedDay > daysInNewMonth || isPastDay) setDayState(null);
|
|
4208
|
-
}
|
|
4209
|
-
}, [
|
|
4210
|
-
selectedDay,
|
|
4211
|
-
selectedYear,
|
|
4212
|
-
today
|
|
4213
|
-
]),
|
|
4214
|
-
setDay: useCallback((d) => setDayState(d), []),
|
|
4302
|
+
setYear,
|
|
4303
|
+
setMonth,
|
|
4304
|
+
setDay,
|
|
4215
4305
|
selectedAddressId,
|
|
4216
4306
|
setSelectedAddressId,
|
|
4217
4307
|
selectedPaymentMethodId,
|
|
4218
4308
|
setSelectedPaymentMethodId,
|
|
4219
|
-
|
|
4220
|
-
|
|
4309
|
+
bounds,
|
|
4310
|
+
canProceedFromStep1,
|
|
4311
|
+
canProceedFromStep2: selectedMonth !== null && selectedDay !== null && !selectedDateOutOfRange,
|
|
4221
4312
|
canProceedFromStep3: selectedAddressId != null,
|
|
4222
4313
|
canProceedFromStep4: selectedPaymentMethodId != null,
|
|
4223
4314
|
formattedDate: useMemo(() => {
|
|
@@ -4446,34 +4537,20 @@ const MONTHS = [
|
|
|
4446
4537
|
"Nov",
|
|
4447
4538
|
"Dec"
|
|
4448
4539
|
];
|
|
4449
|
-
function
|
|
4450
|
-
return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
|
4451
|
-
}
|
|
4452
|
-
function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange, onMonthChange, onDayChange }) {
|
|
4540
|
+
function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange, onMonthChange, onDayChange, bounds }) {
|
|
4453
4541
|
const { t } = useSubscriptionsTranslation();
|
|
4454
|
-
const
|
|
4455
|
-
const currentYear = today.getUTCFullYear();
|
|
4456
|
-
const currentMonth = today.getUTCMonth();
|
|
4457
|
-
const currentDay = today.getUTCDate();
|
|
4542
|
+
const currentYear = bounds.today.getFullYear();
|
|
4458
4543
|
const availableYears = useMemo(() => [
|
|
4459
4544
|
currentYear,
|
|
4460
4545
|
currentYear + 1,
|
|
4461
4546
|
currentYear + 2
|
|
4462
4547
|
], [currentYear]);
|
|
4463
|
-
const
|
|
4464
|
-
|
|
4465
|
-
if (selectedYear > currentYear) return false;
|
|
4466
|
-
return monthIndex < currentMonth;
|
|
4467
|
-
};
|
|
4548
|
+
const isYearDisabled = (year) => isYearOutOfRange(year, bounds);
|
|
4549
|
+
const isMonthDisabled = (monthIndex) => isMonthOutOfRange(selectedYear, monthIndex, bounds);
|
|
4468
4550
|
const daysInSelectedMonth = selectedMonth == null ? 31 : getDaysInMonth(selectedYear, selectedMonth);
|
|
4469
4551
|
const isDayDisabled = (day) => {
|
|
4470
4552
|
if (selectedMonth == null) return true;
|
|
4471
|
-
|
|
4472
|
-
if (selectedYear < currentYear) return true;
|
|
4473
|
-
if (selectedYear > currentYear) return false;
|
|
4474
|
-
if (selectedMonth > currentMonth) return false;
|
|
4475
|
-
if (selectedMonth < currentMonth) return true;
|
|
4476
|
-
return day < currentDay;
|
|
4553
|
+
return isDayOutOfRange(selectedYear, selectedMonth, day, bounds);
|
|
4477
4554
|
};
|
|
4478
4555
|
return /* @__PURE__ */ jsxs("div", {
|
|
4479
4556
|
className: "flex-1 overflow-y-auto px-6 py-4",
|
|
@@ -4496,10 +4573,13 @@ function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange
|
|
|
4496
4573
|
}), /* @__PURE__ */ jsx("div", {
|
|
4497
4574
|
className: "grid grid-cols-3 gap-2",
|
|
4498
4575
|
children: availableYears.map((year) => {
|
|
4576
|
+
const isActive = selectedYear === year;
|
|
4577
|
+
const disabled = isYearDisabled(year);
|
|
4499
4578
|
return /* @__PURE__ */ jsx("button", {
|
|
4500
4579
|
type: "button",
|
|
4580
|
+
disabled,
|
|
4501
4581
|
onClick: () => onYearChange(year),
|
|
4502
|
-
className: `rounded-lg px-3 py-2.5 text-xs font-semibold transition-all ${
|
|
4582
|
+
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" : ""}`,
|
|
4503
4583
|
children: year
|
|
4504
4584
|
}, year);
|
|
4505
4585
|
})
|
|
@@ -4743,6 +4823,7 @@ function BundleSubscriptionsDrawer({ open, onOpenChange, subscriptions: subscrip
|
|
|
4743
4823
|
const { t } = useSubscriptionsTranslation();
|
|
4744
4824
|
const { isMobile } = useSidebar();
|
|
4745
4825
|
const form = useBundleForm({
|
|
4826
|
+
subscriptions: subscriptionList,
|
|
4746
4827
|
addresses,
|
|
4747
4828
|
paymentMethods,
|
|
4748
4829
|
defaultAddressId,
|
|
@@ -4787,7 +4868,8 @@ function BundleSubscriptionsDrawer({ open, onOpenChange, subscriptions: subscrip
|
|
|
4787
4868
|
selectedDay: form.selectedDay,
|
|
4788
4869
|
onYearChange: form.setYear,
|
|
4789
4870
|
onMonthChange: form.setMonth,
|
|
4790
|
-
onDayChange: form.setDay
|
|
4871
|
+
onDayChange: form.setDay,
|
|
4872
|
+
bounds: form.bounds
|
|
4791
4873
|
}),
|
|
4792
4874
|
form.step === 3 && /* @__PURE__ */ jsx(DrawerStepAddress, {
|
|
4793
4875
|
addresses,
|
|
@@ -5348,7 +5430,8 @@ function PauseSubscriptionDialog({ open, onOpenChange, onConfirm, isLoading, err
|
|
|
5348
5430
|
const { t, locale } = useSubscriptionsTranslation();
|
|
5349
5431
|
const [pauseType, setPauseType] = useState("indefinite");
|
|
5350
5432
|
const [selectedOrderCount, setSelectedOrderCount] = useState(null);
|
|
5351
|
-
const
|
|
5433
|
+
const maxSkippableOrders = getMaxSkippableOrders(billingInterval, billingIntervalUnit, currentNextBillDate);
|
|
5434
|
+
const orderCountOptions = Array.from({ length: maxSkippableOrders }, (_, i) => i + 1);
|
|
5352
5435
|
const calculatedResumeDate = selectedOrderCount && currentNextBillDate ? calculateResumeDate(billingInterval, billingIntervalUnit, selectedOrderCount, currentNextBillDate) : null;
|
|
5353
5436
|
useEffect(() => {
|
|
5354
5437
|
if (!open) return;
|
|
@@ -5428,10 +5511,11 @@ function PauseSubscriptionDialog({ open, onOpenChange, onConfirm, isLoading, err
|
|
|
5428
5511
|
type: "radio",
|
|
5429
5512
|
checked: pauseType === "order_count",
|
|
5430
5513
|
onChange: () => setPauseType("order_count"),
|
|
5431
|
-
|
|
5514
|
+
disabled: maxSkippableOrders === 0,
|
|
5515
|
+
className: "border-border accent-primary size-4 focus:ring-0 disabled:opacity-40"
|
|
5432
5516
|
}), /* @__PURE__ */ jsx(Label, {
|
|
5433
5517
|
htmlFor: "pause-order-count",
|
|
5434
|
-
className: "text-foreground cursor-
|
|
5518
|
+
className: `text-sm font-medium ${maxSkippableOrders === 0 ? "text-muted-foreground cursor-not-allowed" : "text-foreground cursor-pointer"}`,
|
|
5435
5519
|
children: t("pause_for_orders")
|
|
5436
5520
|
})]
|
|
5437
5521
|
}), pauseType === "order_count" && /* @__PURE__ */ jsxs("div", {
|
|
@@ -6425,12 +6509,14 @@ function SubscriptionItemsSection({ subscription, displayQuantity, displayNextBi
|
|
|
6425
6509
|
const variant = subscription.variant;
|
|
6426
6510
|
const product = variant?.product;
|
|
6427
6511
|
const quantity = displayQuantity ?? subscription.quantity;
|
|
6512
|
+
const displayStatus = getSubscriptionDisplayStatus(subscription);
|
|
6513
|
+
const paymentFailed = displayStatus === "past_due";
|
|
6428
6514
|
const quantityInputId = `subscription-${subscription.subscription_token}-quantity`;
|
|
6429
6515
|
const pricing = computeSubscriptionPricing(subscription);
|
|
6430
6516
|
const subtotal = formatCurrency(pricing.subtotalUnit * quantity);
|
|
6431
6517
|
const totalPrice = formatCurrency(pricing.totalUnit * quantity);
|
|
6432
6518
|
const effectiveNextBillDate = displayNextBillDate ?? subscription.next_bill_date;
|
|
6433
|
-
const nextOrderTimeOfDay =
|
|
6519
|
+
const nextOrderTimeOfDay = displayStatus === "completed" ? "" : formatTime(effectiveNextBillDate, subscription.timezone, locale);
|
|
6434
6520
|
const nextBillDisplayLabels = {
|
|
6435
6521
|
cancelled: t("date_cancelled"),
|
|
6436
6522
|
completed: t("list_status_completed"),
|
|
@@ -6454,14 +6540,11 @@ function SubscriptionItemsSection({ subscription, displayQuantity, displayNextBi
|
|
|
6454
6540
|
children: [
|
|
6455
6541
|
/* @__PURE__ */ jsx("div", {
|
|
6456
6542
|
className: "text-muted-foreground mb-1 text-sm",
|
|
6457
|
-
children:
|
|
6543
|
+
children: paymentFailed ? t("payment_failed_on") : t("next_order_date")
|
|
6458
6544
|
}),
|
|
6459
6545
|
/* @__PURE__ */ jsx("div", {
|
|
6460
6546
|
className: "text-foreground text-2xl font-bold",
|
|
6461
|
-
children:
|
|
6462
|
-
...subscription,
|
|
6463
|
-
next_bill_date: displayNextBillDate
|
|
6464
|
-
} : subscription, nextBillDisplayLabels, locale)
|
|
6547
|
+
children: paymentFailed ? subscription.last_failed_at ? formatOptionalDate(subscription.last_failed_at, locale) : "—" : getNextBillDisplay(effectiveNextBillDate, displayStatus, nextBillDisplayLabels, locale)
|
|
6465
6548
|
}),
|
|
6466
6549
|
nextOrderTimeOfDay && /* @__PURE__ */ jsxs("div", {
|
|
6467
6550
|
className: "text-muted-foreground mt-1 text-xs",
|
|
@@ -6592,10 +6675,7 @@ function SubscriptionManagementSection({ subscription, actionPolicy, isMutating,
|
|
|
6592
6675
|
const plan = subscription.subscription_plan;
|
|
6593
6676
|
const quantity = subscription.quantity;
|
|
6594
6677
|
const totalPrice = formatCurrency(subscription.price * quantity);
|
|
6595
|
-
const displayStatus = getSubscriptionDisplayStatus(
|
|
6596
|
-
status: subscription.status,
|
|
6597
|
-
billingCycleLimitReached: subscription.billing_cycle_limit_reached
|
|
6598
|
-
});
|
|
6678
|
+
const displayStatus = getSubscriptionDisplayStatus(subscription);
|
|
6599
6679
|
const cadenceKey = getCadenceKey(plan.billing_interval_unit);
|
|
6600
6680
|
const interval = plan.billing_interval;
|
|
6601
6681
|
const unitKeys = UNIT_KEYS[plan.billing_interval_unit.toLowerCase()];
|
|
@@ -6790,7 +6870,7 @@ function SubscriptionManagementSection({ subscription, actionPolicy, isMutating,
|
|
|
6790
6870
|
subscriptionToken: subscription.subscription_token,
|
|
6791
6871
|
customerId: subscription.customer?.id ?? 0,
|
|
6792
6872
|
countryCode: subscription.address?.country_code ?? "US",
|
|
6793
|
-
disabled: subscription
|
|
6873
|
+
disabled: isSubscriptionCompleted(subscription)
|
|
6794
6874
|
}) : subscription.address && /* @__PURE__ */ jsxs("div", {
|
|
6795
6875
|
className: "border-border mb-6 border-b pb-4",
|
|
6796
6876
|
children: [/* @__PURE__ */ jsx("div", {
|
|
@@ -6927,7 +7007,7 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
6927
7007
|
const { data, isLoading, error } = useSubscription(token);
|
|
6928
7008
|
const subscription = data?.subscription;
|
|
6929
7009
|
const customerId = subscription?.customer?.id ?? 0;
|
|
6930
|
-
const waiverPreviewEnabled = subscription?.status === "past_due" && subscription
|
|
7010
|
+
const waiverPreviewEnabled = subscription?.status === "past_due" && !isSubscriptionCompleted(subscription) && subscription.next_retry_at == null;
|
|
6931
7011
|
const waiverPreviewQuery = useFailedCycleWaiverPreview(token, { enabled: waiverPreviewEnabled });
|
|
6932
7012
|
const isWaiverPreviewLoading = waiverPreviewEnabled && waiverPreviewQuery.isFetching;
|
|
6933
7013
|
const waiverPreview = waiverPreviewQuery.data?.failed_cycle_waiver;
|
|
@@ -7087,7 +7167,8 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
7087
7167
|
if (isLoading) return /* @__PURE__ */ jsx(SubscriptionDetailSkeleton, {});
|
|
7088
7168
|
if (!subscription) return null;
|
|
7089
7169
|
const plan = subscription.subscription_plan;
|
|
7090
|
-
const
|
|
7170
|
+
const displayStatus = getSubscriptionDisplayStatus(subscription);
|
|
7171
|
+
const isActive = displayStatus === "active";
|
|
7091
7172
|
const actionPolicy = getSubscriptionActionPolicy({
|
|
7092
7173
|
status: subscription.status,
|
|
7093
7174
|
billingCycleLimitReached: subscription.billing_cycle_limit_reached,
|
|
@@ -7106,7 +7187,7 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
7106
7187
|
const childPaymentRecoveryDisabled = childPaymentRecoveryToken === token;
|
|
7107
7188
|
const waiverMutationPending = waiverMutation.isPending && waiverMutation.variables?.subscriptionToken === token;
|
|
7108
7189
|
const aggregateRecoveryDisabled = directParentRecoveryDisabled || childPaymentRecoveryDisabled || waiverMutationPending;
|
|
7109
|
-
const paymentMethodDisabled = subscription
|
|
7190
|
+
const paymentMethodDisabled = isSubscriptionCompleted(subscription) || directParentRecoveryDisabled || waiverMutationPending || independentParentMutationDisabled;
|
|
7110
7191
|
const isMutating = independentParentMutationDisabled || aggregateRecoveryDisabled;
|
|
7111
7192
|
const handlePauseConfirm = (selection) => {
|
|
7112
7193
|
const pauseParams = { customerId };
|
|
@@ -7163,7 +7244,7 @@ function SubscriptionDetail({ token, onNotFound, onError, onSuccess, onMutationE
|
|
|
7163
7244
|
}, { onSuccess: () => setShowReactivateModal(false) });
|
|
7164
7245
|
};
|
|
7165
7246
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
7166
|
-
|
|
7247
|
+
displayStatus === "past_due" && /* @__PURE__ */ jsx("div", {
|
|
7167
7248
|
className: "mb-4 px-2 sm:px-0 lg:mb-6",
|
|
7168
7249
|
children: /* @__PURE__ */ jsx(PastDueBanner, {
|
|
7169
7250
|
productTitle: subscription.variant?.product?.title ?? null,
|
|
@@ -7483,7 +7564,7 @@ async function invalidateSubscriptionPaymentRecoveryCache(queryClient, subscript
|
|
|
7483
7564
|
}
|
|
7484
7565
|
async function completeSubscriptionPaymentUpdate(args) {
|
|
7485
7566
|
const cached = args.queryClient.getQueryData(subscriptionsKeys.detail(args.updatedSubscriptionToken));
|
|
7486
|
-
if (cached?.subscription.status === "past_due" && cached.subscription
|
|
7567
|
+
if (cached?.subscription.status === "past_due" && !isSubscriptionCompleted(cached.subscription)) {
|
|
7487
7568
|
args.queueRetry(args.updatedSubscriptionToken);
|
|
7488
7569
|
return;
|
|
7489
7570
|
}
|
|
@@ -8274,7 +8355,6 @@ function PortalSubscriptionShippingAddressSectionInner({ addressId, address: cur
|
|
|
8274
8355
|
addressList: addresses,
|
|
8275
8356
|
selectedAddressId: addressId ?? 0,
|
|
8276
8357
|
onSelectAddress: (addr) => {
|
|
8277
|
-
if (disabled) return;
|
|
8278
8358
|
if (addr.id === addressId) return;
|
|
8279
8359
|
updateSubscription.mutate({
|
|
8280
8360
|
subscriptionToken,
|
|
@@ -8282,7 +8362,6 @@ function PortalSubscriptionShippingAddressSectionInner({ addressId, address: cur
|
|
|
8282
8362
|
});
|
|
8283
8363
|
},
|
|
8284
8364
|
onAddAddressClick: () => {
|
|
8285
|
-
if (disabled) return;
|
|
8286
8365
|
setEditingAddress(null);
|
|
8287
8366
|
setIsFormDialogOpen(true);
|
|
8288
8367
|
},
|
|
@@ -8541,4 +8620,4 @@ const subscriptionsScreenPropertySchema = {
|
|
|
8541
8620
|
//#endregion
|
|
8542
8621
|
export { subscriptionsScreenPropertySchema as n, SubscriptionsScreen as t };
|
|
8543
8622
|
|
|
8544
|
-
//# sourceMappingURL=SubscriptionsScreen-
|
|
8623
|
+
//# sourceMappingURL=SubscriptionsScreen-C44-Ft7P.mjs.map
|