@withpotter/pages-admin 0.13.0-next.124 → 0.13.0-next.58
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/admin/_money/cash-postings.js +3 -20
- package/dist/admin/_money/cash-postings.js.map +1 -1
- package/dist/admin/_money/cash.module.css +0 -10
- package/dist/admin/_money/finder-format.js +0 -1
- package/dist/admin/_money/finder-format.js.map +1 -1
- package/dist/admin/_money/format.js +0 -1
- package/dist/admin/_money/format.js.map +1 -1
- package/dist/admin/_overview/activation-panel.js +6 -6
- package/dist/admin/_overview/activation-panel.js.map +1 -1
- package/dist/admin/_overview/attention-groups.js +8 -8
- package/dist/admin/_overview/attention-groups.js.map +1 -1
- package/dist/admin/_overview/attention-panel.js +33 -37
- package/dist/admin/_overview/attention-panel.js.map +1 -1
- package/dist/admin/_overview/attention.module.css +3 -0
- package/dist/admin/_overview/control-room.js +13 -41
- package/dist/admin/_overview/control-room.js.map +1 -1
- package/dist/admin/_overview/kpi-row.js +7 -7
- package/dist/admin/_overview/kpi-row.js.map +1 -1
- package/dist/admin/_overview/leaders-panel.js +1 -1
- package/dist/admin/_overview/leaders-panel.js.map +1 -1
- package/dist/admin/_overview/overdue-outstanding.js +1 -2
- package/dist/admin/_overview/overdue-outstanding.js.map +1 -1
- package/dist/admin/_overview/portfolio-panel.js +5 -5
- package/dist/admin/_overview/portfolio-panel.js.map +1 -1
- package/dist/admin/_overview/position-panel.js +12 -8
- package/dist/admin/_overview/position-panel.js.map +1 -1
- package/dist/admin/_pos/pos-figures.js +5 -18
- package/dist/admin/_pos/pos-figures.js.map +1 -1
- package/dist/admin/_pos/pos-rules.js +0 -2
- package/dist/admin/_pos/pos-rules.js.map +1 -1
- package/dist/admin/_pos/pos-words.js +1 -6
- package/dist/admin/_pos/pos-words.js.map +1 -1
- package/dist/admin/_pos/use-pos.js +1 -70
- package/dist/admin/_pos/use-pos.js.map +1 -1
- package/dist/admin/_shell/nav-config.js +3 -3
- package/dist/admin/_shell/nav-config.js.map +1 -1
- package/dist/admin/_shell/nav-filter.js +2 -4
- package/dist/admin/_shell/nav-filter.js.map +1 -1
- package/dist/admin/_shell/nav-row.js +2 -5
- package/dist/admin/_shell/nav-row.js.map +1 -1
- package/dist/admin/_shell/sidebar-footer.js +0 -20
- package/dist/admin/_shell/sidebar-footer.js.map +1 -1
- package/dist/admin/_shell/sidebar-footer.module.css +0 -17
- package/dist/admin/_shell/sidebar.js +15 -25
- package/dist/admin/_shell/sidebar.js.map +1 -1
- package/dist/admin/_shell/sidebar.module.css +0 -69
- package/dist/admin/_shell/use-fluid-hover.js +6 -37
- package/dist/admin/_shell/use-fluid-hover.js.map +1 -1
- package/dist/admin/_ui/admin.css +0 -7
- package/dist/admin/_ui/data-table.js +1 -1
- package/dist/admin/_ui/data-table.js.map +1 -1
- package/dist/admin/_ui/list-card.js +1 -1
- package/dist/admin/_ui/list-card.js.map +1 -1
- package/dist/admin/_ui/list-card.module.css +16 -2
- package/dist/admin/_ui/money-view.js +0 -1
- package/dist/admin/_ui/money-view.js.map +1 -1
- package/dist/admin/_ui/page-header.js +4 -31
- package/dist/admin/_ui/page-header.js.map +1 -1
- package/dist/admin/_ui/panel.module.css +10 -0
- package/dist/admin/_ui/stat-card.js +2 -11
- package/dist/admin/_ui/stat-card.js.map +1 -1
- package/dist/admin/_ui/trend.js +2 -2
- package/dist/admin/_ui/trend.js.map +1 -1
- package/dist/admin/_ui/workspace-tab.js +1 -11
- package/dist/admin/_ui/workspace-tab.js.map +1 -1
- package/dist/admin/accounts/account-panel.js +6 -49
- package/dist/admin/accounts/account-panel.js.map +1 -1
- package/dist/admin/accounts/account-panel.module.css +0 -73
- package/dist/admin/accounts/account-row.js +2 -11
- package/dist/admin/accounts/account-row.js.map +1 -1
- package/dist/admin/accounts/account-vitals.js +13 -15
- package/dist/admin/accounts/account-vitals.js.map +1 -1
- package/dist/admin/accounts/accounts-table.js +8 -39
- package/dist/admin/accounts/accounts-table.js.map +1 -1
- package/dist/admin/accounts/accounts-workspace.js +2 -2
- package/dist/admin/accounts/accounts-workspace.js.map +1 -1
- package/dist/admin/accounts/owner-session.js +6 -0
- package/dist/admin/accounts/owner-session.js.map +1 -1
- package/dist/admin/accounts/rows.module.css +0 -17
- package/dist/admin/audit/status-pill.js +0 -6
- package/dist/admin/audit/status-pill.js.map +1 -1
- package/dist/admin/audit/status-pill.module.css +0 -4
- package/dist/admin/commerce/commerce-overview.js +2 -2
- package/dist/admin/commerce/commerce-overview.js.map +1 -1
- package/dist/admin/commerce/merchant-meta.js +0 -1
- package/dist/admin/commerce/merchant-meta.js.map +1 -1
- package/dist/admin/commerce/merchant-view.js +2 -2
- package/dist/admin/commerce/merchant-view.js.map +1 -1
- package/dist/admin/feedback/prompt-operations.module.css +2 -0
- package/dist/admin/feedback/prompt-preview.module.css +2 -0
- package/dist/admin/hooks.js +1 -57
- package/dist/admin/hooks.js.map +1 -1
- package/dist/admin/layout.js +2 -8
- package/dist/admin/layout.js.map +1 -1
- package/dist/admin/page.js +8 -28
- package/dist/admin/page.js.map +1 -1
- package/dist/admin/payout-tiers/_tier-dialog.js +21 -31
- package/dist/admin/payout-tiers/_tier-dialog.js.map +1 -1
- package/dist/admin/payout-tiers/tier-preview-result.js +9 -10
- package/dist/admin/payout-tiers/tier-preview-result.js.map +1 -1
- package/dist/admin/payout-tiers/tiers-table.js +17 -40
- package/dist/admin/payout-tiers/tiers-table.js.map +1 -1
- package/dist/admin/payout-tiers/tiers-workspace.js +17 -20
- package/dist/admin/payout-tiers/tiers-workspace.js.map +1 -1
- package/dist/admin/pos/pos-workspace.js +2 -6
- package/dist/admin/pos/pos-workspace.js.map +1 -1
- package/dist/admin/pos/shifts-tab.js +9 -16
- package/dist/admin/pos/shifts-tab.js.map +1 -1
- package/dist/admin/revenue/cohort-panel.js +6 -6
- package/dist/admin/revenue/cohort-panel.js.map +1 -1
- package/dist/admin/revenue/health-panel.js +21 -22
- package/dist/admin/revenue/health-panel.js.map +1 -1
- package/dist/admin/revenue/plan-mix-panel.js +3 -3
- package/dist/admin/revenue/plan-mix-panel.js.map +1 -1
- package/dist/admin/revenue/quality-panel.js +19 -19
- package/dist/admin/revenue/quality-panel.js.map +1 -1
- package/dist/admin/revenue/revenue-kpis.js +50 -111
- package/dist/admin/revenue/revenue-kpis.js.map +1 -1
- package/dist/admin/revenue/revenue-overview.js +46 -39
- package/dist/admin/revenue/revenue-overview.js.map +1 -1
- package/dist/admin/revenue/revenue-retention.js +13 -17
- package/dist/admin/revenue/revenue-retention.js.map +1 -1
- package/dist/admin/revenue/revenue-workspace.js +6 -53
- package/dist/admin/revenue/revenue-workspace.js.map +1 -1
- package/dist/admin/revenue/subscriptions-panel.js +14 -14
- package/dist/admin/revenue/subscriptions-panel.js.map +1 -1
- package/dist/admin/revenue/top-tenants-panel.js +4 -4
- package/dist/admin/revenue/top-tenants-panel.js.map +1 -1
- package/dist/admin/settings/account-tab.js +25 -1
- package/dist/admin/settings/account-tab.js.map +1 -1
- package/dist/admin/settings/general-tab.js +2 -2
- package/dist/admin/settings/general-tab.js.map +1 -1
- package/dist/admin/settings/system-status-card.js +30 -0
- package/dist/admin/settings/system-status-card.js.map +1 -0
- package/dist/admin/support/queue-card.module.css +4 -1
- package/dist/admin/tenants/[id]/commerce/format.js +1 -2
- package/dist/admin/tenants/[id]/commerce/format.js.map +1 -1
- package/dist/admin/tenants/[id]/commerce/recent-orders.js +1 -1
- package/dist/admin/tenants/[id]/commerce/recent-orders.js.map +1 -1
- package/dist/admin/tenants/[id]/page.js +10 -37
- package/dist/admin/tenants/[id]/page.js.map +1 -1
- package/dist/admin/tenants/[id]/tenant-layout.module.css +4 -1
- package/dist/admin/tenants/[id]/tenant-overview.js +2 -3
- package/dist/admin/tenants/[id]/tenant-overview.js.map +1 -1
- package/dist/admin/tenants/[id]/tenant-overview.module.css +1 -1
- package/dist/admin/tenants/[id]/tenant-pos.js +16 -64
- package/dist/admin/tenants/[id]/tenant-pos.js.map +1 -1
- package/dist/admin/tenants/[id]/tenant-wallet-card.js +2 -3
- package/dist/admin/tenants/[id]/tenant-wallet-card.js.map +1 -1
- package/dist/admin/tenants/[id]/verification/document-viewer.js +52 -3
- package/dist/admin/tenants/[id]/verification/document-viewer.js.map +1 -1
- package/dist/admin/tenants/[id]/verification/document-viewer.module.css +0 -51
- package/dist/admin/tenants/[id]/verification/tenant-verification.js +0 -10
- package/dist/admin/tenants/[id]/verification/tenant-verification.js.map +1 -1
- package/dist/admin/tenants/tenant-list-row.js +1 -2
- package/dist/admin/tenants/tenant-list-row.js.map +1 -1
- package/dist/admin/tenants/tenants-table.js +2 -3
- package/dist/admin/tenants/tenants-table.js.map +1 -1
- package/dist/admin/tenants/tenants-workspace.js +2 -2
- package/dist/admin/tenants/tenants-workspace.js.map +1 -1
- package/dist/admin/verification/verification-page.js +3 -19
- package/dist/admin/verification/verification-page.js.map +1 -1
- package/dist/admin/verification/verification.module.css +0 -10
- package/dist/admin/verification/waiting-case-actions.js +68 -0
- package/dist/admin/verification/waiting-case-actions.js.map +1 -0
- package/dist/admin/verification/waiting-cases.js +48 -66
- package/dist/admin/verification/waiting-cases.js.map +1 -1
- package/package.json +5 -5
- package/dist/admin/_pos/olive-balance.js +0 -40
- package/dist/admin/_pos/olive-balance.js.map +0 -1
- package/dist/admin/_pos/olive-state.js +0 -23
- package/dist/admin/_pos/olive-state.js.map +0 -1
- package/dist/admin/_pos/payments-model.js +0 -55
- package/dist/admin/_pos/payments-model.js.map +0 -1
- package/dist/admin/_pos/tenant-operators.js +0 -63
- package/dist/admin/_pos/tenant-operators.js.map +0 -1
- package/dist/admin/_pos/tenant-outlets.js +0 -77
- package/dist/admin/_pos/tenant-outlets.js.map +0 -1
- package/dist/admin/_pos/tenant-pos-figures.js +0 -82
- package/dist/admin/_pos/tenant-pos-figures.js.map +0 -1
- package/dist/admin/_pos/tenant-requests.js +0 -64
- package/dist/admin/_pos/tenant-requests.js.map +0 -1
- package/dist/admin/_pos/tenant-transactions.js +0 -145
- package/dist/admin/_pos/tenant-transactions.js.map +0 -1
- package/dist/admin/_shell/nav-fold.js +0 -14
- package/dist/admin/_shell/nav-fold.js.map +0 -1
- package/dist/admin/_shell/nav-group.js +0 -78
- package/dist/admin/_shell/nav-group.js.map +0 -1
- package/dist/admin/_shell/use-open-groups.js +0 -64
- package/dist/admin/_shell/use-open-groups.js.map +0 -1
- package/dist/admin/_ui/page-header.module.css +0 -45
- package/dist/admin/accounts/account-sessions.js +0 -70
- package/dist/admin/accounts/account-sessions.js.map +0 -1
- package/dist/admin/accounts/account-sessions.module.css +0 -55
- package/dist/admin/accounts/account-stage-filter.js +0 -29
- package/dist/admin/accounts/account-stage-filter.js.map +0 -1
- package/dist/admin/accounts/account-stage.js +0 -81
- package/dist/admin/accounts/account-stage.js.map +0 -1
- package/dist/admin/accounts/hint.js +0 -12
- package/dist/admin/accounts/hint.js.map +0 -1
- package/dist/admin/payout-tiers/requirement-labels.js +0 -70
- package/dist/admin/payout-tiers/requirement-labels.js.map +0 -1
- package/dist/admin/pos/transactions-tab.js +0 -214
- package/dist/admin/pos/transactions-tab.js.map +0 -1
- package/dist/admin/revenue/channel-panel.js +0 -49
- package/dist/admin/revenue/channel-panel.js.map +0 -1
- package/dist/admin/revenue/channel-rows.js +0 -17
- package/dist/admin/revenue/channel-rows.js.map +0 -1
- package/dist/admin/revenue/download-button.js +0 -40
- package/dist/admin/revenue/download-button.js.map +0 -1
- package/dist/admin/revenue/earnings/earnings-colors.js +0 -25
- package/dist/admin/revenue/earnings/earnings-colors.js.map +0 -1
- package/dist/admin/revenue/earnings/earnings-legend.js +0 -75
- package/dist/admin/revenue/earnings/earnings-legend.js.map +0 -1
- package/dist/admin/revenue/earnings/earnings-summary.js +0 -308
- package/dist/admin/revenue/earnings/earnings-summary.js.map +0 -1
- package/dist/admin/revenue/earnings/earnings-table.js +0 -143
- package/dist/admin/revenue/earnings/earnings-table.js.map +0 -1
- package/dist/admin/revenue/earnings/earnings.module.css +0 -201
- package/dist/admin/revenue/earnings/use-earnings.js +0 -27
- package/dist/admin/revenue/earnings/use-earnings.js.map +0 -1
- package/dist/admin/revenue/ledger-model.js +0 -104
- package/dist/admin/revenue/ledger-model.js.map +0 -1
- package/dist/admin/revenue/ledger.module.css +0 -144
- package/dist/admin/revenue/merchant-headline.js +0 -37
- package/dist/admin/revenue/merchant-headline.js.map +0 -1
- package/dist/admin/revenue/merchant-payments-view.js +0 -234
- package/dist/admin/revenue/merchant-payments-view.js.map +0 -1
- package/dist/admin/revenue/method-cards.js +0 -40
- package/dist/admin/revenue/method-cards.js.map +0 -1
- package/dist/admin/revenue/payment-drawer.js +0 -53
- package/dist/admin/revenue/payment-drawer.js.map +0 -1
- package/dist/admin/revenue/plan-lines.js +0 -36
- package/dist/admin/revenue/plan-lines.js.map +0 -1
- package/dist/admin/revenue/plan-payment-drawer.js +0 -42
- package/dist/admin/revenue/plan-payment-drawer.js.map +0 -1
- package/dist/admin/revenue/plans-panel.js +0 -48
- package/dist/admin/revenue/plans-panel.js.map +0 -1
- package/dist/admin/revenue/platform-fees.js +0 -9
- package/dist/admin/revenue/platform-fees.js.map +0 -1
- package/dist/admin/revenue/print-summary-button.js +0 -27
- package/dist/admin/revenue/print-summary-button.js.map +0 -1
- package/dist/admin/revenue/subscriptions-view.js +0 -213
- package/dist/admin/revenue/subscriptions-view.js.map +0 -1
- package/dist/admin/revenue/summary-download.js +0 -38
- package/dist/admin/revenue/summary-download.js.map +0 -1
- package/dist/admin/revenue/summary-print.js +0 -82
- package/dist/admin/revenue/summary-print.js.map +0 -1
- package/dist/admin/revenue/summary-rows.js +0 -44
- package/dist/admin/revenue/summary-rows.js.map +0 -1
- package/dist/admin/revenue/url-filters.js +0 -36
- package/dist/admin/revenue/url-filters.js.map +0 -1
- package/dist/admin/revenue/use-url-filters.js +0 -24
- package/dist/admin/revenue/use-url-filters.js.map +0 -1
- package/dist/admin/tenants/[id]/use-tenant-wallet.js +0 -23
- package/dist/admin/tenants/[id]/use-tenant-wallet.js.map +0 -1
- package/dist/admin/tenants/[id]/verification/document-file.js +0 -78
- package/dist/admin/tenants/[id]/verification/document-file.js.map +0 -1
- package/dist/admin/tenants/[id]/verification/sent-files.js +0 -33
- package/dist/admin/tenants/[id]/verification/sent-files.js.map +0 -1
- package/dist/admin/verification/preview-dialog.js +0 -111
- package/dist/admin/verification/preview-dialog.js.map +0 -1
|
@@ -3,9 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { Button, OverflowItem, OverflowMenu, Th } from "@withpotter/ui-kit";
|
|
5
5
|
import { toCsv } from "@withpotter/lib/csv";
|
|
6
|
-
import {
|
|
7
|
-
platformAdminApi
|
|
8
|
-
} from "@withpotter/lib/admin-api";
|
|
6
|
+
import { platformAdminApi } from "@withpotter/lib/admin-api";
|
|
9
7
|
import {
|
|
10
8
|
ColumnPicker,
|
|
11
9
|
FilterDates,
|
|
@@ -15,27 +13,20 @@ import {
|
|
|
15
13
|
import { usePlatformAccounts } from "../hooks";
|
|
16
14
|
import { AccountPanel } from "./account-panel";
|
|
17
15
|
import { ListCard, ListPager } from "../_ui/list-card";
|
|
18
|
-
import { ACTIVE_HINT, kycLabel, STAGE_LABELS } from "./account-stage";
|
|
19
|
-
import { AccountStageFilter } from "./account-stage-filter";
|
|
20
|
-
import { Hint } from "./hint";
|
|
21
16
|
import { AccountListRow, PROVIDER_LABELS } from "./account-row";
|
|
22
17
|
import { PROVIDER_LABELS as PROVIDER_LABELS2 } from "./account-row";
|
|
23
18
|
const OPTIONAL_COLUMNS = [
|
|
24
19
|
{ key: "provider", label: "Provider" },
|
|
25
|
-
{ key: "kyc", label: "KYC / KYB" },
|
|
26
|
-
{ key: "stage", label: "Stage" },
|
|
27
20
|
{ key: "emailVerified", label: "Email verified" },
|
|
28
21
|
{ key: "workspaces", label: "Workspaces" },
|
|
29
22
|
{ key: "lastLogin", label: "Last login" },
|
|
30
23
|
{ key: "joined", label: "Joined" },
|
|
31
|
-
{ key: "
|
|
24
|
+
{ key: "mfa", label: "MFA enabled" },
|
|
32
25
|
{ key: "activeSessions", label: "Active sessions" },
|
|
33
26
|
{ key: "lastSeen", label: "Last seen" }
|
|
34
27
|
];
|
|
35
28
|
const DEFAULT_VISIBLE = [
|
|
36
29
|
"provider",
|
|
37
|
-
"kyc",
|
|
38
|
-
"stage",
|
|
39
30
|
"emailVerified",
|
|
40
31
|
"workspaces",
|
|
41
32
|
"lastLogin",
|
|
@@ -64,15 +55,13 @@ function toCsvRow(a, visible) {
|
|
|
64
55
|
cells.push(PROVIDER_LABELS[a.authProvider] ?? a.authProvider);
|
|
65
56
|
}
|
|
66
57
|
cells.push(a.status);
|
|
67
|
-
if (visible.has("kyc")) cells.push(kycLabel(a.kycStatus) ?? "");
|
|
68
|
-
if (visible.has("stage")) cells.push(a.stage ? STAGE_LABELS[a.stage] : "");
|
|
69
58
|
if (visible.has("emailVerified")) {
|
|
70
59
|
cells.push(a.emailVerified ? "Verified" : "Unverified");
|
|
71
60
|
}
|
|
72
61
|
if (visible.has("workspaces")) cells.push(String(a.workspaceCount ?? 0));
|
|
73
62
|
if (visible.has("lastLogin")) cells.push(day(a.lastLoginAt) || "Never");
|
|
74
63
|
if (visible.has("joined")) cells.push(day(a.createdAt));
|
|
75
|
-
if (visible.has("
|
|
64
|
+
if (visible.has("mfa")) cells.push(a.mfaEnabled ? "Yes" : "No");
|
|
76
65
|
if (visible.has("activeSessions")) cells.push(String(a.activeSessions ?? 0));
|
|
77
66
|
if (visible.has("lastSeen")) cells.push(day(a.lastSeenAt) || "Never");
|
|
78
67
|
return cells;
|
|
@@ -84,7 +73,6 @@ function AccountsTable({
|
|
|
84
73
|
const [search, setSearch] = useState("");
|
|
85
74
|
const [joinedFrom, setJoinedFrom] = useState("");
|
|
86
75
|
const [joinedTo, setJoinedTo] = useState("");
|
|
87
|
-
const [stage, setStage] = useState("");
|
|
88
76
|
const [page, setPage] = useState(1);
|
|
89
77
|
const [visible, setVisible] = useState(readVisibleColumns);
|
|
90
78
|
const [exporting, setExporting] = useState(false);
|
|
@@ -93,8 +81,7 @@ function AccountsTable({
|
|
|
93
81
|
pageSize: 20,
|
|
94
82
|
search: search || void 0,
|
|
95
83
|
joinedFrom: joinedFrom || void 0,
|
|
96
|
-
joinedTo: joinedTo || void 0
|
|
97
|
-
stage: stage || void 0
|
|
84
|
+
joinedTo: joinedTo || void 0
|
|
98
85
|
});
|
|
99
86
|
const current = data?.rows.find((row) => row.id === selected?.id) ?? selected;
|
|
100
87
|
const totalPages = data ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1;
|
|
@@ -113,19 +100,16 @@ function AccountsTable({
|
|
|
113
100
|
pageSize: 5e3,
|
|
114
101
|
search: search || void 0,
|
|
115
102
|
joinedFrom: joinedFrom || void 0,
|
|
116
|
-
joinedTo: joinedTo || void 0
|
|
117
|
-
stage: stage || void 0
|
|
103
|
+
joinedTo: joinedTo || void 0
|
|
118
104
|
});
|
|
119
105
|
const header = ["Name", "Email"];
|
|
120
106
|
if (visible.has("provider")) header.push("Provider");
|
|
121
107
|
header.push("Status");
|
|
122
|
-
if (visible.has("kyc")) header.push("KYC / KYB");
|
|
123
|
-
if (visible.has("stage")) header.push("Stage");
|
|
124
108
|
if (visible.has("emailVerified")) header.push("Email verified");
|
|
125
109
|
if (visible.has("workspaces")) header.push("Workspaces");
|
|
126
110
|
if (visible.has("lastLogin")) header.push("Last login");
|
|
127
111
|
if (visible.has("joined")) header.push("Joined");
|
|
128
|
-
if (visible.has("
|
|
112
|
+
if (visible.has("mfa")) header.push("MFA enabled");
|
|
129
113
|
if (visible.has("activeSessions")) header.push("Active sessions");
|
|
130
114
|
if (visible.has("lastSeen")) header.push("Last seen");
|
|
131
115
|
const rows = [header, ...page2.rows.map((a2) => toCsvRow(a2, visible))];
|
|
@@ -155,7 +139,7 @@ function AccountsTable({
|
|
|
155
139
|
onRetry: () => void refetch(),
|
|
156
140
|
errorTitle: "Failed to load accounts.",
|
|
157
141
|
isEmpty: data?.rows.length === 0,
|
|
158
|
-
emptyTitle: "No accounts match
|
|
142
|
+
emptyTitle: "No accounts match this search or join date.",
|
|
159
143
|
controls: /* @__PURE__ */ jsxs(Filters, { label: "Filter accounts", children: [
|
|
160
144
|
/* @__PURE__ */ jsx(
|
|
161
145
|
FilterSearch,
|
|
@@ -165,16 +149,6 @@ function AccountsTable({
|
|
|
165
149
|
placeholder: "Search by email or name\u2026"
|
|
166
150
|
}
|
|
167
151
|
),
|
|
168
|
-
/* @__PURE__ */ jsx(
|
|
169
|
-
AccountStageFilter,
|
|
170
|
-
{
|
|
171
|
-
value: stage,
|
|
172
|
-
onChange: (v) => {
|
|
173
|
-
setStage(v);
|
|
174
|
-
setPage(1);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
),
|
|
178
152
|
/* @__PURE__ */ jsx(
|
|
179
153
|
FilterDates,
|
|
180
154
|
{
|
|
@@ -220,16 +194,11 @@ function AccountsTable({
|
|
|
220
194
|
/* @__PURE__ */ jsx(Th, { children: "Account" }),
|
|
221
195
|
visible.has("provider") && /* @__PURE__ */ jsx(Th, { children: "Provider" }),
|
|
222
196
|
/* @__PURE__ */ jsx(Th, { children: "Status" }),
|
|
223
|
-
visible.has("kyc") && /* @__PURE__ */ jsx(Th, { children: "KYC / KYB" }),
|
|
224
|
-
visible.has("stage") && /* @__PURE__ */ jsxs(Th, { children: [
|
|
225
|
-
"Stage",
|
|
226
|
-
/* @__PURE__ */ jsx(Hint, { label: ACTIVE_HINT })
|
|
227
|
-
] }),
|
|
228
197
|
visible.has("emailVerified") && /* @__PURE__ */ jsx(Th, { children: "Email" }),
|
|
229
198
|
visible.has("workspaces") && /* @__PURE__ */ jsx(Th, { align: "right", children: "Workspaces" }),
|
|
230
199
|
visible.has("lastLogin") && /* @__PURE__ */ jsx(Th, { children: "Last login" }),
|
|
231
200
|
visible.has("joined") && /* @__PURE__ */ jsx(Th, { children: "Joined" }),
|
|
232
|
-
visible.has("
|
|
201
|
+
visible.has("mfa") && /* @__PURE__ */ jsx(Th, { children: "MFA" }),
|
|
233
202
|
visible.has("activeSessions") && /* @__PURE__ */ jsx(Th, { align: "right", children: "Sessions" }),
|
|
234
203
|
visible.has("lastSeen") && /* @__PURE__ */ jsx(Th, { children: "Last seen" }),
|
|
235
204
|
/* @__PURE__ */ jsx(Th, { align: "right", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Actions" }) })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/accounts/accounts-table.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Button, OverflowItem, OverflowMenu, Th } from '@withpotter/ui-kit';\nimport { toCsv } from '@withpotter/lib/csv';\nimport {\n platformAdminApi,\n type AccountRow,\n type AccountStage,\n} from '@withpotter/lib/admin-api';\nimport {\n ColumnPicker,\n FilterDates,\n FilterSearch,\n Filters,\n type ColumnOption,\n} from '../_ui';\nimport { usePlatformAccounts } from '../hooks';\nimport { AccountPanel, type AccountSummary } from './account-panel';\nimport { ListCard, ListPager } from '../_ui/list-card';\nimport { ACTIVE_HINT, kycLabel, STAGE_LABELS } from './account-stage';\nimport { AccountStageFilter } from './account-stage-filter';\nimport { Hint } from './hint';\nimport { AccountListRow, PROVIDER_LABELS } from './account-row';\n\nexport { PROVIDER_LABELS } from './account-row';\n\nconst OPTIONAL_COLUMNS: ColumnOption[] = [\n { key: 'provider', label: 'Provider' },\n { key: 'kyc', label: 'KYC / KYB' },\n { key: 'stage', label: 'Stage' },\n { key: 'emailVerified', label: 'Email verified' },\n { key: 'workspaces', label: 'Workspaces' },\n { key: 'lastLogin', label: 'Last login' },\n { key: 'joined', label: 'Joined' },\n { key: 'firstSale', label: 'First sale' },\n { key: 'activeSessions', label: 'Active sessions' },\n { key: 'lastSeen', label: 'Last seen' },\n];\nconst DEFAULT_VISIBLE = [\n 'provider',\n 'kyc',\n 'stage',\n 'emailVerified',\n 'workspaces',\n 'lastLogin',\n 'joined',\n];\nconst COLUMNS_KEY = 'adm-accounts-columns';\n\nfunction readVisibleColumns(): Set<string> {\n if (typeof window === 'undefined') return new Set(DEFAULT_VISIBLE);\n try {\n const raw = window.localStorage.getItem(COLUMNS_KEY);\n return raw\n ? new Set(raw.split(',').filter(Boolean))\n : new Set(DEFAULT_VISIBLE);\n } catch {\n return new Set(DEFAULT_VISIBLE);\n }\n}\n\nfunction writeVisibleColumns(cols: Set<string>): void {\n try {\n window.localStorage.setItem(COLUMNS_KEY, [...cols].join(','));\n } catch {\n /* storage unavailable (private mode / quota) — non-fatal */\n }\n}\n\nconst day = (iso?: string | null) =>\n iso ? new Date(iso).toLocaleDateString() : '';\n\n/** One row's values, in the same column order the table renders. */\nfunction toCsvRow(a: AccountRow, visible: Set<string>): string[] {\n const cells: string[] = [a.name ?? '', a.email];\n if (visible.has('provider')) {\n cells.push(PROVIDER_LABELS[a.authProvider] ?? a.authProvider);\n }\n cells.push(a.status);\n if (visible.has('kyc')) cells.push(kycLabel(a.kycStatus) ?? '');\n if (visible.has('stage')) cells.push(a.stage ? STAGE_LABELS[a.stage] : '');\n if (visible.has('emailVerified')) {\n cells.push(a.emailVerified ? 'Verified' : 'Unverified');\n }\n if (visible.has('workspaces')) cells.push(String(a.workspaceCount ?? 0));\n if (visible.has('lastLogin')) cells.push(day(a.lastLoginAt) || 'Never');\n if (visible.has('joined')) cells.push(day(a.createdAt));\n if (visible.has('firstSale')) cells.push(day(a.firstSaleAt) || 'None yet');\n if (visible.has('activeSessions')) cells.push(String(a.activeSessions ?? 0));\n if (visible.has('lastSeen')) cells.push(day(a.lastSeenAt) || 'Never');\n return cells;\n}\n\n/** Every account, searchable and filterable by stage and join date. */\nexport function AccountsTable({\n selected,\n onSelect,\n}: {\n selected: AccountSummary | null;\n onSelect: (account: AccountSummary | null) => void;\n}) {\n const [search, setSearch] = useState('');\n const [joinedFrom, setJoinedFrom] = useState('');\n const [joinedTo, setJoinedTo] = useState('');\n const [stage, setStage] = useState<AccountStage | ''>('');\n const [page, setPage] = useState(1);\n const [visible, setVisible] = useState<Set<string>>(readVisibleColumns);\n const [exporting, setExporting] = useState(false);\n const { data, isLoading, isError, refetch } = usePlatformAccounts({\n page,\n pageSize: 20,\n search: search || undefined,\n joinedFrom: joinedFrom || undefined,\n joinedTo: joinedTo || undefined,\n stage: stage || undefined,\n });\n // Show the freshest copy of the selected account after an action refetches.\n const current = data?.rows.find((row) => row.id === selected?.id) ?? selected;\n const totalPages = data\n ? Math.max(1, Math.ceil(data.total / data.pageSize))\n : 1;\n const filter = (set: (v: string) => void) => (v: string) => {\n set(v);\n setPage(1);\n };\n\n const changeColumns = (next: Set<string>) => {\n setVisible(next);\n writeVisibleColumns(next);\n };\n\n // Every account matching the current search/join-date filter, not just\n // this page — a export of \"what I'm looking at\" that stops at 20 rows\n // because of pagination would just be confusing.\n const exportCsv = async () => {\n setExporting(true);\n try {\n const page = await platformAdminApi.accounts({\n pageSize: 5000,\n search: search || undefined,\n joinedFrom: joinedFrom || undefined,\n joinedTo: joinedTo || undefined,\n stage: stage || undefined,\n });\n const header = ['Name', 'Email'];\n if (visible.has('provider')) header.push('Provider');\n header.push('Status');\n if (visible.has('kyc')) header.push('KYC / KYB');\n if (visible.has('stage')) header.push('Stage');\n if (visible.has('emailVerified')) header.push('Email verified');\n if (visible.has('workspaces')) header.push('Workspaces');\n if (visible.has('lastLogin')) header.push('Last login');\n if (visible.has('joined')) header.push('Joined');\n if (visible.has('firstSale')) header.push('First sale');\n if (visible.has('activeSessions')) header.push('Active sessions');\n if (visible.has('lastSeen')) header.push('Last seen');\n const rows = [header, ...page.rows.map((a) => toCsvRow(a, visible))];\n const url = URL.createObjectURL(\n new Blob([toCsv(rows)], { type: 'text/csv' }),\n );\n const a = document.createElement('a');\n a.href = url;\n a.download = 'accounts.csv';\n a.click();\n URL.revokeObjectURL(url);\n } finally {\n setExporting(false);\n }\n };\n\n const columns = 3 + visible.size; // Account + Status + Actions, plus optional\n\n return (\n <>\n <ListCard\n title=\"All accounts\"\n count={data?.total}\n columns={columns}\n minWidth={880}\n isLoading={isLoading}\n isError={isError}\n onRetry={() => void refetch()}\n errorTitle=\"Failed to load accounts.\"\n isEmpty={data?.rows.length === 0}\n emptyTitle=\"No accounts match these filters.\"\n controls={\n <Filters label=\"Filter accounts\">\n <FilterSearch\n value={search}\n onChange={filter(setSearch)}\n placeholder=\"Search by email or name…\"\n />\n <AccountStageFilter\n value={stage}\n onChange={(v: AccountStage | '') => {\n setStage(v);\n setPage(1);\n }}\n />\n <FilterDates\n label=\"Joined\"\n fromLabel=\"Joined from\"\n toLabel=\"Joined to\"\n from={joinedFrom}\n to={joinedTo}\n onFrom={filter(setJoinedFrom)}\n onTo={filter(setJoinedTo)}\n />\n {(joinedFrom || joinedTo) && (\n <Button\n variant=\"ghost\"\n onClick={() => {\n setJoinedFrom('');\n setJoinedTo('');\n setPage(1);\n }}\n >\n Clear\n </Button>\n )}\n <ColumnPicker\n options={OPTIONAL_COLUMNS}\n visible={visible}\n onChange={changeColumns}\n />\n <OverflowMenu label=\"Export\">\n <OverflowItem\n onClick={() => void exportCsv()}\n disabled={exporting || !data?.total}\n >\n {exporting ? 'Exporting…' : 'Export CSV'}\n </OverflowItem>\n </OverflowMenu>\n </Filters>\n }\n head={\n <tr>\n <Th>Account</Th>\n {visible.has('provider') && <Th>Provider</Th>}\n <Th>Status</Th>\n {visible.has('kyc') && <Th>KYC / KYB</Th>}\n {visible.has('stage') && (\n <Th>\n Stage\n <Hint label={ACTIVE_HINT} />\n </Th>\n )}\n {visible.has('emailVerified') && <Th>Email</Th>}\n {visible.has('workspaces') && <Th align=\"right\">Workspaces</Th>}\n {visible.has('lastLogin') && <Th>Last login</Th>}\n {visible.has('joined') && <Th>Joined</Th>}\n {visible.has('firstSale') && <Th>First sale</Th>}\n {visible.has('activeSessions') && <Th align=\"right\">Sessions</Th>}\n {visible.has('lastSeen') && <Th>Last seen</Th>}\n <Th align=\"right\">\n <span className=\"sr-only\">Actions</span>\n </Th>\n </tr>\n }\n footer={\n <ListPager\n page={page}\n totalPages={totalPages}\n total={data?.total}\n noun=\"accounts\"\n onPage={setPage}\n />\n }\n >\n {data?.rows.map((a) => (\n <AccountListRow\n key={a.id}\n a={a}\n active={a.id === selected?.id}\n onOpen={() => onSelect(a)}\n visible={visible}\n />\n ))}\n </ListCard>\n <AccountPanel account={current} onClose={() => onSelect(null)} />\n </>\n );\n}\n"],"mappings":"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","names":["PROVIDER_LABELS","page","a"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/accounts/accounts-table.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Button, OverflowItem, OverflowMenu, Th } from '@withpotter/ui-kit';\nimport { toCsv } from '@withpotter/lib/csv';\nimport { platformAdminApi, type AccountRow } from '@withpotter/lib/admin-api';\nimport {\n ColumnPicker,\n FilterDates,\n FilterSearch,\n Filters,\n type ColumnOption,\n} from '../_ui';\nimport { usePlatformAccounts } from '../hooks';\nimport { AccountPanel, type AccountSummary } from './account-panel';\nimport { ListCard, ListPager } from '../_ui/list-card';\nimport { AccountListRow, PROVIDER_LABELS } from './account-row';\n\nexport { PROVIDER_LABELS } from './account-row';\n\nconst OPTIONAL_COLUMNS: ColumnOption[] = [\n { key: 'provider', label: 'Provider' },\n { key: 'emailVerified', label: 'Email verified' },\n { key: 'workspaces', label: 'Workspaces' },\n { key: 'lastLogin', label: 'Last login' },\n { key: 'joined', label: 'Joined' },\n { key: 'mfa', label: 'MFA enabled' },\n { key: 'activeSessions', label: 'Active sessions' },\n { key: 'lastSeen', label: 'Last seen' },\n];\nconst DEFAULT_VISIBLE = [\n 'provider',\n 'emailVerified',\n 'workspaces',\n 'lastLogin',\n 'joined',\n];\nconst COLUMNS_KEY = 'adm-accounts-columns';\n\nfunction readVisibleColumns(): Set<string> {\n if (typeof window === 'undefined') return new Set(DEFAULT_VISIBLE);\n try {\n const raw = window.localStorage.getItem(COLUMNS_KEY);\n return raw\n ? new Set(raw.split(',').filter(Boolean))\n : new Set(DEFAULT_VISIBLE);\n } catch {\n return new Set(DEFAULT_VISIBLE);\n }\n}\n\nfunction writeVisibleColumns(cols: Set<string>): void {\n try {\n window.localStorage.setItem(COLUMNS_KEY, [...cols].join(','));\n } catch {\n /* storage unavailable (private mode / quota) — non-fatal */\n }\n}\n\nconst day = (iso?: string | null) =>\n iso ? new Date(iso).toLocaleDateString() : '';\n\n/** One row's values, in the same column order the table renders. */\nfunction toCsvRow(a: AccountRow, visible: Set<string>): string[] {\n const cells: string[] = [a.name ?? '', a.email];\n if (visible.has('provider')) {\n cells.push(PROVIDER_LABELS[a.authProvider] ?? a.authProvider);\n }\n cells.push(a.status);\n if (visible.has('emailVerified')) {\n cells.push(a.emailVerified ? 'Verified' : 'Unverified');\n }\n if (visible.has('workspaces')) cells.push(String(a.workspaceCount ?? 0));\n if (visible.has('lastLogin')) cells.push(day(a.lastLoginAt) || 'Never');\n if (visible.has('joined')) cells.push(day(a.createdAt));\n if (visible.has('mfa')) cells.push(a.mfaEnabled ? 'Yes' : 'No');\n if (visible.has('activeSessions')) cells.push(String(a.activeSessions ?? 0));\n if (visible.has('lastSeen')) cells.push(day(a.lastSeenAt) || 'Never');\n return cells;\n}\n\n/** Every account, searchable and filterable by join date. */\nexport function AccountsTable({\n selected,\n onSelect,\n}: {\n selected: AccountSummary | null;\n onSelect: (account: AccountSummary | null) => void;\n}) {\n const [search, setSearch] = useState('');\n const [joinedFrom, setJoinedFrom] = useState('');\n const [joinedTo, setJoinedTo] = useState('');\n const [page, setPage] = useState(1);\n const [visible, setVisible] = useState<Set<string>>(readVisibleColumns);\n const [exporting, setExporting] = useState(false);\n const { data, isLoading, isError, refetch } = usePlatformAccounts({\n page,\n pageSize: 20,\n search: search || undefined,\n joinedFrom: joinedFrom || undefined,\n joinedTo: joinedTo || undefined,\n });\n // Show the freshest copy of the selected account after an action refetches.\n const current = data?.rows.find((row) => row.id === selected?.id) ?? selected;\n const totalPages = data\n ? Math.max(1, Math.ceil(data.total / data.pageSize))\n : 1;\n const filter = (set: (v: string) => void) => (v: string) => {\n set(v);\n setPage(1);\n };\n\n const changeColumns = (next: Set<string>) => {\n setVisible(next);\n writeVisibleColumns(next);\n };\n\n // Every account matching the current search/join-date filter, not just\n // this page — a export of \"what I'm looking at\" that stops at 20 rows\n // because of pagination would just be confusing.\n const exportCsv = async () => {\n setExporting(true);\n try {\n const page = await platformAdminApi.accounts({\n pageSize: 5000,\n search: search || undefined,\n joinedFrom: joinedFrom || undefined,\n joinedTo: joinedTo || undefined,\n });\n const header = ['Name', 'Email'];\n if (visible.has('provider')) header.push('Provider');\n header.push('Status');\n if (visible.has('emailVerified')) header.push('Email verified');\n if (visible.has('workspaces')) header.push('Workspaces');\n if (visible.has('lastLogin')) header.push('Last login');\n if (visible.has('joined')) header.push('Joined');\n if (visible.has('mfa')) header.push('MFA enabled');\n if (visible.has('activeSessions')) header.push('Active sessions');\n if (visible.has('lastSeen')) header.push('Last seen');\n const rows = [header, ...page.rows.map((a) => toCsvRow(a, visible))];\n const url = URL.createObjectURL(\n new Blob([toCsv(rows)], { type: 'text/csv' }),\n );\n const a = document.createElement('a');\n a.href = url;\n a.download = 'accounts.csv';\n a.click();\n URL.revokeObjectURL(url);\n } finally {\n setExporting(false);\n }\n };\n\n const columns = 3 + visible.size; // Account + Status + Actions, plus optional\n\n return (\n <>\n <ListCard\n title=\"All accounts\"\n count={data?.total}\n columns={columns}\n minWidth={880}\n isLoading={isLoading}\n isError={isError}\n onRetry={() => void refetch()}\n errorTitle=\"Failed to load accounts.\"\n isEmpty={data?.rows.length === 0}\n emptyTitle=\"No accounts match this search or join date.\"\n controls={\n <Filters label=\"Filter accounts\">\n <FilterSearch\n value={search}\n onChange={filter(setSearch)}\n placeholder=\"Search by email or name…\"\n />\n <FilterDates\n label=\"Joined\"\n fromLabel=\"Joined from\"\n toLabel=\"Joined to\"\n from={joinedFrom}\n to={joinedTo}\n onFrom={filter(setJoinedFrom)}\n onTo={filter(setJoinedTo)}\n />\n {(joinedFrom || joinedTo) && (\n <Button\n variant=\"ghost\"\n onClick={() => {\n setJoinedFrom('');\n setJoinedTo('');\n setPage(1);\n }}\n >\n Clear\n </Button>\n )}\n <ColumnPicker\n options={OPTIONAL_COLUMNS}\n visible={visible}\n onChange={changeColumns}\n />\n <OverflowMenu label=\"Export\">\n <OverflowItem\n onClick={() => void exportCsv()}\n disabled={exporting || !data?.total}\n >\n {exporting ? 'Exporting…' : 'Export CSV'}\n </OverflowItem>\n </OverflowMenu>\n </Filters>\n }\n head={\n <tr>\n <Th>Account</Th>\n {visible.has('provider') && <Th>Provider</Th>}\n <Th>Status</Th>\n {visible.has('emailVerified') && <Th>Email</Th>}\n {visible.has('workspaces') && <Th align=\"right\">Workspaces</Th>}\n {visible.has('lastLogin') && <Th>Last login</Th>}\n {visible.has('joined') && <Th>Joined</Th>}\n {visible.has('mfa') && <Th>MFA</Th>}\n {visible.has('activeSessions') && <Th align=\"right\">Sessions</Th>}\n {visible.has('lastSeen') && <Th>Last seen</Th>}\n <Th align=\"right\">\n <span className=\"sr-only\">Actions</span>\n </Th>\n </tr>\n }\n footer={\n <ListPager\n page={page}\n totalPages={totalPages}\n total={data?.total}\n noun=\"accounts\"\n onPage={setPage}\n />\n }\n >\n {data?.rows.map((a) => (\n <AccountListRow\n key={a.id}\n a={a}\n active={a.id === selected?.id}\n onOpen={() => onSelect(a)}\n visible={visible}\n />\n ))}\n </ListCard>\n <AccountPanel account={current} onClose={() => onSelect(null)} />\n </>\n );\n}\n"],"mappings":"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","names":["PROVIDER_LABELS","page","a"]}
|
|
@@ -45,8 +45,8 @@ function AccountsWorkspace() {
|
|
|
45
45
|
/* @__PURE__ */ jsx(
|
|
46
46
|
PageHeader,
|
|
47
47
|
{
|
|
48
|
-
title: "
|
|
49
|
-
description: `
|
|
48
|
+
title: "People",
|
|
49
|
+
description: `Every person registered on ${ADMIN_NAME}.`,
|
|
50
50
|
actions: tab === "overview" && /* @__PURE__ */ jsx("div", { className: "adm-toolbar", children: /* @__PURE__ */ jsx(
|
|
51
51
|
PeriodSelector,
|
|
52
52
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/accounts/accounts-workspace.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo, useState } from 'react';\nimport { ADMIN_NAME } from '../_shell/admin-brand';\nimport {\n PageHeader,\n PageTabs,\n PeriodSelector,\n customRange,\n periodPhrase,\n rangeFromKey,\n usePersistedDateRange,\n useTabParam,\n} from '../_ui';\nimport { usePlatformAccountsAnalytics } from '../hooks';\nimport { AccountPanel, type AccountSummary } from './account-panel';\nimport { AccountsAnalytics } from './accounts-analytics';\nimport { AccountsTable } from './accounts-table';\n\nconst TABS = [\n { id: 'overview', label: 'Overview' },\n { id: 'all', label: 'All accounts' },\n] as const;\n\nconst KEYS = TABS.map((t) => t.id);\n\n/** People: the period's picture on Overview, every account on its own tab. */\nexport function AccountsWorkspace() {\n const [tab, setTab] = useTabParam(KEYS);\n const [selected, setSelected] = useState<AccountSummary | null>(null);\n const {\n rangeKey,\n setRangeKey,\n customStart,\n customEnd,\n onCustomChange,\n compare,\n } = usePersistedDateRange();\n const range = useMemo(\n () =>\n rangeKey === 'custom'\n ? customRange(customStart, customEnd)\n : rangeFromKey(rangeKey),\n [rangeKey, customStart, customEnd],\n );\n const analytics = usePlatformAccountsAnalytics({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const span = periodPhrase(range);\n\n return (\n <div>\n <PageHeader\n title=\"
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/accounts/accounts-workspace.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo, useState } from 'react';\nimport { ADMIN_NAME } from '../_shell/admin-brand';\nimport {\n PageHeader,\n PageTabs,\n PeriodSelector,\n customRange,\n periodPhrase,\n rangeFromKey,\n usePersistedDateRange,\n useTabParam,\n} from '../_ui';\nimport { usePlatformAccountsAnalytics } from '../hooks';\nimport { AccountPanel, type AccountSummary } from './account-panel';\nimport { AccountsAnalytics } from './accounts-analytics';\nimport { AccountsTable } from './accounts-table';\n\nconst TABS = [\n { id: 'overview', label: 'Overview' },\n { id: 'all', label: 'All accounts' },\n] as const;\n\nconst KEYS = TABS.map((t) => t.id);\n\n/** People: the period's picture on Overview, every account on its own tab. */\nexport function AccountsWorkspace() {\n const [tab, setTab] = useTabParam(KEYS);\n const [selected, setSelected] = useState<AccountSummary | null>(null);\n const {\n rangeKey,\n setRangeKey,\n customStart,\n customEnd,\n onCustomChange,\n compare,\n } = usePersistedDateRange();\n const range = useMemo(\n () =>\n rangeKey === 'custom'\n ? customRange(customStart, customEnd)\n : rangeFromKey(rangeKey),\n [rangeKey, customStart, customEnd],\n );\n const analytics = usePlatformAccountsAnalytics({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const span = periodPhrase(range);\n\n return (\n <div>\n <PageHeader\n title=\"People\"\n description={`Every person registered on ${ADMIN_NAME}.`}\n actions={\n tab === 'overview' && (\n <div className=\"adm-toolbar\">\n <PeriodSelector\n value={rangeKey}\n onChange={setRangeKey}\n customStart={customStart}\n customEnd={customEnd}\n onCustomChange={onCustomChange}\n />\n </div>\n )\n }\n />\n <PageTabs tabs={TABS} active={tab} onChange={setTab} />\n\n {tab === 'overview' && (\n <>\n <AccountsAnalytics\n data={analytics.data}\n isLoading={analytics.isLoading}\n isError={analytics.isError}\n onRetry={() => void analytics.refetch()}\n caption={`${span[0].toUpperCase()}${span.slice(1)}`}\n span={span}\n compare={compare}\n onSelectAccount={setSelected}\n />\n <AccountPanel account={selected} onClose={() => setSelected(null)} />\n </>\n )}\n\n {tab === 'all' && (\n <AccountsTable selected={selected} onSelect={setSelected} />\n )}\n </div>\n );\n}\n"],"mappings":";AA2Dc,SAcN,UAdM,KAcN,YAdM;AAzDd,SAAS,SAAS,gBAAgB;AAClC,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oCAAoC;AAC7C,SAAS,oBAAyC;AAClD,SAAS,yBAAyB;AAClC,SAAS,qBAAqB;AAE9B,MAAM,OAAO;AAAA,EACX,EAAE,IAAI,YAAY,OAAO,WAAW;AAAA,EACpC,EAAE,IAAI,OAAO,OAAO,eAAe;AACrC;AAEA,MAAM,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE;AAG1B,SAAS,oBAAoB;AAClC,QAAM,CAAC,KAAK,MAAM,IAAI,YAAY,IAAI;AACtC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAgC,IAAI;AACpE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,sBAAsB;AAC1B,QAAM,QAAQ;AAAA,IACZ,MACE,aAAa,WACT,YAAY,aAAa,SAAS,IAClC,aAAa,QAAQ;AAAA,IAC3B,CAAC,UAAU,aAAa,SAAS;AAAA,EACnC;AACA,QAAM,YAAY,6BAA6B;AAAA,IAC7C,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,EACjB,CAAC;AACD,QAAM,OAAO,aAAa,KAAK;AAE/B,SACE,qBAAC,SACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAa,8BAA8B,UAAU;AAAA,QACrD,SACE,QAAQ,cACN,oBAAC,SAAI,WAAU,eACb;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF,GACF;AAAA;AAAA,IAGN;AAAA,IACA,oBAAC,YAAS,MAAM,MAAM,QAAQ,KAAK,UAAU,QAAQ;AAAA,IAEpD,QAAQ,cACP,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,UAAU;AAAA,UAChB,WAAW,UAAU;AAAA,UACrB,SAAS,UAAU;AAAA,UACnB,SAAS,MAAM,KAAK,UAAU,QAAQ;AAAA,UACtC,SAAS,GAAG,KAAK,CAAC,EAAE,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AAAA,UACjD;AAAA,UACA;AAAA,UACA,iBAAiB;AAAA;AAAA,MACnB;AAAA,MACA,oBAAC,gBAAa,SAAS,UAAU,SAAS,MAAM,YAAY,IAAI,GAAG;AAAA,OACrE;AAAA,IAGD,QAAQ,SACP,oBAAC,iBAAc,UAAoB,UAAU,aAAa;AAAA,KAE9D;AAEJ;","names":[]}
|
|
@@ -10,9 +10,15 @@ const SESSION_KEYS = [
|
|
|
10
10
|
"tenant",
|
|
11
11
|
"pb_workspaces_cache"
|
|
12
12
|
];
|
|
13
|
+
const encode = (value) => btoa(JSON.stringify(value)).replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
13
14
|
async function seedOwnerSession() {
|
|
14
15
|
const owner = await apiFetch("/accounts/me");
|
|
16
|
+
const exp = Math.floor(Date.now() / 1e3) + 60 * 60;
|
|
15
17
|
clearOwnerSession();
|
|
18
|
+
localStorage.setItem(
|
|
19
|
+
"pb_token",
|
|
20
|
+
`${encode({ alg: "none", typ: "JWT" })}.${encode({ sub: owner.id, email: owner.email, exp, ownerView: true })}.owner-view`
|
|
21
|
+
);
|
|
16
22
|
localStorage.setItem("pb_account_id", owner.id);
|
|
17
23
|
localStorage.setItem("pb_user", JSON.stringify(owner));
|
|
18
24
|
localStorage.setItem("userEmail", owner.email);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/accounts/owner-session.ts"],"sourcesContent":["import { apiFetch } from '@withpotter/lib/api';\n\n/**\n * Hand the merchant dashboard the owner's session after \"View as owner\".\n *\n * The API's impersonation sets the owner's session as an httpOnly cookie on\n * this origin, which every merchant API call already authenticates with. The\n * merchant app, though, decides whether anyone is signed in from
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/accounts/owner-session.ts"],"sourcesContent":["import { apiFetch } from '@withpotter/lib/api';\n\n/**\n * Hand the merchant dashboard the owner's session after \"View as owner\".\n *\n * The API's impersonation sets the owner's session as an httpOnly cookie on\n * this origin, which every merchant API call already authenticates with. The\n * merchant app, though, decides whether anyone is signed in from localStorage\n * (`pb_token`, `pb_user`); finding nothing, it sent the tab to /login and the\n * Admin host bounced it home. So we read the owner through the cookie and seed\n * what the app looks for — the token is only a local marker with the cookie's\n * one-hour expiry; the server never trusts it, because the cookie wins.\n */\nconst SESSION_KEYS = [\n 'pb_token',\n 'pb_user',\n 'pb_account_id',\n 'userEmail',\n 'organizationId',\n 'currentWorkspace',\n 'pb_current_tenant',\n 'tenant',\n 'pb_workspaces_cache',\n];\n\nconst encode = (value: object) =>\n btoa(JSON.stringify(value))\n .replace(/=+$/, '')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_');\n\ninterface OwnerAccount {\n id: string;\n email: string;\n [key: string]: unknown;\n}\n\nexport async function seedOwnerSession(): Promise<void> {\n const owner = await apiFetch<OwnerAccount>('/accounts/me');\n const exp = Math.floor(Date.now() / 1000) + 60 * 60;\n\n clearOwnerSession();\n localStorage.setItem(\n 'pb_token',\n `${encode({ alg: 'none', typ: 'JWT' })}.${encode({ sub: owner.id, email: owner.email, exp, ownerView: true })}.owner-view`,\n );\n localStorage.setItem('pb_account_id', owner.id);\n localStorage.setItem('pb_user', JSON.stringify(owner));\n localStorage.setItem('userEmail', owner.email);\n}\n\n/** Drops any merchant session cached in this browser (and its workspace). */\nexport function clearOwnerSession(): void {\n try {\n SESSION_KEYS.forEach((key) => localStorage.removeItem(key));\n } catch {\n // Storage blocked: nothing cached to clear.\n }\n}\n"],"mappings":"AAAA,SAAS,gBAAgB;AAazB,MAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,SAAS,CAAC,UACd,KAAK,KAAK,UAAU,KAAK,CAAC,EACvB,QAAQ,OAAO,EAAE,EACjB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG;AAQvB,eAAsB,mBAAkC;AACtD,QAAM,QAAQ,MAAM,SAAuB,cAAc;AACzD,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IAAI,KAAK;AAEjD,oBAAkB;AAClB,eAAa;AAAA,IACX;AAAA,IACA,GAAG,OAAO,EAAE,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,IAAI,OAAO,EAAE,KAAK,MAAM,IAAI,OAAO,MAAM,OAAO,KAAK,WAAW,KAAK,CAAC,CAAC;AAAA,EAC/G;AACA,eAAa,QAAQ,iBAAiB,MAAM,EAAE;AAC9C,eAAa,QAAQ,WAAW,KAAK,UAAU,KAAK,CAAC;AACrD,eAAa,QAAQ,aAAa,MAAM,KAAK;AAC/C;AAGO,SAAS,oBAA0B;AACxC,MAAI;AACF,iBAAa,QAAQ,CAAC,QAAQ,aAAa,WAAW,GAAG,CAAC;AAAA,EAC5D,QAAQ;AAAA,EAER;AACF;","names":[]}
|
|
@@ -65,20 +65,3 @@
|
|
|
65
65
|
font-variant-numeric: tabular-nums;
|
|
66
66
|
cursor: default;
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
.hint {
|
|
70
|
-
display: inline-flex;
|
|
71
|
-
align-items: center;
|
|
72
|
-
margin-left: 4px;
|
|
73
|
-
padding: 0;
|
|
74
|
-
border: 0;
|
|
75
|
-
background: none;
|
|
76
|
-
vertical-align: middle;
|
|
77
|
-
color: var(--text-tertiary);
|
|
78
|
-
cursor: help;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.hint:hover,
|
|
82
|
-
.hint:focus-visible {
|
|
83
|
-
color: var(--text-primary);
|
|
84
|
-
}
|
|
@@ -23,12 +23,6 @@ const TONE_OF = {
|
|
|
23
23
|
completed: "complete",
|
|
24
24
|
closed: "complete",
|
|
25
25
|
draft: "draft",
|
|
26
|
-
// Account stages read as progress: grey, blue, amber, teal, green.
|
|
27
|
-
stage_signed_up: "neutral",
|
|
28
|
-
stage_verified: "processing",
|
|
29
|
-
stage_onboarding: "pending",
|
|
30
|
-
stage_kyc_approved: "ahead",
|
|
31
|
-
stage_active: "success",
|
|
32
26
|
deleted: "neutral",
|
|
33
27
|
rejected: "neutral"
|
|
34
28
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/audit/status-pill.tsx"],"sourcesContent":["import styles from './status-pill.module.css';\n\ntype StatusTone =\n | 'success'\n | 'pending'\n | 'failed'\n | 'processing'\n | 'complete'\n | 'draft'\n | '
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/audit/status-pill.tsx"],"sourcesContent":["import styles from './status-pill.module.css';\n\ntype StatusTone =\n | 'success'\n | 'pending'\n | 'failed'\n | 'processing'\n | 'complete'\n | 'draft'\n | 'neutral';\n\nconst TONE_OF: Record<string, StatusTone> = {\n active: 'success',\n verified: 'success',\n approved: 'success',\n resolved: 'success',\n pending: 'pending',\n pending_verification: 'pending',\n unverified: 'pending',\n invited: 'pending',\n paused: 'pending',\n open: 'pending',\n non_renewing: 'pending',\n trialing: 'processing',\n processing: 'processing',\n scheduled: 'processing',\n acknowledged: 'processing',\n suspended: 'failed',\n failed: 'failed',\n flagged: 'failed',\n past_due: 'failed',\n completed: 'complete',\n closed: 'complete',\n draft: 'draft',\n deleted: 'neutral',\n rejected: 'neutral',\n};\n\n/** Words for a status key: `pending_verification` → \"Pending verification\". */\nconst words = (s: string) => {\n const w = s.replace(/[_-]+/g, ' ');\n return w.charAt(0).toUpperCase() + w.slice(1);\n};\n\n/**\n * A status as a 6px dot plus text. Each state reads as itself: live ok,\n * waiting amber, in flight brand blue, stopped red, finished solid grey,\n * draft hollow. Static: nothing pulses.\n */\nexport function StatusPill({\n status,\n label,\n}: {\n status: string;\n label?: string;\n}) {\n const tone = TONE_OF[status.toLowerCase()] ?? 'neutral';\n return (\n <span className={styles.pill} data-tone={tone}>\n <span className={`${styles.dot} adm-status-dot`} aria-hidden />\n {label ?? words(status)}\n </span>\n );\n}\n"],"mappings":"AA0DI,SACE,KADF;AA1DJ,OAAO,YAAY;AAWnB,MAAM,UAAsC;AAAA,EAC1C,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AAAA,EACV,SAAS;AAAA,EACT,sBAAsB;AAAA,EACtB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,cAAc;AAAA,EACd,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AACZ;AAGA,MAAM,QAAQ,CAAC,MAAc;AAC3B,QAAM,IAAI,EAAE,QAAQ,UAAU,GAAG;AACjC,SAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC;AAC9C;AAOO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGG;AACD,QAAM,OAAO,QAAQ,OAAO,YAAY,CAAC,KAAK;AAC9C,SACE,qBAAC,UAAK,WAAW,OAAO,MAAM,aAAW,MACvC;AAAA,wBAAC,UAAK,WAAW,GAAG,OAAO,GAAG,mBAAmB,eAAW,MAAC;AAAA,IAC5D,SAAS,MAAM,MAAM;AAAA,KACxB;AAEJ;","names":[]}
|
|
@@ -70,7 +70,7 @@ function CommerceOverview({
|
|
|
70
70
|
previousOrdersTrend: [],
|
|
71
71
|
compare: false,
|
|
72
72
|
span,
|
|
73
|
-
money: moneyIn(focus ?? "
|
|
73
|
+
money: moneyIn(focus ?? "USD")
|
|
74
74
|
}
|
|
75
75
|
) : pick }) }) }),
|
|
76
76
|
/* @__PURE__ */ jsxs("div", { className: "adm-grid", children: [
|
|
@@ -79,7 +79,7 @@ function CommerceOverview({
|
|
|
79
79
|
{
|
|
80
80
|
rows: rowFor(data?.topTenantsByCurrency, focus)?.tenants ?? [],
|
|
81
81
|
loading,
|
|
82
|
-
money: moneyIn(focus ?? "
|
|
82
|
+
money: moneyIn(focus ?? "USD"),
|
|
83
83
|
caption,
|
|
84
84
|
onOpen: onOpenMerchant
|
|
85
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/commerce/commerce-overview.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport { Button, ErrorBanner } from '@withpotter/ui-kit';\nimport { usePlatformCockpit } from '../hooks';\nimport {\n GmvOrdersChart,\n PICK_CURRENCY,\n Panel,\n focusCurrency,\n moneyIn,\n periodPhrase,\n rowFor,\n toTrend,\n type DateRange,\n} from '../_ui';\nimport { OverviewKpis } from './overview-kpis';\nimport { SalesByService } from './overview-services';\nimport { TopMerchants } from './overview-top-merchants';\nimport styles from './overview.module.css';\n\n/**\n * Commerce across every merchant, from the one cockpit call: the headline\n * figures, who sells most, where the base sits and who needs a look.\n * Nothing here is fetched per merchant. Money comes back once per currency\n * and is never added across currencies or converted.\n */\nexport function CommerceOverview({\n range,\n currency,\n compare,\n onOpenMerchant,\n}: {\n range: DateRange;\n /** The currency filter's choice; '' shows every currency. */\n currency: string;\n /** False for \"all time\": there is no earlier period to compare with. */\n compare: boolean;\n onOpenMerchant: (id: string) => void;\n}) {\n const cockpit = usePlatformCockpit({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const data = cockpit.data;\n const currencies = data?.currencies ?? [];\n // A chart or a ranking draws one currency: the filter's, or the only one.\n const focus = focusCurrency(currencies, currency);\n const span = periodPhrase(range);\n const period = `${span[0].toUpperCase()}${span.slice(1)}`;\n const caption = focus ? `${period} · ${focus}` : period;\n\n const series = useMemo(\n () => rowFor(data?.trend.performanceSeriesByCurrency, focus)?.series,\n [data, focus],\n );\n const gmvTrend = useMemo(() => toTrend(series, 'gmv'), [series]);\n const ordersTrend = useMemo(() => toTrend(series, 'orders'), [series]);\n // Sales by service is one mixed figure: only honest with one currency.\n const services =\n data?.salesByService?.length && currencies.length === 1\n ? data.salesByService\n : null;\n\n if (cockpit.isError) {\n return (\n <ErrorBanner>\n The commerce overview could not be loaded.{' '}\n <Button size=\"sm\" variant=\"secondary\" onClick={() => cockpit.refetch()}>\n Try again\n </Button>\n </ErrorBanner>\n );\n }\n\n const loading = cockpit.isLoading || !data;\n const pick = (\n <p className=\"text-sm text-[var(--text-secondary)]\">{PICK_CURRENCY}</p>\n );\n\n return (\n <div className={styles.stack}>\n <OverviewKpis\n data={data}\n loading={loading}\n currency={currency}\n focus={focus}\n compare={compare}\n caption={caption}\n />\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <Panel title=\"GMV & orders\" caption={caption}>\n {focus || loading ? (\n <GmvOrdersChart\n gmvTrend={gmvTrend}\n ordersTrend={ordersTrend}\n previousGmvTrend={[]}\n previousOrdersTrend={[]}\n compare={false}\n span={span}\n money={moneyIn(focus ?? '
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/commerce/commerce-overview.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport { Button, ErrorBanner } from '@withpotter/ui-kit';\nimport { usePlatformCockpit } from '../hooks';\nimport {\n GmvOrdersChart,\n PICK_CURRENCY,\n Panel,\n focusCurrency,\n moneyIn,\n periodPhrase,\n rowFor,\n toTrend,\n type DateRange,\n} from '../_ui';\nimport { OverviewKpis } from './overview-kpis';\nimport { SalesByService } from './overview-services';\nimport { TopMerchants } from './overview-top-merchants';\nimport styles from './overview.module.css';\n\n/**\n * Commerce across every merchant, from the one cockpit call: the headline\n * figures, who sells most, where the base sits and who needs a look.\n * Nothing here is fetched per merchant. Money comes back once per currency\n * and is never added across currencies or converted.\n */\nexport function CommerceOverview({\n range,\n currency,\n compare,\n onOpenMerchant,\n}: {\n range: DateRange;\n /** The currency filter's choice; '' shows every currency. */\n currency: string;\n /** False for \"all time\": there is no earlier period to compare with. */\n compare: boolean;\n onOpenMerchant: (id: string) => void;\n}) {\n const cockpit = usePlatformCockpit({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const data = cockpit.data;\n const currencies = data?.currencies ?? [];\n // A chart or a ranking draws one currency: the filter's, or the only one.\n const focus = focusCurrency(currencies, currency);\n const span = periodPhrase(range);\n const period = `${span[0].toUpperCase()}${span.slice(1)}`;\n const caption = focus ? `${period} · ${focus}` : period;\n\n const series = useMemo(\n () => rowFor(data?.trend.performanceSeriesByCurrency, focus)?.series,\n [data, focus],\n );\n const gmvTrend = useMemo(() => toTrend(series, 'gmv'), [series]);\n const ordersTrend = useMemo(() => toTrend(series, 'orders'), [series]);\n // Sales by service is one mixed figure: only honest with one currency.\n const services =\n data?.salesByService?.length && currencies.length === 1\n ? data.salesByService\n : null;\n\n if (cockpit.isError) {\n return (\n <ErrorBanner>\n The commerce overview could not be loaded.{' '}\n <Button size=\"sm\" variant=\"secondary\" onClick={() => cockpit.refetch()}>\n Try again\n </Button>\n </ErrorBanner>\n );\n }\n\n const loading = cockpit.isLoading || !data;\n const pick = (\n <p className=\"text-sm text-[var(--text-secondary)]\">{PICK_CURRENCY}</p>\n );\n\n return (\n <div className={styles.stack}>\n <OverviewKpis\n data={data}\n loading={loading}\n currency={currency}\n focus={focus}\n compare={compare}\n caption={caption}\n />\n\n <div className=\"adm-grid\">\n <div className=\"adm-span-12\">\n <Panel title=\"GMV & orders\" caption={caption}>\n {focus || loading ? (\n <GmvOrdersChart\n gmvTrend={gmvTrend}\n ordersTrend={ordersTrend}\n previousGmvTrend={[]}\n previousOrdersTrend={[]}\n compare={false}\n span={span}\n money={moneyIn(focus ?? 'USD')}\n />\n ) : (\n pick\n )}\n </Panel>\n </div>\n </div>\n\n <div className=\"adm-grid\">\n <div className={services ? 'adm-span-7' : 'adm-span-12'}>\n {focus || loading ? (\n <TopMerchants\n rows={rowFor(data?.topTenantsByCurrency, focus)?.tenants ?? []}\n loading={loading}\n money={moneyIn(focus ?? 'USD')}\n caption={caption}\n onOpen={onOpenMerchant}\n />\n ) : (\n <Panel title=\"Top merchants by sales\" caption={caption}>\n {pick}\n </Panel>\n )}\n </div>\n {services && (\n <div className=\"adm-span-5\">\n <SalesByService\n rows={services}\n loading={loading}\n money={moneyIn(currencies[0])}\n caption={caption}\n />\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";AAkEM,SAEE,KAFF;AAhEN,SAAS,eAAe;AACxB,SAAS,QAAQ,mBAAmB;AACpC,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,OAAO,YAAY;AAQZ,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,UAAU,mBAAmB;AAAA,IACjC,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,EACjB,CAAC;AACD,QAAM,OAAO,QAAQ;AACrB,QAAM,aAAa,MAAM,cAAc,CAAC;AAExC,QAAM,QAAQ,cAAc,YAAY,QAAQ;AAChD,QAAM,OAAO,aAAa,KAAK;AAC/B,QAAM,SAAS,GAAG,KAAK,CAAC,EAAE,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AACvD,QAAM,UAAU,QAAQ,GAAG,MAAM,SAAM,KAAK,KAAK;AAEjD,QAAM,SAAS;AAAA,IACb,MAAM,OAAO,MAAM,MAAM,6BAA6B,KAAK,GAAG;AAAA,IAC9D,CAAC,MAAM,KAAK;AAAA,EACd;AACA,QAAM,WAAW,QAAQ,MAAM,QAAQ,QAAQ,KAAK,GAAG,CAAC,MAAM,CAAC;AAC/D,QAAM,cAAc,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,GAAG,CAAC,MAAM,CAAC;AAErE,QAAM,WACJ,MAAM,gBAAgB,UAAU,WAAW,WAAW,IAClD,KAAK,iBACL;AAEN,MAAI,QAAQ,SAAS;AACnB,WACE,qBAAC,eAAY;AAAA;AAAA,MACgC;AAAA,MAC3C,oBAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,SAAS,MAAM,QAAQ,QAAQ,GAAG,uBAExE;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,UAAU,QAAQ,aAAa,CAAC;AACtC,QAAM,OACJ,oBAAC,OAAE,WAAU,wCAAwC,yBAAc;AAGrE,SACE,qBAAC,SAAI,WAAW,OAAO,OACrB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAEA,oBAAC,SAAI,WAAU,YACb,8BAAC,SAAI,WAAU,eACb,8BAAC,SAAM,OAAM,gBAAe,SACzB,mBAAS,UACR;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,kBAAkB,CAAC;AAAA,QACnB,qBAAqB,CAAC;AAAA,QACtB,SAAS;AAAA,QACT;AAAA,QACA,OAAO,QAAQ,SAAS,KAAK;AAAA;AAAA,IAC/B,IAEA,MAEJ,GACF,GACF;AAAA,IAEA,qBAAC,SAAI,WAAU,YACb;AAAA,0BAAC,SAAI,WAAW,WAAW,eAAe,eACvC,mBAAS,UACR;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,OAAO,MAAM,sBAAsB,KAAK,GAAG,WAAW,CAAC;AAAA,UAC7D;AAAA,UACA,OAAO,QAAQ,SAAS,KAAK;AAAA,UAC7B;AAAA,UACA,QAAQ;AAAA;AAAA,MACV,IAEA,oBAAC,SAAM,OAAM,0BAAyB,SACnC,gBACH,GAEJ;AAAA,MACC,YACC,oBAAC,SAAI,WAAU,cACb;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN;AAAA,UACA,OAAO,QAAQ,WAAW,CAAC,CAAC;AAAA,UAC5B;AAAA;AAAA,MACF,GACF;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/commerce/merchant-meta.ts"],"sourcesContent":["import type { TenantRow, TenantStatus } from '@withpotter/lib/admin-api';\nimport type { PillTone } from '../tenants/[id]/commerce/format';\n\n/**\n * GMV is in the merchant's own currency. With the currency known (tenant\n * detail), show it; list rows carry none, so they get a plain number.\n */\nexport const compactMoney = (n: number, currency?: string | null) => {\n if (currency) {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/commerce/merchant-meta.ts"],"sourcesContent":["import type { TenantRow, TenantStatus } from '@withpotter/lib/admin-api';\nimport type { PillTone } from '../tenants/[id]/commerce/format';\n\n/**\n * GMV is in the merchant's own currency. With the currency known (tenant\n * detail), show it; list rows carry none, so they get a plain number.\n */\nexport const compactMoney = (n: number, currency?: string | null) => {\n if (currency) {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n notation: 'compact',\n maximumFractionDigits: 1,\n }).format(n ?? 0);\n } catch {\n // An unknown code falls through to the plain number.\n }\n }\n\n return compactNumber(n);\n};\n\n/**\n * Sales per currency, compact and never added together: \"₦1.2M · $3.4K\".\n * Falls back to the plain number when the API sends no per-currency rows.\n */\nexport const compactSales = (\n rows: ReadonlyArray<{ currency: string; amount: number }> | undefined,\n fallback: number,\n) =>\n rows?.length\n ? rows.map((r) => compactMoney(r.amount, r.currency)).join(' · ')\n : compactNumber(fallback);\n\n/** \"12.4K\": sales without a currency, for list rows. */\nexport const compactNumber = (n: number) =>\n new Intl.NumberFormat('en-US', {\n notation: 'compact',\n maximumFractionDigits: 1,\n }).format(n ?? 0);\n\nexport const STATUS_TONE: Record<TenantStatus, PillTone> = {\n active: 'success',\n pending: 'pending',\n suspended: 'failed',\n deleted: 'neutral',\n};\n\n/**\n * A merchant's logo when the API sends one, flat (`logoUrl`) or on the\n * profile (`profile.logoUrl`). Without it EntityAvatar falls back to initials,\n * so every list picks logos up the day the API starts sending them.\n */\nexport const logoOf = (row: object): string | null => {\n const r = row as {\n logoUrl?: string | null;\n profile?: { logoUrl?: string | null } | null;\n };\n\n return r.logoUrl ?? r.profile?.logoUrl ?? null;\n};\n\n/**\n * Ranked by sales within the rows shown only. Each figure is in its own\n * merchant's currency, so this orders a page; it is not a platform league.\n */\nexport const bySales = (rows: TenantRow[]) =>\n [...rows].sort((a, b) => (b.gmv ?? 0) - (a.gmv ?? 0));\n"],"mappings":"AAOO,MAAM,eAAe,CAAC,GAAW,aAA6B;AACnE,MAAI,UAAU;AACZ,QAAI;AACF,aAAO,IAAI,KAAK,aAAa,SAAS;AAAA,QACpC,OAAO;AAAA,QACP;AAAA,QACA,UAAU;AAAA,QACV,uBAAuB;AAAA,MACzB,CAAC,EAAE,OAAO,KAAK,CAAC;AAAA,IAClB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,cAAc,CAAC;AACxB;AAMO,MAAM,eAAe,CAC1B,MACA,aAEA,MAAM,SACF,KAAK,IAAI,CAAC,MAAM,aAAa,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,KAAK,QAAK,IAC9D,cAAc,QAAQ;AAGrB,MAAM,gBAAgB,CAAC,MAC5B,IAAI,KAAK,aAAa,SAAS;AAAA,EAC7B,UAAU;AAAA,EACV,uBAAuB;AACzB,CAAC,EAAE,OAAO,KAAK,CAAC;AAEX,MAAM,cAA8C;AAAA,EACzD,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AACX;AAOO,MAAM,SAAS,CAAC,QAA+B;AACpD,QAAM,IAAI;AAKV,SAAO,EAAE,WAAW,EAAE,SAAS,WAAW;AAC5C;AAMO,MAAM,UAAU,CAAC,SACtB,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,EAAE,OAAO,MAAM,EAAE,OAAO,EAAE;","names":[]}
|
|
@@ -78,7 +78,7 @@ function MerchantView({ range }) {
|
|
|
78
78
|
] }),
|
|
79
79
|
/* @__PURE__ */ jsxs("span", { className: styles.sub, children: [
|
|
80
80
|
"Shown in ",
|
|
81
|
-
t.currency || "
|
|
81
|
+
t.currency || "USD",
|
|
82
82
|
", the merchant\u2019s currency"
|
|
83
83
|
] })
|
|
84
84
|
] })
|
|
@@ -90,7 +90,7 @@ function MerchantView({ range }) {
|
|
|
90
90
|
MerchantCommerce,
|
|
91
91
|
{
|
|
92
92
|
tenantId: id,
|
|
93
|
-
currency: t?.currency ?? "
|
|
93
|
+
currency: t?.currency ?? "USD",
|
|
94
94
|
range
|
|
95
95
|
},
|
|
96
96
|
id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/commerce/merchant-view.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\nimport { Button, Card, EmptyNote, ErrorBanner } from '@withpotter/ui-kit';\nimport { usePlatformTenant, usePlatformTenants } from '../hooks';\nimport { EntityAvatar, Reveal } from '../_fx';\nimport { Skeleton, type DateRange } from '../_ui';\nimport { MerchantCommerce } from '../tenants/[id]/commerce';\nimport { StatusPill } from '../tenants/[id]/commerce/status-pill';\nimport { bySales, compactSales, STATUS_TONE } from './merchant-meta';\nimport { MerchantPicker } from './merchant-picker';\nimport styles from './console.module.css';\n\n/** \"By merchant\": pick a merchant, then read their commerce. */\nexport function MerchantView({ range }: { range: DateRange }) {\n const router = useRouter();\n const pathname = usePathname();\n const params = useSearchParams();\n const [picking, setPicking] = useState(false);\n\n const top = usePlatformTenants({ pageSize: 50 });\n const fallback = bySales(top.data?.rows ?? [])[0]?.id ?? null;\n const id = params.get('merchant') || fallback;\n const tenant = usePlatformTenant(id ?? '', {\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const t = tenant.data;\n\n const pick = (next: string) => {\n const qs = new URLSearchParams(params.toString());\n qs.set('merchant', next);\n router.replace(`${pathname}?${qs.toString()}`, { scroll: false });\n setPicking(false);\n };\n\n const noMerchants = !top.isLoading && !top.isError && !id;\n\n return (\n <div className={styles.body}>\n {top.isError && !id ? (\n <ErrorBanner>\n Merchants could not be loaded.{' '}\n <Button size=\"sm\" variant=\"secondary\" onClick={() => top.refetch()}>\n Try again\n </Button>\n </ErrorBanner>\n ) : noMerchants ? (\n <EmptyNote\n well\n action={\n <Button variant=\"secondary\" asChild>\n <Link href=\"/admin/tenants\">Go to merchants</Link>\n </Button>\n }\n >\n Once a business signs up, its items, orders and stock appear here.\n </EmptyNote>\n ) : (\n <>\n <Card>\n <Reveal className={styles.current}>\n {t?.profile?.logoUrl && (\n <EntityAvatar\n name={t.businessName}\n src={t.profile.logoUrl}\n size={40}\n />\n )}\n <div className={styles.currentMain}>\n <span className={styles.eyebrow}>Merchant</span>\n <span className={styles.currentName} title={t?.businessName}>\n {t ? t.businessName : <Skeleton width={160} height={20} />}\n </span>\n {t && (\n <span className={styles.currentMeta}>\n <StatusPill\n status={t.status}\n tone={STATUS_TONE[t.status]}\n />\n <span className={styles.sub}>\n {compactSales(\n t.metrics.byCurrency?.map((r) => ({\n currency: r.currency,\n amount: r.gmv,\n })),\n t.metrics.gmv,\n )}{' '}\n lifetime sales\n </span>\n <span className={styles.sub}>\n Shown in {t.currency || '
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/commerce/merchant-view.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\nimport { Button, Card, EmptyNote, ErrorBanner } from '@withpotter/ui-kit';\nimport { usePlatformTenant, usePlatformTenants } from '../hooks';\nimport { EntityAvatar, Reveal } from '../_fx';\nimport { Skeleton, type DateRange } from '../_ui';\nimport { MerchantCommerce } from '../tenants/[id]/commerce';\nimport { StatusPill } from '../tenants/[id]/commerce/status-pill';\nimport { bySales, compactSales, STATUS_TONE } from './merchant-meta';\nimport { MerchantPicker } from './merchant-picker';\nimport styles from './console.module.css';\n\n/** \"By merchant\": pick a merchant, then read their commerce. */\nexport function MerchantView({ range }: { range: DateRange }) {\n const router = useRouter();\n const pathname = usePathname();\n const params = useSearchParams();\n const [picking, setPicking] = useState(false);\n\n const top = usePlatformTenants({ pageSize: 50 });\n const fallback = bySales(top.data?.rows ?? [])[0]?.id ?? null;\n const id = params.get('merchant') || fallback;\n const tenant = usePlatformTenant(id ?? '', {\n startDate: range.startDate,\n endDate: range.endDate,\n });\n const t = tenant.data;\n\n const pick = (next: string) => {\n const qs = new URLSearchParams(params.toString());\n qs.set('merchant', next);\n router.replace(`${pathname}?${qs.toString()}`, { scroll: false });\n setPicking(false);\n };\n\n const noMerchants = !top.isLoading && !top.isError && !id;\n\n return (\n <div className={styles.body}>\n {top.isError && !id ? (\n <ErrorBanner>\n Merchants could not be loaded.{' '}\n <Button size=\"sm\" variant=\"secondary\" onClick={() => top.refetch()}>\n Try again\n </Button>\n </ErrorBanner>\n ) : noMerchants ? (\n <EmptyNote\n well\n action={\n <Button variant=\"secondary\" asChild>\n <Link href=\"/admin/tenants\">Go to merchants</Link>\n </Button>\n }\n >\n Once a business signs up, its items, orders and stock appear here.\n </EmptyNote>\n ) : (\n <>\n <Card>\n <Reveal className={styles.current}>\n {t?.profile?.logoUrl && (\n <EntityAvatar\n name={t.businessName}\n src={t.profile.logoUrl}\n size={40}\n />\n )}\n <div className={styles.currentMain}>\n <span className={styles.eyebrow}>Merchant</span>\n <span className={styles.currentName} title={t?.businessName}>\n {t ? t.businessName : <Skeleton width={160} height={20} />}\n </span>\n {t && (\n <span className={styles.currentMeta}>\n <StatusPill\n status={t.status}\n tone={STATUS_TONE[t.status]}\n />\n <span className={styles.sub}>\n {compactSales(\n t.metrics.byCurrency?.map((r) => ({\n currency: r.currency,\n amount: r.gmv,\n })),\n t.metrics.gmv,\n )}{' '}\n lifetime sales\n </span>\n <span className={styles.sub}>\n Shown in {t.currency || 'USD'}, the merchant’s currency\n </span>\n </span>\n )}\n </div>\n {id && (\n <Button variant=\"ghost\" asChild>\n <Link href={`/admin/tenants/${id}`}>Merchant profile</Link>\n </Button>\n )}\n <Button variant=\"secondary\" onClick={() => setPicking(true)}>\n Change merchant\n </Button>\n </Reveal>\n </Card>\n\n {id && (\n <MerchantCommerce\n key={id}\n tenantId={id}\n currency={t?.currency ?? 'USD'}\n range={range}\n />\n )}\n </>\n )}\n\n <MerchantPicker\n open={picking}\n onOpenChange={setPicking}\n selectedId={id}\n onPick={(row) => pick(row.id)}\n />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/admin/hooks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
3
|
import { platformAdminApi } from "@withpotter/lib/admin-api";
|
|
4
4
|
function useAdminSession(enabled = true) {
|
|
5
5
|
return useQuery({
|
|
@@ -28,49 +28,6 @@ function usePlatformRevenue(range = {}) {
|
|
|
28
28
|
queryFn: () => platformAdminApi.revenue(range)
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
function useGatewayChannels(range = {}) {
|
|
32
|
-
return useQuery({
|
|
33
|
-
queryKey: ["platform-admin", "gateway-channels", range],
|
|
34
|
-
queryFn: () => platformAdminApi.gatewayChannels(range),
|
|
35
|
-
retry: false,
|
|
36
|
-
staleTime: 6e4
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function useMerchantPayments(filters) {
|
|
40
|
-
return useQuery({
|
|
41
|
-
queryKey: ["platform-admin", "revenue", "merchant-payments", filters],
|
|
42
|
-
queryFn: () => platformAdminApi.merchantPayments(filters),
|
|
43
|
-
retry: false,
|
|
44
|
-
staleTime: 3e4,
|
|
45
|
-
placeholderData: keepPreviousData
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function useSubscriptionPayments(filters) {
|
|
49
|
-
return useQuery({
|
|
50
|
-
queryKey: ["platform-admin", "revenue", "subscription-payments", filters],
|
|
51
|
-
queryFn: () => platformAdminApi.subscriptionPayments(filters),
|
|
52
|
-
retry: false,
|
|
53
|
-
staleTime: 3e4,
|
|
54
|
-
placeholderData: keepPreviousData
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
function useMerchantRevenue(filters) {
|
|
58
|
-
return useQuery({
|
|
59
|
-
queryKey: ["platform-admin", "revenue", "merchants", filters],
|
|
60
|
-
queryFn: () => platformAdminApi.merchantRevenue(filters),
|
|
61
|
-
retry: false,
|
|
62
|
-
staleTime: 3e4,
|
|
63
|
-
placeholderData: keepPreviousData
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
function useMerchantOptions(range) {
|
|
67
|
-
return useQuery({
|
|
68
|
-
queryKey: ["platform-admin", "revenue", "merchant-options", range],
|
|
69
|
-
queryFn: () => platformAdminApi.merchantOptions(range),
|
|
70
|
-
retry: false,
|
|
71
|
-
staleTime: 6e4
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
31
|
function usePlatformTenantsAnalytics(range = {}) {
|
|
75
32
|
return useQuery({
|
|
76
33
|
queryKey: ["platform-admin", "tenants-analytics", range],
|
|
@@ -211,13 +168,6 @@ function useAdminRoles() {
|
|
|
211
168
|
queryFn: () => platformAdminApi.roles()
|
|
212
169
|
});
|
|
213
170
|
}
|
|
214
|
-
function useAccountSessions(id) {
|
|
215
|
-
return useQuery({
|
|
216
|
-
queryKey: ["platform-admin", "account-sessions", id],
|
|
217
|
-
queryFn: () => platformAdminApi.accountSessions(id),
|
|
218
|
-
enabled: !!id
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
171
|
function useAccountTenants(id) {
|
|
222
172
|
return useQuery({
|
|
223
173
|
queryKey: ["platform-admin", "account-tenants", id],
|
|
@@ -238,15 +188,10 @@ function usePlatformAuditAnalytics(range = {}) {
|
|
|
238
188
|
});
|
|
239
189
|
}
|
|
240
190
|
export {
|
|
241
|
-
useAccountSessions,
|
|
242
191
|
useAccountTenants,
|
|
243
192
|
useAdminPermissions,
|
|
244
193
|
useAdminRoles,
|
|
245
194
|
useAdminSession,
|
|
246
|
-
useGatewayChannels,
|
|
247
|
-
useMerchantOptions,
|
|
248
|
-
useMerchantPayments,
|
|
249
|
-
useMerchantRevenue,
|
|
250
195
|
usePlatformAccounts,
|
|
251
196
|
usePlatformAccountsAnalytics,
|
|
252
197
|
usePlatformAdmins,
|
|
@@ -259,7 +204,6 @@ export {
|
|
|
259
204
|
usePlatformTenant,
|
|
260
205
|
usePlatformTenants,
|
|
261
206
|
usePlatformTenantsAnalytics,
|
|
262
|
-
useSubscriptionPayments,
|
|
263
207
|
useTenantAnalytics,
|
|
264
208
|
useTenantCustomerInsights,
|
|
265
209
|
useTenantCustomers,
|