@fonderie/react-admin-screens 0.2.0 → 0.3.0
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 +4 -2
- package/dist/index.cjs +289 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +287 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,12 +11,13 @@ Status: **experimental** (0.x).
|
|
|
11
11
|
| Today | Attention | what needs me today — empty is green |
|
|
12
12
|
| System | Modules · Configuration · Doctor · Routes | what did I deploy · is it configured · is it working · what is exposed |
|
|
13
13
|
| People | Users | why can't this person log in — lookup, sessions, sign-ins, suspend, sign out everywhere (`authClient`) |
|
|
14
|
+
| Money | Catalog · Subscriber | what am I selling (configured vs stored) · what is this subscriber on, their wallet, ledger, a manual grant (`billingClient`) |
|
|
14
15
|
| Settings | Config & secrets | the `@fonderie/config` admin screens, as a sub-page |
|
|
15
16
|
| Messaging | Templates | the `@fonderie/courier` admin screens, as a sub-page |
|
|
16
17
|
| Activity | Admin log · Access | who did what · who can be here |
|
|
17
18
|
|
|
18
19
|
```ts
|
|
19
|
-
import { AdminClient, AuthAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
|
|
20
|
+
import { AdminClient, AuthAdminClient, BillingAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
|
|
20
21
|
import { AdminShell } from '@fonderie/react-admin-screens';
|
|
21
22
|
|
|
22
23
|
const base = { baseUrl: 'https://api.example.com', adminToken, actor: 'louis' };
|
|
@@ -25,10 +26,11 @@ const client = new AdminClient(base);
|
|
|
25
26
|
const configClient = new ConfigAdminClient({ ...base, prefix: '/_admin' });
|
|
26
27
|
const courierClient = new CourierAdminClient({ ...base, prefix: '/_admin' });
|
|
27
28
|
const authClient = new AuthAdminClient(base); // @fonderie/auth ≥ 7.8
|
|
29
|
+
const billingClient = new BillingAdminClient(base); // @fonderie/billing ≥ 9.10
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
```tsx
|
|
31
|
-
<AdminShell client={client} configClient={configClient} courierClient={courierClient} authClient={authClient} />
|
|
33
|
+
<AdminShell client={client} configClient={configClient} courierClient={courierClient} authClient={authClient} billingClient={billingClient} />
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
Pass `page` and `onNavigate` to own the URL (one route per page); omit both
|
package/dist/index.cjs
CHANGED
|
@@ -23,10 +23,12 @@ __export(index_exports, {
|
|
|
23
23
|
AdminLogScreen: () => AdminLogScreen,
|
|
24
24
|
AdminShell: () => AdminShell,
|
|
25
25
|
AttentionScreen: () => AttentionScreen,
|
|
26
|
+
CatalogScreen: () => CatalogScreen,
|
|
26
27
|
ConfigScreen: () => ConfigScreen,
|
|
27
28
|
DoctorScreen: () => DoctorScreen,
|
|
28
29
|
ModulesScreen: () => ModulesScreen,
|
|
29
30
|
RoutesScreen: () => RoutesScreen,
|
|
31
|
+
SubscriberScreen: () => SubscriberScreen,
|
|
30
32
|
TokensScreen: () => TokensScreen,
|
|
31
33
|
UsersScreen: () => UsersScreen
|
|
32
34
|
});
|
|
@@ -35,7 +37,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
35
37
|
// src/screens/AdminShell.tsx
|
|
36
38
|
var import_react_config_admin_screens = require("@fonderie/react-config-admin-screens");
|
|
37
39
|
var import_react_courier_admin_screens = require("@fonderie/react-courier-admin-screens");
|
|
38
|
-
var
|
|
40
|
+
var import_react3 = require("react");
|
|
39
41
|
|
|
40
42
|
// src/styles.ts
|
|
41
43
|
var styles = {
|
|
@@ -509,8 +511,251 @@ function UsersScreen({ client }) {
|
|
|
509
511
|
] });
|
|
510
512
|
}
|
|
511
513
|
|
|
512
|
-
// src/screens/
|
|
514
|
+
// src/screens/CatalogScreen.tsx
|
|
515
|
+
var import_react_admin9 = require("@fonderie/react-admin");
|
|
513
516
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
517
|
+
function CatalogScreen({ client }) {
|
|
518
|
+
const { catalog, isLoading, error, refresh, deletePlan } = (0, import_react_admin9.useAdminCatalog)(client);
|
|
519
|
+
const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
|
|
520
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.container, children: [
|
|
521
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.toolbar, children: [
|
|
522
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { style: { ...styles.title, marginBottom: 0 }, children: "Catalog" }),
|
|
523
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
524
|
+
"button",
|
|
525
|
+
{
|
|
526
|
+
type: "button",
|
|
527
|
+
style: styles.button,
|
|
528
|
+
onClick: () => void refresh(),
|
|
529
|
+
disabled: isLoading,
|
|
530
|
+
children: "Refresh"
|
|
531
|
+
}
|
|
532
|
+
)
|
|
533
|
+
] }),
|
|
534
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
535
|
+
isLoading && !catalog ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
536
|
+
catalog ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
537
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Configured (code)" }),
|
|
538
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("pre", { style: { ...styles.mono, background: "#f9fafb", padding: 12, overflowX: "auto" }, children: JSON.stringify(catalog.configured, null, 2) }),
|
|
539
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Stored (database)" }),
|
|
540
|
+
catalog.stored.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.muted, children: "No stored plans." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { style: styles.table, children: [
|
|
541
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Plan" }),
|
|
543
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Tier" }),
|
|
544
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Seats" }),
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Monthly" }),
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Yearly" }),
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Trial" }),
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th })
|
|
549
|
+
] }) }),
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: p.name }),
|
|
553
|
+
p.description ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.muted, children: p.description }) : null
|
|
554
|
+
] }),
|
|
555
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: p.tier }),
|
|
556
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: p.seats ?? "\u221E" }),
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
|
|
558
|
+
money(p.pricing?.monthly),
|
|
559
|
+
" ",
|
|
560
|
+
p.pricing?.currency ?? ""
|
|
561
|
+
] }),
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: money(p.pricing?.yearly) }),
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: p.trialDays ? `${p.trialDays} d` : "\u2014" }),
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
565
|
+
"button",
|
|
566
|
+
{
|
|
567
|
+
type: "button",
|
|
568
|
+
style: styles.button,
|
|
569
|
+
onClick: () => {
|
|
570
|
+
if (window.confirm(`Delete stored plan "${p.name}"?`))
|
|
571
|
+
void deletePlan(p.id).catch(() => {
|
|
572
|
+
});
|
|
573
|
+
},
|
|
574
|
+
children: "Delete"
|
|
575
|
+
}
|
|
576
|
+
) })
|
|
577
|
+
] }, p.id)) })
|
|
578
|
+
] })
|
|
579
|
+
] }) : null
|
|
580
|
+
] });
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// src/screens/SubscriberScreen.tsx
|
|
584
|
+
var import_react_admin10 = require("@fonderie/react-admin");
|
|
585
|
+
var import_react2 = require("react");
|
|
586
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
587
|
+
function SubscriberScreen({ client }) {
|
|
588
|
+
const [type, setType] = (0, import_react2.useState)("user");
|
|
589
|
+
const [idInput, setIdInput] = (0, import_react2.useState)("");
|
|
590
|
+
const [subscriber, setSubscriber] = (0, import_react2.useState)(null);
|
|
591
|
+
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_react_admin10.useAdminSubscriber)(client, subscriber, { limit: 20 });
|
|
592
|
+
const [amount, setAmount] = (0, import_react2.useState)("");
|
|
593
|
+
const [note, setNote] = (0, import_react2.useState)("");
|
|
594
|
+
const [granted, setGranted] = (0, import_react2.useState)(null);
|
|
595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.container, children: [
|
|
596
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: styles.title, children: "Subscriber" }),
|
|
597
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
598
|
+
"form",
|
|
599
|
+
{
|
|
600
|
+
style: styles.toolbar,
|
|
601
|
+
onSubmit: (e) => {
|
|
602
|
+
e.preventDefault();
|
|
603
|
+
setGranted(null);
|
|
604
|
+
setSubscriber(idInput.trim() ? { type, id: idInput.trim() } : null);
|
|
605
|
+
},
|
|
606
|
+
children: [
|
|
607
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
608
|
+
"select",
|
|
609
|
+
{
|
|
610
|
+
value: type,
|
|
611
|
+
onChange: (e) => setType(e.target.value),
|
|
612
|
+
style: styles.button,
|
|
613
|
+
"aria-label": "Type",
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "user", children: "user" }),
|
|
616
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "workspace", children: "workspace" })
|
|
617
|
+
]
|
|
618
|
+
}
|
|
619
|
+
),
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
621
|
+
"input",
|
|
622
|
+
{
|
|
623
|
+
value: idInput,
|
|
624
|
+
onChange: (e) => setIdInput(e.target.value),
|
|
625
|
+
placeholder: "subscriber id",
|
|
626
|
+
style: { ...styles.button, cursor: "text", minWidth: 280 },
|
|
627
|
+
"aria-label": "Subscriber id"
|
|
628
|
+
}
|
|
629
|
+
),
|
|
630
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" })
|
|
631
|
+
]
|
|
632
|
+
}
|
|
633
|
+
),
|
|
634
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
635
|
+
subscriber && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
636
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Subscription" }),
|
|
637
|
+
subscription ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tbody", { children: [
|
|
638
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
639
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "plan" }),
|
|
640
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
|
|
641
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: subscription.plan }),
|
|
642
|
+
" \xB7 ",
|
|
643
|
+
subscription.interval
|
|
644
|
+
] })
|
|
645
|
+
] }),
|
|
646
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
647
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "status" }),
|
|
648
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
|
|
649
|
+
subscription.status,
|
|
650
|
+
subscription.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""
|
|
651
|
+
] })
|
|
652
|
+
] }),
|
|
653
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "period" }),
|
|
655
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
|
|
656
|
+
subscription.currentPeriodStart ? new Date(subscription.currentPeriodStart).toLocaleDateString() : "\u2014",
|
|
657
|
+
" ",
|
|
658
|
+
"\u2192",
|
|
659
|
+
" ",
|
|
660
|
+
subscription.currentPeriodEnd ? new Date(subscription.currentPeriodEnd).toLocaleDateString() : "\u2014"
|
|
661
|
+
] })
|
|
662
|
+
] }),
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "provider" }),
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: subscription.providerSubscriptionId ?? "\u2014" })
|
|
666
|
+
] })
|
|
667
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "No subscription." }),
|
|
668
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Wallet" }),
|
|
669
|
+
wallet ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
670
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { children: [
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: wallet.balance }),
|
|
672
|
+
" ",
|
|
673
|
+
wallet.currency,
|
|
674
|
+
" ",
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: styles.muted, children: [
|
|
676
|
+
"(granted ",
|
|
677
|
+
wallet.granted ?? "0",
|
|
678
|
+
" \xB7 purchased ",
|
|
679
|
+
wallet.purchased ?? "0",
|
|
680
|
+
") \xB7 minor units, precision ",
|
|
681
|
+
wallet.precision
|
|
682
|
+
] })
|
|
683
|
+
] }),
|
|
684
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
685
|
+
"form",
|
|
686
|
+
{
|
|
687
|
+
style: styles.toolbar,
|
|
688
|
+
onSubmit: (e) => {
|
|
689
|
+
e.preventDefault();
|
|
690
|
+
const key = `admin-grant-${subscriber.type}-${subscriber.id}-${Date.now()}`;
|
|
691
|
+
void grant({
|
|
692
|
+
amount: amount.trim(),
|
|
693
|
+
...note ? { description: note } : {},
|
|
694
|
+
idempotencyKey: key
|
|
695
|
+
}).then(() => {
|
|
696
|
+
setGranted(`Granted ${amount.trim()} ${wallet.currency}.`);
|
|
697
|
+
setAmount("");
|
|
698
|
+
setNote("");
|
|
699
|
+
}).catch(() => {
|
|
700
|
+
});
|
|
701
|
+
},
|
|
702
|
+
children: [
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
704
|
+
"input",
|
|
705
|
+
{
|
|
706
|
+
value: amount,
|
|
707
|
+
onChange: (e) => setAmount(e.target.value),
|
|
708
|
+
placeholder: "amount (minor units)",
|
|
709
|
+
style: { ...styles.button, cursor: "text" },
|
|
710
|
+
"aria-label": "Amount"
|
|
711
|
+
}
|
|
712
|
+
),
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
714
|
+
"input",
|
|
715
|
+
{
|
|
716
|
+
value: note,
|
|
717
|
+
onChange: (e) => setNote(e.target.value),
|
|
718
|
+
placeholder: "reason (optional)",
|
|
719
|
+
style: { ...styles.button, cursor: "text", minWidth: 220 },
|
|
720
|
+
"aria-label": "Reason"
|
|
721
|
+
}
|
|
722
|
+
),
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "submit", style: styles.button, disabled: !/^\d+$/.test(amount.trim()), children: "Grant" }),
|
|
724
|
+
granted ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.ok, children: granted }) : null
|
|
725
|
+
]
|
|
726
|
+
}
|
|
727
|
+
),
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Ledger" }),
|
|
729
|
+
ledger.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "Nothing moved yet." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { style: styles.table, children: [
|
|
730
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
731
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "When" }),
|
|
732
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Kind" }),
|
|
733
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Amount" }),
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Note" })
|
|
735
|
+
] }) }),
|
|
736
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: ledger.map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
737
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(t.createdAt).toLocaleString() }),
|
|
738
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: t.type }),
|
|
739
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t.amount }),
|
|
740
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.description ?? "" })
|
|
741
|
+
] }, t.id)) })
|
|
742
|
+
] }),
|
|
743
|
+
hasMoreLedger ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
744
|
+
"button",
|
|
745
|
+
{
|
|
746
|
+
type: "button",
|
|
747
|
+
style: { ...styles.button, marginTop: 8 },
|
|
748
|
+
onClick: () => void loadMoreLedger(),
|
|
749
|
+
children: "Load more"
|
|
750
|
+
}
|
|
751
|
+
) : null
|
|
752
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "No wallet \u2014 billing has no wallet configuration." })
|
|
753
|
+
] }) : null
|
|
754
|
+
] });
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// src/screens/AdminShell.tsx
|
|
758
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
514
759
|
var NAV = [
|
|
515
760
|
{ group: "Today", items: [{ page: "attention", label: "Attention" }] },
|
|
516
761
|
{
|
|
@@ -523,6 +768,13 @@ var NAV = [
|
|
|
523
768
|
]
|
|
524
769
|
},
|
|
525
770
|
{ group: "People", items: [{ page: "users", label: "Users", needs: "auth" }] },
|
|
771
|
+
{
|
|
772
|
+
group: "Money",
|
|
773
|
+
items: [
|
|
774
|
+
{ page: "catalog", label: "Catalog", needs: "billing" },
|
|
775
|
+
{ page: "subscriber", label: "Subscriber", needs: "billing" }
|
|
776
|
+
]
|
|
777
|
+
},
|
|
526
778
|
{ group: "Settings", items: [{ page: "settings", label: "Config & secrets", needs: "config" }] },
|
|
527
779
|
{ group: "Messaging", items: [{ page: "templates", label: "Templates", needs: "courier" }] },
|
|
528
780
|
{
|
|
@@ -538,52 +790,60 @@ function AdminShell({
|
|
|
538
790
|
configClient,
|
|
539
791
|
courierClient,
|
|
540
792
|
authClient,
|
|
793
|
+
billingClient,
|
|
541
794
|
environment,
|
|
542
795
|
page,
|
|
543
796
|
onNavigate
|
|
544
797
|
}) {
|
|
545
|
-
const [own, setOwn] = (0,
|
|
798
|
+
const [own, setOwn] = (0, import_react3.useState)("attention");
|
|
546
799
|
const current = page ?? own;
|
|
547
800
|
const go = (p) => {
|
|
548
801
|
if (onNavigate) onNavigate(p);
|
|
549
802
|
if (page === void 0) setOwn(p);
|
|
550
803
|
};
|
|
551
|
-
const [editing, setEditing] = (0,
|
|
804
|
+
const [editing, setEditing] = (0, import_react3.useState)(null);
|
|
552
805
|
const has = {
|
|
553
806
|
config: Boolean(configClient),
|
|
554
807
|
courier: Boolean(courierClient),
|
|
555
|
-
auth: Boolean(authClient)
|
|
808
|
+
auth: Boolean(authClient),
|
|
809
|
+
billing: Boolean(billingClient)
|
|
556
810
|
};
|
|
557
811
|
let body;
|
|
558
812
|
switch (current) {
|
|
559
813
|
case "attention":
|
|
560
|
-
body = /* @__PURE__ */ (0,
|
|
814
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AttentionScreen, { client });
|
|
561
815
|
break;
|
|
562
816
|
case "modules":
|
|
563
|
-
body = /* @__PURE__ */ (0,
|
|
817
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ModulesScreen, { client });
|
|
564
818
|
break;
|
|
565
819
|
case "doctor":
|
|
566
|
-
body = /* @__PURE__ */ (0,
|
|
820
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DoctorScreen, { client });
|
|
567
821
|
break;
|
|
568
822
|
case "config":
|
|
569
|
-
body = /* @__PURE__ */ (0,
|
|
823
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ConfigScreen, { client });
|
|
570
824
|
break;
|
|
571
825
|
case "routes":
|
|
572
|
-
body = /* @__PURE__ */ (0,
|
|
826
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RoutesScreen, { client });
|
|
573
827
|
break;
|
|
574
828
|
case "tokens":
|
|
575
|
-
body = /* @__PURE__ */ (0,
|
|
829
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TokensScreen, { client });
|
|
576
830
|
break;
|
|
577
831
|
case "log":
|
|
578
|
-
body = /* @__PURE__ */ (0,
|
|
832
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AdminLogScreen, { client });
|
|
833
|
+
break;
|
|
834
|
+
case "catalog":
|
|
835
|
+
body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to see the catalog here." });
|
|
836
|
+
break;
|
|
837
|
+
case "subscriber":
|
|
838
|
+
body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to look up subscribers here." });
|
|
579
839
|
break;
|
|
580
840
|
case "users":
|
|
581
|
-
body = authClient ? /* @__PURE__ */ (0,
|
|
841
|
+
body = authClient ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UsersScreen, { client: authClient }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Pass an AuthAdminClient to look up users here." });
|
|
582
842
|
break;
|
|
583
843
|
case "settings":
|
|
584
|
-
body = !configClient ? /* @__PURE__ */ (0,
|
|
585
|
-
/* @__PURE__ */ (0,
|
|
586
|
-
/* @__PURE__ */ (0,
|
|
844
|
+
body = !configClient ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
845
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
|
|
846
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
587
847
|
import_react_config_admin_screens.ConfigEditorScreen,
|
|
588
848
|
{
|
|
589
849
|
client: configClient,
|
|
@@ -593,7 +853,7 @@ function AdminShell({
|
|
|
593
853
|
onSaved: () => setEditing(null)
|
|
594
854
|
}
|
|
595
855
|
)
|
|
596
|
-
] }) : /* @__PURE__ */ (0,
|
|
856
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
597
857
|
import_react_config_admin_screens.ConfigListScreen,
|
|
598
858
|
{
|
|
599
859
|
client: configClient,
|
|
@@ -604,9 +864,9 @@ function AdminShell({
|
|
|
604
864
|
);
|
|
605
865
|
break;
|
|
606
866
|
case "templates":
|
|
607
|
-
body = !courierClient ? /* @__PURE__ */ (0,
|
|
608
|
-
/* @__PURE__ */ (0,
|
|
609
|
-
/* @__PURE__ */ (0,
|
|
867
|
+
body = !courierClient ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
868
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
|
|
869
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
610
870
|
import_react_courier_admin_screens.TemplateEditorScreen,
|
|
611
871
|
{
|
|
612
872
|
client: courierClient,
|
|
@@ -614,7 +874,7 @@ function AdminShell({
|
|
|
614
874
|
onSaved: () => setEditing(null)
|
|
615
875
|
}
|
|
616
876
|
)
|
|
617
|
-
] }) : /* @__PURE__ */ (0,
|
|
877
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
618
878
|
import_react_courier_admin_screens.TemplateListScreen,
|
|
619
879
|
{
|
|
620
880
|
client: courierClient,
|
|
@@ -623,13 +883,13 @@ function AdminShell({
|
|
|
623
883
|
);
|
|
624
884
|
break;
|
|
625
885
|
}
|
|
626
|
-
return /* @__PURE__ */ (0,
|
|
627
|
-
/* @__PURE__ */ (0,
|
|
886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.shell, children: [
|
|
887
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("nav", { style: styles.nav, "aria-label": "Admin", children: NAV.map((g) => {
|
|
628
888
|
const items = g.items.filter((i) => !i.needs || has[i.needs]);
|
|
629
889
|
if (items.length === 0) return null;
|
|
630
|
-
return /* @__PURE__ */ (0,
|
|
631
|
-
/* @__PURE__ */ (0,
|
|
632
|
-
items.map((i) => /* @__PURE__ */ (0,
|
|
890
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
|
|
891
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.navGroup, children: g.group }),
|
|
892
|
+
items.map((i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
633
893
|
"button",
|
|
634
894
|
{
|
|
635
895
|
type: "button",
|
|
@@ -645,7 +905,7 @@ function AdminShell({
|
|
|
645
905
|
))
|
|
646
906
|
] }, g.group);
|
|
647
907
|
}) }),
|
|
648
|
-
/* @__PURE__ */ (0,
|
|
908
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("main", { style: styles.main, children: body })
|
|
649
909
|
] });
|
|
650
910
|
}
|
|
651
911
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -653,10 +913,12 @@ function AdminShell({
|
|
|
653
913
|
AdminLogScreen,
|
|
654
914
|
AdminShell,
|
|
655
915
|
AttentionScreen,
|
|
916
|
+
CatalogScreen,
|
|
656
917
|
ConfigScreen,
|
|
657
918
|
DoctorScreen,
|
|
658
919
|
ModulesScreen,
|
|
659
920
|
RoutesScreen,
|
|
921
|
+
SubscriberScreen,
|
|
660
922
|
TokensScreen,
|
|
661
923
|
UsersScreen
|
|
662
924
|
});
|