@withpotter/pages-admin 0.13.0-next.74 → 0.13.0-next.77

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.
Files changed (38) hide show
  1. package/dist/admin/_shell/nav-fold.js +1 -1
  2. package/dist/admin/_shell/nav-fold.js.map +1 -1
  3. package/dist/admin/_shell/nav-group.js +2 -2
  4. package/dist/admin/_shell/nav-group.js.map +1 -1
  5. package/dist/admin/_shell/sidebar.js +6 -3
  6. package/dist/admin/_shell/sidebar.js.map +1 -1
  7. package/dist/admin/_shell/use-open-groups.js +20 -0
  8. package/dist/admin/_shell/use-open-groups.js.map +1 -0
  9. package/dist/admin/accounts/account-panel.js +15 -4
  10. package/dist/admin/accounts/account-panel.js.map +1 -1
  11. package/dist/admin/accounts/account-panel.module.css +21 -0
  12. package/dist/admin/accounts/account-row.js +11 -2
  13. package/dist/admin/accounts/account-row.js.map +1 -1
  14. package/dist/admin/accounts/account-sessions.js +51 -0
  15. package/dist/admin/accounts/account-sessions.js.map +1 -0
  16. package/dist/admin/accounts/account-sessions.module.css +53 -0
  17. package/dist/admin/accounts/account-stage-filter.js +29 -0
  18. package/dist/admin/accounts/account-stage-filter.js.map +1 -0
  19. package/dist/admin/accounts/account-stage.js +47 -0
  20. package/dist/admin/accounts/account-stage.js.map +1 -0
  21. package/dist/admin/accounts/accounts-table.js +39 -8
  22. package/dist/admin/accounts/accounts-table.js.map +1 -1
  23. package/dist/admin/accounts/hint.js +12 -0
  24. package/dist/admin/accounts/hint.js.map +1 -0
  25. package/dist/admin/accounts/rows.module.css +17 -0
  26. package/dist/admin/hooks.js +8 -0
  27. package/dist/admin/hooks.js.map +1 -1
  28. package/dist/admin/settings/account-tab.js +1 -25
  29. package/dist/admin/settings/account-tab.js.map +1 -1
  30. package/dist/admin/tenants/tenant-list-row.js +2 -1
  31. package/dist/admin/tenants/tenant-list-row.js.map +1 -1
  32. package/dist/admin/tenants/tenants-table.js +2 -1
  33. package/dist/admin/tenants/tenants-table.js.map +1 -1
  34. package/package.json +5 -5
  35. package/dist/admin/_shell/use-open-group.js +0 -16
  36. package/dist/admin/_shell/use-open-group.js.map +0 -1
  37. package/dist/admin/settings/system-status-card.js +0 -30
  38. package/dist/admin/settings/system-status-card.js.map +0 -1
@@ -3,7 +3,9 @@ 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 { platformAdminApi } from "@withpotter/lib/admin-api";
6
+ import {
7
+ platformAdminApi
8
+ } from "@withpotter/lib/admin-api";
7
9
  import {
8
10
  ColumnPicker,
9
11
  FilterDates,
@@ -13,20 +15,27 @@ import {
13
15
  import { usePlatformAccounts } from "../hooks";
14
16
  import { AccountPanel } from "./account-panel";
15
17
  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";
16
21
  import { AccountListRow, PROVIDER_LABELS } from "./account-row";
17
22
  import { PROVIDER_LABELS as PROVIDER_LABELS2 } from "./account-row";
18
23
  const OPTIONAL_COLUMNS = [
19
24
  { key: "provider", label: "Provider" },
25
+ { key: "kyc", label: "KYC / KYB" },
26
+ { key: "stage", label: "Stage" },
20
27
  { key: "emailVerified", label: "Email verified" },
21
28
  { key: "workspaces", label: "Workspaces" },
22
29
  { key: "lastLogin", label: "Last login" },
23
30
  { key: "joined", label: "Joined" },
24
- { key: "mfa", label: "MFA enabled" },
31
+ { key: "firstSale", label: "First sale" },
25
32
  { key: "activeSessions", label: "Active sessions" },
26
33
  { key: "lastSeen", label: "Last seen" }
27
34
  ];
28
35
  const DEFAULT_VISIBLE = [
29
36
  "provider",
37
+ "kyc",
38
+ "stage",
30
39
  "emailVerified",
31
40
  "workspaces",
32
41
  "lastLogin",
@@ -55,13 +64,15 @@ function toCsvRow(a, visible) {
55
64
  cells.push(PROVIDER_LABELS[a.authProvider] ?? a.authProvider);
56
65
  }
57
66
  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] : "");
58
69
  if (visible.has("emailVerified")) {
59
70
  cells.push(a.emailVerified ? "Verified" : "Unverified");
60
71
  }
61
72
  if (visible.has("workspaces")) cells.push(String(a.workspaceCount ?? 0));
62
73
  if (visible.has("lastLogin")) cells.push(day(a.lastLoginAt) || "Never");
63
74
  if (visible.has("joined")) cells.push(day(a.createdAt));
64
- if (visible.has("mfa")) cells.push(a.mfaEnabled ? "Yes" : "No");
75
+ if (visible.has("firstSale")) cells.push(day(a.firstSaleAt) || "None yet");
65
76
  if (visible.has("activeSessions")) cells.push(String(a.activeSessions ?? 0));
66
77
  if (visible.has("lastSeen")) cells.push(day(a.lastSeenAt) || "Never");
67
78
  return cells;
@@ -73,6 +84,7 @@ function AccountsTable({
73
84
  const [search, setSearch] = useState("");
74
85
  const [joinedFrom, setJoinedFrom] = useState("");
75
86
  const [joinedTo, setJoinedTo] = useState("");
87
+ const [stage, setStage] = useState("");
76
88
  const [page, setPage] = useState(1);
77
89
  const [visible, setVisible] = useState(readVisibleColumns);
78
90
  const [exporting, setExporting] = useState(false);
@@ -81,7 +93,8 @@ function AccountsTable({
81
93
  pageSize: 20,
82
94
  search: search || void 0,
83
95
  joinedFrom: joinedFrom || void 0,
84
- joinedTo: joinedTo || void 0
96
+ joinedTo: joinedTo || void 0,
97
+ stage: stage || void 0
85
98
  });
86
99
  const current = data?.rows.find((row) => row.id === selected?.id) ?? selected;
87
100
  const totalPages = data ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1;
@@ -100,16 +113,19 @@ function AccountsTable({
100
113
  pageSize: 5e3,
101
114
  search: search || void 0,
102
115
  joinedFrom: joinedFrom || void 0,
103
- joinedTo: joinedTo || void 0
116
+ joinedTo: joinedTo || void 0,
117
+ stage: stage || void 0
104
118
  });
105
119
  const header = ["Name", "Email"];
106
120
  if (visible.has("provider")) header.push("Provider");
107
121
  header.push("Status");
122
+ if (visible.has("kyc")) header.push("KYC / KYB");
123
+ if (visible.has("stage")) header.push("Stage");
108
124
  if (visible.has("emailVerified")) header.push("Email verified");
109
125
  if (visible.has("workspaces")) header.push("Workspaces");
110
126
  if (visible.has("lastLogin")) header.push("Last login");
111
127
  if (visible.has("joined")) header.push("Joined");
112
- if (visible.has("mfa")) header.push("MFA enabled");
128
+ if (visible.has("firstSale")) header.push("First sale");
113
129
  if (visible.has("activeSessions")) header.push("Active sessions");
114
130
  if (visible.has("lastSeen")) header.push("Last seen");
115
131
  const rows = [header, ...page2.rows.map((a2) => toCsvRow(a2, visible))];
@@ -139,7 +155,7 @@ function AccountsTable({
139
155
  onRetry: () => void refetch(),
140
156
  errorTitle: "Failed to load accounts.",
141
157
  isEmpty: data?.rows.length === 0,
142
- emptyTitle: "No accounts match this search or join date.",
158
+ emptyTitle: "No accounts match these filters.",
143
159
  controls: /* @__PURE__ */ jsxs(Filters, { label: "Filter accounts", children: [
144
160
  /* @__PURE__ */ jsx(
145
161
  FilterSearch,
@@ -149,6 +165,16 @@ function AccountsTable({
149
165
  placeholder: "Search by email or name\u2026"
150
166
  }
151
167
  ),
168
+ /* @__PURE__ */ jsx(
169
+ AccountStageFilter,
170
+ {
171
+ value: stage,
172
+ onChange: (v) => {
173
+ setStage(v);
174
+ setPage(1);
175
+ }
176
+ }
177
+ ),
152
178
  /* @__PURE__ */ jsx(
153
179
  FilterDates,
154
180
  {
@@ -194,11 +220,16 @@ function AccountsTable({
194
220
  /* @__PURE__ */ jsx(Th, { children: "Account" }),
195
221
  visible.has("provider") && /* @__PURE__ */ jsx(Th, { children: "Provider" }),
196
222
  /* @__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
+ ] }),
197
228
  visible.has("emailVerified") && /* @__PURE__ */ jsx(Th, { children: "Email" }),
198
229
  visible.has("workspaces") && /* @__PURE__ */ jsx(Th, { align: "right", children: "Workspaces" }),
199
230
  visible.has("lastLogin") && /* @__PURE__ */ jsx(Th, { children: "Last login" }),
200
231
  visible.has("joined") && /* @__PURE__ */ jsx(Th, { children: "Joined" }),
201
- visible.has("mfa") && /* @__PURE__ */ jsx(Th, { children: "MFA" }),
232
+ visible.has("firstSale") && /* @__PURE__ */ jsx(Th, { children: "First sale" }),
202
233
  visible.has("activeSessions") && /* @__PURE__ */ jsx(Th, { align: "right", children: "Sessions" }),
203
234
  visible.has("lastSeen") && /* @__PURE__ */ jsx(Th, { children: "Last seen" }),
204
235
  /* @__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 { 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"]}
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"]}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Info } from "lucide-react";
4
+ import { Tooltip } from "@withpotter/ui-kit";
5
+ import styles from "./rows.module.css";
6
+ function Hint({ label }) {
7
+ return /* @__PURE__ */ jsx(Tooltip, { label, children: /* @__PURE__ */ jsx("button", { type: "button", className: styles.hint, "aria-label": label, children: /* @__PURE__ */ jsx(Info, { size: 13, "aria-hidden": true }) }) });
8
+ }
9
+ export {
10
+ Hint
11
+ };
12
+ //# sourceMappingURL=hint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/accounts/hint.tsx"],"sourcesContent":["'use client';\n\nimport { Info } from 'lucide-react';\nimport { Tooltip } from '@withpotter/ui-kit';\nimport styles from './rows.module.css';\n\n/** A small info icon that explains a term on hover or focus. */\nexport function Hint({ label }: { label: string }) {\n return (\n <Tooltip label={label}>\n <button type=\"button\" className={styles.hint} aria-label={label}>\n <Info size={13} aria-hidden />\n </button>\n </Tooltip>\n );\n}\n"],"mappings":";AAWQ;AATR,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,OAAO,YAAY;AAGZ,SAAS,KAAK,EAAE,MAAM,GAAsB;AACjD,SACE,oBAAC,WAAQ,OACP,8BAAC,YAAO,MAAK,UAAS,WAAW,OAAO,MAAM,cAAY,OACxD,8BAAC,QAAK,MAAM,IAAI,eAAW,MAAC,GAC9B,GACF;AAEJ;","names":[]}
@@ -65,3 +65,20 @@
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
+ }
@@ -168,6 +168,13 @@ function useAdminRoles() {
168
168
  queryFn: () => platformAdminApi.roles()
169
169
  });
170
170
  }
171
+ function useAccountSessions(id) {
172
+ return useQuery({
173
+ queryKey: ["platform-admin", "account-sessions", id],
174
+ queryFn: () => platformAdminApi.accountSessions(id),
175
+ enabled: !!id
176
+ });
177
+ }
171
178
  function useAccountTenants(id) {
172
179
  return useQuery({
173
180
  queryKey: ["platform-admin", "account-tenants", id],
@@ -188,6 +195,7 @@ function usePlatformAuditAnalytics(range = {}) {
188
195
  });
189
196
  }
190
197
  export {
198
+ useAccountSessions,
191
199
  useAccountTenants,
192
200
  useAdminPermissions,
193
201
  useAdminRoles,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin/hooks.ts"],"sourcesContent":["'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { platformAdminApi } from '@withpotter/lib/admin-api';\nimport type { TenantListParams } from '@withpotter/lib/admin-tenants-query';\n\nexport function useAdminSession(enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'session'],\n queryFn: () => platformAdminApi.me(),\n enabled,\n retry: false,\n staleTime: 60_000,\n });\n}\n\nexport function usePlatformOverview() {\n return useQuery({\n queryKey: ['platform-admin', 'overview'],\n queryFn: () => platformAdminApi.overview(),\n });\n}\n\nexport function usePlatformCockpit(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'cockpit', range],\n queryFn: () => platformAdminApi.cockpit(range),\n });\n}\n\nexport function usePlatformRevenue(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', range],\n queryFn: () => platformAdminApi.revenue(range),\n });\n}\n\nexport function usePlatformTenantsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants-analytics', range],\n queryFn: () => platformAdminApi.tenantsAnalytics(range),\n });\n}\n\nexport function usePlatformTenants(params: TenantListParams) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants', params],\n queryFn: () => platformAdminApi.tenants(params),\n });\n}\n\nexport function usePlatformTenant(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant', id, range],\n queryFn: () => platformAdminApi.tenant(id, range),\n enabled: !!id,\n });\n}\n\nexport function useTenantAnalytics(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-analytics', id, range],\n queryFn: () => platformAdminApi.tenantAnalytics(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantFinance(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-finance', id, range],\n queryFn: () => platformAdminApi.tenantFinance(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantTransactions(\n id: string,\n params: {\n status?: string;\n type?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-transactions', id, params],\n queryFn: () => platformAdminApi.tenantTransactions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomers(\n id: string,\n params: {\n search?: string;\n type?: string;\n status?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customers', id, params],\n queryFn: () => platformAdminApi.tenantCustomers(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProducts(\n id: string,\n params: { type?: string; search?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-products', id, params],\n queryFn: () => platformAdminApi.tenantProducts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProductInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-product-insights', id, range],\n queryFn: () => platformAdminApi.tenantProductInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomerInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customer-insights', id, range],\n queryFn: () => platformAdminApi.tenantCustomerInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantInvoices(\n id: string,\n params: {\n status?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-invoices', id, params],\n queryFn: () => platformAdminApi.tenantInvoices(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantLoyalty(id: string, enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-loyalty', id],\n queryFn: () => platformAdminApi.tenantLoyalty(id),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantDiscounts(\n id: string,\n params: {\n status?: string;\n discountType?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-discounts', id, params],\n queryFn: () => platformAdminApi.tenantDiscounts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSettlements(\n id: string,\n params: {\n page?: number;\n limit?: number;\n startDate?: string;\n endDate?: string;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-settlements', id, params],\n queryFn: () => platformAdminApi.tenantSettlements(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSubscriptions(\n id: string,\n params: {\n status?: string;\n planId?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-subscriptions', id, params],\n queryFn: () => platformAdminApi.tenantSubscriptions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function usePlatformAccounts(params: {\n page?: number;\n pageSize?: number;\n search?: string;\n joinedFrom?: string;\n joinedTo?: string;\n}) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts', params],\n queryFn: () => platformAdminApi.accounts(params),\n });\n}\n\nexport function usePlatformAccountsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts-analytics', range],\n queryFn: () => platformAdminApi.accountsAnalytics(range),\n });\n}\n\nexport function usePlatformAdmins() {\n return useQuery({\n queryKey: ['platform-admin', 'admins'],\n queryFn: () => platformAdminApi.admins(),\n });\n}\n\nexport function usePlatformAdminsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'admins-analytics', range],\n queryFn: () => platformAdminApi.adminsAnalytics(range),\n });\n}\n\nexport function useAdminPermissions() {\n return useQuery({\n queryKey: ['platform-admin', 'admin-permissions'],\n queryFn: () => platformAdminApi.adminPermissions(),\n staleTime: 5 * 60_000,\n });\n}\n\nexport function useAdminRoles() {\n return useQuery({\n queryKey: ['platform-admin', 'roles'],\n queryFn: () => platformAdminApi.roles(),\n });\n}\n\nexport function useAccountTenants(id: string | null) {\n return useQuery({\n queryKey: ['platform-admin', 'account-tenants', id],\n queryFn: () => platformAdminApi.accountTenants(id!),\n enabled: !!id,\n });\n}\n\nexport function usePlatformAudit(\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n action?: string;\n adminEmail?: string;\n from?: string;\n to?: string;\n } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit', params],\n queryFn: () => platformAdminApi.audit(params),\n });\n}\n\nexport function usePlatformAuditAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit-analytics', range],\n queryFn: () => platformAdminApi.auditAnalytics(range),\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/admin/hooks.ts"],"sourcesContent":["'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { platformAdminApi } from '@withpotter/lib/admin-api';\nimport type { TenantListParams } from '@withpotter/lib/admin-tenants-query';\nimport type { AccountStage } from '@withpotter/lib/admin-account-types';\n\nexport function useAdminSession(enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'session'],\n queryFn: () => platformAdminApi.me(),\n enabled,\n retry: false,\n staleTime: 60_000,\n });\n}\n\nexport function usePlatformOverview() {\n return useQuery({\n queryKey: ['platform-admin', 'overview'],\n queryFn: () => platformAdminApi.overview(),\n });\n}\n\nexport function usePlatformCockpit(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'cockpit', range],\n queryFn: () => platformAdminApi.cockpit(range),\n });\n}\n\nexport function usePlatformRevenue(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'revenue', range],\n queryFn: () => platformAdminApi.revenue(range),\n });\n}\n\nexport function usePlatformTenantsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants-analytics', range],\n queryFn: () => platformAdminApi.tenantsAnalytics(range),\n });\n}\n\nexport function usePlatformTenants(params: TenantListParams) {\n return useQuery({\n queryKey: ['platform-admin', 'tenants', params],\n queryFn: () => platformAdminApi.tenants(params),\n });\n}\n\nexport function usePlatformTenant(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant', id, range],\n queryFn: () => platformAdminApi.tenant(id, range),\n enabled: !!id,\n });\n}\n\nexport function useTenantAnalytics(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-analytics', id, range],\n queryFn: () => platformAdminApi.tenantAnalytics(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantFinance(\n id: string,\n range: { startDate?: string; endDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-finance', id, range],\n queryFn: () => platformAdminApi.tenantFinance(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantTransactions(\n id: string,\n params: {\n status?: string;\n type?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-transactions', id, params],\n queryFn: () => platformAdminApi.tenantTransactions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomers(\n id: string,\n params: {\n search?: string;\n type?: string;\n status?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customers', id, params],\n queryFn: () => platformAdminApi.tenantCustomers(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProducts(\n id: string,\n params: { type?: string; search?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-products', id, params],\n queryFn: () => platformAdminApi.tenantProducts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantProductInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-product-insights', id, range],\n queryFn: () => platformAdminApi.tenantProductInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantCustomerInsights(\n id: string,\n range: { startDate?: string } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-customer-insights', id, range],\n queryFn: () => platformAdminApi.tenantCustomerInsights(id, range),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantInvoices(\n id: string,\n params: {\n status?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-invoices', id, params],\n queryFn: () => platformAdminApi.tenantInvoices(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantLoyalty(id: string, enabled = true) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-loyalty', id],\n queryFn: () => platformAdminApi.tenantLoyalty(id),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantDiscounts(\n id: string,\n params: {\n status?: string;\n discountType?: string;\n search?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-discounts', id, params],\n queryFn: () => platformAdminApi.tenantDiscounts(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSettlements(\n id: string,\n params: {\n page?: number;\n limit?: number;\n startDate?: string;\n endDate?: string;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-settlements', id, params],\n queryFn: () => platformAdminApi.tenantSettlements(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function useTenantSubscriptions(\n id: string,\n params: {\n status?: string;\n planId?: string;\n page?: number;\n limit?: number;\n } = {},\n enabled = true,\n) {\n return useQuery({\n queryKey: ['platform-admin', 'tenant-subscriptions', id, params],\n queryFn: () => platformAdminApi.tenantSubscriptions(id, params),\n enabled: !!id && enabled,\n });\n}\n\nexport function usePlatformAccounts(params: {\n page?: number;\n pageSize?: number;\n search?: string;\n joinedFrom?: string;\n joinedTo?: string;\n stage?: AccountStage;\n}) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts', params],\n queryFn: () => platformAdminApi.accounts(params),\n });\n}\n\nexport function usePlatformAccountsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'accounts-analytics', range],\n queryFn: () => platformAdminApi.accountsAnalytics(range),\n });\n}\n\nexport function usePlatformAdmins() {\n return useQuery({\n queryKey: ['platform-admin', 'admins'],\n queryFn: () => platformAdminApi.admins(),\n });\n}\n\nexport function usePlatformAdminsAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'admins-analytics', range],\n queryFn: () => platformAdminApi.adminsAnalytics(range),\n });\n}\n\nexport function useAdminPermissions() {\n return useQuery({\n queryKey: ['platform-admin', 'admin-permissions'],\n queryFn: () => platformAdminApi.adminPermissions(),\n staleTime: 5 * 60_000,\n });\n}\n\nexport function useAdminRoles() {\n return useQuery({\n queryKey: ['platform-admin', 'roles'],\n queryFn: () => platformAdminApi.roles(),\n });\n}\n\nexport function useAccountSessions(id: string | null) {\n return useQuery({\n queryKey: ['platform-admin', 'account-sessions', id],\n queryFn: () => platformAdminApi.accountSessions(id!),\n enabled: !!id,\n });\n}\n\nexport function useAccountTenants(id: string | null) {\n return useQuery({\n queryKey: ['platform-admin', 'account-tenants', id],\n queryFn: () => platformAdminApi.accountTenants(id!),\n enabled: !!id,\n });\n}\n\nexport function usePlatformAudit(\n params: {\n page?: number;\n pageSize?: number;\n search?: string;\n action?: string;\n adminEmail?: string;\n from?: string;\n to?: string;\n } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit', params],\n queryFn: () => platformAdminApi.audit(params),\n });\n}\n\nexport function usePlatformAuditAnalytics(\n range: { startDate?: string; endDate?: string } = {},\n) {\n return useQuery({\n queryKey: ['platform-admin', 'audit-analytics', range],\n queryFn: () => platformAdminApi.auditAnalytics(range),\n });\n}\n"],"mappings":"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","names":[]}
@@ -2,21 +2,17 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
4
  import { useRouter } from "next/navigation";
5
- import { Button, useConfirm, useToast } from "@withpotter/ui-kit";
5
+ import { Button } from "@withpotter/ui-kit";
6
6
  import { SUPPORT_INBOX_EMAIL } from "@withpotter/lib/support-inbox";
7
7
  import { useAdminSession } from "../hooks";
8
- import { settingsStore } from "../_settings";
9
8
  import { useModuleOn } from "../_shell/modules-context";
10
9
  import { signOutAdmin } from "../_shell/sign-out";
11
10
  import { ChangePasswordDialog } from "./change-password-dialog";
12
11
  import { ProfileCard } from "./profile-card";
13
12
  import { SettingRow, SettingsCard } from "./setting-row";
14
- import { SystemStatusCard } from "./system-status-card";
15
13
  import styles from "./settings.module.css";
16
14
  function AccountTab() {
17
15
  const router = useRouter();
18
- const confirm = useConfirm();
19
- const { toast } = useToast();
20
16
  const { data: session } = useAdminSession();
21
17
  const [changing, setChanging] = useState(false);
22
18
  const [leaving, setLeaving] = useState(false);
@@ -26,17 +22,6 @@ function AccountTab() {
26
22
  await signOutAdmin();
27
23
  router.replace("/admin/login");
28
24
  };
29
- const reset = async () => {
30
- const ok = await confirm({
31
- title: "Reset settings on this device?",
32
- description: "Density, accessibility, notification and shortcut choices go back to their defaults. Your account is not affected.",
33
- confirmLabel: "Reset settings",
34
- tone: "danger"
35
- });
36
- if (!ok) return;
37
- settingsStore.reset();
38
- toast({ title: "Settings reset on this device" });
39
- };
40
25
  return /* @__PURE__ */ jsxs("div", { className: styles.stack, children: [
41
26
  session && /* @__PURE__ */ jsx(ProfileCard, { session }),
42
27
  /* @__PURE__ */ jsxs(SettingsCard, { title: "Security", children: [
@@ -57,14 +42,6 @@ function AccountTab() {
57
42
  }
58
43
  )
59
44
  ] }),
60
- /* @__PURE__ */ jsx(SettingsCard, { title: "This device", children: /* @__PURE__ */ jsx(
61
- SettingRow,
62
- {
63
- label: "Reset all settings on this device",
64
- description: "Every preference on this page returns to its default.",
65
- children: /* @__PURE__ */ jsx(Button, { variant: "danger", onClick: reset, children: "Reset" })
66
- }
67
- ) }),
68
45
  supportOn && /* @__PURE__ */ jsx(SettingsCard, { title: "Support inbox", children: /* @__PURE__ */ jsx(
69
46
  SettingRow,
70
47
  {
@@ -73,7 +50,6 @@ function AccountTab() {
73
50
  children: /* @__PURE__ */ jsx("span", { className: styles.value, title: SUPPORT_INBOX_EMAIL, children: SUPPORT_INBOX_EMAIL })
74
51
  }
75
52
  ) }),
76
- /* @__PURE__ */ jsx(SystemStatusCard, {}),
77
53
  changing && /* @__PURE__ */ jsx(ChangePasswordDialog, { onClose: () => setChanging(false) })
78
54
  ] });
79
55
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/settings/account-tab.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { Button, useConfirm, useToast } from '@withpotter/ui-kit';\nimport { SUPPORT_INBOX_EMAIL } from '@withpotter/lib/support-inbox';\nimport { useAdminSession } from '../hooks';\nimport { settingsStore } from '../_settings';\nimport { useModuleOn } from '../_shell/modules-context';\nimport { signOutAdmin } from '../_shell/sign-out';\nimport { ChangePasswordDialog } from './change-password-dialog';\nimport { ProfileCard } from './profile-card';\nimport { SettingRow, SettingsCard } from './setting-row';\nimport { SystemStatusCard } from './system-status-card';\nimport styles from './settings.module.css';\n\n/**\n * Who you are, how you sign in, and the box's own health. The support inbox\n * address shows only where this box serves Support.\n */\nexport function AccountTab() {\n const router = useRouter();\n const confirm = useConfirm();\n const { toast } = useToast();\n const { data: session } = useAdminSession();\n const [changing, setChanging] = useState(false);\n const [leaving, setLeaving] = useState(false);\n const supportOn = useModuleOn('support');\n\n const signOut = async () => {\n setLeaving(true);\n await signOutAdmin();\n router.replace('/admin/login');\n };\n\n const reset = async () => {\n const ok = await confirm({\n title: 'Reset settings on this device?',\n description:\n 'Density, accessibility, notification and shortcut choices go back to their defaults. Your account is not affected.',\n confirmLabel: 'Reset settings',\n tone: 'danger',\n });\n if (!ok) return;\n settingsStore.reset();\n toast({ title: 'Settings reset on this device' });\n };\n\n return (\n <div className={styles.stack}>\n {session && <ProfileCard session={session} />}\n <SettingsCard title=\"Security\">\n <SettingRow\n label=\"Password\"\n description=\"At least 12 characters. You stay signed in here.\"\n >\n <Button variant=\"secondary\" onClick={() => setChanging(true)}>\n Change password\n </Button>\n </SettingRow>\n <SettingRow\n label=\"Sign out\"\n description=\"Also ends any View as owner session.\"\n >\n <Button variant=\"secondary\" loading={leaving} onClick={signOut}>\n Sign out\n </Button>\n </SettingRow>\n </SettingsCard>\n <SettingsCard title=\"This device\">\n <SettingRow\n label=\"Reset all settings on this device\"\n description=\"Every preference on this page returns to its default.\"\n >\n <Button variant=\"danger\" onClick={reset}>\n Reset\n </Button>\n </SettingRow>\n </SettingsCard>\n {supportOn && (\n <SettingsCard title=\"Support inbox\">\n <SettingRow\n label=\"Inbound address\"\n description=\"Merchants write here; each email opens a case in Support.\"\n >\n <span className={styles.value} title={SUPPORT_INBOX_EMAIL}>\n {SUPPORT_INBOX_EMAIL}\n </span>\n </SettingRow>\n </SettingsCard>\n )}\n <SystemStatusCard />\n {changing && <ChangePasswordDialog onClose={() => setChanging(false)} />}\n </div>\n );\n}\n"],"mappings":";AAkDkB,cACZ,YADY;AAhDlB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,QAAQ,YAAY,gBAAgB;AAC7C,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B,SAAS,4BAA4B;AACrC,SAAS,mBAAmB;AAC5B,SAAS,YAAY,oBAAoB;AACzC,SAAS,wBAAwB;AACjC,OAAO,YAAY;AAMZ,SAAS,aAAa;AAC3B,QAAM,SAAS,UAAU;AACzB,QAAM,UAAU,WAAW;AAC3B,QAAM,EAAE,MAAM,IAAI,SAAS;AAC3B,QAAM,EAAE,MAAM,QAAQ,IAAI,gBAAgB;AAC1C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,YAAY,YAAY,SAAS;AAEvC,QAAM,UAAU,YAAY;AAC1B,eAAW,IAAI;AACf,UAAM,aAAa;AACnB,WAAO,QAAQ,cAAc;AAAA,EAC/B;AAEA,QAAM,QAAQ,YAAY;AACxB,UAAM,KAAK,MAAM,QAAQ;AAAA,MACvB,OAAO;AAAA,MACP,aACE;AAAA,MACF,cAAc;AAAA,MACd,MAAM;AAAA,IACR,CAAC;AACD,QAAI,CAAC,GAAI;AACT,kBAAc,MAAM;AACpB,UAAM,EAAE,OAAO,gCAAgC,CAAC;AAAA,EAClD;AAEA,SACE,qBAAC,SAAI,WAAW,OAAO,OACpB;AAAA,eAAW,oBAAC,eAAY,SAAkB;AAAA,IAC3C,qBAAC,gBAAa,OAAM,YAClB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,aAAY;AAAA,UAEZ,8BAAC,UAAO,SAAQ,aAAY,SAAS,MAAM,YAAY,IAAI,GAAG,6BAE9D;AAAA;AAAA,MACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,aAAY;AAAA,UAEZ,8BAAC,UAAO,SAAQ,aAAY,SAAS,SAAS,SAAS,SAAS,sBAEhE;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IACA,oBAAC,gBAAa,OAAM,eAClB;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QAEZ,8BAAC,UAAO,SAAQ,UAAS,SAAS,OAAO,mBAEzC;AAAA;AAAA,IACF,GACF;AAAA,IACC,aACC,oBAAC,gBAAa,OAAM,iBAClB;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QAEZ,8BAAC,UAAK,WAAW,OAAO,OAAO,OAAO,qBACnC,+BACH;AAAA;AAAA,IACF,GACF;AAAA,IAEF,oBAAC,oBAAiB;AAAA,IACjB,YAAY,oBAAC,wBAAqB,SAAS,MAAM,YAAY,KAAK,GAAG;AAAA,KACxE;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/settings/account-tab.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { Button } from '@withpotter/ui-kit';\nimport { SUPPORT_INBOX_EMAIL } from '@withpotter/lib/support-inbox';\nimport { useAdminSession } from '../hooks';\nimport { useModuleOn } from '../_shell/modules-context';\nimport { signOutAdmin } from '../_shell/sign-out';\nimport { ChangePasswordDialog } from './change-password-dialog';\nimport { ProfileCard } from './profile-card';\nimport { SettingRow, SettingsCard } from './setting-row';\nimport styles from './settings.module.css';\n\n/**\n * Who you are and how you sign in. The support inbox\n * address shows only where this box serves Support.\n */\nexport function AccountTab() {\n const router = useRouter();\n const { data: session } = useAdminSession();\n const [changing, setChanging] = useState(false);\n const [leaving, setLeaving] = useState(false);\n const supportOn = useModuleOn('support');\n\n const signOut = async () => {\n setLeaving(true);\n await signOutAdmin();\n router.replace('/admin/login');\n };\n\n return (\n <div className={styles.stack}>\n {session && <ProfileCard session={session} />}\n <SettingsCard title=\"Security\">\n <SettingRow\n label=\"Password\"\n description=\"At least 12 characters. You stay signed in here.\"\n >\n <Button variant=\"secondary\" onClick={() => setChanging(true)}>\n Change password\n </Button>\n </SettingRow>\n <SettingRow\n label=\"Sign out\"\n description=\"Also ends any View as owner session.\"\n >\n <Button variant=\"secondary\" loading={leaving} onClick={signOut}>\n Sign out\n </Button>\n </SettingRow>\n </SettingsCard>\n {supportOn && (\n <SettingsCard title=\"Support inbox\">\n <SettingRow\n label=\"Inbound address\"\n description=\"Merchants write here; each email opens a case in Support.\"\n >\n <span className={styles.value} title={SUPPORT_INBOX_EMAIL}>\n {SUPPORT_INBOX_EMAIL}\n </span>\n </SettingRow>\n </SettingsCard>\n )}\n {changing && <ChangePasswordDialog onClose={() => setChanging(false)} />}\n </div>\n );\n}\n"],"mappings":";AAiCkB,cACZ,YADY;AA/BlB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,cAAc;AACvB,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B,SAAS,4BAA4B;AACrC,SAAS,mBAAmB;AAC5B,SAAS,YAAY,oBAAoB;AACzC,OAAO,YAAY;AAMZ,SAAS,aAAa;AAC3B,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,MAAM,QAAQ,IAAI,gBAAgB;AAC1C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,YAAY,YAAY,SAAS;AAEvC,QAAM,UAAU,YAAY;AAC1B,eAAW,IAAI;AACf,UAAM,aAAa;AACnB,WAAO,QAAQ,cAAc;AAAA,EAC/B;AAEA,SACE,qBAAC,SAAI,WAAW,OAAO,OACpB;AAAA,eAAW,oBAAC,eAAY,SAAkB;AAAA,IAC3C,qBAAC,gBAAa,OAAM,YAClB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,aAAY;AAAA,UAEZ,8BAAC,UAAO,SAAQ,aAAY,SAAS,MAAM,YAAY,IAAI,GAAG,6BAE9D;AAAA;AAAA,MACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,aAAY;AAAA,UAEZ,8BAAC,UAAO,SAAQ,aAAY,SAAS,SAAS,SAAS,SAAS,sBAEhE;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IACC,aACC,oBAAC,gBAAa,OAAM,iBAClB;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QAEZ,8BAAC,UAAK,WAAW,OAAO,OAAO,OAAO,qBACnC,+BACH;AAAA;AAAA,IACF,GACF;AAAA,IAED,YAAY,oBAAC,wBAAqB,SAAS,MAAM,YAAY,KAAK,GAAG;AAAA,KACxE;AAEJ;","names":[]}
@@ -95,9 +95,10 @@ function TenantListRow({
95
95
  children: t.businessName
96
96
  }
97
97
  ),
98
- /* @__PURE__ */ jsx("span", { className: rows.secondary, title: t.slug, children: t.slug })
98
+ /* @__PURE__ */ jsx("span", { className: rows.secondary, title: t.slug, children: [t.slug, t.phone].filter(Boolean).join(" \xB7 ") })
99
99
  ] })
100
100
  ] }) }),
101
+ /* @__PURE__ */ jsx("td", { className: `${list.clip} ${list.muted}`, children: /* @__PURE__ */ jsx("span", { title: t.email ?? t.ownerEmail ?? void 0, children: t.email ?? t.ownerEmail ?? EMPTY }) }),
101
102
  /* @__PURE__ */ jsx("td", { className: `${list.clip} ${list.muted}`, children: countryText(t.country, t.countryCode) ? /* @__PURE__ */ jsx(CountryLabel, { country: t.country, code: t.countryCode }) : EMPTY }),
102
103
  /* @__PURE__ */ jsx("td", { className: `${list.clip} ${list.muted}`, children: t.industryKey ?? EMPTY }),
103
104
  /* @__PURE__ */ jsx("td", { className: list.num, children: /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/tenants/tenant-list-row.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport {\n OverflowItem,\n OverflowMenu,\n TableRow,\n useConfirm,\n useToast,\n} from '@withpotter/ui-kit';\nimport { platformAdminApi, type TenantRow } from '@withpotter/lib/admin-api';\nimport { EntityAvatar } from '../_fx';\nimport { CountryLabel } from '../_ui/country-label';\nimport { countryText } from '../_ui/country-text';\nimport { EMPTY } from '../_ui/list-card';\nimport { MoneyLines } from '../_ui/money-lines';\nimport { useAccountActions } from '../accounts/use-account-actions';\nimport { useModuleOn } from '../_shell/modules-context';\nimport { useAdminSession } from '../hooks';\nimport { StatusPill } from '../audit/status-pill';\nimport { AccountOfficerDialog } from './[id]/account-officer-dialog';\nimport { officerAction } from './account-officer-action';\nimport { logoOf } from './tenants-logo';\nimport list from '../_ui/list-card.module.css';\nimport rows from '../accounts/rows.module.css';\n\n/** One business: identity, money, status and a ••• menu. */\nexport function TenantListRow({\n t,\n onOpen,\n}: {\n t: TenantRow;\n onOpen: () => void;\n}) {\n const queryClient = useQueryClient();\n const confirm = useConfirm();\n const { toast } = useToast();\n const { impersonate } = useAccountActions();\n const ownerView = useModuleOn('ownerView');\n const { data: session } = useAdminSession();\n const officerChoice = officerAction(\n t.accountOfficer,\n session?.role === 'superadmin',\n t.status,\n );\n const [picking, setPicking] = useState(false);\n const href = `/admin/tenants/${t.id}`;\n const suspended = t.status === 'suspended';\n const logo = logoOf(t);\n const fail = (title: string) => (e: Error) =>\n toast({ title, description: e.message, variant: 'destructive' });\n\n const status = useMutation({\n mutationFn: () =>\n platformAdminApi.setTenantStatus(\n t.id,\n suspended ? 'active' : 'suspended',\n ),\n onSuccess: () => {\n toast({\n title: `${t.businessName} ${suspended ? 'restored' : 'suspended'}`,\n });\n void queryClient.invalidateQueries({\n queryKey: ['platform-admin', 'tenants'],\n });\n },\n onError: fail('The status was not changed'),\n });\n\n // The owner is looked up first, so the tab is reserved inside the click\n // (before the await); opened afterwards it would be blocked as a pop-up.\n const viewAsOwner = useMutation({\n mutationFn: async (tab: Window | null) => {\n const detail = await platformAdminApi.tenant(t.id);\n const owner = detail.owner?.accountId;\n\n if (!owner) throw new Error('This business has no owner account.');\n\n impersonate.mutate(owner, tab);\n },\n onError: (error, tab) => {\n tab?.close();\n fail('Could not open the owner’s view')(error);\n },\n });\n\n const toggle = async () => {\n const ok = await confirm({\n title: suspended\n ? `Restore ${t.businessName}?`\n : `Suspend ${t.businessName}?`,\n description: suspended\n ? 'Their store and dashboard come back online straight away.'\n : 'Their store goes offline and their team loses access until restored.',\n confirmLabel: suspended ? 'Restore' : 'Suspend',\n tone: suspended ? 'default' : 'danger',\n });\n if (ok) status.mutate();\n };\n\n return (\n <TableRow onClick={onOpen}>\n <td>\n <span className={rows.identity}>\n {logo && <EntityAvatar name={t.businessName} src={logo} size={32} />}\n <span className={rows.identityText}>\n <Link\n href={href}\n className={rows.primary}\n title={t.businessName}\n onClick={(e) => e.stopPropagation()}\n >\n {t.businessName}\n </Link>\n <span className={rows.secondary} title={t.slug}>\n {t.slug}\n </span>\n </span>\n </span>\n </td>\n <td className={`${list.clip} ${list.muted}`}>\n {countryText(t.country, t.countryCode) ? (\n <CountryLabel country={t.country} code={t.countryCode} />\n ) : (\n EMPTY\n )}\n </td>\n <td className={`${list.clip} ${list.muted}`}>{t.industryKey ?? EMPTY}</td>\n <td className={list.num}>\n {/* One line per currency the business sells in; never added up. */}\n <MoneyLines\n rows={t.gmvByCurrency}\n currency=\"\"\n amount={(r) => r.amount}\n empty={EMPTY}\n />\n </td>\n <td className={list.nowrap}>\n <StatusPill status={t.status} />\n </td>\n <td\n className={`${list.clip} ${list.muted}`}\n onClick={(e) => e.stopPropagation()}\n >\n {officerChoice ? (\n <button\n type=\"button\"\n className={rows.nameButton}\n title={\n t.accountOfficer\n ? `${t.accountOfficer.name}. Change the account officer`\n : 'Assign an account officer'\n }\n onClick={() => setPicking(true)}\n >\n {t.accountOfficer?.name ?? 'Assign'}\n </button>\n ) : (\n (t.accountOfficer?.name ?? EMPTY)\n )}\n </td>\n <td className={`${list.nowrap} ${list.muted}`}>\n {new Date(t.createdAt).toLocaleDateString()}\n </td>\n <td className={rows.menuCell} onClick={(e) => e.stopPropagation()}>\n <OverflowMenu label={`Actions for ${t.businessName}`}>\n <OverflowItem onClick={onOpen}>View merchant</OverflowItem>\n {ownerView && (\n <OverflowItem\n disabled={viewAsOwner.isPending}\n onClick={() => viewAsOwner.mutate(impersonate.reserveTab())}\n >\n View as owner\n </OverflowItem>\n )}\n {officerChoice && (\n <OverflowItem onClick={() => setPicking(true)}>\n {officerChoice === 'assign'\n ? 'Assign account officer'\n : 'Change account officer'}\n </OverflowItem>\n )}\n {t.status !== 'deleted' && (\n <OverflowItem\n onClick={() => void toggle()}\n destructive={!suspended}\n >\n {suspended ? 'Restore' : 'Suspend'}\n </OverflowItem>\n )}\n </OverflowMenu>\n {picking && (\n <AccountOfficerDialog\n open\n tenantId={t.id}\n name={t.businessName}\n currentId={t.accountOfficer?.id ?? null}\n onClose={() => setPicking(false)}\n />\n )}\n </td>\n </TableRow>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/tenants/tenant-list-row.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport Link from 'next/link';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport {\n OverflowItem,\n OverflowMenu,\n TableRow,\n useConfirm,\n useToast,\n} from '@withpotter/ui-kit';\nimport { platformAdminApi, type TenantRow } from '@withpotter/lib/admin-api';\nimport { EntityAvatar } from '../_fx';\nimport { CountryLabel } from '../_ui/country-label';\nimport { countryText } from '../_ui/country-text';\nimport { EMPTY } from '../_ui/list-card';\nimport { MoneyLines } from '../_ui/money-lines';\nimport { useAccountActions } from '../accounts/use-account-actions';\nimport { useModuleOn } from '../_shell/modules-context';\nimport { useAdminSession } from '../hooks';\nimport { StatusPill } from '../audit/status-pill';\nimport { AccountOfficerDialog } from './[id]/account-officer-dialog';\nimport { officerAction } from './account-officer-action';\nimport { logoOf } from './tenants-logo';\nimport list from '../_ui/list-card.module.css';\nimport rows from '../accounts/rows.module.css';\n\n/** One business: identity, money, status and a ••• menu. */\nexport function TenantListRow({\n t,\n onOpen,\n}: {\n t: TenantRow;\n onOpen: () => void;\n}) {\n const queryClient = useQueryClient();\n const confirm = useConfirm();\n const { toast } = useToast();\n const { impersonate } = useAccountActions();\n const ownerView = useModuleOn('ownerView');\n const { data: session } = useAdminSession();\n const officerChoice = officerAction(\n t.accountOfficer,\n session?.role === 'superadmin',\n t.status,\n );\n const [picking, setPicking] = useState(false);\n const href = `/admin/tenants/${t.id}`;\n const suspended = t.status === 'suspended';\n const logo = logoOf(t);\n const fail = (title: string) => (e: Error) =>\n toast({ title, description: e.message, variant: 'destructive' });\n\n const status = useMutation({\n mutationFn: () =>\n platformAdminApi.setTenantStatus(\n t.id,\n suspended ? 'active' : 'suspended',\n ),\n onSuccess: () => {\n toast({\n title: `${t.businessName} ${suspended ? 'restored' : 'suspended'}`,\n });\n void queryClient.invalidateQueries({\n queryKey: ['platform-admin', 'tenants'],\n });\n },\n onError: fail('The status was not changed'),\n });\n\n // The owner is looked up first, so the tab is reserved inside the click\n // (before the await); opened afterwards it would be blocked as a pop-up.\n const viewAsOwner = useMutation({\n mutationFn: async (tab: Window | null) => {\n const detail = await platformAdminApi.tenant(t.id);\n const owner = detail.owner?.accountId;\n\n if (!owner) throw new Error('This business has no owner account.');\n\n impersonate.mutate(owner, tab);\n },\n onError: (error, tab) => {\n tab?.close();\n fail('Could not open the owner’s view')(error);\n },\n });\n\n const toggle = async () => {\n const ok = await confirm({\n title: suspended\n ? `Restore ${t.businessName}?`\n : `Suspend ${t.businessName}?`,\n description: suspended\n ? 'Their store and dashboard come back online straight away.'\n : 'Their store goes offline and their team loses access until restored.',\n confirmLabel: suspended ? 'Restore' : 'Suspend',\n tone: suspended ? 'default' : 'danger',\n });\n if (ok) status.mutate();\n };\n\n return (\n <TableRow onClick={onOpen}>\n <td>\n <span className={rows.identity}>\n {logo && <EntityAvatar name={t.businessName} src={logo} size={32} />}\n <span className={rows.identityText}>\n <Link\n href={href}\n className={rows.primary}\n title={t.businessName}\n onClick={(e) => e.stopPropagation()}\n >\n {t.businessName}\n </Link>\n <span className={rows.secondary} title={t.slug}>\n {[t.slug, t.phone].filter(Boolean).join(' · ')}\n </span>\n </span>\n </span>\n </td>\n <td className={`${list.clip} ${list.muted}`}>\n <span title={t.email ?? t.ownerEmail ?? undefined}>\n {t.email ?? t.ownerEmail ?? EMPTY}\n </span>\n </td>\n <td className={`${list.clip} ${list.muted}`}>\n {countryText(t.country, t.countryCode) ? (\n <CountryLabel country={t.country} code={t.countryCode} />\n ) : (\n EMPTY\n )}\n </td>\n <td className={`${list.clip} ${list.muted}`}>{t.industryKey ?? EMPTY}</td>\n <td className={list.num}>\n {/* One line per currency the business sells in; never added up. */}\n <MoneyLines\n rows={t.gmvByCurrency}\n currency=\"\"\n amount={(r) => r.amount}\n empty={EMPTY}\n />\n </td>\n <td className={list.nowrap}>\n <StatusPill status={t.status} />\n </td>\n <td\n className={`${list.clip} ${list.muted}`}\n onClick={(e) => e.stopPropagation()}\n >\n {officerChoice ? (\n <button\n type=\"button\"\n className={rows.nameButton}\n title={\n t.accountOfficer\n ? `${t.accountOfficer.name}. Change the account officer`\n : 'Assign an account officer'\n }\n onClick={() => setPicking(true)}\n >\n {t.accountOfficer?.name ?? 'Assign'}\n </button>\n ) : (\n (t.accountOfficer?.name ?? EMPTY)\n )}\n </td>\n <td className={`${list.nowrap} ${list.muted}`}>\n {new Date(t.createdAt).toLocaleDateString()}\n </td>\n <td className={rows.menuCell} onClick={(e) => e.stopPropagation()}>\n <OverflowMenu label={`Actions for ${t.businessName}`}>\n <OverflowItem onClick={onOpen}>View merchant</OverflowItem>\n {ownerView && (\n <OverflowItem\n disabled={viewAsOwner.isPending}\n onClick={() => viewAsOwner.mutate(impersonate.reserveTab())}\n >\n View as owner\n </OverflowItem>\n )}\n {officerChoice && (\n <OverflowItem onClick={() => setPicking(true)}>\n {officerChoice === 'assign'\n ? 'Assign account officer'\n : 'Change account officer'}\n </OverflowItem>\n )}\n {t.status !== 'deleted' && (\n <OverflowItem\n onClick={() => void toggle()}\n destructive={!suspended}\n >\n {suspended ? 'Restore' : 'Suspend'}\n </OverflowItem>\n )}\n </OverflowMenu>\n {picking && (\n <AccountOfficerDialog\n open\n tenantId={t.id}\n name={t.businessName}\n currentId={t.accountOfficer?.id ?? null}\n onClose={() => setPicking(false)}\n />\n )}\n </td>\n </TableRow>\n );\n}\n"],"mappings":"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","names":[]}
@@ -37,7 +37,7 @@ function TenantsTable() {
37
37
  {
38
38
  title: "All merchants",
39
39
  count: data?.total,
40
- columns: 8,
40
+ columns: 9,
41
41
  minWidth: 1e3,
42
42
  isLoading,
43
43
  isError,
@@ -99,6 +99,7 @@ function TenantsTable() {
99
99
  ] }),
100
100
  head: /* @__PURE__ */ jsxs("tr", { children: [
101
101
  /* @__PURE__ */ jsx(Th, { children: "Business" }),
102
+ /* @__PURE__ */ jsx(Th, { children: "Email" }),
102
103
  /* @__PURE__ */ jsx(Th, { children: "Country" }),
103
104
  /* @__PURE__ */ jsx(Th, { children: "Industry" }),
104
105
  /* @__PURE__ */ jsx(Th, { align: "right", children: "GMV (USD)" }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/tenants/tenants-table.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { Th } from '@withpotter/ui-kit';\nimport type { TenantStatus } from '@withpotter/lib/admin-api';\nimport { usePlatformTenants } from '../hooks';\nimport { ListCard, ListPager } from '../_ui/list-card';\nimport { TenantListRow } from './tenant-list-row';\nimport { FilterSearch, FilterSelect, Filters } from '../_ui';\nimport { CountryFilter, useCountryParam } from './country-filter';\nimport { AccountOfficerFilter, useOfficerParam } from './account-officer-filter';\n\nconst STATUS_OPTIONS: TenantStatus[] = [\n 'active',\n 'pending',\n 'suspended',\n 'deleted',\n];\n\nconst sentence = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);\n\n/** Every business, searchable by name or slug, narrowed by status, country or officer. */\nexport function TenantsTable() {\n const router = useRouter();\n const [search, setSearch] = useState('');\n const [status, setStatus] = useState<TenantStatus | ''>('');\n const [country, setCountry] = useCountryParam();\n const [officer, setOfficer] = useOfficerParam();\n const [page, setPage] = useState(1);\n const { data, isLoading, isError, refetch } = usePlatformTenants({\n page,\n pageSize: 20,\n search: search || undefined,\n status: status || undefined,\n country: country || undefined,\n accountOfficerId: officer || undefined,\n });\n const totalPages = data\n ? Math.max(1, Math.ceil(data.total / data.pageSize))\n : 1;\n\n return (\n <ListCard\n title=\"All merchants\"\n count={data?.total}\n columns={8}\n minWidth={1000}\n isLoading={isLoading}\n isError={isError}\n onRetry={() => void refetch()}\n errorTitle=\"Failed to load merchants.\"\n isEmpty={data?.rows.length === 0}\n emptyTitle=\"No merchants found\"\n emptyDescription=\"Try a different search, status, country or officer.\"\n controls={\n <Filters label=\"Filter merchants\">\n <FilterSearch\n value={search}\n onChange={(v) => {\n setSearch(v);\n setPage(1);\n }}\n placeholder=\"Search by name or slug…\"\n />\n <FilterSelect\n label=\"Status\"\n value={status}\n onChange={(v) => {\n setStatus(v as TenantStatus | '');\n setPage(1);\n }}\n options={[\n { value: '', label: 'All statuses' },\n ...STATUS_OPTIONS.map((s) => ({\n value: s,\n label: sentence(s),\n })),\n ]}\n />\n <CountryFilter\n value={country}\n onChange={(v) => {\n setCountry(v);\n setPage(1);\n }}\n />\n <AccountOfficerFilter\n value={officer}\n onChange={(v) => {\n setOfficer(v);\n setPage(1);\n }}\n />\n </Filters>\n }\n head={\n <tr>\n <Th>Business</Th>\n <Th>Country</Th>\n <Th>Industry</Th>\n <Th align=\"right\">GMV (USD)</Th>\n <Th>Status</Th>\n <Th>Account officer</Th>\n <Th>Joined</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=\"merchants\"\n onPage={setPage}\n />\n }\n >\n {data?.rows.map((t) => (\n <TenantListRow\n key={t.id}\n t={t}\n onOpen={() => router.push(`/admin/tenants/${t.id}`)}\n />\n ))}\n </ListCard>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/tenants/tenants-table.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { Th } from '@withpotter/ui-kit';\nimport type { TenantStatus } from '@withpotter/lib/admin-api';\nimport { usePlatformTenants } from '../hooks';\nimport { ListCard, ListPager } from '../_ui/list-card';\nimport { TenantListRow } from './tenant-list-row';\nimport { FilterSearch, FilterSelect, Filters } from '../_ui';\nimport { CountryFilter, useCountryParam } from './country-filter';\nimport { AccountOfficerFilter, useOfficerParam } from './account-officer-filter';\n\nconst STATUS_OPTIONS: TenantStatus[] = [\n 'active',\n 'pending',\n 'suspended',\n 'deleted',\n];\n\nconst sentence = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);\n\n/** Every business, searchable by name or slug, narrowed by status, country or officer. */\nexport function TenantsTable() {\n const router = useRouter();\n const [search, setSearch] = useState('');\n const [status, setStatus] = useState<TenantStatus | ''>('');\n const [country, setCountry] = useCountryParam();\n const [officer, setOfficer] = useOfficerParam();\n const [page, setPage] = useState(1);\n const { data, isLoading, isError, refetch } = usePlatformTenants({\n page,\n pageSize: 20,\n search: search || undefined,\n status: status || undefined,\n country: country || undefined,\n accountOfficerId: officer || undefined,\n });\n const totalPages = data\n ? Math.max(1, Math.ceil(data.total / data.pageSize))\n : 1;\n\n return (\n <ListCard\n title=\"All merchants\"\n count={data?.total}\n columns={9}\n minWidth={1000}\n isLoading={isLoading}\n isError={isError}\n onRetry={() => void refetch()}\n errorTitle=\"Failed to load merchants.\"\n isEmpty={data?.rows.length === 0}\n emptyTitle=\"No merchants found\"\n emptyDescription=\"Try a different search, status, country or officer.\"\n controls={\n <Filters label=\"Filter merchants\">\n <FilterSearch\n value={search}\n onChange={(v) => {\n setSearch(v);\n setPage(1);\n }}\n placeholder=\"Search by name or slug…\"\n />\n <FilterSelect\n label=\"Status\"\n value={status}\n onChange={(v) => {\n setStatus(v as TenantStatus | '');\n setPage(1);\n }}\n options={[\n { value: '', label: 'All statuses' },\n ...STATUS_OPTIONS.map((s) => ({\n value: s,\n label: sentence(s),\n })),\n ]}\n />\n <CountryFilter\n value={country}\n onChange={(v) => {\n setCountry(v);\n setPage(1);\n }}\n />\n <AccountOfficerFilter\n value={officer}\n onChange={(v) => {\n setOfficer(v);\n setPage(1);\n }}\n />\n </Filters>\n }\n head={\n <tr>\n <Th>Business</Th>\n <Th>Email</Th>\n <Th>Country</Th>\n <Th>Industry</Th>\n <Th align=\"right\">GMV (USD)</Th>\n <Th>Status</Th>\n <Th>Account officer</Th>\n <Th>Joined</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=\"merchants\"\n onPage={setPage}\n />\n }\n >\n {data?.rows.map((t) => (\n <TenantListRow\n key={t.id}\n t={t}\n onOpen={() => router.push(`/admin/tenants/${t.id}`)}\n />\n ))}\n </ListCard>\n );\n}\n"],"mappings":";AAwDQ,SACE,KADF;AAtDR,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,UAAU;AAEnB,SAAS,0BAA0B;AACnC,SAAS,UAAU,iBAAiB;AACpC,SAAS,qBAAqB;AAC9B,SAAS,cAAc,cAAc,eAAe;AACpD,SAAS,eAAe,uBAAuB;AAC/C,SAAS,sBAAsB,uBAAuB;AAEtD,MAAM,iBAAiC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,WAAW,CAAC,MAAc,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC;AAG9D,SAAS,eAAe;AAC7B,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,EAAE;AACvC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA4B,EAAE;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAI,gBAAgB;AAC9C,QAAM,CAAC,SAAS,UAAU,IAAI,gBAAgB;AAC9C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,CAAC;AAClC,QAAM,EAAE,MAAM,WAAW,SAAS,QAAQ,IAAI,mBAAmB;AAAA,IAC/D;AAAA,IACA,UAAU;AAAA,IACV,QAAQ,UAAU;AAAA,IAClB,QAAQ,UAAU;AAAA,IAClB,SAAS,WAAW;AAAA,IACpB,kBAAkB,WAAW;AAAA,EAC/B,CAAC;AACD,QAAM,aAAa,OACf,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,QAAQ,KAAK,QAAQ,CAAC,IACjD;AAEJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,OAAO,MAAM;AAAA,MACb,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA,SAAS,MAAM,KAAK,QAAQ;AAAA,MAC5B,YAAW;AAAA,MACX,SAAS,MAAM,KAAK,WAAW;AAAA,MAC/B,YAAW;AAAA,MACX,kBAAiB;AAAA,MACjB,UACE,qBAAC,WAAQ,OAAM,oBACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU,CAAC,MAAM;AACf,wBAAU,CAAC;AACX,sBAAQ,CAAC;AAAA,YACX;AAAA,YACA,aAAY;AAAA;AAAA,QACd;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,OAAO;AAAA,YACP,UAAU,CAAC,MAAM;AACf,wBAAU,CAAsB;AAChC,sBAAQ,CAAC;AAAA,YACX;AAAA,YACA,SAAS;AAAA,cACP,EAAE,OAAO,IAAI,OAAO,eAAe;AAAA,cACnC,GAAG,eAAe,IAAI,CAAC,OAAO;AAAA,gBAC5B,OAAO;AAAA,gBACP,OAAO,SAAS,CAAC;AAAA,cACnB,EAAE;AAAA,YACJ;AAAA;AAAA,QACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU,CAAC,MAAM;AACf,yBAAW,CAAC;AACZ,sBAAQ,CAAC;AAAA,YACX;AAAA;AAAA,QACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU,CAAC,MAAM;AACf,yBAAW,CAAC;AACZ,sBAAQ,CAAC;AAAA,YACX;AAAA;AAAA,QACF;AAAA,SACF;AAAA,MAEF,MACE,qBAAC,QACC;AAAA,4BAAC,MAAG,sBAAQ;AAAA,QACZ,oBAAC,MAAG,mBAAK;AAAA,QACT,oBAAC,MAAG,qBAAO;AAAA,QACX,oBAAC,MAAG,sBAAQ;AAAA,QACZ,oBAAC,MAAG,OAAM,SAAQ,uBAAS;AAAA,QAC3B,oBAAC,MAAG,oBAAM;AAAA,QACV,oBAAC,MAAG,6BAAe;AAAA,QACnB,oBAAC,MAAG,oBAAM;AAAA,QACV,oBAAC,MAAG,OAAM,SACR,8BAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,SACF;AAAA,MAEF,QACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,OAAO,MAAM;AAAA,UACb,MAAK;AAAA,UACL,QAAQ;AAAA;AAAA,MACV;AAAA,MAGD,gBAAM,KAAK,IAAI,CAAC,MACf;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,QAAQ,MAAM,OAAO,KAAK,kBAAkB,EAAE,EAAE,EAAE;AAAA;AAAA,QAF7C,EAAE;AAAA,MAGT,CACD;AAAA;AAAA,EACH;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withpotter/pages-admin",
3
- "version": "0.13.0-next.74",
3
+ "version": "0.13.0-next.77",
4
4
  "description": "Box console platform-admin routes: overview, revenue, accounts, tenants, admins, roles, audit.",
5
5
  "license": "UNLICENSED",
6
6
  "sideEffects": false,
@@ -31,9 +31,9 @@
31
31
  "dependencies": {
32
32
  "@radix-ui/react-popover": "^1.1.23",
33
33
  "@tanstack/react-query": "^5.90.20",
34
- "@withpotter/lib": "^0.13.0-next.74",
35
- "@withpotter/platform-admin": "^0.13.0-next.74",
36
- "@withpotter/ui-kit": "^0.13.0-next.74",
34
+ "@withpotter/lib": "^0.13.0-next.77",
35
+ "@withpotter/platform-admin": "^0.13.0-next.77",
36
+ "@withpotter/ui-kit": "^0.13.0-next.77",
37
37
  "lucide-react": "^0.562.0",
38
38
  "motion": "^12.42.2"
39
39
  },
@@ -50,7 +50,7 @@
50
50
  "typescript": "^5"
51
51
  },
52
52
  "publishConfig": {
53
- "registry": "https://registry.npmjs.org",
53
+ "registry": "https://registry.npmjs.org/",
54
54
  "access": "restricted"
55
55
  }
56
56
  }
@@ -1,16 +0,0 @@
1
- "use client";
2
- import { useState } from "react";
3
- function useOpenGroup(pathname) {
4
- const [choice, setChoice] = useState(void 0);
5
- const setGroupOpen = (label, next) => setChoice(next ? label : null);
6
- const [choiceRoute, setChoiceRoute] = useState(pathname);
7
- if (choiceRoute !== pathname) {
8
- setChoiceRoute(pathname);
9
- setChoice(void 0);
10
- }
11
- return { choice, setGroupOpen };
12
- }
13
- export {
14
- useOpenGroup
15
- };
16
- //# sourceMappingURL=use-open-group.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/admin/_shell/use-open-group.ts"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport type { GroupChoice } from './nav-fold';\n\n/**\n * Which sidebar group is showing its rows: ONE, none, or \"not said yet\"\n * (`undefined`, which leaves the group owning the current page open). The\n * merchant rail's useOpenHub, for the admin's groups.\n */\nexport function useOpenGroup(pathname: string) {\n const [choice, setChoice] = useState<GroupChoice>(undefined);\n const setGroupOpen = (label: string, next: boolean) =>\n setChoice(next ? label : null);\n // A new route retires the choice, or arriving from inside the page would\n // leave the rail on the last group pressed, with the current row hidden.\n // Adjusted during render, not in an effect, so no stale frame paints first.\n const [choiceRoute, setChoiceRoute] = useState(pathname);\n\n if (choiceRoute !== pathname) {\n setChoiceRoute(pathname);\n setChoice(undefined);\n }\n\n return { choice, setGroupOpen };\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AAQlB,SAAS,aAAa,UAAkB;AAC7C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAsB,MAAS;AAC3D,QAAM,eAAe,CAAC,OAAe,SACnC,UAAU,OAAO,QAAQ,IAAI;AAI/B,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,QAAQ;AAEvD,MAAI,gBAAgB,UAAU;AAC5B,mBAAe,QAAQ;AACvB,cAAU,MAAS;AAAA,EACrB;AAEA,SAAO,EAAE,QAAQ,aAAa;AAChC;","names":[]}