@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/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
- /** Why charges are held back: the merchant's own setup by name, `mesub` for any cause of Mesub's. */
37
- type MesubBlockedReason = 'puller_not_allowed' | 'receiver_not_allowed' | 'receiver_account_missing' | 'receiver_account_frozen' | 'mint_gone' | 'mesub';
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
- /** Why charges are held back: the merchant's own setup by name, `mesub` for any cause of Mesub's. */
37
- type MesubBlockedReason = 'puller_not_allowed' | 'receiver_not_allowed' | 'receiver_account_missing' | 'receiver_account_frozen' | 'mint_gone' | 'mesub';
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 Array.isArray(answer.subscriptions) ? answer.subscriptions : [];
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__ */ jsx6(
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: body
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) => {