@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/dist/index.d.cts
CHANGED
|
@@ -33,8 +33,12 @@ interface MesubPlan {
|
|
|
33
33
|
ends_at: string | null;
|
|
34
34
|
}
|
|
35
35
|
type MesubSubscriptionStatus = 'pending' | 'active' | 'cancelled' | 'unpaid' | 'stopped' | 'ended' | 'failed' | 'expired' | 'superseded';
|
|
36
|
-
/**
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Why charges are held back: the merchant's own setup by name (the last two
|
|
38
|
+
* the token issuer's to lift), `mesub` for any cause of Mesub's. The widget
|
|
39
|
+
* words every one the same to the subscriber.
|
|
40
|
+
*/
|
|
41
|
+
type MesubBlockedReason = 'puller_not_allowed' | 'receiver_not_allowed' | 'receiver_account_missing' | 'receiver_account_frozen' | 'receiver_account_needs_memo' | 'receiver_account_confidential_only' | 'mint_gone' | 'mint_paused' | 'mint_transfer_hook' | 'mesub';
|
|
38
42
|
/**
|
|
39
43
|
* Why a `stopped` one stopped (Mesub-io/backend#402): every retry failed, the
|
|
40
44
|
* Free date to pay by passed, or the wallet closed the account that lets
|
|
@@ -59,6 +63,8 @@ interface MesubSubscription {
|
|
|
59
63
|
current_period_end: string | null;
|
|
60
64
|
next_charge_at: string | null;
|
|
61
65
|
next_retry_at: string | null;
|
|
66
|
+
next_retry_number?: number | null;
|
|
67
|
+
retries_allowed?: number | null;
|
|
62
68
|
retry_deadline: string | null;
|
|
63
69
|
access_until: string | null;
|
|
64
70
|
closable?: boolean;
|
|
@@ -125,6 +131,7 @@ interface PayNowResult {
|
|
|
125
131
|
interface UseSubscriptionsResult {
|
|
126
132
|
state: 'loading' | 'ready' | 'signed-out' | 'error';
|
|
127
133
|
subscriptions: MesubHeldSubscription[];
|
|
134
|
+
hasMore: boolean;
|
|
128
135
|
error: string | null;
|
|
129
136
|
reload(): Promise<void>;
|
|
130
137
|
payNow(id: string): Promise<PayNowResult>;
|
package/dist/index.d.ts
CHANGED
|
@@ -33,8 +33,12 @@ interface MesubPlan {
|
|
|
33
33
|
ends_at: string | null;
|
|
34
34
|
}
|
|
35
35
|
type MesubSubscriptionStatus = 'pending' | 'active' | 'cancelled' | 'unpaid' | 'stopped' | 'ended' | 'failed' | 'expired' | 'superseded';
|
|
36
|
-
/**
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Why charges are held back: the merchant's own setup by name (the last two
|
|
38
|
+
* the token issuer's to lift), `mesub` for any cause of Mesub's. The widget
|
|
39
|
+
* words every one the same to the subscriber.
|
|
40
|
+
*/
|
|
41
|
+
type MesubBlockedReason = 'puller_not_allowed' | 'receiver_not_allowed' | 'receiver_account_missing' | 'receiver_account_frozen' | 'receiver_account_needs_memo' | 'receiver_account_confidential_only' | 'mint_gone' | 'mint_paused' | 'mint_transfer_hook' | 'mesub';
|
|
38
42
|
/**
|
|
39
43
|
* Why a `stopped` one stopped (Mesub-io/backend#402): every retry failed, the
|
|
40
44
|
* Free date to pay by passed, or the wallet closed the account that lets
|
|
@@ -59,6 +63,8 @@ interface MesubSubscription {
|
|
|
59
63
|
current_period_end: string | null;
|
|
60
64
|
next_charge_at: string | null;
|
|
61
65
|
next_retry_at: string | null;
|
|
66
|
+
next_retry_number?: number | null;
|
|
67
|
+
retries_allowed?: number | null;
|
|
62
68
|
retry_deadline: string | null;
|
|
63
69
|
access_until: string | null;
|
|
64
70
|
closable?: boolean;
|
|
@@ -125,6 +131,7 @@ interface PayNowResult {
|
|
|
125
131
|
interface UseSubscriptionsResult {
|
|
126
132
|
state: 'loading' | 'ready' | 'signed-out' | 'error';
|
|
127
133
|
subscriptions: MesubHeldSubscription[];
|
|
134
|
+
hasMore: boolean;
|
|
128
135
|
error: string | null;
|
|
129
136
|
reload(): Promise<void>;
|
|
130
137
|
payNow(id: string): Promise<PayNowResult>;
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,10 @@ function paidOf(answer) {
|
|
|
41
41
|
const whole = Array.isArray(answer.payments) && answer.payments.length < LISTED_AT_MOST;
|
|
42
42
|
return whole ? read(answer.listed_paid) : null;
|
|
43
43
|
}
|
|
44
|
+
function paymentsErrorOf(answer) {
|
|
45
|
+
const error = answer.payments_error;
|
|
46
|
+
return isObject(error) && typeof error.code === "string" && typeof error.message === "string" ? { code: error.code, message: error.message } : null;
|
|
47
|
+
}
|
|
44
48
|
function createApi(options) {
|
|
45
49
|
const base = options.endpoint.replace(/\/+$/, "");
|
|
46
50
|
const doFetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
@@ -111,7 +115,11 @@ function createApi(options) {
|
|
|
111
115
|
),
|
|
112
116
|
subscriptions: async () => {
|
|
113
117
|
const answer = await request("GET", "/subscriptions", void 0, REQUEST_TIMEOUT_MS);
|
|
114
|
-
return
|
|
118
|
+
return {
|
|
119
|
+
subscriptions: Array.isArray(answer.subscriptions) ? answer.subscriptions : [],
|
|
120
|
+
// An older server does not say: read as whole.
|
|
121
|
+
has_more: answer.has_more === true
|
|
122
|
+
};
|
|
115
123
|
},
|
|
116
124
|
subscription: async (id) => {
|
|
117
125
|
const answer = await request("GET", at(id), void 0, REQUEST_TIMEOUT_MS);
|
|
@@ -119,7 +127,8 @@ function createApi(options) {
|
|
|
119
127
|
subscription: answer.subscription,
|
|
120
128
|
upcoming: Array.isArray(answer.upcoming) ? answer.upcoming : [],
|
|
121
129
|
payments: Array.isArray(answer.payments) ? answer.payments : null,
|
|
122
|
-
paid: paidOf(answer)
|
|
130
|
+
paid: paidOf(answer),
|
|
131
|
+
payments_error: paymentsErrorOf(answer)
|
|
123
132
|
};
|
|
124
133
|
},
|
|
125
134
|
prepare: async (plan, wallet) => await request(
|
|
@@ -2161,6 +2170,7 @@ function payableOf(row, now) {
|
|
|
2161
2170
|
const deadline = Date.parse(row.retry_deadline ?? "");
|
|
2162
2171
|
return Number.isNaN(deadline) || deadline > now;
|
|
2163
2172
|
}
|
|
2173
|
+
var MORE_NOT_LISTED = "Only your most recent subscriptions are listed here.";
|
|
2164
2174
|
var PAY_NOW_SENT = "Payment sent. It shows here once the network confirms it.";
|
|
2165
2175
|
function payNowRefusal(failure) {
|
|
2166
2176
|
if (!(failure instanceof MesubClientError)) return "Something went wrong.";
|
|
@@ -2186,6 +2196,7 @@ function useSubscriptions() {
|
|
|
2186
2196
|
const { api, revision, manage: open } = useMesubInternal();
|
|
2187
2197
|
const [state, setState] = useState4("loading");
|
|
2188
2198
|
const [rows, setRows] = useState4([]);
|
|
2199
|
+
const [hasMore, setHasMore] = useState4(false);
|
|
2189
2200
|
const [error, setError] = useState4(null);
|
|
2190
2201
|
const [now, setNow] = useState4(() => Date.now());
|
|
2191
2202
|
const read = useRef4(0);
|
|
@@ -2201,7 +2212,8 @@ function useSubscriptions() {
|
|
|
2201
2212
|
try {
|
|
2202
2213
|
const served = await api.subscriptions();
|
|
2203
2214
|
if (!alive.current || id !== read.current) return;
|
|
2204
|
-
setRows(served.filter((row) => HELD.has(row.status)));
|
|
2215
|
+
setRows(served.subscriptions.filter((row) => HELD.has(row.status)));
|
|
2216
|
+
setHasMore(served.has_more);
|
|
2205
2217
|
setNow(Date.now());
|
|
2206
2218
|
setError(null);
|
|
2207
2219
|
setState("ready");
|
|
@@ -2209,6 +2221,7 @@ function useSubscriptions() {
|
|
|
2209
2221
|
if (!alive.current || id !== read.current) return;
|
|
2210
2222
|
if (signedOut(failure)) {
|
|
2211
2223
|
setRows([]);
|
|
2224
|
+
setHasMore(false);
|
|
2212
2225
|
setError(null);
|
|
2213
2226
|
setState("signed-out");
|
|
2214
2227
|
return;
|
|
@@ -2262,7 +2275,7 @@ function useSubscriptions() {
|
|
|
2262
2275
|
},
|
|
2263
2276
|
[api, reload]
|
|
2264
2277
|
);
|
|
2265
|
-
return { state, subscriptions, error, reload, payNow, manage };
|
|
2278
|
+
return { state, subscriptions, hasMore, error, reload, payNow, manage };
|
|
2266
2279
|
}
|
|
2267
2280
|
var STATUS = {
|
|
2268
2281
|
active: "Active",
|
|
@@ -2394,7 +2407,7 @@ function PayNow({ pay }) {
|
|
|
2394
2407
|
}
|
|
2395
2408
|
function ManageSubscriptions({ onChanged, ...rest }) {
|
|
2396
2409
|
const { theme } = useMesubInternal();
|
|
2397
|
-
const { state, subscriptions, error, reload, payNow, manage } = useSubscriptions();
|
|
2410
|
+
const { state, subscriptions, hasMore, error, reload, payNow, manage } = useSubscriptions();
|
|
2398
2411
|
const plans = usePlans(subscriptions.flatMap((row) => row.plan ? [row.plan] : []));
|
|
2399
2412
|
const [retrying, setRetrying] = useState4(false);
|
|
2400
2413
|
async function act(id) {
|
|
@@ -2429,7 +2442,7 @@ function ManageSubscriptions({ onChanged, ...rest }) {
|
|
|
2429
2442
|
}
|
|
2430
2443
|
)
|
|
2431
2444
|
] });
|
|
2432
|
-
} else if (subscriptions.length === 0) {
|
|
2445
|
+
} else if (subscriptions.length === 0 && !hasMore) {
|
|
2433
2446
|
body = /* @__PURE__ */ jsx6("p", { "data-mesub-empty": "none", children: "You have no subscription yet." });
|
|
2434
2447
|
} else {
|
|
2435
2448
|
body = /* @__PURE__ */ jsx6("ul", { "data-mesub-subscription-list": "", "aria-label": "Your subscriptions", children: subscriptions.map((row) => {
|
|
@@ -2491,14 +2504,17 @@ function ManageSubscriptions({ onChanged, ...rest }) {
|
|
|
2491
2504
|
] }, row.id);
|
|
2492
2505
|
}) });
|
|
2493
2506
|
}
|
|
2494
|
-
return /* @__PURE__ */
|
|
2507
|
+
return /* @__PURE__ */ jsxs5(
|
|
2495
2508
|
"div",
|
|
2496
2509
|
{
|
|
2497
2510
|
...rest,
|
|
2498
2511
|
"data-mesub-subscriptions": "",
|
|
2499
2512
|
"data-mesub-state": state,
|
|
2500
2513
|
"data-mesub-theme": theme,
|
|
2501
|
-
children:
|
|
2514
|
+
children: [
|
|
2515
|
+
body,
|
|
2516
|
+
state === "ready" && hasMore ? /* @__PURE__ */ jsx6("p", { "data-mesub-subscription-note": "", children: MORE_NOT_LISTED }) : null
|
|
2517
|
+
]
|
|
2502
2518
|
}
|
|
2503
2519
|
);
|
|
2504
2520
|
}
|
|
@@ -2563,6 +2579,7 @@ function useDetail(row) {
|
|
|
2563
2579
|
}, [api, id, revision]);
|
|
2564
2580
|
return detail?.subscription.id === id ? detail : null;
|
|
2565
2581
|
}
|
|
2582
|
+
var PAYMENTS_UNREAD = "Past payments could not be read just now.";
|
|
2566
2583
|
var PAST_SHOWN = 5;
|
|
2567
2584
|
var PAST_STEP = 10;
|
|
2568
2585
|
function SubscriptionDialog({
|
|
@@ -2572,7 +2589,7 @@ function SubscriptionDialog({
|
|
|
2572
2589
|
const [shown, setShown] = useState5(PAST_SHOWN);
|
|
2573
2590
|
const titleId = useId3();
|
|
2574
2591
|
const { chain } = useMesubInternal();
|
|
2575
|
-
const { state, subscriptions, error, reload, payNow, manage } = useSubscriptions();
|
|
2592
|
+
const { state, subscriptions, hasMore, error, reload, payNow, manage } = useSubscriptions();
|
|
2576
2593
|
const row = pickSubscription(subscriptions, slug) ?? null;
|
|
2577
2594
|
const plan = usePlan(row?.plan);
|
|
2578
2595
|
const detail = useDetail(row);
|
|
@@ -2596,7 +2613,7 @@ function SubscriptionDialog({
|
|
|
2596
2613
|
} else if (!row) {
|
|
2597
2614
|
body = /* @__PURE__ */ jsxs6(Fragment6, { children: [
|
|
2598
2615
|
/* @__PURE__ */ jsx7("h2", { id: titleId, children: "No subscription yet" }),
|
|
2599
|
-
/* @__PURE__ */ jsx7("p", { children: "You are not subscribed to this plan." })
|
|
2616
|
+
/* @__PURE__ */ jsx7("p", { children: hasMore ? "None of your most recent subscriptions is to this plan." : "You are not subscribed to this plan." })
|
|
2600
2617
|
] });
|
|
2601
2618
|
} else {
|
|
2602
2619
|
const name = plan?.name ?? row.plan ?? "Subscription";
|
|
@@ -2605,6 +2622,7 @@ function SubscriptionDialog({
|
|
|
2605
2622
|
const note = noteOf(row);
|
|
2606
2623
|
const upcoming = detail?.upcoming ?? [];
|
|
2607
2624
|
const past = detail?.payments ?? [];
|
|
2625
|
+
const unread = detail?.payments === null && detail.payments_error !== null;
|
|
2608
2626
|
const total = detail?.paid?.amount ? paidBrief(detail.paid.amount, plan, formatAmount) : null;
|
|
2609
2627
|
const rate = plan ? briefPrice(plan) : null;
|
|
2610
2628
|
const due = (display) => display ? `${grouped(display)}${symbolOf(plan)}` : "";
|
|
@@ -2656,7 +2674,7 @@ function SubscriptionDialog({
|
|
|
2656
2674
|
/* @__PURE__ */ jsx7("dd", { title: row.wallet, children: shortAddress(row.wallet) })
|
|
2657
2675
|
] })
|
|
2658
2676
|
] }),
|
|
2659
|
-
upcoming.length > 0 || past.length > 0 ? (
|
|
2677
|
+
upcoming.length > 0 || past.length > 0 || unread ? (
|
|
2660
2678
|
// Closed until asked for, as the terms are on the checkout: same toggle.
|
|
2661
2679
|
/* @__PURE__ */ jsxs6("details", { "data-mesub-terms": "", "data-mesub-payments": "", children: [
|
|
2662
2680
|
/* @__PURE__ */ jsx7("summary", { children: "Payments" }),
|
|
@@ -2678,6 +2696,10 @@ function SubscriptionDialog({
|
|
|
2678
2696
|
`next-${next.due_at}`
|
|
2679
2697
|
)) })
|
|
2680
2698
|
] }) : null,
|
|
2699
|
+
unread ? /* @__PURE__ */ jsxs6("section", { "aria-label": "Past payments", children: [
|
|
2700
|
+
/* @__PURE__ */ jsx7("h3", { children: "Past" }),
|
|
2701
|
+
/* @__PURE__ */ jsx7("p", { "data-mesub-payments-error": "", children: PAYMENTS_UNREAD })
|
|
2702
|
+
] }) : null,
|
|
2681
2703
|
past.length > 0 ? /* @__PURE__ */ jsxs6("section", { "aria-label": "Past payments", children: [
|
|
2682
2704
|
/* @__PURE__ */ jsx7("h3", { children: "Past" }),
|
|
2683
2705
|
/* @__PURE__ */ jsx7("ul", { children: past.slice(0, shown).map((payment) => {
|