@mesub/react 0.1.2 → 0.1.3
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 +6 -0
- package/dist/index.cjs +33 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +33 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles.css +10 -1
package/README.md
CHANGED
|
@@ -214,6 +214,9 @@ nor past its date to pay by. What came of it is said under the button: the
|
|
|
214
214
|
payment on its way, or why not (a short wallet spends no retry). On Free,
|
|
215
215
|
where Mesub does not try again on its own, the card shows that date to pay by.
|
|
216
216
|
|
|
217
|
+
When the server could not read a subscription's past payments, its window
|
|
218
|
+
says so in one line rather than show none.
|
|
219
|
+
|
|
217
220
|
One whose charges are held back for a cause that is not the customer's
|
|
218
221
|
(`blocked_since`) says so in one line: payments are on hold, nothing is asked
|
|
219
222
|
of them, and until when their access runs. The cause is never named to them,
|
|
@@ -245,6 +248,9 @@ function Mine() {
|
|
|
245
248
|
- `subscriptions` are newest first, each with `action`: `cancel`, `resume`,
|
|
246
249
|
`close` or null, and `payable`: whether **Pay now** can succeed. Checkouts
|
|
247
250
|
nobody signed are left out.
|
|
251
|
+
- `hasMore` is true when the customer holds more than the server listed (its
|
|
252
|
+
500 newest): older ones are missing. `ManageSubscriptions` says so under its
|
|
253
|
+
list.
|
|
248
254
|
- `payNow(id)` pays that late payment now and resolves `{ ok, message }`, the
|
|
249
255
|
words to show; it never throws.
|
|
250
256
|
- `manage(id)` opens the dialog for that action and resolves when it closes:
|
package/dist/index.cjs
CHANGED
|
@@ -71,6 +71,10 @@ function paidOf(answer) {
|
|
|
71
71
|
const whole = Array.isArray(answer.payments) && answer.payments.length < LISTED_AT_MOST;
|
|
72
72
|
return whole ? read(answer.listed_paid) : null;
|
|
73
73
|
}
|
|
74
|
+
function paymentsErrorOf(answer) {
|
|
75
|
+
const error = answer.payments_error;
|
|
76
|
+
return isObject(error) && typeof error.code === "string" && typeof error.message === "string" ? { code: error.code, message: error.message } : null;
|
|
77
|
+
}
|
|
74
78
|
function createApi(options) {
|
|
75
79
|
const base = options.endpoint.replace(/\/+$/, "");
|
|
76
80
|
const doFetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
@@ -141,7 +145,11 @@ function createApi(options) {
|
|
|
141
145
|
),
|
|
142
146
|
subscriptions: async () => {
|
|
143
147
|
const answer = await request("GET", "/subscriptions", void 0, REQUEST_TIMEOUT_MS);
|
|
144
|
-
return
|
|
148
|
+
return {
|
|
149
|
+
subscriptions: Array.isArray(answer.subscriptions) ? answer.subscriptions : [],
|
|
150
|
+
// An older server does not say: read as whole.
|
|
151
|
+
has_more: answer.has_more === true
|
|
152
|
+
};
|
|
145
153
|
},
|
|
146
154
|
subscription: async (id) => {
|
|
147
155
|
const answer = await request("GET", at(id), void 0, REQUEST_TIMEOUT_MS);
|
|
@@ -149,7 +157,8 @@ function createApi(options) {
|
|
|
149
157
|
subscription: answer.subscription,
|
|
150
158
|
upcoming: Array.isArray(answer.upcoming) ? answer.upcoming : [],
|
|
151
159
|
payments: Array.isArray(answer.payments) ? answer.payments : null,
|
|
152
|
-
paid: paidOf(answer)
|
|
160
|
+
paid: paidOf(answer),
|
|
161
|
+
payments_error: paymentsErrorOf(answer)
|
|
153
162
|
};
|
|
154
163
|
},
|
|
155
164
|
prepare: async (plan, wallet) => await request(
|
|
@@ -2185,6 +2194,7 @@ function payableOf(row, now) {
|
|
|
2185
2194
|
const deadline = Date.parse(row.retry_deadline ?? "");
|
|
2186
2195
|
return Number.isNaN(deadline) || deadline > now;
|
|
2187
2196
|
}
|
|
2197
|
+
var MORE_NOT_LISTED = "Only your most recent subscriptions are listed here.";
|
|
2188
2198
|
var PAY_NOW_SENT = "Payment sent. It shows here once the network confirms it.";
|
|
2189
2199
|
function payNowRefusal(failure) {
|
|
2190
2200
|
if (!(failure instanceof MesubClientError)) return "Something went wrong.";
|
|
@@ -2210,6 +2220,7 @@ function useSubscriptions() {
|
|
|
2210
2220
|
const { api, revision, manage: open } = useMesubInternal();
|
|
2211
2221
|
const [state, setState] = (0, import_react9.useState)("loading");
|
|
2212
2222
|
const [rows, setRows] = (0, import_react9.useState)([]);
|
|
2223
|
+
const [hasMore, setHasMore] = (0, import_react9.useState)(false);
|
|
2213
2224
|
const [error, setError] = (0, import_react9.useState)(null);
|
|
2214
2225
|
const [now, setNow] = (0, import_react9.useState)(() => Date.now());
|
|
2215
2226
|
const read = (0, import_react9.useRef)(0);
|
|
@@ -2225,7 +2236,8 @@ function useSubscriptions() {
|
|
|
2225
2236
|
try {
|
|
2226
2237
|
const served = await api.subscriptions();
|
|
2227
2238
|
if (!alive.current || id !== read.current) return;
|
|
2228
|
-
setRows(served.filter((row) => HELD.has(row.status)));
|
|
2239
|
+
setRows(served.subscriptions.filter((row) => HELD.has(row.status)));
|
|
2240
|
+
setHasMore(served.has_more);
|
|
2229
2241
|
setNow(Date.now());
|
|
2230
2242
|
setError(null);
|
|
2231
2243
|
setState("ready");
|
|
@@ -2233,6 +2245,7 @@ function useSubscriptions() {
|
|
|
2233
2245
|
if (!alive.current || id !== read.current) return;
|
|
2234
2246
|
if (signedOut(failure)) {
|
|
2235
2247
|
setRows([]);
|
|
2248
|
+
setHasMore(false);
|
|
2236
2249
|
setError(null);
|
|
2237
2250
|
setState("signed-out");
|
|
2238
2251
|
return;
|
|
@@ -2286,7 +2299,7 @@ function useSubscriptions() {
|
|
|
2286
2299
|
},
|
|
2287
2300
|
[api, reload]
|
|
2288
2301
|
);
|
|
2289
|
-
return { state, subscriptions, error, reload, payNow, manage };
|
|
2302
|
+
return { state, subscriptions, hasMore, error, reload, payNow, manage };
|
|
2290
2303
|
}
|
|
2291
2304
|
var STATUS = {
|
|
2292
2305
|
active: "Active",
|
|
@@ -2418,7 +2431,7 @@ function PayNow({ pay }) {
|
|
|
2418
2431
|
}
|
|
2419
2432
|
function ManageSubscriptions({ onChanged, ...rest }) {
|
|
2420
2433
|
const { theme } = useMesubInternal();
|
|
2421
|
-
const { state, subscriptions, error, reload, payNow, manage } = useSubscriptions();
|
|
2434
|
+
const { state, subscriptions, hasMore, error, reload, payNow, manage } = useSubscriptions();
|
|
2422
2435
|
const plans = usePlans(subscriptions.flatMap((row) => row.plan ? [row.plan] : []));
|
|
2423
2436
|
const [retrying, setRetrying] = (0, import_react9.useState)(false);
|
|
2424
2437
|
async function act(id) {
|
|
@@ -2453,7 +2466,7 @@ function ManageSubscriptions({ onChanged, ...rest }) {
|
|
|
2453
2466
|
}
|
|
2454
2467
|
)
|
|
2455
2468
|
] });
|
|
2456
|
-
} else if (subscriptions.length === 0) {
|
|
2469
|
+
} else if (subscriptions.length === 0 && !hasMore) {
|
|
2457
2470
|
body = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { "data-mesub-empty": "none", children: "You have no subscription yet." });
|
|
2458
2471
|
} else {
|
|
2459
2472
|
body = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { "data-mesub-subscription-list": "", "aria-label": "Your subscriptions", children: subscriptions.map((row) => {
|
|
@@ -2515,14 +2528,17 @@ function ManageSubscriptions({ onChanged, ...rest }) {
|
|
|
2515
2528
|
] }, row.id);
|
|
2516
2529
|
}) });
|
|
2517
2530
|
}
|
|
2518
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.
|
|
2531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2519
2532
|
"div",
|
|
2520
2533
|
{
|
|
2521
2534
|
...rest,
|
|
2522
2535
|
"data-mesub-subscriptions": "",
|
|
2523
2536
|
"data-mesub-state": state,
|
|
2524
2537
|
"data-mesub-theme": theme,
|
|
2525
|
-
children:
|
|
2538
|
+
children: [
|
|
2539
|
+
body,
|
|
2540
|
+
state === "ready" && hasMore ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { "data-mesub-subscription-note": "", children: MORE_NOT_LISTED }) : null
|
|
2541
|
+
]
|
|
2526
2542
|
}
|
|
2527
2543
|
);
|
|
2528
2544
|
}
|
|
@@ -2587,6 +2603,7 @@ function useDetail(row) {
|
|
|
2587
2603
|
}, [api, id, revision]);
|
|
2588
2604
|
return detail?.subscription.id === id ? detail : null;
|
|
2589
2605
|
}
|
|
2606
|
+
var PAYMENTS_UNREAD = "Past payments could not be read just now.";
|
|
2590
2607
|
var PAST_SHOWN = 5;
|
|
2591
2608
|
var PAST_STEP = 10;
|
|
2592
2609
|
function SubscriptionDialog({
|
|
@@ -2596,7 +2613,7 @@ function SubscriptionDialog({
|
|
|
2596
2613
|
const [shown, setShown] = (0, import_react10.useState)(PAST_SHOWN);
|
|
2597
2614
|
const titleId = (0, import_react10.useId)();
|
|
2598
2615
|
const { chain } = useMesubInternal();
|
|
2599
|
-
const { state, subscriptions, error, reload, payNow, manage } = useSubscriptions();
|
|
2616
|
+
const { state, subscriptions, hasMore, error, reload, payNow, manage } = useSubscriptions();
|
|
2600
2617
|
const row = pickSubscription(subscriptions, slug) ?? null;
|
|
2601
2618
|
const plan = usePlan(row?.plan);
|
|
2602
2619
|
const detail = useDetail(row);
|
|
@@ -2620,7 +2637,7 @@ function SubscriptionDialog({
|
|
|
2620
2637
|
} else if (!row) {
|
|
2621
2638
|
body = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2622
2639
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { id: titleId, children: "No subscription yet" }),
|
|
2623
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "You are not subscribed to this plan." })
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: hasMore ? "None of your most recent subscriptions is to this plan." : "You are not subscribed to this plan." })
|
|
2624
2641
|
] });
|
|
2625
2642
|
} else {
|
|
2626
2643
|
const name = plan?.name ?? row.plan ?? "Subscription";
|
|
@@ -2629,6 +2646,7 @@ function SubscriptionDialog({
|
|
|
2629
2646
|
const note = noteOf(row);
|
|
2630
2647
|
const upcoming = detail?.upcoming ?? [];
|
|
2631
2648
|
const past = detail?.payments ?? [];
|
|
2649
|
+
const unread = detail?.payments === null && detail.payments_error !== null;
|
|
2632
2650
|
const total = detail?.paid?.amount ? paidBrief(detail.paid.amount, plan, formatAmount) : null;
|
|
2633
2651
|
const rate = plan ? briefPrice(plan) : null;
|
|
2634
2652
|
const due = (display) => display ? `${grouped(display)}${symbolOf(plan)}` : "";
|
|
@@ -2680,7 +2698,7 @@ function SubscriptionDialog({
|
|
|
2680
2698
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dd", { title: row.wallet, children: shortAddress(row.wallet) })
|
|
2681
2699
|
] })
|
|
2682
2700
|
] }),
|
|
2683
|
-
upcoming.length > 0 || past.length > 0 ? (
|
|
2701
|
+
upcoming.length > 0 || past.length > 0 || unread ? (
|
|
2684
2702
|
// Closed until asked for, as the terms are on the checkout: same toggle.
|
|
2685
2703
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { "data-mesub-terms": "", "data-mesub-payments": "", children: [
|
|
2686
2704
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { children: "Payments" }),
|
|
@@ -2702,6 +2720,10 @@ function SubscriptionDialog({
|
|
|
2702
2720
|
`next-${next.due_at}`
|
|
2703
2721
|
)) })
|
|
2704
2722
|
] }) : null,
|
|
2723
|
+
unread ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { "aria-label": "Past payments", children: [
|
|
2724
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: "Past" }),
|
|
2725
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { "data-mesub-payments-error": "", children: PAYMENTS_UNREAD })
|
|
2726
|
+
] }) : null,
|
|
2705
2727
|
past.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { "aria-label": "Past payments", children: [
|
|
2706
2728
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: "Past" }),
|
|
2707
2729
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { children: past.slice(0, shown).map((payment) => {
|