@fonderie/react-admin-screens 1.2.0 → 1.3.1
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.cjs +625 -471
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -4
- package/dist/index.d.ts +20 -4
- package/dist/index.js +615 -462
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/screens/AdminShell.tsx
|
|
2
2
|
import { ConfigEditorScreen, ConfigListScreen } from "@fonderie/react-config-admin-screens";
|
|
3
3
|
import { TemplateEditorScreen, TemplateListScreen } from "@fonderie/react-courier-admin-screens";
|
|
4
|
-
import { useEffect, useState as
|
|
4
|
+
import { useEffect as useEffect2, useState as useState9 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/styles.ts
|
|
7
7
|
var t = {
|
|
@@ -1505,11 +1505,218 @@ import {
|
|
|
1505
1505
|
useAdminUserSessions,
|
|
1506
1506
|
useAdminUsers
|
|
1507
1507
|
} from "@fonderie/react-admin";
|
|
1508
|
-
import { useState as
|
|
1508
|
+
import { useState as useState6 } from "react";
|
|
1509
|
+
|
|
1510
|
+
// src/billing.ts
|
|
1511
|
+
import { useEffect, useState as useState4 } from "react";
|
|
1512
|
+
function periodEnd(s) {
|
|
1513
|
+
if (!s.currentPeriodEnd) return null;
|
|
1514
|
+
const date = new Date(s.currentPeriodEnd).toLocaleDateString();
|
|
1515
|
+
if (s.status === "canceled")
|
|
1516
|
+
return { label: new Date(s.currentPeriodEnd) < /* @__PURE__ */ new Date() ? "Ended" : "Ends", date };
|
|
1517
|
+
if (s.cancelAtPeriodEnd) return { label: "Ends", date };
|
|
1518
|
+
return { label: "Renews", date };
|
|
1519
|
+
}
|
|
1520
|
+
var statusTone = (status) => status === "active" ? "ok" : status === "trialing" ? "info" : status === "past_due" || status === "unpaid" ? "warn" : "neutral";
|
|
1521
|
+
function useSubscriptionIndex(client) {
|
|
1522
|
+
const [index, setIndex] = useState4(null);
|
|
1523
|
+
useEffect(() => {
|
|
1524
|
+
if (!client) return;
|
|
1525
|
+
let live = true;
|
|
1526
|
+
(async () => {
|
|
1527
|
+
const map = /* @__PURE__ */ new Map();
|
|
1528
|
+
let cursor;
|
|
1529
|
+
for (let page = 0; page < 20; page++) {
|
|
1530
|
+
const { result } = await client.listSubscriptions({
|
|
1531
|
+
limit: 100,
|
|
1532
|
+
...cursor ? { cursor } : {}
|
|
1533
|
+
});
|
|
1534
|
+
for (const s of result.subscriptions) {
|
|
1535
|
+
const key = `${s.subscriberType}/${s.subscriberId}`;
|
|
1536
|
+
if (!map.has(key)) map.set(key, s);
|
|
1537
|
+
}
|
|
1538
|
+
if (!result.nextCursor) break;
|
|
1539
|
+
cursor = result.nextCursor;
|
|
1540
|
+
}
|
|
1541
|
+
if (live) setIndex(map);
|
|
1542
|
+
})().catch(() => {
|
|
1543
|
+
if (live) setIndex(/* @__PURE__ */ new Map());
|
|
1544
|
+
});
|
|
1545
|
+
return () => {
|
|
1546
|
+
live = false;
|
|
1547
|
+
};
|
|
1548
|
+
}, [client]);
|
|
1549
|
+
return index;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
// src/screens/SubscriberBilling.tsx
|
|
1553
|
+
import { useAdminSubscriber } from "@fonderie/react-admin";
|
|
1554
|
+
import { useState as useState5 } from "react";
|
|
1509
1555
|
import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1510
|
-
function
|
|
1511
|
-
const
|
|
1512
|
-
const [
|
|
1556
|
+
function SubscriberBilling({ client, subscriber }) {
|
|
1557
|
+
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = useAdminSubscriber(client, subscriber, { limit: 20 });
|
|
1558
|
+
const [amount, setAmount] = useState5("");
|
|
1559
|
+
const [note, setNote] = useState5("");
|
|
1560
|
+
const [granted, setGranted] = useState5(null);
|
|
1561
|
+
if (isLoading && !wallet && !subscription) return /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Loading billing\u2026" });
|
|
1562
|
+
const end = subscription ? periodEnd(subscription) : null;
|
|
1563
|
+
return /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1564
|
+
error ? /* @__PURE__ */ jsx11("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
1565
|
+
/* @__PURE__ */ jsxs11("div", { style: { ...styles.grid, marginBottom: 16 }, children: [
|
|
1566
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.card, children: [
|
|
1567
|
+
/* @__PURE__ */ jsx11("div", { style: styles.statLabel, children: "Plan" }),
|
|
1568
|
+
/* @__PURE__ */ jsxs11(
|
|
1569
|
+
"div",
|
|
1570
|
+
{
|
|
1571
|
+
style: {
|
|
1572
|
+
display: "flex",
|
|
1573
|
+
alignItems: "center",
|
|
1574
|
+
gap: 8,
|
|
1575
|
+
marginTop: 6,
|
|
1576
|
+
flexWrap: "wrap"
|
|
1577
|
+
},
|
|
1578
|
+
children: [
|
|
1579
|
+
/* @__PURE__ */ jsx11("strong", { style: { fontSize: 18 }, children: subscription ? subscription.plan : "Free" }),
|
|
1580
|
+
subscription ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1581
|
+
/* @__PURE__ */ jsxs11("span", { style: styles.muted, children: [
|
|
1582
|
+
"\xB7 ",
|
|
1583
|
+
subscription.interval
|
|
1584
|
+
] }),
|
|
1585
|
+
/* @__PURE__ */ jsx11(Pill, { tone: statusTone(subscription.status), children: subscription.status })
|
|
1586
|
+
] }) : /* @__PURE__ */ jsx11("span", { style: styles.muted, children: "no subscription" })
|
|
1587
|
+
]
|
|
1588
|
+
}
|
|
1589
|
+
),
|
|
1590
|
+
end ? /* @__PURE__ */ jsxs11("div", { style: styles.statHint, children: [
|
|
1591
|
+
end.label,
|
|
1592
|
+
" ",
|
|
1593
|
+
end.date
|
|
1594
|
+
] }) : null,
|
|
1595
|
+
subscription?.providerSubscriptionId ? /* @__PURE__ */ jsx11("div", { style: { ...styles.statHint, fontFamily: "var(--fonderie-mono,monospace)" }, children: subscription.providerSubscriptionId }) : null
|
|
1596
|
+
] }),
|
|
1597
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.card, children: [
|
|
1598
|
+
/* @__PURE__ */ jsx11("div", { style: styles.statLabel, children: "Credits" }),
|
|
1599
|
+
wallet ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1600
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.statValue, children: [
|
|
1601
|
+
wallet.balance,
|
|
1602
|
+
" ",
|
|
1603
|
+
/* @__PURE__ */ jsx11("span", { style: { fontSize: 14, fontWeight: 500 }, children: wallet.currency })
|
|
1604
|
+
] }),
|
|
1605
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.statHint, children: [
|
|
1606
|
+
wallet.purchased ?? "0",
|
|
1607
|
+
" permanent \xB7 ",
|
|
1608
|
+
wallet.granted ?? "0",
|
|
1609
|
+
" plan allowance",
|
|
1610
|
+
wallet.grantedExpiresAt ? ` (expires ${new Date(wallet.grantedExpiresAt).toLocaleDateString()})` : ""
|
|
1611
|
+
] })
|
|
1612
|
+
] }) : /* @__PURE__ */ jsx11("div", { style: styles.statHint, children: "No wallet \u2014 billing has no wallet configuration." })
|
|
1613
|
+
] })
|
|
1614
|
+
] }),
|
|
1615
|
+
wallet ? /* @__PURE__ */ jsxs11(
|
|
1616
|
+
"form",
|
|
1617
|
+
{
|
|
1618
|
+
style: {
|
|
1619
|
+
...styles.card,
|
|
1620
|
+
display: "flex",
|
|
1621
|
+
gap: 8,
|
|
1622
|
+
alignItems: "center",
|
|
1623
|
+
flexWrap: "wrap",
|
|
1624
|
+
marginBottom: 16
|
|
1625
|
+
},
|
|
1626
|
+
onSubmit: (e) => {
|
|
1627
|
+
e.preventDefault();
|
|
1628
|
+
const key = `admin-grant-${subscriber.type}-${subscriber.id}-${Date.now()}`;
|
|
1629
|
+
void grant({
|
|
1630
|
+
amount: amount.trim(),
|
|
1631
|
+
...note ? { description: note } : {},
|
|
1632
|
+
idempotencyKey: key
|
|
1633
|
+
}).then(() => {
|
|
1634
|
+
setGranted(`Granted ${amount.trim()} ${wallet.currency}.`);
|
|
1635
|
+
setAmount("");
|
|
1636
|
+
setNote("");
|
|
1637
|
+
}).catch(() => {
|
|
1638
|
+
});
|
|
1639
|
+
},
|
|
1640
|
+
children: [
|
|
1641
|
+
/* @__PURE__ */ jsx11("strong", { style: { fontSize: 13.5, marginRight: 4 }, children: "Grant credits" }),
|
|
1642
|
+
/* @__PURE__ */ jsx11(
|
|
1643
|
+
"input",
|
|
1644
|
+
{
|
|
1645
|
+
value: amount,
|
|
1646
|
+
onChange: (e) => setAmount(e.target.value),
|
|
1647
|
+
placeholder: `amount (${wallet.currency})`,
|
|
1648
|
+
inputMode: "numeric",
|
|
1649
|
+
style: { ...styles.input, width: 150 },
|
|
1650
|
+
"aria-label": "Amount"
|
|
1651
|
+
}
|
|
1652
|
+
),
|
|
1653
|
+
/* @__PURE__ */ jsx11(
|
|
1654
|
+
"input",
|
|
1655
|
+
{
|
|
1656
|
+
value: note,
|
|
1657
|
+
onChange: (e) => setNote(e.target.value),
|
|
1658
|
+
placeholder: "reason (optional)",
|
|
1659
|
+
style: { ...styles.input, flex: 1, minWidth: 180 },
|
|
1660
|
+
"aria-label": "Reason"
|
|
1661
|
+
}
|
|
1662
|
+
),
|
|
1663
|
+
/* @__PURE__ */ jsxs11(
|
|
1664
|
+
"button",
|
|
1665
|
+
{
|
|
1666
|
+
type: "submit",
|
|
1667
|
+
style: styles.buttonPrimary,
|
|
1668
|
+
disabled: !/^\d+$/.test(amount.trim()),
|
|
1669
|
+
children: [
|
|
1670
|
+
/* @__PURE__ */ jsx11(Icon, { name: "plus", size: 14 }),
|
|
1671
|
+
"Grant"
|
|
1672
|
+
]
|
|
1673
|
+
}
|
|
1674
|
+
),
|
|
1675
|
+
granted ? /* @__PURE__ */ jsx11("span", { style: styles.ok, children: granted }) : null
|
|
1676
|
+
]
|
|
1677
|
+
}
|
|
1678
|
+
) : null,
|
|
1679
|
+
wallet ? ledger.length === 0 ? /* @__PURE__ */ jsx11(Empty, { icon: "subscriber", title: "No credit movements yet" }) : /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1680
|
+
/* @__PURE__ */ jsxs11("table", { style: styles.table, children: [
|
|
1681
|
+
/* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsxs11("tr", { children: [
|
|
1682
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "When" }),
|
|
1683
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Kind" }),
|
|
1684
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Amount" }),
|
|
1685
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Note" })
|
|
1686
|
+
] }) }),
|
|
1687
|
+
/* @__PURE__ */ jsx11("tbody", { children: ledger.map((t2) => /* @__PURE__ */ jsxs11("tr", { children: [
|
|
1688
|
+
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children: new Date(t2.createdAt).toLocaleString() }),
|
|
1689
|
+
/* @__PURE__ */ jsx11("td", { style: styles.td, children: t2.type }),
|
|
1690
|
+
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.mono }, children: t2.amount }),
|
|
1691
|
+
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted }, children: t2.description ?? "" })
|
|
1692
|
+
] }, t2.id)) })
|
|
1693
|
+
] }),
|
|
1694
|
+
hasMoreLedger ? /* @__PURE__ */ jsx11(
|
|
1695
|
+
"button",
|
|
1696
|
+
{
|
|
1697
|
+
type: "button",
|
|
1698
|
+
style: { ...styles.button, marginTop: 8 },
|
|
1699
|
+
onClick: () => void loadMoreLedger(),
|
|
1700
|
+
children: "Load more"
|
|
1701
|
+
}
|
|
1702
|
+
) : null
|
|
1703
|
+
] }) : null
|
|
1704
|
+
] });
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
// src/screens/UsersScreen.tsx
|
|
1708
|
+
import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1709
|
+
function UsersScreen({
|
|
1710
|
+
client,
|
|
1711
|
+
pageSize = 50,
|
|
1712
|
+
billingClient,
|
|
1713
|
+
openUserId
|
|
1714
|
+
}) {
|
|
1715
|
+
const [input, setInput] = useState6("");
|
|
1716
|
+
const [selected, setSelected] = useState6(
|
|
1717
|
+
openUserId ? { id: openUserId } : null
|
|
1718
|
+
);
|
|
1719
|
+
const plans = useSubscriptionIndex(billingClient);
|
|
1513
1720
|
const list = useAdminUsers(client, { limit: pageSize });
|
|
1514
1721
|
const { user, isLoading, error, suspend, unsuspend, revokeSessions } = useAdminUser(
|
|
1515
1722
|
client,
|
|
@@ -1518,20 +1725,20 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1518
1725
|
const userId = user?.id ?? null;
|
|
1519
1726
|
const sessions = useAdminUserSessions(client, userId);
|
|
1520
1727
|
const history = useAdminLoginHistory(client, userId, { limit: 20 });
|
|
1521
|
-
const yesNo = (v) => v ? /* @__PURE__ */
|
|
1728
|
+
const yesNo = (v) => v ? /* @__PURE__ */ jsx12(Pill, { tone: "ok", children: "yes" }) : /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: "no" });
|
|
1522
1729
|
const clear = () => {
|
|
1523
1730
|
setSelected(null);
|
|
1524
1731
|
setInput("");
|
|
1525
1732
|
};
|
|
1526
|
-
return /* @__PURE__ */
|
|
1527
|
-
/* @__PURE__ */
|
|
1733
|
+
return /* @__PURE__ */ jsxs12("div", { style: styles.container, children: [
|
|
1734
|
+
/* @__PURE__ */ jsx12(
|
|
1528
1735
|
PageHeader,
|
|
1529
1736
|
{
|
|
1530
1737
|
title: "Users",
|
|
1531
1738
|
lead: "Everyone signed up. Open an account for its sessions, sign-ins and the suspend and sign-out controls."
|
|
1532
1739
|
}
|
|
1533
1740
|
),
|
|
1534
|
-
/* @__PURE__ */
|
|
1741
|
+
/* @__PURE__ */ jsxs12(
|
|
1535
1742
|
"form",
|
|
1536
1743
|
{
|
|
1537
1744
|
style: styles.toolbar,
|
|
@@ -1541,7 +1748,7 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1541
1748
|
setSelected(email ? { email } : null);
|
|
1542
1749
|
},
|
|
1543
1750
|
children: [
|
|
1544
|
-
/* @__PURE__ */
|
|
1751
|
+
/* @__PURE__ */ jsx12(
|
|
1545
1752
|
"input",
|
|
1546
1753
|
{
|
|
1547
1754
|
type: "email",
|
|
@@ -1552,14 +1759,14 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1552
1759
|
"aria-label": "Email"
|
|
1553
1760
|
}
|
|
1554
1761
|
),
|
|
1555
|
-
/* @__PURE__ */
|
|
1556
|
-
/* @__PURE__ */
|
|
1762
|
+
/* @__PURE__ */ jsxs12("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
1763
|
+
/* @__PURE__ */ jsx12(Icon, { name: "search", size: 14 }),
|
|
1557
1764
|
"Look up"
|
|
1558
1765
|
] }),
|
|
1559
|
-
selected ? /* @__PURE__ */
|
|
1560
|
-
/* @__PURE__ */
|
|
1766
|
+
selected ? /* @__PURE__ */ jsxs12("button", { type: "button", style: styles.buttonGhost, onClick: clear, children: [
|
|
1767
|
+
/* @__PURE__ */ jsx12(Icon, { name: "back", size: 14 }),
|
|
1561
1768
|
"All users"
|
|
1562
|
-
] }) : /* @__PURE__ */
|
|
1769
|
+
] }) : /* @__PURE__ */ jsx12(
|
|
1563
1770
|
"button",
|
|
1564
1771
|
{
|
|
1565
1772
|
type: "button",
|
|
@@ -1572,18 +1779,37 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1572
1779
|
]
|
|
1573
1780
|
}
|
|
1574
1781
|
),
|
|
1575
|
-
error ? /* @__PURE__ */
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
/* @__PURE__ */
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1782
|
+
error && !(error.status === 404 && selected?.id) ? /* @__PURE__ */ jsx12("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
|
|
1783
|
+
error?.status === 404 && selected?.id ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1784
|
+
/* @__PURE__ */ jsxs12("div", { style: styles.notice, role: "status", children: [
|
|
1785
|
+
/* @__PURE__ */ jsx12("strong", { children: "No account with id " }),
|
|
1786
|
+
/* @__PURE__ */ jsx12("code", { style: styles.code, children: selected.id }),
|
|
1787
|
+
/* @__PURE__ */ jsx12("strong", { children: "." }),
|
|
1788
|
+
" It was deleted, or never existed here. Its billing records remain."
|
|
1789
|
+
] }),
|
|
1790
|
+
billingClient ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1791
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "Plan & credits" }),
|
|
1792
|
+
/* @__PURE__ */ jsx12(
|
|
1793
|
+
SubscriberBilling,
|
|
1794
|
+
{
|
|
1795
|
+
client: billingClient,
|
|
1796
|
+
subscriber: { type: "user", id: selected.id }
|
|
1797
|
+
}
|
|
1798
|
+
)
|
|
1799
|
+
] }) : null
|
|
1800
|
+
] }) : null,
|
|
1801
|
+
!selected ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1802
|
+
list.error ? /* @__PURE__ */ jsx12("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
1803
|
+
list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx12(Empty, { icon: "users", title: "No users yet", children: "Sign-ups appear here as they happen." }) : /* @__PURE__ */ jsxs12("table", { style: styles.table, children: [
|
|
1804
|
+
/* @__PURE__ */ jsx12("thead", { children: /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1805
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Email" }),
|
|
1806
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Name" }),
|
|
1807
|
+
billingClient ? /* @__PURE__ */ jsx12("th", { style: styles.th, children: "Plan" }) : null,
|
|
1808
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Created" }),
|
|
1809
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Status" })
|
|
1584
1810
|
] }) }),
|
|
1585
|
-
/* @__PURE__ */
|
|
1586
|
-
/* @__PURE__ */
|
|
1811
|
+
/* @__PURE__ */ jsx12("tbody", { children: list.users.map((u) => /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1812
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: /* @__PURE__ */ jsx12(
|
|
1587
1813
|
"button",
|
|
1588
1814
|
{
|
|
1589
1815
|
type: "button",
|
|
@@ -1592,17 +1818,28 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1592
1818
|
children: u.email
|
|
1593
1819
|
}
|
|
1594
1820
|
) }),
|
|
1595
|
-
/* @__PURE__ */
|
|
1596
|
-
/* @__PURE__ */
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1821
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ jsx12("span", { style: styles.muted, children: "\u2014" }) }),
|
|
1822
|
+
billingClient ? /* @__PURE__ */ jsx12("td", { style: styles.td, children: (() => {
|
|
1823
|
+
const sub = plans?.get(`user/${u.id}`);
|
|
1824
|
+
if (!plans) return /* @__PURE__ */ jsx12("span", { style: styles.muted, children: "\u2026" });
|
|
1825
|
+
if (!sub || sub.status === "canceled")
|
|
1826
|
+
return /* @__PURE__ */ jsx12("span", { style: styles.muted, children: "free" });
|
|
1827
|
+
return /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1828
|
+
/* @__PURE__ */ jsx12("strong", { children: sub.plan }),
|
|
1829
|
+
" ",
|
|
1830
|
+
sub.status !== "active" ? /* @__PURE__ */ jsx12(Pill, { tone: statusTone(sub.status), children: sub.status }) : null
|
|
1831
|
+
] });
|
|
1832
|
+
})() }) : null,
|
|
1833
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
|
|
1834
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1835
|
+
u.suspended ? /* @__PURE__ */ jsx12(Pill, { tone: "warn", children: "suspended" }) : null,
|
|
1836
|
+
u.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: "deleted" }) : null,
|
|
1837
|
+
!u.suspended && !u.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "ok", children: "active" }) : null
|
|
1601
1838
|
] })
|
|
1602
1839
|
] }, u.id)) })
|
|
1603
1840
|
] }),
|
|
1604
|
-
list.isLoading ? /* @__PURE__ */
|
|
1605
|
-
list.hasMore && !list.isLoading ? /* @__PURE__ */
|
|
1841
|
+
list.isLoading ? /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
1842
|
+
list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx12(
|
|
1606
1843
|
"button",
|
|
1607
1844
|
{
|
|
1608
1845
|
type: "button",
|
|
@@ -1612,48 +1849,48 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1612
1849
|
}
|
|
1613
1850
|
) : null
|
|
1614
1851
|
] }) : null,
|
|
1615
|
-
user ? /* @__PURE__ */
|
|
1616
|
-
/* @__PURE__ */
|
|
1852
|
+
user ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1853
|
+
/* @__PURE__ */ jsxs12("h2", { style: styles.subtitle, children: [
|
|
1617
1854
|
user.firstName || user.lastName ? `${user.firstName} ${user.lastName}`.trim() : user.email,
|
|
1618
1855
|
" ",
|
|
1619
|
-
user.suspended ? /* @__PURE__ */
|
|
1620
|
-
user.deletedAt ? /* @__PURE__ */
|
|
1856
|
+
user.suspended ? /* @__PURE__ */ jsx12(Pill, { tone: "warn", children: "suspended" }) : null,
|
|
1857
|
+
user.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: "deleted" }) : null
|
|
1621
1858
|
] }),
|
|
1622
|
-
/* @__PURE__ */
|
|
1623
|
-
/* @__PURE__ */
|
|
1624
|
-
/* @__PURE__ */
|
|
1625
|
-
/* @__PURE__ */
|
|
1859
|
+
/* @__PURE__ */ jsx12("table", { style: styles.table, children: /* @__PURE__ */ jsxs12("tbody", { children: [
|
|
1860
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1861
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "id" }),
|
|
1862
|
+
/* @__PURE__ */ jsx12("td", { style: { ...styles.td, ...styles.mono }, children: user.id })
|
|
1626
1863
|
] }),
|
|
1627
|
-
/* @__PURE__ */
|
|
1628
|
-
/* @__PURE__ */
|
|
1629
|
-
/* @__PURE__ */
|
|
1864
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1865
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "email" }),
|
|
1866
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1630
1867
|
user.email,
|
|
1631
1868
|
" \xB7 verified ",
|
|
1632
1869
|
yesNo(user.isEmailVerified)
|
|
1633
1870
|
] })
|
|
1634
1871
|
] }),
|
|
1635
|
-
/* @__PURE__ */
|
|
1636
|
-
/* @__PURE__ */
|
|
1637
|
-
/* @__PURE__ */
|
|
1872
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1873
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "MFA" }),
|
|
1874
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: yesNo(user.mfaEnabled) })
|
|
1638
1875
|
] }),
|
|
1639
|
-
/* @__PURE__ */
|
|
1640
|
-
/* @__PURE__ */
|
|
1641
|
-
/* @__PURE__ */
|
|
1876
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1877
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "provider" }),
|
|
1878
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1642
1879
|
user.provider || "password",
|
|
1643
1880
|
user.hasPassword ? "" : " \xB7 no password set"
|
|
1644
1881
|
] })
|
|
1645
1882
|
] }),
|
|
1646
|
-
/* @__PURE__ */
|
|
1647
|
-
/* @__PURE__ */
|
|
1648
|
-
/* @__PURE__ */
|
|
1883
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1884
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "last login" }),
|
|
1885
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: user.lastLogin ? new Date(user.lastLogin).toLocaleString() : /* @__PURE__ */ jsx12("span", { style: styles.muted, children: "never" }) })
|
|
1649
1886
|
] }),
|
|
1650
|
-
/* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
1652
|
-
/* @__PURE__ */
|
|
1887
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1888
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "created" }),
|
|
1889
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: new Date(user.createdAt).toLocaleString() })
|
|
1653
1890
|
] })
|
|
1654
1891
|
] }) }),
|
|
1655
|
-
/* @__PURE__ */
|
|
1656
|
-
user.suspended ? /* @__PURE__ */
|
|
1892
|
+
/* @__PURE__ */ jsxs12("div", { style: { ...styles.toolbar, marginTop: 12 }, children: [
|
|
1893
|
+
user.suspended ? /* @__PURE__ */ jsx12(
|
|
1657
1894
|
"button",
|
|
1658
1895
|
{
|
|
1659
1896
|
type: "button",
|
|
@@ -1662,7 +1899,7 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1662
1899
|
disabled: isLoading,
|
|
1663
1900
|
children: "Unsuspend"
|
|
1664
1901
|
}
|
|
1665
|
-
) : /* @__PURE__ */
|
|
1902
|
+
) : /* @__PURE__ */ jsx12(
|
|
1666
1903
|
"button",
|
|
1667
1904
|
{
|
|
1668
1905
|
type: "button",
|
|
@@ -1672,7 +1909,7 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1672
1909
|
children: "Suspend"
|
|
1673
1910
|
}
|
|
1674
1911
|
),
|
|
1675
|
-
/* @__PURE__ */
|
|
1912
|
+
/* @__PURE__ */ jsx12(
|
|
1676
1913
|
"button",
|
|
1677
1914
|
{
|
|
1678
1915
|
type: "button",
|
|
@@ -1683,38 +1920,48 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1683
1920
|
}
|
|
1684
1921
|
)
|
|
1685
1922
|
] }),
|
|
1686
|
-
/* @__PURE__ */
|
|
1687
|
-
|
|
1688
|
-
/* @__PURE__ */
|
|
1923
|
+
billingClient ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1924
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "Plan & credits" }),
|
|
1925
|
+
/* @__PURE__ */ jsx12(
|
|
1926
|
+
SubscriberBilling,
|
|
1927
|
+
{
|
|
1928
|
+
client: billingClient,
|
|
1929
|
+
subscriber: { type: "user", id: user.id }
|
|
1930
|
+
}
|
|
1931
|
+
)
|
|
1932
|
+
] }) : null,
|
|
1933
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "Live sessions" }),
|
|
1934
|
+
sessions.sessions.length === 0 ? /* @__PURE__ */ jsx12("p", { style: styles.muted, children: "None." }) : /* @__PURE__ */ jsx12("ul", { style: styles.list, children: sessions.sessions.map((s) => /* @__PURE__ */ jsxs12("li", { style: styles.row, children: [
|
|
1935
|
+
/* @__PURE__ */ jsx12("span", { style: styles.mono, children: s.ipAddress ?? "\u2014" }),
|
|
1689
1936
|
" ",
|
|
1690
|
-
describeLocation(s.location) ? /* @__PURE__ */
|
|
1937
|
+
describeLocation(s.location) ? /* @__PURE__ */ jsxs12("span", { style: styles.muted, children: [
|
|
1691
1938
|
describeLocation(s.location),
|
|
1692
1939
|
" "
|
|
1693
1940
|
] }) : null,
|
|
1694
|
-
/* @__PURE__ */
|
|
1941
|
+
/* @__PURE__ */ jsx12("span", { style: styles.muted, children: s.userAgent ?? "" }),
|
|
1695
1942
|
" ",
|
|
1696
|
-
/* @__PURE__ */
|
|
1943
|
+
/* @__PURE__ */ jsxs12("span", { style: styles.muted, children: [
|
|
1697
1944
|
"since ",
|
|
1698
1945
|
new Date(s.createdAt).toLocaleString()
|
|
1699
1946
|
] })
|
|
1700
1947
|
] }, s.id)) }),
|
|
1701
|
-
/* @__PURE__ */
|
|
1702
|
-
history.events.length === 0 && !history.isLoading ? /* @__PURE__ */
|
|
1703
|
-
/* @__PURE__ */
|
|
1948
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "Recent sign-ins" }),
|
|
1949
|
+
history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ jsx12("p", { style: styles.muted, children: "None recorded." }) : /* @__PURE__ */ jsx12("ul", { style: styles.list, children: history.events.map((e) => /* @__PURE__ */ jsxs12("li", { style: styles.row, children: [
|
|
1950
|
+
/* @__PURE__ */ jsx12(Pill, { tone: e.outcome === "success" ? "ok" : "bad", children: e.outcome }),
|
|
1704
1951
|
" ",
|
|
1705
|
-
/* @__PURE__ */
|
|
1952
|
+
/* @__PURE__ */ jsx12("span", { style: styles.muted, children: e.method }),
|
|
1706
1953
|
" ",
|
|
1707
|
-
/* @__PURE__ */
|
|
1954
|
+
/* @__PURE__ */ jsx12("span", { style: styles.mono, children: e.ipAddress ?? "\u2014" }),
|
|
1708
1955
|
" ",
|
|
1709
|
-
describeLocation(e.location) ? /* @__PURE__ */
|
|
1710
|
-
e.location?.proxy || e.location?.hosting ? /* @__PURE__ */
|
|
1956
|
+
describeLocation(e.location) ? /* @__PURE__ */ jsx12("span", { style: styles.muted, children: describeLocation(e.location) }) : null,
|
|
1957
|
+
e.location?.proxy || e.location?.hosting ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1711
1958
|
" ",
|
|
1712
|
-
/* @__PURE__ */
|
|
1959
|
+
/* @__PURE__ */ jsx12(Pill, { tone: "warn", children: e.location.proxy ? "proxy/VPN" : "hosting" })
|
|
1713
1960
|
] }) : null,
|
|
1714
1961
|
" ",
|
|
1715
|
-
/* @__PURE__ */
|
|
1962
|
+
/* @__PURE__ */ jsx12("span", { style: styles.muted, children: new Date(e.createdAt).toLocaleString() })
|
|
1716
1963
|
] }, e.id)) }),
|
|
1717
|
-
history.hasMore && !history.isLoading ? /* @__PURE__ */
|
|
1964
|
+
history.hasMore && !history.isLoading ? /* @__PURE__ */ jsx12(
|
|
1718
1965
|
"button",
|
|
1719
1966
|
{
|
|
1720
1967
|
type: "button",
|
|
@@ -1729,24 +1976,24 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
1729
1976
|
|
|
1730
1977
|
// src/screens/CatalogScreen.tsx
|
|
1731
1978
|
import { useAdminCatalog } from "@fonderie/react-admin";
|
|
1732
|
-
import { Fragment as
|
|
1979
|
+
import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1733
1980
|
function CatalogScreen({ client }) {
|
|
1734
1981
|
const { catalog, isLoading, error, refresh, deletePlan } = useAdminCatalog(client);
|
|
1735
1982
|
const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
|
|
1736
|
-
return /* @__PURE__ */
|
|
1737
|
-
/* @__PURE__ */
|
|
1983
|
+
return /* @__PURE__ */ jsxs13("div", { style: styles.container, children: [
|
|
1984
|
+
/* @__PURE__ */ jsx13(
|
|
1738
1985
|
PageHeader,
|
|
1739
1986
|
{
|
|
1740
1987
|
title: "Catalog",
|
|
1741
1988
|
lead: "What you sell: plans as configured in code, and as stored in the database, side by side.",
|
|
1742
|
-
actions: /* @__PURE__ */
|
|
1989
|
+
actions: /* @__PURE__ */ jsx13(RefreshButton, { onClick: () => void refresh(), busy: isLoading })
|
|
1743
1990
|
}
|
|
1744
1991
|
),
|
|
1745
|
-
error ? /* @__PURE__ */
|
|
1746
|
-
isLoading && !catalog ? /* @__PURE__ */
|
|
1747
|
-
catalog ? /* @__PURE__ */
|
|
1748
|
-
/* @__PURE__ */
|
|
1749
|
-
/* @__PURE__ */
|
|
1992
|
+
error ? /* @__PURE__ */ jsx13("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
1993
|
+
isLoading && !catalog ? /* @__PURE__ */ jsx13("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
1994
|
+
catalog ? /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
1995
|
+
/* @__PURE__ */ jsx13("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Configured (code)" }),
|
|
1996
|
+
/* @__PURE__ */ jsx13(
|
|
1750
1997
|
"pre",
|
|
1751
1998
|
{
|
|
1752
1999
|
style: {
|
|
@@ -1760,32 +2007,32 @@ function CatalogScreen({ client }) {
|
|
|
1760
2007
|
children: JSON.stringify(catalog.configured, null, 2)
|
|
1761
2008
|
}
|
|
1762
2009
|
),
|
|
1763
|
-
/* @__PURE__ */
|
|
1764
|
-
catalog.stored.length === 0 ? /* @__PURE__ */
|
|
1765
|
-
/* @__PURE__ */
|
|
1766
|
-
/* @__PURE__ */
|
|
1767
|
-
/* @__PURE__ */
|
|
1768
|
-
/* @__PURE__ */
|
|
1769
|
-
/* @__PURE__ */
|
|
1770
|
-
/* @__PURE__ */
|
|
1771
|
-
/* @__PURE__ */
|
|
1772
|
-
/* @__PURE__ */
|
|
2010
|
+
/* @__PURE__ */ jsx13("h2", { style: styles.subtitle, children: "Stored (database)" }),
|
|
2011
|
+
catalog.stored.length === 0 ? /* @__PURE__ */ jsx13(Empty, { icon: "catalog", title: "No stored plans", children: "Plans are configured in code; nothing has been written to the database." }) : /* @__PURE__ */ jsxs13("table", { style: styles.table, children: [
|
|
2012
|
+
/* @__PURE__ */ jsx13("thead", { children: /* @__PURE__ */ jsxs13("tr", { children: [
|
|
2013
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Plan" }),
|
|
2014
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Tier" }),
|
|
2015
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Seats" }),
|
|
2016
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Monthly" }),
|
|
2017
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Yearly" }),
|
|
2018
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Trial" }),
|
|
2019
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th })
|
|
1773
2020
|
] }) }),
|
|
1774
|
-
/* @__PURE__ */
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
1777
|
-
p.description ? /* @__PURE__ */
|
|
2021
|
+
/* @__PURE__ */ jsx13("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ jsxs13("tr", { children: [
|
|
2022
|
+
/* @__PURE__ */ jsxs13("td", { style: styles.td, children: [
|
|
2023
|
+
/* @__PURE__ */ jsx13("strong", { children: p.name }),
|
|
2024
|
+
p.description ? /* @__PURE__ */ jsx13("div", { style: styles.muted, children: p.description }) : null
|
|
1778
2025
|
] }),
|
|
1779
|
-
/* @__PURE__ */
|
|
1780
|
-
/* @__PURE__ */
|
|
1781
|
-
/* @__PURE__ */
|
|
2026
|
+
/* @__PURE__ */ jsx13("td", { style: styles.td, children: p.tier }),
|
|
2027
|
+
/* @__PURE__ */ jsx13("td", { style: styles.td, children: p.seats ?? "\u221E" }),
|
|
2028
|
+
/* @__PURE__ */ jsxs13("td", { style: styles.td, children: [
|
|
1782
2029
|
money(p.pricing?.monthly),
|
|
1783
2030
|
" ",
|
|
1784
2031
|
p.pricing?.currency ?? ""
|
|
1785
2032
|
] }),
|
|
1786
|
-
/* @__PURE__ */
|
|
1787
|
-
/* @__PURE__ */
|
|
1788
|
-
/* @__PURE__ */
|
|
2033
|
+
/* @__PURE__ */ jsx13("td", { style: styles.td, children: money(p.pricing?.yearly) }),
|
|
2034
|
+
/* @__PURE__ */ jsx13("td", { style: styles.td, children: p.trialDays ? `${p.trialDays} d` : "\u2014" }),
|
|
2035
|
+
/* @__PURE__ */ jsx13("td", { style: styles.td, children: /* @__PURE__ */ jsx13(
|
|
1789
2036
|
"button",
|
|
1790
2037
|
{
|
|
1791
2038
|
type: "button",
|
|
@@ -1805,114 +2052,148 @@ function CatalogScreen({ client }) {
|
|
|
1805
2052
|
}
|
|
1806
2053
|
|
|
1807
2054
|
// src/screens/SubscriberScreen.tsx
|
|
1808
|
-
import {
|
|
1809
|
-
import { useState as
|
|
1810
|
-
import { Fragment as
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
2055
|
+
import { useAdminSubscribers } from "@fonderie/react-admin";
|
|
2056
|
+
import { useState as useState7 } from "react";
|
|
2057
|
+
import { Fragment as Fragment9, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2058
|
+
var FILTERS = [
|
|
2059
|
+
{ label: "All", match: () => true },
|
|
2060
|
+
{ label: "Active", match: (s) => s === "active" },
|
|
2061
|
+
{ label: "Trialing", match: (s) => s === "trialing" },
|
|
2062
|
+
{ label: "Past due", match: (s) => s === "past_due" || s === "unpaid" },
|
|
2063
|
+
{ label: "Canceled", match: (s) => s === "canceled" }
|
|
2064
|
+
];
|
|
2065
|
+
function SubscriberScreen({ client, pageSize = 50, onOpenUser }) {
|
|
1815
2066
|
const list = useAdminSubscribers(client, { limit: pageSize });
|
|
1816
|
-
const
|
|
1817
|
-
const [
|
|
1818
|
-
const [
|
|
1819
|
-
const [
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
2067
|
+
const [filter, setFilter] = useState7("All");
|
|
2068
|
+
const [open, setOpen] = useState7(null);
|
|
2069
|
+
const [type, setType] = useState7("workspace");
|
|
2070
|
+
const [idInput, setIdInput] = useState7("");
|
|
2071
|
+
if (open) {
|
|
2072
|
+
return /* @__PURE__ */ jsxs14("div", { style: styles.container, children: [
|
|
2073
|
+
/* @__PURE__ */ jsx14(
|
|
2074
|
+
PageHeader,
|
|
2075
|
+
{
|
|
2076
|
+
title: `${open.type}/${open.id}`,
|
|
2077
|
+
lead: "Plan, credits and what moved.",
|
|
2078
|
+
actions: /* @__PURE__ */ jsxs14("button", { type: "button", style: styles.buttonGhost, onClick: () => setOpen(null), children: [
|
|
2079
|
+
/* @__PURE__ */ jsx14(Icon, { name: "back", size: 14 }),
|
|
2080
|
+
"All subscriptions"
|
|
2081
|
+
] })
|
|
2082
|
+
}
|
|
2083
|
+
),
|
|
2084
|
+
/* @__PURE__ */ jsx14(SubscriberBilling, { client, subscriber: open })
|
|
2085
|
+
] });
|
|
2086
|
+
}
|
|
2087
|
+
const match = FILTERS.find((f) => f.label === filter)?.match ?? (() => true);
|
|
2088
|
+
const rows = list.subscriptions.filter((s) => match(s.status));
|
|
2089
|
+
const openRow = (t2, id) => t2 === "user" && onOpenUser ? onOpenUser(id) : setOpen({ type: t2, id });
|
|
2090
|
+
return /* @__PURE__ */ jsxs14("div", { style: styles.container, children: [
|
|
2091
|
+
/* @__PURE__ */ jsx14(
|
|
1828
2092
|
PageHeader,
|
|
1829
2093
|
{
|
|
1830
|
-
title: "
|
|
1831
|
-
lead: "Who is
|
|
2094
|
+
title: "Subscriptions",
|
|
2095
|
+
lead: "Who pays, and who is behind. A user's plan and credits are also on their page under Users \u2014 free users appear only there.",
|
|
2096
|
+
actions: /* @__PURE__ */ jsx14(RefreshButton, { onClick: () => void list.refresh(), busy: list.isLoading })
|
|
1832
2097
|
}
|
|
1833
2098
|
),
|
|
1834
|
-
/* @__PURE__ */
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
placeholder: "subscriber id",
|
|
1863
|
-
style: { ...styles.input, minWidth: 280 },
|
|
1864
|
-
"aria-label": "Subscriber id"
|
|
1865
|
-
}
|
|
1866
|
-
),
|
|
1867
|
-
/* @__PURE__ */ jsxs13("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
1868
|
-
/* @__PURE__ */ jsx13(Icon, { name: "search", size: 14 }),
|
|
1869
|
-
"Look up"
|
|
1870
|
-
] }),
|
|
1871
|
-
subscriber ? /* @__PURE__ */ jsxs13(
|
|
1872
|
-
"button",
|
|
1873
|
-
{
|
|
1874
|
-
type: "button",
|
|
1875
|
-
style: styles.button,
|
|
1876
|
-
onClick: () => {
|
|
1877
|
-
setSubscriber(null);
|
|
1878
|
-
setIdInput("");
|
|
1879
|
-
setGranted(null);
|
|
2099
|
+
/* @__PURE__ */ jsxs14("div", { style: { ...styles.toolbar, justifyContent: "space-between" }, children: [
|
|
2100
|
+
/* @__PURE__ */ jsx14(
|
|
2101
|
+
"fieldset",
|
|
2102
|
+
{
|
|
2103
|
+
style: {
|
|
2104
|
+
display: "flex",
|
|
2105
|
+
gap: 6,
|
|
2106
|
+
flexWrap: "wrap",
|
|
2107
|
+
border: "none",
|
|
2108
|
+
margin: 0,
|
|
2109
|
+
padding: 0,
|
|
2110
|
+
minWidth: 0
|
|
2111
|
+
},
|
|
2112
|
+
"aria-label": "Filter by status",
|
|
2113
|
+
children: FILTERS.map((f) => {
|
|
2114
|
+
const n = list.subscriptions.filter((s) => f.match(s.status)).length;
|
|
2115
|
+
const on = filter === f.label;
|
|
2116
|
+
return /* @__PURE__ */ jsxs14(
|
|
2117
|
+
"button",
|
|
2118
|
+
{
|
|
2119
|
+
type: "button",
|
|
2120
|
+
"aria-pressed": on,
|
|
2121
|
+
onClick: () => setFilter(f.label),
|
|
2122
|
+
style: { ...on ? styles.buttonPrimary : styles.button, height: 28 },
|
|
2123
|
+
children: [
|
|
2124
|
+
f.label,
|
|
2125
|
+
/* @__PURE__ */ jsx14("span", { style: { opacity: 0.7 }, children: n })
|
|
2126
|
+
]
|
|
1880
2127
|
},
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
2128
|
+
f.label
|
|
2129
|
+
);
|
|
2130
|
+
})
|
|
2131
|
+
}
|
|
2132
|
+
),
|
|
2133
|
+
/* @__PURE__ */ jsxs14(
|
|
2134
|
+
"form",
|
|
2135
|
+
{
|
|
2136
|
+
style: { display: "flex", gap: 6 },
|
|
2137
|
+
onSubmit: (e) => {
|
|
2138
|
+
e.preventDefault();
|
|
2139
|
+
if (idInput.trim()) openRow(type, idInput.trim());
|
|
2140
|
+
},
|
|
2141
|
+
children: [
|
|
2142
|
+
/* @__PURE__ */ jsxs14(
|
|
2143
|
+
"select",
|
|
2144
|
+
{
|
|
2145
|
+
value: type,
|
|
2146
|
+
onChange: (e) => setType(e.target.value),
|
|
2147
|
+
style: styles.input,
|
|
2148
|
+
"aria-label": "Type",
|
|
2149
|
+
children: [
|
|
2150
|
+
/* @__PURE__ */ jsx14("option", { value: "workspace", children: "workspace" }),
|
|
2151
|
+
/* @__PURE__ */ jsx14("option", { value: "user", children: "user" })
|
|
2152
|
+
]
|
|
2153
|
+
}
|
|
2154
|
+
),
|
|
2155
|
+
/* @__PURE__ */ jsx14(
|
|
2156
|
+
"input",
|
|
2157
|
+
{
|
|
2158
|
+
value: idInput,
|
|
2159
|
+
onChange: (e) => setIdInput(e.target.value),
|
|
2160
|
+
placeholder: "subscriber id",
|
|
2161
|
+
style: { ...styles.input, width: 220 },
|
|
2162
|
+
"aria-label": "Subscriber id"
|
|
2163
|
+
}
|
|
2164
|
+
),
|
|
2165
|
+
/* @__PURE__ */ jsxs14("button", { type: "submit", style: styles.button, disabled: !idInput.trim(), children: [
|
|
2166
|
+
/* @__PURE__ */ jsx14(Icon, { name: "search", size: 14 }),
|
|
2167
|
+
"Open"
|
|
2168
|
+
] })
|
|
2169
|
+
]
|
|
2170
|
+
}
|
|
2171
|
+
)
|
|
2172
|
+
] }),
|
|
2173
|
+
list.error ? /* @__PURE__ */ jsx14("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
2174
|
+
rows.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx14(
|
|
2175
|
+
Empty,
|
|
2176
|
+
{
|
|
2177
|
+
icon: "subscriber",
|
|
2178
|
+
title: filter === "All" ? "No subscriptions yet" : `No ${filter.toLowerCase()} subscriptions`,
|
|
2179
|
+
children: "Subscriptions appear here once someone checks out."
|
|
1897
2180
|
}
|
|
1898
|
-
),
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
/* @__PURE__ */
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
/* @__PURE__ */ jsx13("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ jsxs13("tr", { children: [
|
|
1910
|
-
/* @__PURE__ */ jsx13("td", { style: styles.td, children: /* @__PURE__ */ jsxs13(
|
|
2181
|
+
) : /* @__PURE__ */ jsxs14("table", { style: styles.table, children: [
|
|
2182
|
+
/* @__PURE__ */ jsx14("thead", { children: /* @__PURE__ */ jsxs14("tr", { children: [
|
|
2183
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "Subscriber" }),
|
|
2184
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "Plan" }),
|
|
2185
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "Status" }),
|
|
2186
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "Renews / ends" })
|
|
2187
|
+
] }) }),
|
|
2188
|
+
/* @__PURE__ */ jsx14("tbody", { children: rows.map((s) => {
|
|
2189
|
+
const end = periodEnd(s);
|
|
2190
|
+
return /* @__PURE__ */ jsxs14("tr", { children: [
|
|
2191
|
+
/* @__PURE__ */ jsx14("td", { style: styles.td, children: /* @__PURE__ */ jsxs14(
|
|
1911
2192
|
"button",
|
|
1912
2193
|
{
|
|
1913
2194
|
type: "button",
|
|
1914
2195
|
style: { ...styles.link, ...styles.mono },
|
|
1915
|
-
onClick: () =>
|
|
2196
|
+
onClick: () => openRow(s.subscriberType, s.subscriberId),
|
|
1916
2197
|
children: [
|
|
1917
2198
|
s.subscriberType,
|
|
1918
2199
|
"/",
|
|
@@ -1920,206 +2201,56 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
1920
2201
|
]
|
|
1921
2202
|
}
|
|
1922
2203
|
) }),
|
|
1923
|
-
/* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
"
|
|
1926
|
-
|
|
2204
|
+
/* @__PURE__ */ jsxs14("td", { style: styles.td, children: [
|
|
2205
|
+
/* @__PURE__ */ jsx14("strong", { children: s.plan }),
|
|
2206
|
+
" ",
|
|
2207
|
+
/* @__PURE__ */ jsxs14("span", { style: styles.muted, children: [
|
|
2208
|
+
"\xB7 ",
|
|
2209
|
+
s.interval
|
|
2210
|
+
] })
|
|
1927
2211
|
] }),
|
|
1928
|
-
/* @__PURE__ */
|
|
1929
|
-
/* @__PURE__ */
|
|
1930
|
-
|
|
1931
|
-
{
|
|
1932
|
-
tone: s.status === "active" ? "ok" : s.status === "trialing" ? "info" : s.status === "past_due" ? "warn" : "neutral",
|
|
1933
|
-
children: s.status
|
|
1934
|
-
}
|
|
1935
|
-
),
|
|
1936
|
-
s.cancelAtPeriodEnd ? /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
2212
|
+
/* @__PURE__ */ jsxs14("td", { style: styles.td, children: [
|
|
2213
|
+
/* @__PURE__ */ jsx14(Pill, { tone: statusTone(s.status), children: s.status }),
|
|
2214
|
+
s.cancelAtPeriodEnd && s.status !== "canceled" ? /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
1937
2215
|
" ",
|
|
1938
|
-
/* @__PURE__ */
|
|
2216
|
+
/* @__PURE__ */ jsx14(Pill, { tone: "warn", dot: false, children: "cancels" })
|
|
1939
2217
|
] }) : null
|
|
1940
2218
|
] }),
|
|
1941
|
-
/* @__PURE__ */
|
|
1942
|
-
|
|
1943
|
-
] }),
|
|
1944
|
-
list.isLoading ? /* @__PURE__ */ jsx13("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
1945
|
-
list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx13(
|
|
1946
|
-
"button",
|
|
1947
|
-
{
|
|
1948
|
-
type: "button",
|
|
1949
|
-
style: { ...styles.button, marginTop: 8 },
|
|
1950
|
-
onClick: () => void list.loadMore(),
|
|
1951
|
-
children: "Load more"
|
|
1952
|
-
}
|
|
1953
|
-
) : null
|
|
1954
|
-
] }) : null,
|
|
1955
|
-
subscriber && !isLoading ? /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
1956
|
-
/* @__PURE__ */ jsx13("h2", { style: styles.subtitle, children: "Subscription" }),
|
|
1957
|
-
subscription ? /* @__PURE__ */ jsx13("table", { style: styles.table, children: /* @__PURE__ */ jsxs13("tbody", { children: [
|
|
1958
|
-
/* @__PURE__ */ jsxs13("tr", { children: [
|
|
1959
|
-
/* @__PURE__ */ jsx13("td", { style: styles.td, children: "plan" }),
|
|
1960
|
-
/* @__PURE__ */ jsxs13("td", { style: styles.td, children: [
|
|
1961
|
-
/* @__PURE__ */ jsx13("strong", { children: subscription.plan }),
|
|
1962
|
-
" \xB7 ",
|
|
1963
|
-
subscription.interval
|
|
1964
|
-
] })
|
|
1965
|
-
] }),
|
|
1966
|
-
/* @__PURE__ */ jsxs13("tr", { children: [
|
|
1967
|
-
/* @__PURE__ */ jsx13("td", { style: styles.td, children: "status" }),
|
|
1968
|
-
/* @__PURE__ */ jsxs13("td", { style: styles.td, children: [
|
|
1969
|
-
subscription.status,
|
|
1970
|
-
subscription.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""
|
|
1971
|
-
] })
|
|
1972
|
-
] }),
|
|
1973
|
-
/* @__PURE__ */ jsxs13("tr", { children: [
|
|
1974
|
-
/* @__PURE__ */ jsx13("td", { style: styles.td, children: "period" }),
|
|
1975
|
-
/* @__PURE__ */ jsxs13("td", { style: styles.td, children: [
|
|
1976
|
-
subscription.currentPeriodStart ? new Date(subscription.currentPeriodStart).toLocaleDateString() : "\u2014",
|
|
2219
|
+
/* @__PURE__ */ jsx14("td", { style: { ...styles.td, whiteSpace: "nowrap" }, children: end ? /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
2220
|
+
/* @__PURE__ */ jsx14("span", { style: styles.muted, children: end.label }),
|
|
1977
2221
|
" ",
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
style: {
|
|
1994
|
-
...styles.card,
|
|
1995
|
-
display: "flex",
|
|
1996
|
-
alignItems: "baseline",
|
|
1997
|
-
gap: 8,
|
|
1998
|
-
flexWrap: "wrap"
|
|
1999
|
-
},
|
|
2000
|
-
children: [
|
|
2001
|
-
/* @__PURE__ */ jsx13(
|
|
2002
|
-
"strong",
|
|
2003
|
-
{
|
|
2004
|
-
style: {
|
|
2005
|
-
fontSize: 22,
|
|
2006
|
-
letterSpacing: "var(--fonderie-tracking-display,-0.05em)"
|
|
2007
|
-
},
|
|
2008
|
-
children: wallet.balance
|
|
2009
|
-
}
|
|
2010
|
-
),
|
|
2011
|
-
" ",
|
|
2012
|
-
wallet.currency,
|
|
2013
|
-
" ",
|
|
2014
|
-
/* @__PURE__ */ jsxs13("span", { style: styles.muted, children: [
|
|
2015
|
-
"(granted ",
|
|
2016
|
-
wallet.granted ?? "0",
|
|
2017
|
-
" \xB7 purchased ",
|
|
2018
|
-
wallet.purchased ?? "0",
|
|
2019
|
-
") \xB7 minor units, precision ",
|
|
2020
|
-
wallet.precision
|
|
2021
|
-
] })
|
|
2022
|
-
]
|
|
2023
|
-
}
|
|
2024
|
-
),
|
|
2025
|
-
/* @__PURE__ */ jsxs13(
|
|
2026
|
-
"form",
|
|
2027
|
-
{
|
|
2028
|
-
style: styles.toolbar,
|
|
2029
|
-
onSubmit: (e) => {
|
|
2030
|
-
e.preventDefault();
|
|
2031
|
-
const key = `admin-grant-${subscriber.type}-${subscriber.id}-${Date.now()}`;
|
|
2032
|
-
void grant({
|
|
2033
|
-
amount: amount.trim(),
|
|
2034
|
-
...note ? { description: note } : {},
|
|
2035
|
-
idempotencyKey: key
|
|
2036
|
-
}).then(() => {
|
|
2037
|
-
setGranted(`Granted ${amount.trim()} ${wallet.currency}.`);
|
|
2038
|
-
setAmount("");
|
|
2039
|
-
setNote("");
|
|
2040
|
-
}).catch(() => {
|
|
2041
|
-
});
|
|
2042
|
-
},
|
|
2043
|
-
children: [
|
|
2044
|
-
/* @__PURE__ */ jsx13(
|
|
2045
|
-
"input",
|
|
2046
|
-
{
|
|
2047
|
-
value: amount,
|
|
2048
|
-
onChange: (e) => setAmount(e.target.value),
|
|
2049
|
-
placeholder: "amount (minor units)",
|
|
2050
|
-
style: styles.input,
|
|
2051
|
-
"aria-label": "Amount"
|
|
2052
|
-
}
|
|
2053
|
-
),
|
|
2054
|
-
/* @__PURE__ */ jsx13(
|
|
2055
|
-
"input",
|
|
2056
|
-
{
|
|
2057
|
-
value: note,
|
|
2058
|
-
onChange: (e) => setNote(e.target.value),
|
|
2059
|
-
placeholder: "reason (optional)",
|
|
2060
|
-
style: { ...styles.input, minWidth: 220 },
|
|
2061
|
-
"aria-label": "Reason"
|
|
2062
|
-
}
|
|
2063
|
-
),
|
|
2064
|
-
/* @__PURE__ */ jsxs13(
|
|
2065
|
-
"button",
|
|
2066
|
-
{
|
|
2067
|
-
type: "submit",
|
|
2068
|
-
style: styles.buttonPrimary,
|
|
2069
|
-
disabled: !/^\d+$/.test(amount.trim()),
|
|
2070
|
-
children: [
|
|
2071
|
-
/* @__PURE__ */ jsx13(Icon, { name: "plus", size: 14 }),
|
|
2072
|
-
"Grant"
|
|
2073
|
-
]
|
|
2074
|
-
}
|
|
2075
|
-
),
|
|
2076
|
-
granted ? /* @__PURE__ */ jsx13("span", { style: styles.ok, children: granted }) : null
|
|
2077
|
-
]
|
|
2078
|
-
}
|
|
2079
|
-
),
|
|
2080
|
-
/* @__PURE__ */ jsx13("h2", { style: styles.subtitle, children: "Ledger" }),
|
|
2081
|
-
ledger.length === 0 ? /* @__PURE__ */ jsx13(Empty, { icon: "subscriber", title: "Nothing moved yet" }) : /* @__PURE__ */ jsxs13("table", { style: styles.table, children: [
|
|
2082
|
-
/* @__PURE__ */ jsx13("thead", { children: /* @__PURE__ */ jsxs13("tr", { children: [
|
|
2083
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "When" }),
|
|
2084
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Kind" }),
|
|
2085
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Amount" }),
|
|
2086
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Note" })
|
|
2087
|
-
] }) }),
|
|
2088
|
-
/* @__PURE__ */ jsx13("tbody", { children: ledger.map((t2) => /* @__PURE__ */ jsxs13("tr", { children: [
|
|
2089
|
-
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.muted }, children: new Date(t2.createdAt).toLocaleString() }),
|
|
2090
|
-
/* @__PURE__ */ jsx13("td", { style: styles.td, children: t2.type }),
|
|
2091
|
-
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.mono }, children: t2.amount }),
|
|
2092
|
-
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.muted }, children: t2.description ?? "" })
|
|
2093
|
-
] }, t2.id)) })
|
|
2094
|
-
] }),
|
|
2095
|
-
hasMoreLedger ? /* @__PURE__ */ jsx13(
|
|
2096
|
-
"button",
|
|
2097
|
-
{
|
|
2098
|
-
type: "button",
|
|
2099
|
-
style: { ...styles.button, marginTop: 8 },
|
|
2100
|
-
onClick: () => void loadMoreLedger(),
|
|
2101
|
-
children: "Load more"
|
|
2102
|
-
}
|
|
2103
|
-
) : null
|
|
2104
|
-
] }) : /* @__PURE__ */ jsx13("p", { style: styles.muted, children: "No wallet \u2014 billing has no wallet configuration." })
|
|
2105
|
-
] }) : null
|
|
2222
|
+
end.date
|
|
2223
|
+
] }) : /* @__PURE__ */ jsx14("span", { style: styles.muted, children: "\u2014" }) })
|
|
2224
|
+
] }, s.id);
|
|
2225
|
+
}) })
|
|
2226
|
+
] }),
|
|
2227
|
+
list.isLoading ? /* @__PURE__ */ jsx14("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
2228
|
+
list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx14(
|
|
2229
|
+
"button",
|
|
2230
|
+
{
|
|
2231
|
+
type: "button",
|
|
2232
|
+
style: { ...styles.button, marginTop: 8 },
|
|
2233
|
+
onClick: () => void list.loadMore(),
|
|
2234
|
+
children: "Load more"
|
|
2235
|
+
}
|
|
2236
|
+
) : null
|
|
2106
2237
|
] });
|
|
2107
2238
|
}
|
|
2108
2239
|
|
|
2109
2240
|
// src/screens/AuditScreen.tsx
|
|
2110
2241
|
import { useAdminAudit } from "@fonderie/react-admin";
|
|
2111
|
-
import { useState as
|
|
2112
|
-
import { jsx as
|
|
2242
|
+
import { useState as useState8 } from "react";
|
|
2243
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2113
2244
|
function AuditScreen({ client, pageSize = 50 }) {
|
|
2114
|
-
const [draft, setDraft] =
|
|
2115
|
-
const [filter, setFilter] =
|
|
2245
|
+
const [draft, setDraft] = useState8({ workspaceId: "", type: "", actorId: "" });
|
|
2246
|
+
const [filter, setFilter] = useState8(
|
|
2116
2247
|
{}
|
|
2117
2248
|
);
|
|
2118
2249
|
const { events, hasMore, isLoading, error, refresh, loadMore } = useAdminAudit(client, {
|
|
2119
2250
|
...filter,
|
|
2120
2251
|
limit: pageSize
|
|
2121
2252
|
});
|
|
2122
|
-
const field = (key, placeholder) => /* @__PURE__ */
|
|
2253
|
+
const field = (key, placeholder) => /* @__PURE__ */ jsx15(
|
|
2123
2254
|
"input",
|
|
2124
2255
|
{
|
|
2125
2256
|
value: draft[key],
|
|
@@ -2129,15 +2260,15 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
2129
2260
|
"aria-label": placeholder
|
|
2130
2261
|
}
|
|
2131
2262
|
);
|
|
2132
|
-
return /* @__PURE__ */
|
|
2133
|
-
/* @__PURE__ */
|
|
2263
|
+
return /* @__PURE__ */ jsxs15("div", { style: styles.container, children: [
|
|
2264
|
+
/* @__PURE__ */ jsx15(
|
|
2134
2265
|
PageHeader,
|
|
2135
2266
|
{
|
|
2136
2267
|
title: "Audit",
|
|
2137
2268
|
lead: "What happened, across every workspace unless you name one. The chain's integrity verdict is on the Doctor page."
|
|
2138
2269
|
}
|
|
2139
2270
|
),
|
|
2140
|
-
/* @__PURE__ */
|
|
2271
|
+
/* @__PURE__ */ jsxs15(
|
|
2141
2272
|
"form",
|
|
2142
2273
|
{
|
|
2143
2274
|
style: styles.toolbar,
|
|
@@ -2153,11 +2284,11 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
2153
2284
|
field("workspaceId", "workspace id (all if empty)"),
|
|
2154
2285
|
field("type", "event type"),
|
|
2155
2286
|
field("actorId", "actor id"),
|
|
2156
|
-
/* @__PURE__ */
|
|
2157
|
-
/* @__PURE__ */
|
|
2287
|
+
/* @__PURE__ */ jsxs15("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
2288
|
+
/* @__PURE__ */ jsx15(Icon, { name: "search", size: 14 }),
|
|
2158
2289
|
"Filter"
|
|
2159
2290
|
] }),
|
|
2160
|
-
/* @__PURE__ */
|
|
2291
|
+
/* @__PURE__ */ jsx15(
|
|
2161
2292
|
"button",
|
|
2162
2293
|
{
|
|
2163
2294
|
type: "button",
|
|
@@ -2170,25 +2301,25 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
2170
2301
|
]
|
|
2171
2302
|
}
|
|
2172
2303
|
),
|
|
2173
|
-
error ? /* @__PURE__ */
|
|
2174
|
-
events.length === 0 && !isLoading ? /* @__PURE__ */
|
|
2175
|
-
/* @__PURE__ */
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
/* @__PURE__ */
|
|
2179
|
-
/* @__PURE__ */
|
|
2180
|
-
/* @__PURE__ */
|
|
2304
|
+
error ? /* @__PURE__ */ jsx15("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
2305
|
+
events.length === 0 && !isLoading ? /* @__PURE__ */ jsx15(Empty, { icon: "audit", title: "Nothing recorded for this filter" }) : /* @__PURE__ */ jsxs15("table", { style: styles.table, children: [
|
|
2306
|
+
/* @__PURE__ */ jsx15("thead", { children: /* @__PURE__ */ jsxs15("tr", { children: [
|
|
2307
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "When" }),
|
|
2308
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "Type" }),
|
|
2309
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "Workspace" }),
|
|
2310
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "Actor" }),
|
|
2311
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "Request" })
|
|
2181
2312
|
] }) }),
|
|
2182
|
-
/* @__PURE__ */
|
|
2183
|
-
/* @__PURE__ */
|
|
2184
|
-
/* @__PURE__ */
|
|
2185
|
-
/* @__PURE__ */
|
|
2186
|
-
/* @__PURE__ */
|
|
2187
|
-
/* @__PURE__ */
|
|
2313
|
+
/* @__PURE__ */ jsx15("tbody", { children: events.map((e) => /* @__PURE__ */ jsxs15("tr", { children: [
|
|
2314
|
+
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
|
|
2315
|
+
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
|
|
2316
|
+
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
|
|
2317
|
+
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
|
|
2318
|
+
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
|
|
2188
2319
|
] }, e.id)) })
|
|
2189
2320
|
] }),
|
|
2190
|
-
isLoading ? /* @__PURE__ */
|
|
2191
|
-
hasMore && !isLoading ? /* @__PURE__ */
|
|
2321
|
+
isLoading ? /* @__PURE__ */ jsx15("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
2322
|
+
hasMore && !isLoading ? /* @__PURE__ */ jsx15(
|
|
2192
2323
|
"button",
|
|
2193
2324
|
{
|
|
2194
2325
|
type: "button",
|
|
@@ -2201,7 +2332,7 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
2201
2332
|
}
|
|
2202
2333
|
|
|
2203
2334
|
// src/screens/AdminShell.tsx
|
|
2204
|
-
import { Fragment as
|
|
2335
|
+
import { Fragment as Fragment10, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2205
2336
|
var ICON = {
|
|
2206
2337
|
attention: "attention",
|
|
2207
2338
|
modules: "modules",
|
|
@@ -2222,8 +2353,8 @@ var ICON = {
|
|
|
2222
2353
|
var NARROW = "(max-width: 820px)";
|
|
2223
2354
|
function useNarrow() {
|
|
2224
2355
|
const query = typeof window !== "undefined" && window.matchMedia ? window.matchMedia(NARROW) : null;
|
|
2225
|
-
const [narrow, setNarrow] =
|
|
2226
|
-
|
|
2356
|
+
const [narrow, setNarrow] = useState9(() => query?.matches ?? false);
|
|
2357
|
+
useEffect2(() => {
|
|
2227
2358
|
if (!query) return;
|
|
2228
2359
|
const on = (e) => setNarrow(e.matches);
|
|
2229
2360
|
query.addEventListener("change", on);
|
|
@@ -2247,7 +2378,7 @@ var NAV = [
|
|
|
2247
2378
|
group: "Money",
|
|
2248
2379
|
items: [
|
|
2249
2380
|
{ page: "catalog", label: "Catalog", needs: "billing" },
|
|
2250
|
-
{ page: "subscriber", label: "
|
|
2381
|
+
{ page: "subscriber", label: "Subscriptions", needs: "billing" }
|
|
2251
2382
|
]
|
|
2252
2383
|
},
|
|
2253
2384
|
{ group: "Settings", items: [{ page: "settings", label: "Config & secrets", needs: "config" }] },
|
|
@@ -2280,15 +2411,16 @@ function AdminShell({
|
|
|
2280
2411
|
currentOperator
|
|
2281
2412
|
}) {
|
|
2282
2413
|
const narrow = useNarrow();
|
|
2283
|
-
const [drawer, setDrawer] =
|
|
2284
|
-
const [own, setOwn] =
|
|
2414
|
+
const [drawer, setDrawer] = useState9(false);
|
|
2415
|
+
const [own, setOwn] = useState9("attention");
|
|
2416
|
+
const [openUser, setOpenUser] = useState9(void 0);
|
|
2285
2417
|
const current = page ?? own;
|
|
2286
2418
|
const go = (p) => {
|
|
2287
2419
|
if (onNavigate) onNavigate(p);
|
|
2288
2420
|
if (page === void 0) setOwn(p);
|
|
2289
2421
|
setDrawer(false);
|
|
2290
2422
|
};
|
|
2291
|
-
const [editing, setEditing] =
|
|
2423
|
+
const [editing, setEditing] = useState9(null);
|
|
2292
2424
|
const has = {
|
|
2293
2425
|
config: Boolean(configClient),
|
|
2294
2426
|
courier: Boolean(courierClient),
|
|
@@ -2300,51 +2432,70 @@ function AdminShell({
|
|
|
2300
2432
|
let body;
|
|
2301
2433
|
switch (current) {
|
|
2302
2434
|
case "attention":
|
|
2303
|
-
body = /* @__PURE__ */
|
|
2435
|
+
body = /* @__PURE__ */ jsx16(AttentionScreen, { client });
|
|
2304
2436
|
break;
|
|
2305
2437
|
case "modules":
|
|
2306
|
-
body = /* @__PURE__ */
|
|
2438
|
+
body = /* @__PURE__ */ jsx16(ModulesScreen, { client });
|
|
2307
2439
|
break;
|
|
2308
2440
|
case "doctor":
|
|
2309
|
-
body = /* @__PURE__ */
|
|
2441
|
+
body = /* @__PURE__ */ jsx16(DoctorScreen, { client });
|
|
2310
2442
|
break;
|
|
2311
2443
|
case "environment":
|
|
2312
|
-
body = /* @__PURE__ */
|
|
2444
|
+
body = /* @__PURE__ */ jsx16(EnvironmentScreen, { client });
|
|
2313
2445
|
break;
|
|
2314
2446
|
case "routes":
|
|
2315
|
-
body = /* @__PURE__ */
|
|
2447
|
+
body = /* @__PURE__ */ jsx16(RoutesScreen, { client });
|
|
2316
2448
|
break;
|
|
2317
2449
|
case "tokens":
|
|
2318
|
-
body = /* @__PURE__ */
|
|
2450
|
+
body = /* @__PURE__ */ jsx16(TokensScreen, { client });
|
|
2319
2451
|
break;
|
|
2320
2452
|
case "operators":
|
|
2321
|
-
body = /* @__PURE__ */
|
|
2453
|
+
body = /* @__PURE__ */ jsx16(OperatorsScreen, { client, me: currentOperator });
|
|
2322
2454
|
break;
|
|
2323
2455
|
case "migrations":
|
|
2324
|
-
body = /* @__PURE__ */
|
|
2456
|
+
body = /* @__PURE__ */ jsx16(MigrationsScreen, { client });
|
|
2325
2457
|
break;
|
|
2326
2458
|
case "log":
|
|
2327
|
-
body = /* @__PURE__ */
|
|
2459
|
+
body = /* @__PURE__ */ jsx16(AdminLogScreen, { client });
|
|
2328
2460
|
break;
|
|
2329
2461
|
case "catalog":
|
|
2330
|
-
body = billingClient ? /* @__PURE__ */
|
|
2462
|
+
body = billingClient ? /* @__PURE__ */ jsx16(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to see the catalog here." });
|
|
2331
2463
|
break;
|
|
2332
2464
|
case "subscriber":
|
|
2333
|
-
body = billingClient ? /* @__PURE__ */
|
|
2465
|
+
body = billingClient ? /* @__PURE__ */ jsx16(
|
|
2466
|
+
SubscriberScreen,
|
|
2467
|
+
{
|
|
2468
|
+
client: billingClient,
|
|
2469
|
+
...authClient ? {
|
|
2470
|
+
onOpenUser: (id) => {
|
|
2471
|
+
setOpenUser(id);
|
|
2472
|
+
go("users");
|
|
2473
|
+
}
|
|
2474
|
+
} : {}
|
|
2475
|
+
}
|
|
2476
|
+
) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to look up subscribers here." });
|
|
2334
2477
|
break;
|
|
2335
2478
|
case "audit":
|
|
2336
|
-
body = auditClient ? /* @__PURE__ */
|
|
2479
|
+
body = auditClient ? /* @__PURE__ */ jsx16(AuditScreen, { client: auditClient }) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuditAdminClient to see the audit trail here." });
|
|
2337
2480
|
break;
|
|
2338
2481
|
case "users":
|
|
2339
|
-
body = authClient ? /* @__PURE__ */
|
|
2482
|
+
body = authClient ? /* @__PURE__ */ jsx16(
|
|
2483
|
+
UsersScreen,
|
|
2484
|
+
{
|
|
2485
|
+
client: authClient,
|
|
2486
|
+
billingClient,
|
|
2487
|
+
openUserId: openUser
|
|
2488
|
+
},
|
|
2489
|
+
openUser ?? "list"
|
|
2490
|
+
) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuthAdminClient to look up users here." });
|
|
2340
2491
|
break;
|
|
2341
2492
|
case "settings":
|
|
2342
|
-
body = !configClient ? /* @__PURE__ */
|
|
2343
|
-
/* @__PURE__ */
|
|
2344
|
-
/* @__PURE__ */
|
|
2493
|
+
body = !configClient ? /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
2494
|
+
/* @__PURE__ */ jsx16("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ jsxs16("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
|
|
2495
|
+
/* @__PURE__ */ jsx16(Icon, { name: "back", size: 14 }),
|
|
2345
2496
|
"Config & secrets"
|
|
2346
2497
|
] }) }),
|
|
2347
|
-
/* @__PURE__ */
|
|
2498
|
+
/* @__PURE__ */ jsx16(
|
|
2348
2499
|
ConfigEditorScreen,
|
|
2349
2500
|
{
|
|
2350
2501
|
client: configClient,
|
|
@@ -2354,7 +2505,7 @@ function AdminShell({
|
|
|
2354
2505
|
onSaved: () => setEditing(null)
|
|
2355
2506
|
}
|
|
2356
2507
|
)
|
|
2357
|
-
] }) : /* @__PURE__ */
|
|
2508
|
+
] }) : /* @__PURE__ */ jsx16(
|
|
2358
2509
|
ConfigListScreen,
|
|
2359
2510
|
{
|
|
2360
2511
|
client: configClient,
|
|
@@ -2367,12 +2518,12 @@ function AdminShell({
|
|
|
2367
2518
|
);
|
|
2368
2519
|
break;
|
|
2369
2520
|
case "templates":
|
|
2370
|
-
body = !courierClient ? /* @__PURE__ */
|
|
2371
|
-
/* @__PURE__ */
|
|
2372
|
-
/* @__PURE__ */
|
|
2521
|
+
body = !courierClient ? /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
2522
|
+
/* @__PURE__ */ jsx16("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ jsxs16("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
|
|
2523
|
+
/* @__PURE__ */ jsx16(Icon, { name: "back", size: 14 }),
|
|
2373
2524
|
"Templates"
|
|
2374
2525
|
] }) }),
|
|
2375
|
-
/* @__PURE__ */
|
|
2526
|
+
/* @__PURE__ */ jsx16(
|
|
2376
2527
|
TemplateEditorScreen,
|
|
2377
2528
|
{
|
|
2378
2529
|
client: courierClient,
|
|
@@ -2380,7 +2531,7 @@ function AdminShell({
|
|
|
2380
2531
|
onSaved: () => setEditing(null)
|
|
2381
2532
|
}
|
|
2382
2533
|
)
|
|
2383
|
-
] }) : /* @__PURE__ */
|
|
2534
|
+
] }) : /* @__PURE__ */ jsx16(
|
|
2384
2535
|
TemplateListScreen,
|
|
2385
2536
|
{
|
|
2386
2537
|
client: courierClient,
|
|
@@ -2390,11 +2541,11 @@ function AdminShell({
|
|
|
2390
2541
|
break;
|
|
2391
2542
|
}
|
|
2392
2543
|
const production = envLabel ? /^prod/i.test(envLabel) : false;
|
|
2393
|
-
const brand = /* @__PURE__ */
|
|
2394
|
-
/* @__PURE__ */
|
|
2395
|
-
/* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
2397
|
-
envLabel ? /* @__PURE__ */
|
|
2544
|
+
const brand = /* @__PURE__ */ jsxs16("div", { style: styles.navBrand, children: [
|
|
2545
|
+
/* @__PURE__ */ jsx16("div", { style: styles.navMark, children: /* @__PURE__ */ jsx16(Icon, { name: "mark", size: 15 }) }),
|
|
2546
|
+
/* @__PURE__ */ jsxs16("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
2547
|
+
/* @__PURE__ */ jsx16("div", { style: styles.navBrandTitle, children: appName }),
|
|
2548
|
+
envLabel ? /* @__PURE__ */ jsx16(
|
|
2398
2549
|
"span",
|
|
2399
2550
|
{
|
|
2400
2551
|
style: {
|
|
@@ -2411,18 +2562,18 @@ function AdminShell({
|
|
|
2411
2562
|
}
|
|
2412
2563
|
) : null
|
|
2413
2564
|
] }),
|
|
2414
|
-
narrow ? /* @__PURE__ */
|
|
2565
|
+
narrow ? /* @__PURE__ */ jsx16(
|
|
2415
2566
|
"button",
|
|
2416
2567
|
{
|
|
2417
2568
|
type: "button",
|
|
2418
2569
|
style: styles.buttonGhost,
|
|
2419
2570
|
"aria-label": "Close menu",
|
|
2420
2571
|
onClick: () => setDrawer(false),
|
|
2421
|
-
children: /* @__PURE__ */
|
|
2572
|
+
children: /* @__PURE__ */ jsx16(Icon, { name: "close" })
|
|
2422
2573
|
}
|
|
2423
2574
|
) : null
|
|
2424
2575
|
] });
|
|
2425
|
-
const nav = /* @__PURE__ */
|
|
2576
|
+
const nav = /* @__PURE__ */ jsxs16(
|
|
2426
2577
|
"nav",
|
|
2427
2578
|
{
|
|
2428
2579
|
style: {
|
|
@@ -2432,14 +2583,14 @@ function AdminShell({
|
|
|
2432
2583
|
"aria-label": "Admin",
|
|
2433
2584
|
children: [
|
|
2434
2585
|
brand,
|
|
2435
|
-
/* @__PURE__ */
|
|
2586
|
+
/* @__PURE__ */ jsx16("div", { style: styles.navScroll, children: NAV.map((g) => {
|
|
2436
2587
|
const items = g.items.filter((i) => !i.needs || has[i.needs]);
|
|
2437
2588
|
if (items.length === 0) return null;
|
|
2438
|
-
return /* @__PURE__ */
|
|
2439
|
-
/* @__PURE__ */
|
|
2589
|
+
return /* @__PURE__ */ jsxs16("div", { children: [
|
|
2590
|
+
/* @__PURE__ */ jsx16("div", { style: styles.navGroup, children: g.group }),
|
|
2440
2591
|
items.map((i) => {
|
|
2441
2592
|
const active = current === i.page;
|
|
2442
|
-
return /* @__PURE__ */
|
|
2593
|
+
return /* @__PURE__ */ jsxs16(
|
|
2443
2594
|
"button",
|
|
2444
2595
|
{
|
|
2445
2596
|
type: "button",
|
|
@@ -2448,10 +2599,11 @@ function AdminShell({
|
|
|
2448
2599
|
"aria-current": active ? "page" : void 0,
|
|
2449
2600
|
onClick: () => {
|
|
2450
2601
|
setEditing(null);
|
|
2602
|
+
setOpenUser(void 0);
|
|
2451
2603
|
go(i.page);
|
|
2452
2604
|
},
|
|
2453
2605
|
children: [
|
|
2454
|
-
/* @__PURE__ */
|
|
2606
|
+
/* @__PURE__ */ jsx16(Icon, { name: ICON[i.page], style: active ? styles.navIconActive : void 0 }),
|
|
2455
2607
|
i.label
|
|
2456
2608
|
]
|
|
2457
2609
|
},
|
|
@@ -2460,15 +2612,15 @@ function AdminShell({
|
|
|
2460
2612
|
})
|
|
2461
2613
|
] }, g.group);
|
|
2462
2614
|
}) }),
|
|
2463
|
-
footer ? /* @__PURE__ */
|
|
2615
|
+
footer ? /* @__PURE__ */ jsx16("div", { style: styles.navFooter, children: footer }) : null
|
|
2464
2616
|
]
|
|
2465
2617
|
}
|
|
2466
2618
|
);
|
|
2467
2619
|
const title = NAV.flatMap((g) => g.items).find((i) => i.page === current)?.label ?? "";
|
|
2468
|
-
return /* @__PURE__ */
|
|
2469
|
-
narrow ? /* @__PURE__ */
|
|
2470
|
-
/* @__PURE__ */
|
|
2471
|
-
/* @__PURE__ */
|
|
2620
|
+
return /* @__PURE__ */ jsxs16("div", { style: { ...styles.shell, ...narrow ? { flexDirection: "column" } : {} }, children: [
|
|
2621
|
+
narrow ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
2622
|
+
/* @__PURE__ */ jsxs16("div", { style: styles.topbar, children: [
|
|
2623
|
+
/* @__PURE__ */ jsx16(
|
|
2472
2624
|
"button",
|
|
2473
2625
|
{
|
|
2474
2626
|
type: "button",
|
|
@@ -2476,18 +2628,18 @@ function AdminShell({
|
|
|
2476
2628
|
"aria-label": "Open menu",
|
|
2477
2629
|
"aria-expanded": drawer,
|
|
2478
2630
|
onClick: () => setDrawer(true),
|
|
2479
|
-
children: /* @__PURE__ */
|
|
2631
|
+
children: /* @__PURE__ */ jsx16(Icon, { name: "menu" })
|
|
2480
2632
|
}
|
|
2481
2633
|
),
|
|
2482
|
-
/* @__PURE__ */
|
|
2483
|
-
envLabel ? /* @__PURE__ */
|
|
2634
|
+
/* @__PURE__ */ jsx16("span", { style: { fontWeight: 600, fontSize: 14 }, children: title }),
|
|
2635
|
+
envLabel ? /* @__PURE__ */ jsx16("span", { style: { ...styles.badge, marginLeft: "auto" }, children: envLabel }) : null
|
|
2484
2636
|
] }),
|
|
2485
|
-
drawer ? /* @__PURE__ */
|
|
2637
|
+
drawer ? /* @__PURE__ */ jsxs16("div", { style: styles.drawer, children: [
|
|
2486
2638
|
nav,
|
|
2487
|
-
/* @__PURE__ */
|
|
2639
|
+
/* @__PURE__ */ jsx16("div", { style: styles.scrim, onClick: () => setDrawer(false), "aria-hidden": "true" })
|
|
2488
2640
|
] }) : null
|
|
2489
2641
|
] }) : nav,
|
|
2490
|
-
/* @__PURE__ */
|
|
2642
|
+
/* @__PURE__ */ jsx16("main", { className: "fonderie-admin-main", style: styles.main, children: body })
|
|
2491
2643
|
] });
|
|
2492
2644
|
}
|
|
2493
2645
|
export {
|
|
@@ -2502,6 +2654,7 @@ export {
|
|
|
2502
2654
|
ModulesScreen,
|
|
2503
2655
|
OperatorsScreen,
|
|
2504
2656
|
RoutesScreen,
|
|
2657
|
+
SubscriberBilling,
|
|
2505
2658
|
SubscriberScreen,
|
|
2506
2659
|
TokensScreen,
|
|
2507
2660
|
UsersScreen
|