@fluid-app/portal-sdk 0.1.484 → 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-DPymXVC4.cjs → SubscriptionsScreen-9NJY-K63.cjs} +143 -65
- package/dist/SubscriptionsScreen-9NJY-K63.cjs.map +1 -0
- package/dist/{SubscriptionsScreen-BKJALFrF.mjs → SubscriptionsScreen-C44-Ft7P.mjs} +143 -65
- package/dist/SubscriptionsScreen-C44-Ft7P.mjs.map +1 -0
- package/dist/{SubscriptionsScreen-DIxkq3nu.cjs → SubscriptionsScreen-CKbJgV4Y.cjs} +1 -1
- package/dist/{SubscriptionsScreen-B8vSO2d9.mjs → SubscriptionsScreen-Duigd4Qu.mjs} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +14 -14
- package/dist/SubscriptionsScreen-BKJALFrF.mjs.map +0 -1
- package/dist/SubscriptionsScreen-DPymXVC4.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("-");
|
|
@@ -4194,6 +4237,30 @@ function isPaymentMethodUsable(pm) {
|
|
|
4194
4237
|
return Boolean(addr.address1 && addr.city && addr.state && addr.zip && addr.country_code);
|
|
4195
4238
|
}
|
|
4196
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
|
|
4197
4264
|
//#region src/screens/subscriptions/bundle-drawer/use-bundle-form.ts
|
|
4198
4265
|
function pickDefaultAddressId(addresses, defaultAddressId) {
|
|
4199
4266
|
if (defaultAddressId != null) {
|
|
@@ -4214,11 +4281,11 @@ function pickDefaultPaymentMethodId(paymentMethods, defaultPaymentMethodId) {
|
|
|
4214
4281
|
if (flagged) return flagged.id;
|
|
4215
4282
|
return usable[0]?.id ?? null;
|
|
4216
4283
|
}
|
|
4217
|
-
function useBundleForm({ addresses, paymentMethods, defaultAddressId, defaultPaymentMethodId }) {
|
|
4284
|
+
function useBundleForm({ subscriptions: subscriptionList, addresses, paymentMethods, defaultAddressId, defaultPaymentMethodId }) {
|
|
4218
4285
|
const [step, setStep] = (0, react.useState)(1);
|
|
4219
4286
|
const [selectedTokens, setSelectedTokens] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
4220
4287
|
const today = (0, react.useMemo)(() => /* @__PURE__ */ new Date(), []);
|
|
4221
|
-
const [selectedYear, setYearState] = (0, react.useState)(today.
|
|
4288
|
+
const [selectedYear, setYearState] = (0, react.useState)(today.getFullYear());
|
|
4222
4289
|
const [selectedMonth, setMonthState] = (0, react.useState)(null);
|
|
4223
4290
|
const [selectedDay, setDayState] = (0, react.useState)(null);
|
|
4224
4291
|
const [selectedAddressId, setSelectedAddressId] = (0, react.useState)(() => pickDefaultAddressId(addresses, defaultAddressId));
|
|
@@ -4237,55 +4304,73 @@ function useBundleForm({ addresses, paymentMethods, defaultAddressId, defaultPay
|
|
|
4237
4304
|
paymentMethods,
|
|
4238
4305
|
defaultPaymentMethodId
|
|
4239
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);
|
|
4240
4356
|
return {
|
|
4241
4357
|
step,
|
|
4242
4358
|
setStep,
|
|
4243
4359
|
selectedTokens,
|
|
4244
|
-
toggleToken
|
|
4245
|
-
setSelectedTokens((prev) => {
|
|
4246
|
-
const next = new Set(prev);
|
|
4247
|
-
if (next.has(token)) next.delete(token);
|
|
4248
|
-
else next.add(token);
|
|
4249
|
-
return next;
|
|
4250
|
-
});
|
|
4251
|
-
}, []),
|
|
4360
|
+
toggleToken,
|
|
4252
4361
|
selectedYear,
|
|
4253
4362
|
selectedMonth,
|
|
4254
4363
|
selectedDay,
|
|
4255
|
-
setYear
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
const isPastMonth = y < today.getUTCFullYear() || y === today.getUTCFullYear() && selectedMonth < today.getUTCMonth();
|
|
4259
|
-
const isPastDay = y === today.getUTCFullYear() && selectedMonth === today.getUTCMonth() && selectedDay != null && selectedDay < today.getUTCDate();
|
|
4260
|
-
if (isPastMonth) {
|
|
4261
|
-
setMonthState(null);
|
|
4262
|
-
setDayState(null);
|
|
4263
|
-
} else if (isPastDay) setDayState(null);
|
|
4264
|
-
}
|
|
4265
|
-
}, [
|
|
4266
|
-
selectedMonth,
|
|
4267
|
-
selectedDay,
|
|
4268
|
-
today
|
|
4269
|
-
]),
|
|
4270
|
-
setMonth: (0, react.useCallback)((m) => {
|
|
4271
|
-
setMonthState(m);
|
|
4272
|
-
if (selectedDay != null) {
|
|
4273
|
-
const daysInNewMonth = new Date(Date.UTC(selectedYear, m + 1, 0)).getUTCDate();
|
|
4274
|
-
const isPastDay = selectedYear === today.getUTCFullYear() && m === today.getUTCMonth() && selectedDay < today.getUTCDate();
|
|
4275
|
-
if (selectedDay > daysInNewMonth || isPastDay) setDayState(null);
|
|
4276
|
-
}
|
|
4277
|
-
}, [
|
|
4278
|
-
selectedDay,
|
|
4279
|
-
selectedYear,
|
|
4280
|
-
today
|
|
4281
|
-
]),
|
|
4282
|
-
setDay: (0, react.useCallback)((d) => setDayState(d), []),
|
|
4364
|
+
setYear,
|
|
4365
|
+
setMonth,
|
|
4366
|
+
setDay,
|
|
4283
4367
|
selectedAddressId,
|
|
4284
4368
|
setSelectedAddressId,
|
|
4285
4369
|
selectedPaymentMethodId,
|
|
4286
4370
|
setSelectedPaymentMethodId,
|
|
4287
|
-
|
|
4288
|
-
|
|
4371
|
+
bounds,
|
|
4372
|
+
canProceedFromStep1,
|
|
4373
|
+
canProceedFromStep2: selectedMonth !== null && selectedDay !== null && !selectedDateOutOfRange,
|
|
4289
4374
|
canProceedFromStep3: selectedAddressId != null,
|
|
4290
4375
|
canProceedFromStep4: selectedPaymentMethodId != null,
|
|
4291
4376
|
formattedDate: (0, react.useMemo)(() => {
|
|
@@ -4514,34 +4599,20 @@ const MONTHS = [
|
|
|
4514
4599
|
"Nov",
|
|
4515
4600
|
"Dec"
|
|
4516
4601
|
];
|
|
4517
|
-
function
|
|
4518
|
-
return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
|
4519
|
-
}
|
|
4520
|
-
function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange, onMonthChange, onDayChange }) {
|
|
4602
|
+
function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange, onMonthChange, onDayChange, bounds }) {
|
|
4521
4603
|
const { t } = useSubscriptionsTranslation();
|
|
4522
|
-
const
|
|
4523
|
-
const currentYear = today.getUTCFullYear();
|
|
4524
|
-
const currentMonth = today.getUTCMonth();
|
|
4525
|
-
const currentDay = today.getUTCDate();
|
|
4604
|
+
const currentYear = bounds.today.getFullYear();
|
|
4526
4605
|
const availableYears = (0, react.useMemo)(() => [
|
|
4527
4606
|
currentYear,
|
|
4528
4607
|
currentYear + 1,
|
|
4529
4608
|
currentYear + 2
|
|
4530
4609
|
], [currentYear]);
|
|
4531
|
-
const
|
|
4532
|
-
|
|
4533
|
-
if (selectedYear > currentYear) return false;
|
|
4534
|
-
return monthIndex < currentMonth;
|
|
4535
|
-
};
|
|
4610
|
+
const isYearDisabled = (year) => isYearOutOfRange(year, bounds);
|
|
4611
|
+
const isMonthDisabled = (monthIndex) => isMonthOutOfRange(selectedYear, monthIndex, bounds);
|
|
4536
4612
|
const daysInSelectedMonth = selectedMonth == null ? 31 : getDaysInMonth(selectedYear, selectedMonth);
|
|
4537
4613
|
const isDayDisabled = (day) => {
|
|
4538
4614
|
if (selectedMonth == null) return true;
|
|
4539
|
-
|
|
4540
|
-
if (selectedYear < currentYear) return true;
|
|
4541
|
-
if (selectedYear > currentYear) return false;
|
|
4542
|
-
if (selectedMonth > currentMonth) return false;
|
|
4543
|
-
if (selectedMonth < currentMonth) return true;
|
|
4544
|
-
return day < currentDay;
|
|
4615
|
+
return isDayOutOfRange(selectedYear, selectedMonth, day, bounds);
|
|
4545
4616
|
};
|
|
4546
4617
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4547
4618
|
className: "flex-1 overflow-y-auto px-6 py-4",
|
|
@@ -4564,10 +4635,13 @@ function DrawerStepDate({ selectedYear, selectedMonth, selectedDay, onYearChange
|
|
|
4564
4635
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4565
4636
|
className: "grid grid-cols-3 gap-2",
|
|
4566
4637
|
children: availableYears.map((year) => {
|
|
4638
|
+
const isActive = selectedYear === year;
|
|
4639
|
+
const disabled = isYearDisabled(year);
|
|
4567
4640
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4568
4641
|
type: "button",
|
|
4642
|
+
disabled,
|
|
4569
4643
|
onClick: () => onYearChange(year),
|
|
4570
|
-
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" : ""}`,
|
|
4571
4645
|
children: year
|
|
4572
4646
|
}, year);
|
|
4573
4647
|
})
|
|
@@ -4811,6 +4885,7 @@ function BundleSubscriptionsDrawer({ open, onOpenChange, subscriptions: subscrip
|
|
|
4811
4885
|
const { t } = useSubscriptionsTranslation();
|
|
4812
4886
|
const { isMobile } = require_sidebar.useSidebar();
|
|
4813
4887
|
const form = useBundleForm({
|
|
4888
|
+
subscriptions: subscriptionList,
|
|
4814
4889
|
addresses,
|
|
4815
4890
|
paymentMethods,
|
|
4816
4891
|
defaultAddressId,
|
|
@@ -4855,7 +4930,8 @@ function BundleSubscriptionsDrawer({ open, onOpenChange, subscriptions: subscrip
|
|
|
4855
4930
|
selectedDay: form.selectedDay,
|
|
4856
4931
|
onYearChange: form.setYear,
|
|
4857
4932
|
onMonthChange: form.setMonth,
|
|
4858
|
-
onDayChange: form.setDay
|
|
4933
|
+
onDayChange: form.setDay,
|
|
4934
|
+
bounds: form.bounds
|
|
4859
4935
|
}),
|
|
4860
4936
|
form.step === 3 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DrawerStepAddress, {
|
|
4861
4937
|
addresses,
|
|
@@ -5416,7 +5492,8 @@ function PauseSubscriptionDialog({ open, onOpenChange, onConfirm, isLoading, err
|
|
|
5416
5492
|
const { t, locale } = useSubscriptionsTranslation();
|
|
5417
5493
|
const [pauseType, setPauseType] = (0, react.useState)("indefinite");
|
|
5418
5494
|
const [selectedOrderCount, setSelectedOrderCount] = (0, react.useState)(null);
|
|
5419
|
-
const
|
|
5495
|
+
const maxSkippableOrders = getMaxSkippableOrders(billingInterval, billingIntervalUnit, currentNextBillDate);
|
|
5496
|
+
const orderCountOptions = Array.from({ length: maxSkippableOrders }, (_, i) => i + 1);
|
|
5420
5497
|
const calculatedResumeDate = selectedOrderCount && currentNextBillDate ? calculateResumeDate(billingInterval, billingIntervalUnit, selectedOrderCount, currentNextBillDate) : null;
|
|
5421
5498
|
(0, react.useEffect)(() => {
|
|
5422
5499
|
if (!open) return;
|
|
@@ -5496,10 +5573,11 @@ function PauseSubscriptionDialog({ open, onOpenChange, onConfirm, isLoading, err
|
|
|
5496
5573
|
type: "radio",
|
|
5497
5574
|
checked: pauseType === "order_count",
|
|
5498
5575
|
onChange: () => setPauseType("order_count"),
|
|
5499
|
-
|
|
5576
|
+
disabled: maxSkippableOrders === 0,
|
|
5577
|
+
className: "border-border accent-primary size-4 focus:ring-0 disabled:opacity-40"
|
|
5500
5578
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Label, {
|
|
5501
5579
|
htmlFor: "pause-order-count",
|
|
5502
|
-
className: "text-foreground cursor-
|
|
5580
|
+
className: `text-sm font-medium ${maxSkippableOrders === 0 ? "text-muted-foreground cursor-not-allowed" : "text-foreground cursor-pointer"}`,
|
|
5503
5581
|
children: t("pause_for_orders")
|
|
5504
5582
|
})]
|
|
5505
5583
|
}), pauseType === "order_count" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -8615,4 +8693,4 @@ Object.defineProperty(exports, "subscriptionsScreenPropertySchema", {
|
|
|
8615
8693
|
}
|
|
8616
8694
|
});
|
|
8617
8695
|
|
|
8618
|
-
//# sourceMappingURL=SubscriptionsScreen-
|
|
8696
|
+
//# sourceMappingURL=SubscriptionsScreen-9NJY-K63.cjs.map
|