@withpotter/pages-admin 0.13.0-next.124 → 0.13.0-next.59
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/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 +7 -6
- package/dist/admin/payout-tiers/tiers-table.js.map +1 -1
- package/dist/admin/payout-tiers/tiers-workspace.js +2 -2
- 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
|
@@ -8,49 +8,49 @@ function SubscriptionsPanel({
|
|
|
8
8
|
}) {
|
|
9
9
|
const rows = [
|
|
10
10
|
{
|
|
11
|
-
label: "
|
|
11
|
+
label: "Past due",
|
|
12
12
|
status: "past_due",
|
|
13
|
-
note: "
|
|
13
|
+
note: "Payment failed, at risk of churning",
|
|
14
14
|
value: integer.format(recurring.pastDueSubscriptions),
|
|
15
15
|
tone: recurring.pastDueSubscriptions > 0 ? "danger" : "default"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
label: "
|
|
18
|
+
label: "Non-renewing",
|
|
19
19
|
status: "non_renewing",
|
|
20
|
-
note: "
|
|
20
|
+
note: "Set to cancel at period end",
|
|
21
21
|
value: integer.format(recurring.nonRenewingSubscriptions),
|
|
22
22
|
tone: recurring.nonRenewingSubscriptions > 0 ? "danger" : "default"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
label: "Active",
|
|
26
26
|
status: "active",
|
|
27
|
-
note: "Paying
|
|
27
|
+
note: "Paying on a live billing cycle",
|
|
28
28
|
value: integer.format(recurring.activeSubscriptions)
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
|
-
label: "
|
|
31
|
+
label: "Trialing",
|
|
32
32
|
status: "trialing",
|
|
33
|
-
note: "
|
|
33
|
+
note: "In trial, not yet billed",
|
|
34
34
|
value: integer.format(recurring.trialingSubscriptions)
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
|
-
label: "
|
|
38
|
-
note: `Started
|
|
37
|
+
label: "New this period",
|
|
38
|
+
note: `Started in ${span}`,
|
|
39
39
|
value: integer.format(recurring.newInRange)
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
|
-
label: "
|
|
43
|
-
note: `
|
|
42
|
+
label: "Churned this period",
|
|
43
|
+
note: `Cancelled in ${span}`,
|
|
44
44
|
value: integer.format(recurring.churnedInRange),
|
|
45
45
|
tone: recurring.churnedInRange > 0 ? "danger" : "default"
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
|
-
label: "Cancelled
|
|
49
|
-
note: "
|
|
48
|
+
label: "Cancelled",
|
|
49
|
+
note: "Lifetime total",
|
|
50
50
|
value: integer.format(recurring.cancelledSubscriptions)
|
|
51
51
|
}
|
|
52
52
|
];
|
|
53
|
-
return /* @__PURE__ */ jsx(Panel, { title: "
|
|
53
|
+
return /* @__PURE__ */ jsx(Panel, { title: "Subscriptions", caption: "Today", height: "var(--adm-panel-h)", children: /* @__PURE__ */ jsx(FigureList, { rows }) });
|
|
54
54
|
}
|
|
55
55
|
export {
|
|
56
56
|
SubscriptionsPanel
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/revenue/subscriptions-panel.tsx"],"sourcesContent":["import type { PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { Panel } from '../_ui';\nimport { FigureList, type Figure } from './figure-list';\n\nconst integer = new Intl.NumberFormat('en-US');\n\n/** Where the subscription base stands, and what started in the window. */\nexport function SubscriptionsPanel({\n recurring,\n span,\n}: {\n recurring: PlatformRevenue['recurring'];\n span: string;\n}) {\n const rows: Figure[] = [\n {\n label: '
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/revenue/subscriptions-panel.tsx"],"sourcesContent":["import type { PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { Panel } from '../_ui';\nimport { FigureList, type Figure } from './figure-list';\n\nconst integer = new Intl.NumberFormat('en-US');\n\n/** Where the subscription base stands, and what started in the window. */\nexport function SubscriptionsPanel({\n recurring,\n span,\n}: {\n recurring: PlatformRevenue['recurring'];\n span: string;\n}) {\n const rows: Figure[] = [\n {\n label: 'Past due',\n status: 'past_due',\n note: 'Payment failed, at risk of churning',\n value: integer.format(recurring.pastDueSubscriptions),\n tone: recurring.pastDueSubscriptions > 0 ? 'danger' : 'default',\n },\n {\n label: 'Non-renewing',\n status: 'non_renewing',\n note: 'Set to cancel at period end',\n value: integer.format(recurring.nonRenewingSubscriptions),\n tone: recurring.nonRenewingSubscriptions > 0 ? 'danger' : 'default',\n },\n {\n label: 'Active',\n status: 'active',\n note: 'Paying on a live billing cycle',\n value: integer.format(recurring.activeSubscriptions),\n },\n {\n label: 'Trialing',\n status: 'trialing',\n note: 'In trial, not yet billed',\n value: integer.format(recurring.trialingSubscriptions),\n },\n {\n label: 'New this period',\n note: `Started in ${span}`,\n value: integer.format(recurring.newInRange),\n },\n {\n label: 'Churned this period',\n note: `Cancelled in ${span}`,\n value: integer.format(recurring.churnedInRange),\n tone: recurring.churnedInRange > 0 ? 'danger' : 'default',\n },\n {\n label: 'Cancelled',\n note: 'Lifetime total',\n value: integer.format(recurring.cancelledSubscriptions),\n },\n ];\n\n return (\n <Panel title=\"Subscriptions\" caption=\"Today\" height=\"var(--adm-panel-h)\">\n <FigureList rows={rows} />\n </Panel>\n );\n}\n"],"mappings":"AA6DM;AA5DN,SAAS,aAAa;AACtB,SAAS,kBAA+B;AAExC,MAAM,UAAU,IAAI,KAAK,aAAa,OAAO;AAGtC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AACF,GAGG;AACD,QAAM,OAAiB;AAAA,IACrB;AAAA,MACE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,QAAQ,OAAO,UAAU,oBAAoB;AAAA,MACpD,MAAM,UAAU,uBAAuB,IAAI,WAAW;AAAA,IACxD;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,QAAQ,OAAO,UAAU,wBAAwB;AAAA,MACxD,MAAM,UAAU,2BAA2B,IAAI,WAAW;AAAA,IAC5D;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,QAAQ,OAAO,UAAU,mBAAmB;AAAA,IACrD;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,QAAQ,OAAO,UAAU,qBAAqB;AAAA,IACvD;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,MAAM,cAAc,IAAI;AAAA,MACxB,OAAO,QAAQ,OAAO,UAAU,UAAU;AAAA,IAC5C;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,MAAM,gBAAgB,IAAI;AAAA,MAC1B,OAAO,QAAQ,OAAO,UAAU,cAAc;AAAA,MAC9C,MAAM,UAAU,iBAAiB,IAAI,WAAW;AAAA,IAClD;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO,QAAQ,OAAO,UAAU,sBAAsB;AAAA,IACxD;AAAA,EACF;AAEA,SACE,oBAAC,SAAM,OAAM,iBAAgB,SAAQ,SAAQ,QAAO,sBAClD,8BAAC,cAAW,MAAY,GAC1B;AAEJ;","names":[]}
|
|
@@ -17,7 +17,7 @@ function TopTenantsPanel({
|
|
|
17
17
|
return /* @__PURE__ */ jsx(
|
|
18
18
|
Panel,
|
|
19
19
|
{
|
|
20
|
-
title: "
|
|
20
|
+
title: "Top merchants by GMV",
|
|
21
21
|
count: tenants.length || void 0,
|
|
22
22
|
caption: focus ?? void 0,
|
|
23
23
|
action: /* @__PURE__ */ jsx(Link, { href: "/admin/tenants", children: "View all" }),
|
|
@@ -31,9 +31,9 @@ function TopTenantsPanel({
|
|
|
31
31
|
head: /* @__PURE__ */ jsxs("tr", { children: [
|
|
32
32
|
/* @__PURE__ */ jsx(Th, { children: "Merchant" }),
|
|
33
33
|
/* @__PURE__ */ jsx(Th, { align: "right", children: "Orders" }),
|
|
34
|
-
/* @__PURE__ */ jsx(Th, { align: "right", children: "
|
|
35
|
-
/* @__PURE__ */ jsx(Th, { align: "right", children: "
|
|
36
|
-
/* @__PURE__ */ jsx(Th, { align: "right", children: "
|
|
34
|
+
/* @__PURE__ */ jsx(Th, { align: "right", children: "AOV" }),
|
|
35
|
+
/* @__PURE__ */ jsx(Th, { align: "right", children: "GMV" }),
|
|
36
|
+
/* @__PURE__ */ jsx(Th, { align: "right", children: "% of GMV" })
|
|
37
37
|
] }),
|
|
38
38
|
children: tenants.map((t) => {
|
|
39
39
|
const aov = t.orders > 0 ? t.gmv / t.orders : 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/revenue/top-tenants-panel.tsx"],"sourcesContent":["import Link from 'next/link';\nimport { useRouter } from 'next/navigation';\nimport { EmptyNote, TableRow, TableShell, Th } from '@withpotter/ui-kit';\nimport type { PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { EntityAvatar } from '../_fx';\nimport { PICK_CURRENCY, Panel, moneyIn } from '../_ui';\nimport { logoOf } from '../tenants/tenants-logo';\nimport styles from './revenue.module.css';\n\nconst integer = new Intl.NumberFormat('en-US');\n\n/**\n * Merchants ranked by GMV within one currency, with order count, AOV and\n * share of that currency's lifetime GMV.\n */\nexport function TopTenantsPanel({\n tenants,\n lifetime,\n focus,\n}: {\n tenants: PlatformRevenue['gmv']['topTenants'];\n /** Lifetime GMV in `focus`, the base for each share. */\n lifetime: number;\n /** The one currency ranked, or null when there are several and none is chosen. */\n focus: string | null;\n}) {\n const router = useRouter();\n const money = moneyIn(focus ?? '');\n\n return (\n <Panel\n title=\"
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/revenue/top-tenants-panel.tsx"],"sourcesContent":["import Link from 'next/link';\nimport { useRouter } from 'next/navigation';\nimport { EmptyNote, TableRow, TableShell, Th } from '@withpotter/ui-kit';\nimport type { PlatformRevenue } from '@withpotter/lib/admin-api';\nimport { EntityAvatar } from '../_fx';\nimport { PICK_CURRENCY, Panel, moneyIn } from '../_ui';\nimport { logoOf } from '../tenants/tenants-logo';\nimport styles from './revenue.module.css';\n\nconst integer = new Intl.NumberFormat('en-US');\n\n/**\n * Merchants ranked by GMV within one currency, with order count, AOV and\n * share of that currency's lifetime GMV.\n */\nexport function TopTenantsPanel({\n tenants,\n lifetime,\n focus,\n}: {\n tenants: PlatformRevenue['gmv']['topTenants'];\n /** Lifetime GMV in `focus`, the base for each share. */\n lifetime: number;\n /** The one currency ranked, or null when there are several and none is chosen. */\n focus: string | null;\n}) {\n const router = useRouter();\n const money = moneyIn(focus ?? '');\n\n return (\n <Panel\n title=\"Top merchants by GMV\"\n count={tenants.length || undefined}\n caption={focus ?? undefined}\n action={<Link href=\"/admin/tenants\">View all</Link>}\n flush\n >\n {tenants.length === 0 ? (\n <EmptyNote className={styles.empty}>\n {focus ? `No ${focus} merchant revenue recorded yet.` : PICK_CURRENCY}\n </EmptyNote>\n ) : (\n <TableShell\n bare\n minWidth={520}\n density=\"compact\"\n head={\n <tr>\n <Th>Merchant</Th>\n <Th align=\"right\">Orders</Th>\n <Th align=\"right\">AOV</Th>\n <Th align=\"right\">GMV</Th>\n <Th align=\"right\">% of GMV</Th>\n </tr>\n }\n >\n {tenants.map((t) => {\n const aov = t.orders > 0 ? t.gmv / t.orders : 0;\n const share = lifetime > 0 ? (t.gmv / lifetime) * 100 : 0;\n const logo = logoOf(t);\n return (\n <TableRow\n key={t.id}\n onClick={() => router.push(`/admin/tenants/${t.id}`)}\n >\n <td className={styles.name}>\n <span className={styles.tenant}>\n {logo && (\n <EntityAvatar\n name={t.businessName}\n src={logo}\n size={28}\n />\n )}\n <span className={styles.tenantText}>\n <Link\n href={`/admin/tenants/${t.id}`}\n title={t.businessName}\n onClick={(e) => e.stopPropagation()}\n >\n {t.businessName}\n </Link>\n {t.slug && (\n <span className={styles.slug} title={t.slug}>\n {t.slug}\n </span>\n )}\n </span>\n </span>\n </td>\n <td className={styles.num}>{integer.format(t.orders)}</td>\n <td className={styles.num}>{money(aov)}</td>\n <td className={styles.numStrong}>{money(t.gmv)}</td>\n <td className={styles.num}>\n <span className={styles.share}>\n <span className={styles.shareTrack} aria-hidden>\n <span\n className={styles.shareFill}\n style={{ width: `${Math.min(share, 100)}%` }}\n />\n </span>\n {share.toFixed(1)}%\n </span>\n </td>\n </TableRow>\n );\n })}\n </TableShell>\n )}\n </Panel>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,17 +2,21 @@
|
|
|
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 } from "@withpotter/ui-kit";
|
|
5
|
+
import { Button, useConfirm, useToast } 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";
|
|
8
9
|
import { useModuleOn } from "../_shell/modules-context";
|
|
9
10
|
import { signOutAdmin } from "../_shell/sign-out";
|
|
10
11
|
import { ChangePasswordDialog } from "./change-password-dialog";
|
|
11
12
|
import { ProfileCard } from "./profile-card";
|
|
12
13
|
import { SettingRow, SettingsCard } from "./setting-row";
|
|
14
|
+
import { SystemStatusCard } from "./system-status-card";
|
|
13
15
|
import styles from "./settings.module.css";
|
|
14
16
|
function AccountTab() {
|
|
15
17
|
const router = useRouter();
|
|
18
|
+
const confirm = useConfirm();
|
|
19
|
+
const { toast } = useToast();
|
|
16
20
|
const { data: session } = useAdminSession();
|
|
17
21
|
const [changing, setChanging] = useState(false);
|
|
18
22
|
const [leaving, setLeaving] = useState(false);
|
|
@@ -22,6 +26,17 @@ function AccountTab() {
|
|
|
22
26
|
await signOutAdmin();
|
|
23
27
|
router.replace("/admin/login");
|
|
24
28
|
};
|
|
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
|
+
};
|
|
25
40
|
return /* @__PURE__ */ jsxs("div", { className: styles.stack, children: [
|
|
26
41
|
session && /* @__PURE__ */ jsx(ProfileCard, { session }),
|
|
27
42
|
/* @__PURE__ */ jsxs(SettingsCard, { title: "Security", children: [
|
|
@@ -42,6 +57,14 @@ function AccountTab() {
|
|
|
42
57
|
}
|
|
43
58
|
)
|
|
44
59
|
] }),
|
|
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
|
+
) }),
|
|
45
68
|
supportOn && /* @__PURE__ */ jsx(SettingsCard, { title: "Support inbox", children: /* @__PURE__ */ jsx(
|
|
46
69
|
SettingRow,
|
|
47
70
|
{
|
|
@@ -50,6 +73,7 @@ function AccountTab() {
|
|
|
50
73
|
children: /* @__PURE__ */ jsx("span", { className: styles.value, title: SUPPORT_INBOX_EMAIL, children: SUPPORT_INBOX_EMAIL })
|
|
51
74
|
}
|
|
52
75
|
) }),
|
|
76
|
+
/* @__PURE__ */ jsx(SystemStatusCard, {}),
|
|
53
77
|
changing && /* @__PURE__ */ jsx(ChangePasswordDialog, { onClose: () => setChanging(false) })
|
|
54
78
|
] });
|
|
55
79
|
}
|
|
@@ -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 } 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
|
|
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":[]}
|
|
@@ -17,8 +17,8 @@ const THEMES = [
|
|
|
17
17
|
const START_OPTIONS = [
|
|
18
18
|
{ value: "overview", label: "Overview" },
|
|
19
19
|
{ value: "support", label: "Support" },
|
|
20
|
-
{ value: "merchants", label: "
|
|
21
|
-
{ value: "people", label: "
|
|
20
|
+
{ value: "merchants", label: "Merchants" },
|
|
21
|
+
{ value: "people", label: "People" }
|
|
22
22
|
];
|
|
23
23
|
function GeneralTab() {
|
|
24
24
|
const settings = useSettings();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/settings/general-tab.tsx"],"sourcesContent":["'use client';\n\nimport { Select } from '@withpotter/ui-kit';\nimport { useTheme } from '@withpotter/lib/theme-context';\nimport { RANGE_OPTIONS, usePersistedDateRange, type RangeKey } from '../_ui';\nimport { useSettings, type AdminSettings } from '../_settings';\nimport { useModuleOn } from '../_shell/modules-context';\nimport { useSidebarCollapsed, sidebarStore } from '../_shell/use-shell-prefs';\nimport { Segmented, SettingRow, SettingsCard } from './setting-row';\nimport { useSave } from './use-save';\nimport styles from './settings.module.css';\n\ntype Theme = 'system' | 'light' | 'dark';\n\nconst THEMES = [\n { value: 'system' as Theme, label: 'System' },\n { value: 'light' as Theme, label: 'Light' },\n { value: 'dark' as Theme, label: 'Dark' },\n];\n\nconst START_OPTIONS: Array<{\n value: AdminSettings['startPage'];\n label: string;\n}> = [\n { value: 'overview', label: 'Overview' },\n { value: 'support', label: 'Support' },\n { value: 'merchants', label: '
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/settings/general-tab.tsx"],"sourcesContent":["'use client';\n\nimport { Select } from '@withpotter/ui-kit';\nimport { useTheme } from '@withpotter/lib/theme-context';\nimport { RANGE_OPTIONS, usePersistedDateRange, type RangeKey } from '../_ui';\nimport { useSettings, type AdminSettings } from '../_settings';\nimport { useModuleOn } from '../_shell/modules-context';\nimport { useSidebarCollapsed, sidebarStore } from '../_shell/use-shell-prefs';\nimport { Segmented, SettingRow, SettingsCard } from './setting-row';\nimport { useSave } from './use-save';\nimport styles from './settings.module.css';\n\ntype Theme = 'system' | 'light' | 'dark';\n\nconst THEMES = [\n { value: 'system' as Theme, label: 'System' },\n { value: 'light' as Theme, label: 'Light' },\n { value: 'dark' as Theme, label: 'Dark' },\n];\n\nconst START_OPTIONS: Array<{\n value: AdminSettings['startPage'];\n label: string;\n}> = [\n { value: 'overview', label: 'Overview' },\n { value: 'support', label: 'Support' },\n { value: 'merchants', label: 'Merchants' },\n { value: 'people', label: 'People' },\n];\n\n/**\n * Look, layout and the views every page opens with. No display currency on a\n * box: money is shown per currency and never converted, so there is nothing\n * to pick. Support is a start page only where this box serves Support.\n */\nexport function GeneralTab() {\n const settings = useSettings();\n const { update, saved } = useSave();\n const { theme, setTheme } = useTheme();\n const { rangeKey, setRangeKey } = usePersistedDateRange();\n const collapsed = useSidebarCollapsed();\n const supportOn = useModuleOn('support');\n const startOptions = START_OPTIONS.filter(\n (o) => supportOn || o.value !== 'support'\n );\n\n return (\n <div className={styles.stack}>\n <SettingsCard title=\"Appearance\">\n <SettingRow\n label=\"Theme\"\n description=\"System follows your computer's light or dark setting.\"\n >\n <Segmented\n label=\"Theme\"\n value={theme}\n options={THEMES}\n onChange={(next) => {\n setTheme(next);\n saved();\n }}\n />\n </SettingRow>\n <SettingRow\n label=\"Density\"\n description=\"Compact fits more rows and cards on screen.\"\n >\n <Segmented\n label=\"Density\"\n value={settings.density}\n options={[\n { value: 'comfortable', label: 'Comfortable' },\n { value: 'compact', label: 'Compact' },\n ]}\n onChange={(density) => update({ density })}\n />\n </SettingRow>\n <SettingRow\n label=\"Sidebar\"\n description=\"Collapsed shows icons only. You can also toggle it from the sidebar.\"\n >\n <Segmented\n label=\"Sidebar\"\n value={collapsed ? 'collapsed' : 'expanded'}\n options={[\n { value: 'expanded', label: 'Expanded' },\n { value: 'collapsed', label: 'Collapsed' },\n ]}\n onChange={(next) => {\n sidebarStore.set(next === 'collapsed');\n saved();\n }}\n />\n </SettingRow>\n </SettingsCard>\n\n <SettingsCard title=\"Defaults\" description=\"What pages open with.\">\n <SettingRow\n label=\"Default period\"\n description=\"The date range reports and charts start on.\"\n >\n <Select\n className={styles.select}\n ariaLabel=\"Default period\"\n value={rangeKey}\n options={RANGE_OPTIONS.map((o) => ({\n value: o.key,\n label: o.label,\n }))}\n onChange={(key) => {\n setRangeKey(key as RangeKey);\n saved();\n }}\n />\n </SettingRow>\n <SettingRow\n label=\"Start page\"\n description=\"Where the console opens when you sign in or reload on Overview.\"\n >\n <Select\n className={styles.select}\n ariaLabel=\"Start page\"\n value={settings.startPage}\n options={startOptions}\n onChange={(value) =>\n update({ startPage: value as AdminSettings['startPage'] })\n }\n />\n </SettingRow>\n </SettingsCard>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useQuery } from "@tanstack/react-query";
|
|
4
|
+
import { adminReadinessApi } from "@withpotter/lib/admin-readiness-api";
|
|
5
|
+
import { overallOf, SystemStatusPanel } from "../_shell/system-status-panel";
|
|
6
|
+
import { SettingsCard } from "./setting-row";
|
|
7
|
+
function SystemStatusCard() {
|
|
8
|
+
const query = useQuery({
|
|
9
|
+
queryKey: ["platform-admin", "readiness"],
|
|
10
|
+
queryFn: adminReadinessApi.readiness,
|
|
11
|
+
staleTime: 6e4,
|
|
12
|
+
retry: 1
|
|
13
|
+
});
|
|
14
|
+
return /* @__PURE__ */ jsx(SettingsCard, { title: "System status", children: /* @__PURE__ */ jsx(
|
|
15
|
+
SystemStatusPanel,
|
|
16
|
+
{
|
|
17
|
+
data: query.data,
|
|
18
|
+
overall: overallOf(query.data, query.isError),
|
|
19
|
+
isLoading: query.isLoading,
|
|
20
|
+
isError: query.isError,
|
|
21
|
+
isFetching: query.isFetching,
|
|
22
|
+
checkedAt: query.dataUpdatedAt,
|
|
23
|
+
onRefresh: () => void query.refetch()
|
|
24
|
+
}
|
|
25
|
+
) });
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
SystemStatusCard
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=system-status-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/settings/system-status-card.tsx"],"sourcesContent":["'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { adminReadinessApi } from '@withpotter/lib/admin-readiness-api';\nimport { overallOf, SystemStatusPanel } from '../_shell/system-status-panel';\nimport { SettingsCard } from './setting-row';\n\n/** The deployment's integration checks, each with its state. */\nexport function SystemStatusCard() {\n const query = useQuery({\n queryKey: ['platform-admin', 'readiness'],\n queryFn: adminReadinessApi.readiness,\n staleTime: 60_000,\n retry: 1,\n });\n\n return (\n <SettingsCard title=\"System status\">\n <SystemStatusPanel\n data={query.data}\n overall={overallOf(query.data, query.isError)}\n isLoading={query.isLoading}\n isError={query.isError}\n isFetching={query.isFetching}\n checkedAt={query.dataUpdatedAt}\n onRefresh={() => void query.refetch()}\n />\n </SettingsCard>\n );\n}\n"],"mappings":";AAkBM;AAhBN,SAAS,gBAAgB;AACzB,SAAS,yBAAyB;AAClC,SAAS,WAAW,yBAAyB;AAC7C,SAAS,oBAAoB;AAGtB,SAAS,mBAAmB;AACjC,QAAM,QAAQ,SAAS;AAAA,IACrB,UAAU,CAAC,kBAAkB,WAAW;AAAA,IACxC,SAAS,kBAAkB;AAAA,IAC3B,WAAW;AAAA,IACX,OAAO;AAAA,EACT,CAAC;AAED,SACE,oBAAC,gBAAa,OAAM,iBAClB;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,MAAM;AAAA,MACZ,SAAS,UAAU,MAAM,MAAM,MAAM,OAAO;AAAA,MAC5C,WAAW,MAAM;AAAA,MACjB,SAAS,MAAM;AAAA,MACf,YAAY,MAAM;AAAA,MAClB,WAAW,MAAM;AAAA,MACjB,WAAW,MAAM,KAAK,MAAM,QAAQ;AAAA;AAAA,EACtC,GACF;AAEJ;","names":[]}
|
|
@@ -75,8 +75,11 @@
|
|
|
75
75
|
outline-offset: -2px;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
/*
|
|
78
|
+
/* Sticky column header with a hairline, not a shadow. */
|
|
79
79
|
.scroll thead th {
|
|
80
|
+
position: sticky;
|
|
81
|
+
top: 0;
|
|
82
|
+
z-index: 1;
|
|
80
83
|
background: var(--bg-base);
|
|
81
84
|
box-shadow: inset 0 -1px 0 var(--border-subtle);
|
|
82
85
|
white-space: nowrap;
|
|
@@ -3,8 +3,7 @@ function moneyIn(currency, decimals = 0) {
|
|
|
3
3
|
try {
|
|
4
4
|
return new Intl.NumberFormat("en-US", {
|
|
5
5
|
style: "currency",
|
|
6
|
-
|
|
7
|
-
currency: currency || "NGN",
|
|
6
|
+
currency: currency || "USD",
|
|
8
7
|
maximumFractionDigits: decimals
|
|
9
8
|
}).format(n);
|
|
10
9
|
} catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/admin/tenants/%5Bid%5D/commerce/format.ts"],"sourcesContent":["import type { TenantProduct } from '@withpotter/lib/admin-api';\n\n/** Amounts in the merchant's own currency, whole units for headlines. */\nexport function moneyIn(currency: string, decimals = 0) {\n return (n: number) => {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n
|
|
1
|
+
{"version":3,"sources":["../../../../../src/admin/tenants/%5Bid%5D/commerce/format.ts"],"sourcesContent":["import type { TenantProduct } from '@withpotter/lib/admin-api';\n\n/** Amounts in the merchant's own currency, whole units for headlines. */\nexport function moneyIn(currency: string, decimals = 0) {\n return (n: number) => {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: currency || 'USD',\n maximumFractionDigits: decimals,\n }).format(n);\n } catch {\n return `${currency} ${Math.round(n).toLocaleString()}`;\n }\n };\n}\n\nexport type Money = (n: number) => string;\n\n/** 1.2k / 3.4m, for figures in tight tiles. */\nexport const compact = (n: number) =>\n new Intl.NumberFormat('en-US', {\n notation: 'compact',\n maximumFractionDigits: 1,\n }).format(n);\n\nexport const shortDate = (iso: string) =>\n new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric' }).format(\n new Date(iso),\n );\n\n/** Sentence-case a machine word: \"checked_in\" → \"Checked in\". */\nexport const humanize = (s: string) => {\n const t = s.replace(/[_-]+/g, ' ').trim();\n return t ? t[0].toUpperCase() + t.slice(1) : '–';\n};\n\nexport type PillTone =\n 'success' | 'pending' | 'failed' | 'processing' | 'neutral';\n\nconst TONE_OF: Record<string, PillTone> = {\n completed: 'success',\n paid: 'success',\n success: 'success',\n settled: 'success',\n fulfilled: 'success',\n delivered: 'success',\n collected: 'success',\n pending: 'pending',\n unpaid: 'pending',\n awaiting_confirmation: 'pending',\n authorized: 'pending',\n unfulfilled: 'pending',\n partial: 'pending',\n confirmed: 'processing',\n processing: 'processing',\n checked_in: 'processing',\n ready: 'processing',\n failed: 'failed',\n reversed: 'failed',\n expired: 'failed',\n cancelled: 'neutral',\n refunded: 'neutral',\n partially_refunded: 'neutral',\n};\n\nexport const toneOf = (status: string): PillTone =>\n TONE_OF[status?.toLowerCase()] ?? 'neutral';\n\nexport type StockState = {\n label: string;\n tone: PillTone;\n available: number | null;\n};\n\n/** What a shelf looks like for one item, from the counts the API sends. */\nexport function stockOf(p: TenantProduct): StockState {\n if (!p.trackInventory || p.quantity == null)\n return { label: 'Not tracked', tone: 'neutral', available: null };\n\n const available = p.quantity - (p.reserved ?? 0);\n\n if (available <= 0)\n return { label: 'Out of stock', tone: 'failed', available };\n\n if (p.lowStockThreshold != null && available <= p.lowStockThreshold)\n return { label: `Low · ${available}`, tone: 'pending', available };\n\n return {\n label: `In stock · ${compact(available)}`,\n tone: 'success',\n available,\n };\n}\n"],"mappings":"AAGO,SAAS,QAAQ,UAAkB,WAAW,GAAG;AACtD,SAAO,CAAC,MAAc;AACpB,QAAI;AACF,aAAO,IAAI,KAAK,aAAa,SAAS;AAAA,QACpC,OAAO;AAAA,QACP,UAAU,YAAY;AAAA,QACtB,uBAAuB;AAAA,MACzB,CAAC,EAAE,OAAO,CAAC;AAAA,IACb,QAAQ;AACN,aAAO,GAAG,QAAQ,IAAI,KAAK,MAAM,CAAC,EAAE,eAAe,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AAKO,MAAM,UAAU,CAAC,MACtB,IAAI,KAAK,aAAa,SAAS;AAAA,EAC7B,UAAU;AAAA,EACV,uBAAuB;AACzB,CAAC,EAAE,OAAO,CAAC;AAEN,MAAM,YAAY,CAAC,QACxB,IAAI,KAAK,eAAe,MAAM,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC,EAAE;AAAA,EAChE,IAAI,KAAK,GAAG;AACd;AAGK,MAAM,WAAW,CAAC,MAAc;AACrC,QAAM,IAAI,EAAE,QAAQ,UAAU,GAAG,EAAE,KAAK;AACxC,SAAO,IAAI,EAAE,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,IAAI;AAC/C;AAKA,MAAM,UAAoC;AAAA,EACxC,WAAW;AAAA,EACX,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,uBAAuB;AAAA,EACvB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,WAAW;AAAA,EACX,UAAU;AAAA,EACV,oBAAoB;AACtB;AAEO,MAAM,SAAS,CAAC,WACrB,QAAQ,QAAQ,YAAY,CAAC,KAAK;AAS7B,SAAS,QAAQ,GAA8B;AACpD,MAAI,CAAC,EAAE,kBAAkB,EAAE,YAAY;AACrC,WAAO,EAAE,OAAO,eAAe,MAAM,WAAW,WAAW,KAAK;AAElE,QAAM,YAAY,EAAE,YAAY,EAAE,YAAY;AAE9C,MAAI,aAAa;AACf,WAAO,EAAE,OAAO,gBAAgB,MAAM,UAAU,UAAU;AAE5D,MAAI,EAAE,qBAAqB,QAAQ,aAAa,EAAE;AAChD,WAAO,EAAE,OAAO,YAAS,SAAS,IAAI,MAAM,WAAW,UAAU;AAEnE,SAAO;AAAA,IACL,OAAO,iBAAc,QAAQ,SAAS,CAAC;AAAA,IACvC,MAAM;AAAA,IACN;AAAA,EACF;AACF;","names":[]}
|
|
@@ -39,7 +39,7 @@ function RecentOrders({
|
|
|
39
39
|
/* @__PURE__ */ jsx(Th, { children: "Customer" }),
|
|
40
40
|
/* @__PURE__ */ jsx(Th, { align: "right", children: "Total" }),
|
|
41
41
|
/* @__PURE__ */ jsx(Th, { children: "Payment" }),
|
|
42
|
-
/* @__PURE__ */ jsx(Th, { children: "
|
|
42
|
+
/* @__PURE__ */ jsx(Th, { children: "Status" }),
|
|
43
43
|
/* @__PURE__ */ jsx(Th, { align: "right", children: "Placed" })
|
|
44
44
|
] }),
|
|
45
45
|
children: loading ? Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx("tr", { "aria-hidden": true, children: /* @__PURE__ */ jsx("td", { colSpan: 6, children: /* @__PURE__ */ jsx(Skeleton, { height: 20 }) }) }, i)) : orders.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 6, className: styles.emptyCell, children: "No orders yet. They show here as soon as a customer checks out." }) }) : orders.map((o) => /* @__PURE__ */ jsxs(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/admin/tenants/%5Bid%5D/commerce/recent-orders.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport type {\n DashboardStats,\n TenantActivityOrder,\n Transaction,\n} from '@withpotter/lib/admin-api';\nimport { TableRow, TableShell, Th } from '@withpotter/ui-kit';\nimport { Panel, Skeleton } from '../../../_ui';\nimport { moneyIn, shortDate } from './format';\nimport { OrderDrawer } from './order-drawer';\nimport { OrderPipeline } from './order-pipeline';\nimport { StatusPill } from './status-pill';\nimport styles from './orders.module.css';\n\n/** The order pipeline over the latest orders; a row opens the order. */\nexport function RecentOrders({\n orders,\n stats,\n transactions,\n loading,\n statsLoading,\n currency,\n}: {\n orders: TenantActivityOrder[];\n stats: DashboardStats['orderStats'] | undefined;\n transactions: Transaction[];\n loading: boolean;\n statsLoading: boolean;\n currency: string;\n}) {\n const [open, setOpen] = useState<TenantActivityOrder | null>(null);\n\n return (\n <>\n <Panel\n title=\"Orders\"\n count={stats?.total}\n caption={stats ? `${stats.today.toLocaleString()} today` : undefined}\n height=\"calc(var(--adm-panel-h) + 120px)\"\n flush\n >\n <OrderPipeline stats={stats} loading={statsLoading} />\n <TableShell\n bare\n minWidth={640}\n density=\"compact\"\n head={\n <tr>\n <Th>Order</Th>\n <Th>Customer</Th>\n <Th align=\"right\">Total</Th>\n <Th>Payment</Th>\n <Th>
|
|
1
|
+
{"version":3,"sources":["../../../../../src/admin/tenants/%5Bid%5D/commerce/recent-orders.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport type {\n DashboardStats,\n TenantActivityOrder,\n Transaction,\n} from '@withpotter/lib/admin-api';\nimport { TableRow, TableShell, Th } from '@withpotter/ui-kit';\nimport { Panel, Skeleton } from '../../../_ui';\nimport { moneyIn, shortDate } from './format';\nimport { OrderDrawer } from './order-drawer';\nimport { OrderPipeline } from './order-pipeline';\nimport { StatusPill } from './status-pill';\nimport styles from './orders.module.css';\n\n/** The order pipeline over the latest orders; a row opens the order. */\nexport function RecentOrders({\n orders,\n stats,\n transactions,\n loading,\n statsLoading,\n currency,\n}: {\n orders: TenantActivityOrder[];\n stats: DashboardStats['orderStats'] | undefined;\n transactions: Transaction[];\n loading: boolean;\n statsLoading: boolean;\n currency: string;\n}) {\n const [open, setOpen] = useState<TenantActivityOrder | null>(null);\n\n return (\n <>\n <Panel\n title=\"Orders\"\n count={stats?.total}\n caption={stats ? `${stats.today.toLocaleString()} today` : undefined}\n height=\"calc(var(--adm-panel-h) + 120px)\"\n flush\n >\n <OrderPipeline stats={stats} loading={statsLoading} />\n <TableShell\n bare\n minWidth={640}\n density=\"compact\"\n head={\n <tr>\n <Th>Order</Th>\n <Th>Customer</Th>\n <Th align=\"right\">Total</Th>\n <Th>Payment</Th>\n <Th>Status</Th>\n <Th align=\"right\">Placed</Th>\n </tr>\n }\n >\n {loading ? (\n Array.from({ length: 5 }, (_, i) => (\n <tr key={i} aria-hidden>\n <td colSpan={6}>\n <Skeleton height={20} />\n </td>\n </tr>\n ))\n ) : orders.length === 0 ? (\n <tr>\n <td colSpan={6} className={styles.emptyCell}>\n No orders yet. They show here as soon as a customer checks out.\n </td>\n </tr>\n ) : (\n orders.map((o) => (\n <TableRow\n key={o.id}\n active={open?.id === o.id}\n onClick={() => setOpen(o)}\n >\n <td className={styles.mono} title={o.orderNumber}>\n {/* The row opens on click; this is its keyboard way in. */}\n <button\n type=\"button\"\n className={styles.orderLink}\n onClick={(e) => {\n e.stopPropagation();\n setOpen(o);\n }}\n >\n {o.orderNumber}\n </button>\n </td>\n <td>\n <span\n className={styles.truncate}\n title={o.customerName || o.customerEmail}\n >\n {o.customerName || o.customerEmail}\n </span>\n </td>\n <td className={styles.num}>\n {moneyIn(o.currency || currency, 2)(o.total)}\n </td>\n <td>\n <StatusPill status={o.paymentStatus} />\n </td>\n <td>\n <StatusPill status={o.status} />\n </td>\n <td className={styles.num}>{shortDate(o.createdAt)}</td>\n </TableRow>\n ))\n )}\n </TableShell>\n </Panel>\n <OrderDrawer\n order={open}\n transactions={transactions}\n currency={currency}\n onClose={() => setOpen(null)}\n />\n </>\n );\n}\n"],"mappings":";AAmCI,mBAQI,KAMI,YAdR;AAjCJ,SAAS,gBAAgB;AAMzB,SAAS,UAAU,YAAY,UAAU;AACzC,SAAS,OAAO,gBAAgB;AAChC,SAAS,SAAS,iBAAiB;AACnC,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,OAAO,YAAY;AAGZ,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAqC,IAAI;AAEjE,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,OAAO;AAAA,QACd,SAAS,QAAQ,GAAG,MAAM,MAAM,eAAe,CAAC,WAAW;AAAA,QAC3D,QAAO;AAAA,QACP,OAAK;AAAA,QAEL;AAAA,8BAAC,iBAAc,OAAc,SAAS,cAAc;AAAA,UACpD;AAAA,YAAC;AAAA;AAAA,cACC,MAAI;AAAA,cACJ,UAAU;AAAA,cACV,SAAQ;AAAA,cACR,MACE,qBAAC,QACC;AAAA,oCAAC,MAAG,mBAAK;AAAA,gBACT,oBAAC,MAAG,sBAAQ;AAAA,gBACZ,oBAAC,MAAG,OAAM,SAAQ,mBAAK;AAAA,gBACvB,oBAAC,MAAG,qBAAO;AAAA,gBACX,oBAAC,MAAG,oBAAM;AAAA,gBACV,oBAAC,MAAG,OAAM,SAAQ,oBAAM;AAAA,iBAC1B;AAAA,cAGD,oBACC,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,MAC5B,oBAAC,QAAW,eAAW,MACrB,8BAAC,QAAG,SAAS,GACX,8BAAC,YAAS,QAAQ,IAAI,GACxB,KAHO,CAIT,CACD,IACC,OAAO,WAAW,IACpB,oBAAC,QACC,8BAAC,QAAG,SAAS,GAAG,WAAW,OAAO,WAAW,6EAE7C,GACF,IAEA,OAAO,IAAI,CAAC,MACV;AAAA,gBAAC;AAAA;AAAA,kBAEC,QAAQ,MAAM,OAAO,EAAE;AAAA,kBACvB,SAAS,MAAM,QAAQ,CAAC;AAAA,kBAExB;AAAA,wCAAC,QAAG,WAAW,OAAO,MAAM,OAAO,EAAE,aAEnC;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,WAAW,OAAO;AAAA,wBAClB,SAAS,CAAC,MAAM;AACd,4BAAE,gBAAgB;AAClB,kCAAQ,CAAC;AAAA,wBACX;AAAA,wBAEC,YAAE;AAAA;AAAA,oBACL,GACF;AAAA,oBACA,oBAAC,QACC;AAAA,sBAAC;AAAA;AAAA,wBACC,WAAW,OAAO;AAAA,wBAClB,OAAO,EAAE,gBAAgB,EAAE;AAAA,wBAE1B,YAAE,gBAAgB,EAAE;AAAA;AAAA,oBACvB,GACF;AAAA,oBACA,oBAAC,QAAG,WAAW,OAAO,KACnB,kBAAQ,EAAE,YAAY,UAAU,CAAC,EAAE,EAAE,KAAK,GAC7C;AAAA,oBACA,oBAAC,QACC,8BAAC,cAAW,QAAQ,EAAE,eAAe,GACvC;AAAA,oBACA,oBAAC,QACC,8BAAC,cAAW,QAAQ,EAAE,QAAQ,GAChC;AAAA,oBACA,oBAAC,QAAG,WAAW,OAAO,KAAM,oBAAU,EAAE,SAAS,GAAE;AAAA;AAAA;AAAA,gBAlC9C,EAAE;AAAA,cAmCT,CACD;AAAA;AAAA,UAEL;AAAA;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,SAAS,MAAM,QAAQ,IAAI;AAAA;AAAA,IAC7B;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -14,7 +14,6 @@ import { moduleOn } from "../../_shell/nav-modules";
|
|
|
14
14
|
import { TenantOverview } from "./tenant-overview";
|
|
15
15
|
import { TenantPeoplePanel } from "./tenant-people-panel";
|
|
16
16
|
import { TenantWalletCard } from "./tenant-wallet-card";
|
|
17
|
-
import { useTenantWallet } from "./use-tenant-wallet";
|
|
18
17
|
import { LedgerCurrencyFilter, MerchantLedger } from "./merchant-ledger";
|
|
19
18
|
import { TenantSupport } from "./tenant-support";
|
|
20
19
|
import { TenantVerification } from "./verification/tenant-verification";
|
|
@@ -62,7 +61,6 @@ function moneyCur(n, currency) {
|
|
|
62
61
|
try {
|
|
63
62
|
return new Intl.NumberFormat("en-US", {
|
|
64
63
|
style: "currency",
|
|
65
|
-
currencyDisplay: "narrowSymbol",
|
|
66
64
|
currency,
|
|
67
65
|
maximumFractionDigits: 0
|
|
68
66
|
}).format(n);
|
|
@@ -70,10 +68,6 @@ function moneyCur(n, currency) {
|
|
|
70
68
|
return `${currency} ${n.toFixed(0)}`;
|
|
71
69
|
}
|
|
72
70
|
}
|
|
73
|
-
function sharedCurrency(rows) {
|
|
74
|
-
const codes = new Set(rows.map((r) => r.currency));
|
|
75
|
-
return codes.size === 1 ? [...codes][0] || null : null;
|
|
76
|
-
}
|
|
77
71
|
function num(n) {
|
|
78
72
|
return new Intl.NumberFormat("en-US").format(n ?? 0);
|
|
79
73
|
}
|
|
@@ -159,11 +153,6 @@ function TenantDetailPage({
|
|
|
159
153
|
startDate: range.startDate,
|
|
160
154
|
endDate: range.endDate
|
|
161
155
|
});
|
|
162
|
-
const { wallet, walletNote } = useTenantWallet(
|
|
163
|
-
id,
|
|
164
|
-
walletLedger,
|
|
165
|
-
data?.wallet
|
|
166
|
-
);
|
|
167
156
|
const queryClient = useQueryClient();
|
|
168
157
|
const statusMutation = useMutation({
|
|
169
158
|
mutationFn: (status) => platformAdminApi.setTenantStatus(id, status),
|
|
@@ -180,8 +169,7 @@ function TenantDetailPage({
|
|
|
180
169
|
return /* @__PURE__ */ jsx("p", { style: { color: "var(--error)" }, children: "Failed to load tenant." });
|
|
181
170
|
}
|
|
182
171
|
if (isLoading || !data) return /* @__PURE__ */ jsx(AdmLoading, { label: "Loading tenant\u2026" });
|
|
183
|
-
const
|
|
184
|
-
const currency = data.currency ?? "NGN";
|
|
172
|
+
const currency = data.currency ?? "USD";
|
|
185
173
|
const currencyControl = /* @__PURE__ */ jsx(
|
|
186
174
|
CurrencyFilter,
|
|
187
175
|
{
|
|
@@ -189,7 +177,7 @@ function TenantDetailPage({
|
|
|
189
177
|
onChange: setShown,
|
|
190
178
|
currencies: currenciesIn(
|
|
191
179
|
data.currencies,
|
|
192
|
-
|
|
180
|
+
data.wallet?.balances.map((b) => b.currency),
|
|
193
181
|
data.recentOrders.map((o) => o.currency)
|
|
194
182
|
)
|
|
195
183
|
}
|
|
@@ -220,8 +208,7 @@ function TenantDetailPage({
|
|
|
220
208
|
tab === "overview" && /* @__PURE__ */ jsx(
|
|
221
209
|
TenantOverview,
|
|
222
210
|
{
|
|
223
|
-
data
|
|
224
|
-
walletNote,
|
|
211
|
+
data,
|
|
225
212
|
periodLabel: periodPhrase(range),
|
|
226
213
|
periodControl,
|
|
227
214
|
recentOrders: /* @__PURE__ */ jsx(
|
|
@@ -278,14 +265,7 @@ function TenantDetailPage({
|
|
|
278
265
|
]
|
|
279
266
|
}
|
|
280
267
|
),
|
|
281
|
-
group === "wallet" && current !== "money" && /* @__PURE__ */ jsx(
|
|
282
|
-
TenantWalletCard,
|
|
283
|
-
{
|
|
284
|
-
data: view,
|
|
285
|
-
currency: shown,
|
|
286
|
-
walletNote
|
|
287
|
-
}
|
|
288
|
-
),
|
|
268
|
+
group === "wallet" && current !== "money" && /* @__PURE__ */ jsx(TenantWalletCard, { data, currency: shown }),
|
|
289
269
|
current === "money" && /* @__PURE__ */ jsx(
|
|
290
270
|
MerchantLedger,
|
|
291
271
|
{
|
|
@@ -1570,17 +1550,15 @@ function InvoicesTab({ id }) {
|
|
|
1570
1550
|
if (isError) return /* @__PURE__ */ jsx(EmptyPanel, { children: "Failed to load invoices." });
|
|
1571
1551
|
const rows = data?.invoices ?? [];
|
|
1572
1552
|
const s = data?.stats;
|
|
1573
|
-
const invoiceCurrency = sharedCurrency(rows) ?? "NGN";
|
|
1574
|
-
const invoiceMoney = (n) => moneyCur(n, invoiceCurrency);
|
|
1575
1553
|
const statItems = [
|
|
1576
1554
|
{
|
|
1577
1555
|
label: "Revenue",
|
|
1578
|
-
value:
|
|
1556
|
+
value: moneyCur(s?.totalRevenue ?? 0, "USD"),
|
|
1579
1557
|
hint: "Total amount collected from invoices that have been paid."
|
|
1580
1558
|
},
|
|
1581
1559
|
{
|
|
1582
1560
|
label: "Outstanding",
|
|
1583
|
-
value:
|
|
1561
|
+
value: moneyCur(s?.totalOutstanding ?? 0, "USD"),
|
|
1584
1562
|
hint: "Amount still owed across sent and overdue invoices that have not been paid."
|
|
1585
1563
|
},
|
|
1586
1564
|
{
|
|
@@ -1776,7 +1754,7 @@ function DiscountsTab({ id }) {
|
|
|
1776
1754
|
/* @__PURE__ */ jsx("tbody", { children: rows.map((d) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
1777
1755
|
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: d.code }),
|
|
1778
1756
|
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: d.name }),
|
|
1779
|
-
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: d.discountType === "percentage" ? `${d.value}%` : moneyCur(d.value, "
|
|
1757
|
+
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: d.discountType === "percentage" ? `${d.value}%` : moneyCur(d.value, "USD") }),
|
|
1780
1758
|
/* @__PURE__ */ jsxs("td", { style: tableStyles.cellMuted, children: [
|
|
1781
1759
|
num(d.usageCount),
|
|
1782
1760
|
d.usageLimit ? ` / ${num(d.usageLimit)}` : ""
|
|
@@ -1801,7 +1779,7 @@ function SettlementsTab({ id, range }) {
|
|
|
1801
1779
|
if (isError) return /* @__PURE__ */ jsx(EmptyPanel, { children: "Failed to load settlements." });
|
|
1802
1780
|
if (isLoading || !data) return /* @__PURE__ */ jsx(AdmLoading, { label: "Loading settlements\u2026" });
|
|
1803
1781
|
const sum = data.summary;
|
|
1804
|
-
const cur = sum.currency || "
|
|
1782
|
+
const cur = sum.currency || "USD";
|
|
1805
1783
|
const banks = data.bankAccounts ?? [];
|
|
1806
1784
|
const rows = data.settlements ?? [];
|
|
1807
1785
|
const statItems = [
|
|
@@ -1891,7 +1869,7 @@ function SubscriptionsTab({ id }) {
|
|
|
1891
1869
|
if (isLoading || !data) return /* @__PURE__ */ jsx(AdmLoading, { label: "Loading subscriptions\u2026" });
|
|
1892
1870
|
const stats = data.stats;
|
|
1893
1871
|
const rows = data.subscriptions ?? [];
|
|
1894
|
-
const mrrCurrency = rows[0]?.currency || "
|
|
1872
|
+
const mrrCurrency = rows[0]?.currency || "USD";
|
|
1895
1873
|
const statItems = [
|
|
1896
1874
|
{
|
|
1897
1875
|
label: "Active",
|
|
@@ -2240,7 +2218,6 @@ function ActivityTable({
|
|
|
2240
2218
|
/* @__PURE__ */ jsx("th", { style: tableStyles.th, children: "Customer" }),
|
|
2241
2219
|
/* @__PURE__ */ jsx("th", { style: tableStyles.th, children: "Total" }),
|
|
2242
2220
|
/* @__PURE__ */ jsx("th", { style: tableStyles.th, children: "Payment" }),
|
|
2243
|
-
/* @__PURE__ */ jsx("th", { style: tableStyles.th, children: "Paid by" }),
|
|
2244
2221
|
/* @__PURE__ */ jsx("th", { style: tableStyles.th, children: "Status" }),
|
|
2245
2222
|
/* @__PURE__ */ jsx("th", { style: tableStyles.th, children: "Date" })
|
|
2246
2223
|
] }) }),
|
|
@@ -2249,10 +2226,7 @@ function ActivityTable({
|
|
|
2249
2226
|
"#",
|
|
2250
2227
|
o.orderNumber
|
|
2251
2228
|
] }),
|
|
2252
|
-
/* @__PURE__ */
|
|
2253
|
-
o.customerName ?? o.customerEmail,
|
|
2254
|
-
o.customerName ? /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "var(--text-tertiary)" }, children: [o.customerEmail, o.customerPhone].filter(Boolean).join(" \xB7 ") }) : null
|
|
2255
|
-
] }),
|
|
2229
|
+
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: o.customerName ?? o.customerEmail }),
|
|
2256
2230
|
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: moneyCur(o.total, o.currency) }),
|
|
2257
2231
|
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: /* @__PURE__ */ jsx(
|
|
2258
2232
|
Badge,
|
|
@@ -2261,7 +2235,6 @@ function ActivityTable({
|
|
|
2261
2235
|
children: o.paymentStatus
|
|
2262
2236
|
}
|
|
2263
2237
|
) }),
|
|
2264
|
-
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: o.paymentMethod ?? /* @__PURE__ */ jsx("span", { style: { color: "var(--text-tertiary)" }, children: "Not recorded" }) }),
|
|
2265
2238
|
/* @__PURE__ */ jsx("td", { style: tableStyles.cell, children: /* @__PURE__ */ jsx(
|
|
2266
2239
|
Badge,
|
|
2267
2240
|
{
|