@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.
Files changed (260) hide show
  1. package/dist/admin/_money/cash-postings.js +3 -20
  2. package/dist/admin/_money/cash-postings.js.map +1 -1
  3. package/dist/admin/_money/cash.module.css +0 -10
  4. package/dist/admin/_money/finder-format.js +0 -1
  5. package/dist/admin/_money/finder-format.js.map +1 -1
  6. package/dist/admin/_money/format.js +0 -1
  7. package/dist/admin/_money/format.js.map +1 -1
  8. package/dist/admin/_overview/activation-panel.js +6 -6
  9. package/dist/admin/_overview/activation-panel.js.map +1 -1
  10. package/dist/admin/_overview/attention-groups.js +8 -8
  11. package/dist/admin/_overview/attention-groups.js.map +1 -1
  12. package/dist/admin/_overview/attention-panel.js +33 -37
  13. package/dist/admin/_overview/attention-panel.js.map +1 -1
  14. package/dist/admin/_overview/attention.module.css +3 -0
  15. package/dist/admin/_overview/control-room.js +13 -41
  16. package/dist/admin/_overview/control-room.js.map +1 -1
  17. package/dist/admin/_overview/kpi-row.js +7 -7
  18. package/dist/admin/_overview/kpi-row.js.map +1 -1
  19. package/dist/admin/_overview/leaders-panel.js +1 -1
  20. package/dist/admin/_overview/leaders-panel.js.map +1 -1
  21. package/dist/admin/_overview/overdue-outstanding.js +1 -2
  22. package/dist/admin/_overview/overdue-outstanding.js.map +1 -1
  23. package/dist/admin/_overview/portfolio-panel.js +5 -5
  24. package/dist/admin/_overview/portfolio-panel.js.map +1 -1
  25. package/dist/admin/_overview/position-panel.js +12 -8
  26. package/dist/admin/_overview/position-panel.js.map +1 -1
  27. package/dist/admin/_pos/pos-figures.js +5 -18
  28. package/dist/admin/_pos/pos-figures.js.map +1 -1
  29. package/dist/admin/_pos/pos-rules.js +0 -2
  30. package/dist/admin/_pos/pos-rules.js.map +1 -1
  31. package/dist/admin/_pos/pos-words.js +1 -6
  32. package/dist/admin/_pos/pos-words.js.map +1 -1
  33. package/dist/admin/_pos/use-pos.js +1 -70
  34. package/dist/admin/_pos/use-pos.js.map +1 -1
  35. package/dist/admin/_shell/nav-config.js +3 -3
  36. package/dist/admin/_shell/nav-config.js.map +1 -1
  37. package/dist/admin/_shell/nav-filter.js +2 -4
  38. package/dist/admin/_shell/nav-filter.js.map +1 -1
  39. package/dist/admin/_shell/nav-row.js +2 -5
  40. package/dist/admin/_shell/nav-row.js.map +1 -1
  41. package/dist/admin/_shell/sidebar-footer.js +0 -20
  42. package/dist/admin/_shell/sidebar-footer.js.map +1 -1
  43. package/dist/admin/_shell/sidebar-footer.module.css +0 -17
  44. package/dist/admin/_shell/sidebar.js +15 -25
  45. package/dist/admin/_shell/sidebar.js.map +1 -1
  46. package/dist/admin/_shell/sidebar.module.css +0 -69
  47. package/dist/admin/_shell/use-fluid-hover.js +6 -37
  48. package/dist/admin/_shell/use-fluid-hover.js.map +1 -1
  49. package/dist/admin/_ui/admin.css +0 -7
  50. package/dist/admin/_ui/data-table.js +1 -1
  51. package/dist/admin/_ui/data-table.js.map +1 -1
  52. package/dist/admin/_ui/list-card.js +1 -1
  53. package/dist/admin/_ui/list-card.js.map +1 -1
  54. package/dist/admin/_ui/list-card.module.css +16 -2
  55. package/dist/admin/_ui/money-view.js +0 -1
  56. package/dist/admin/_ui/money-view.js.map +1 -1
  57. package/dist/admin/_ui/page-header.js +4 -31
  58. package/dist/admin/_ui/page-header.js.map +1 -1
  59. package/dist/admin/_ui/panel.module.css +10 -0
  60. package/dist/admin/_ui/stat-card.js +2 -11
  61. package/dist/admin/_ui/stat-card.js.map +1 -1
  62. package/dist/admin/_ui/trend.js +2 -2
  63. package/dist/admin/_ui/trend.js.map +1 -1
  64. package/dist/admin/accounts/account-panel.js +6 -49
  65. package/dist/admin/accounts/account-panel.js.map +1 -1
  66. package/dist/admin/accounts/account-panel.module.css +0 -73
  67. package/dist/admin/accounts/account-row.js +2 -11
  68. package/dist/admin/accounts/account-row.js.map +1 -1
  69. package/dist/admin/accounts/account-vitals.js +13 -15
  70. package/dist/admin/accounts/account-vitals.js.map +1 -1
  71. package/dist/admin/accounts/accounts-table.js +8 -39
  72. package/dist/admin/accounts/accounts-table.js.map +1 -1
  73. package/dist/admin/accounts/accounts-workspace.js +2 -2
  74. package/dist/admin/accounts/accounts-workspace.js.map +1 -1
  75. package/dist/admin/accounts/owner-session.js +6 -0
  76. package/dist/admin/accounts/owner-session.js.map +1 -1
  77. package/dist/admin/accounts/rows.module.css +0 -17
  78. package/dist/admin/audit/status-pill.js +0 -6
  79. package/dist/admin/audit/status-pill.js.map +1 -1
  80. package/dist/admin/audit/status-pill.module.css +0 -4
  81. package/dist/admin/commerce/commerce-overview.js +2 -2
  82. package/dist/admin/commerce/commerce-overview.js.map +1 -1
  83. package/dist/admin/commerce/merchant-meta.js +0 -1
  84. package/dist/admin/commerce/merchant-meta.js.map +1 -1
  85. package/dist/admin/commerce/merchant-view.js +2 -2
  86. package/dist/admin/commerce/merchant-view.js.map +1 -1
  87. package/dist/admin/feedback/prompt-operations.module.css +2 -0
  88. package/dist/admin/feedback/prompt-preview.module.css +2 -0
  89. package/dist/admin/hooks.js +1 -57
  90. package/dist/admin/hooks.js.map +1 -1
  91. package/dist/admin/layout.js +2 -8
  92. package/dist/admin/layout.js.map +1 -1
  93. package/dist/admin/page.js +8 -28
  94. package/dist/admin/page.js.map +1 -1
  95. package/dist/admin/payout-tiers/_tier-dialog.js +21 -31
  96. package/dist/admin/payout-tiers/_tier-dialog.js.map +1 -1
  97. package/dist/admin/payout-tiers/tier-preview-result.js +9 -10
  98. package/dist/admin/payout-tiers/tier-preview-result.js.map +1 -1
  99. package/dist/admin/payout-tiers/tiers-table.js +7 -6
  100. package/dist/admin/payout-tiers/tiers-table.js.map +1 -1
  101. package/dist/admin/payout-tiers/tiers-workspace.js +2 -2
  102. package/dist/admin/payout-tiers/tiers-workspace.js.map +1 -1
  103. package/dist/admin/pos/pos-workspace.js +2 -6
  104. package/dist/admin/pos/pos-workspace.js.map +1 -1
  105. package/dist/admin/pos/shifts-tab.js +9 -16
  106. package/dist/admin/pos/shifts-tab.js.map +1 -1
  107. package/dist/admin/revenue/cohort-panel.js +6 -6
  108. package/dist/admin/revenue/cohort-panel.js.map +1 -1
  109. package/dist/admin/revenue/health-panel.js +21 -22
  110. package/dist/admin/revenue/health-panel.js.map +1 -1
  111. package/dist/admin/revenue/plan-mix-panel.js +3 -3
  112. package/dist/admin/revenue/plan-mix-panel.js.map +1 -1
  113. package/dist/admin/revenue/quality-panel.js +19 -19
  114. package/dist/admin/revenue/quality-panel.js.map +1 -1
  115. package/dist/admin/revenue/revenue-kpis.js +50 -111
  116. package/dist/admin/revenue/revenue-kpis.js.map +1 -1
  117. package/dist/admin/revenue/revenue-overview.js +46 -39
  118. package/dist/admin/revenue/revenue-overview.js.map +1 -1
  119. package/dist/admin/revenue/revenue-retention.js +13 -17
  120. package/dist/admin/revenue/revenue-retention.js.map +1 -1
  121. package/dist/admin/revenue/revenue-workspace.js +6 -53
  122. package/dist/admin/revenue/revenue-workspace.js.map +1 -1
  123. package/dist/admin/revenue/subscriptions-panel.js +14 -14
  124. package/dist/admin/revenue/subscriptions-panel.js.map +1 -1
  125. package/dist/admin/revenue/top-tenants-panel.js +4 -4
  126. package/dist/admin/revenue/top-tenants-panel.js.map +1 -1
  127. package/dist/admin/settings/account-tab.js +25 -1
  128. package/dist/admin/settings/account-tab.js.map +1 -1
  129. package/dist/admin/settings/general-tab.js +2 -2
  130. package/dist/admin/settings/general-tab.js.map +1 -1
  131. package/dist/admin/settings/system-status-card.js +30 -0
  132. package/dist/admin/settings/system-status-card.js.map +1 -0
  133. package/dist/admin/support/queue-card.module.css +4 -1
  134. package/dist/admin/tenants/[id]/commerce/format.js +1 -2
  135. package/dist/admin/tenants/[id]/commerce/format.js.map +1 -1
  136. package/dist/admin/tenants/[id]/commerce/recent-orders.js +1 -1
  137. package/dist/admin/tenants/[id]/commerce/recent-orders.js.map +1 -1
  138. package/dist/admin/tenants/[id]/page.js +10 -37
  139. package/dist/admin/tenants/[id]/page.js.map +1 -1
  140. package/dist/admin/tenants/[id]/tenant-layout.module.css +4 -1
  141. package/dist/admin/tenants/[id]/tenant-overview.js +2 -3
  142. package/dist/admin/tenants/[id]/tenant-overview.js.map +1 -1
  143. package/dist/admin/tenants/[id]/tenant-overview.module.css +1 -1
  144. package/dist/admin/tenants/[id]/tenant-pos.js +16 -64
  145. package/dist/admin/tenants/[id]/tenant-pos.js.map +1 -1
  146. package/dist/admin/tenants/[id]/tenant-wallet-card.js +2 -3
  147. package/dist/admin/tenants/[id]/tenant-wallet-card.js.map +1 -1
  148. package/dist/admin/tenants/[id]/verification/document-viewer.js +52 -3
  149. package/dist/admin/tenants/[id]/verification/document-viewer.js.map +1 -1
  150. package/dist/admin/tenants/[id]/verification/document-viewer.module.css +0 -51
  151. package/dist/admin/tenants/[id]/verification/tenant-verification.js +0 -10
  152. package/dist/admin/tenants/[id]/verification/tenant-verification.js.map +1 -1
  153. package/dist/admin/tenants/tenant-list-row.js +1 -2
  154. package/dist/admin/tenants/tenant-list-row.js.map +1 -1
  155. package/dist/admin/tenants/tenants-table.js +2 -3
  156. package/dist/admin/tenants/tenants-table.js.map +1 -1
  157. package/dist/admin/tenants/tenants-workspace.js +2 -2
  158. package/dist/admin/tenants/tenants-workspace.js.map +1 -1
  159. package/dist/admin/verification/verification-page.js +3 -19
  160. package/dist/admin/verification/verification-page.js.map +1 -1
  161. package/dist/admin/verification/verification.module.css +0 -10
  162. package/dist/admin/verification/waiting-case-actions.js +68 -0
  163. package/dist/admin/verification/waiting-case-actions.js.map +1 -0
  164. package/dist/admin/verification/waiting-cases.js +48 -66
  165. package/dist/admin/verification/waiting-cases.js.map +1 -1
  166. package/package.json +5 -5
  167. package/dist/admin/_pos/olive-balance.js +0 -40
  168. package/dist/admin/_pos/olive-balance.js.map +0 -1
  169. package/dist/admin/_pos/olive-state.js +0 -23
  170. package/dist/admin/_pos/olive-state.js.map +0 -1
  171. package/dist/admin/_pos/payments-model.js +0 -55
  172. package/dist/admin/_pos/payments-model.js.map +0 -1
  173. package/dist/admin/_pos/tenant-operators.js +0 -63
  174. package/dist/admin/_pos/tenant-operators.js.map +0 -1
  175. package/dist/admin/_pos/tenant-outlets.js +0 -77
  176. package/dist/admin/_pos/tenant-outlets.js.map +0 -1
  177. package/dist/admin/_pos/tenant-pos-figures.js +0 -82
  178. package/dist/admin/_pos/tenant-pos-figures.js.map +0 -1
  179. package/dist/admin/_pos/tenant-requests.js +0 -64
  180. package/dist/admin/_pos/tenant-requests.js.map +0 -1
  181. package/dist/admin/_pos/tenant-transactions.js +0 -145
  182. package/dist/admin/_pos/tenant-transactions.js.map +0 -1
  183. package/dist/admin/_shell/nav-fold.js +0 -14
  184. package/dist/admin/_shell/nav-fold.js.map +0 -1
  185. package/dist/admin/_shell/nav-group.js +0 -78
  186. package/dist/admin/_shell/nav-group.js.map +0 -1
  187. package/dist/admin/_shell/use-open-groups.js +0 -64
  188. package/dist/admin/_shell/use-open-groups.js.map +0 -1
  189. package/dist/admin/_ui/page-header.module.css +0 -45
  190. package/dist/admin/accounts/account-sessions.js +0 -70
  191. package/dist/admin/accounts/account-sessions.js.map +0 -1
  192. package/dist/admin/accounts/account-sessions.module.css +0 -55
  193. package/dist/admin/accounts/account-stage-filter.js +0 -29
  194. package/dist/admin/accounts/account-stage-filter.js.map +0 -1
  195. package/dist/admin/accounts/account-stage.js +0 -81
  196. package/dist/admin/accounts/account-stage.js.map +0 -1
  197. package/dist/admin/accounts/hint.js +0 -12
  198. package/dist/admin/accounts/hint.js.map +0 -1
  199. package/dist/admin/payout-tiers/requirement-labels.js +0 -70
  200. package/dist/admin/payout-tiers/requirement-labels.js.map +0 -1
  201. package/dist/admin/pos/transactions-tab.js +0 -214
  202. package/dist/admin/pos/transactions-tab.js.map +0 -1
  203. package/dist/admin/revenue/channel-panel.js +0 -49
  204. package/dist/admin/revenue/channel-panel.js.map +0 -1
  205. package/dist/admin/revenue/channel-rows.js +0 -17
  206. package/dist/admin/revenue/channel-rows.js.map +0 -1
  207. package/dist/admin/revenue/download-button.js +0 -40
  208. package/dist/admin/revenue/download-button.js.map +0 -1
  209. package/dist/admin/revenue/earnings/earnings-colors.js +0 -25
  210. package/dist/admin/revenue/earnings/earnings-colors.js.map +0 -1
  211. package/dist/admin/revenue/earnings/earnings-legend.js +0 -75
  212. package/dist/admin/revenue/earnings/earnings-legend.js.map +0 -1
  213. package/dist/admin/revenue/earnings/earnings-summary.js +0 -308
  214. package/dist/admin/revenue/earnings/earnings-summary.js.map +0 -1
  215. package/dist/admin/revenue/earnings/earnings-table.js +0 -143
  216. package/dist/admin/revenue/earnings/earnings-table.js.map +0 -1
  217. package/dist/admin/revenue/earnings/earnings.module.css +0 -201
  218. package/dist/admin/revenue/earnings/use-earnings.js +0 -27
  219. package/dist/admin/revenue/earnings/use-earnings.js.map +0 -1
  220. package/dist/admin/revenue/ledger-model.js +0 -104
  221. package/dist/admin/revenue/ledger-model.js.map +0 -1
  222. package/dist/admin/revenue/ledger.module.css +0 -144
  223. package/dist/admin/revenue/merchant-headline.js +0 -37
  224. package/dist/admin/revenue/merchant-headline.js.map +0 -1
  225. package/dist/admin/revenue/merchant-payments-view.js +0 -234
  226. package/dist/admin/revenue/merchant-payments-view.js.map +0 -1
  227. package/dist/admin/revenue/method-cards.js +0 -40
  228. package/dist/admin/revenue/method-cards.js.map +0 -1
  229. package/dist/admin/revenue/payment-drawer.js +0 -53
  230. package/dist/admin/revenue/payment-drawer.js.map +0 -1
  231. package/dist/admin/revenue/plan-lines.js +0 -36
  232. package/dist/admin/revenue/plan-lines.js.map +0 -1
  233. package/dist/admin/revenue/plan-payment-drawer.js +0 -42
  234. package/dist/admin/revenue/plan-payment-drawer.js.map +0 -1
  235. package/dist/admin/revenue/plans-panel.js +0 -48
  236. package/dist/admin/revenue/plans-panel.js.map +0 -1
  237. package/dist/admin/revenue/platform-fees.js +0 -9
  238. package/dist/admin/revenue/platform-fees.js.map +0 -1
  239. package/dist/admin/revenue/print-summary-button.js +0 -27
  240. package/dist/admin/revenue/print-summary-button.js.map +0 -1
  241. package/dist/admin/revenue/subscriptions-view.js +0 -213
  242. package/dist/admin/revenue/subscriptions-view.js.map +0 -1
  243. package/dist/admin/revenue/summary-download.js +0 -38
  244. package/dist/admin/revenue/summary-download.js.map +0 -1
  245. package/dist/admin/revenue/summary-print.js +0 -82
  246. package/dist/admin/revenue/summary-print.js.map +0 -1
  247. package/dist/admin/revenue/summary-rows.js +0 -44
  248. package/dist/admin/revenue/summary-rows.js.map +0 -1
  249. package/dist/admin/revenue/url-filters.js +0 -36
  250. package/dist/admin/revenue/url-filters.js.map +0 -1
  251. package/dist/admin/revenue/use-url-filters.js +0 -24
  252. package/dist/admin/revenue/use-url-filters.js.map +0 -1
  253. package/dist/admin/tenants/[id]/use-tenant-wallet.js +0 -23
  254. package/dist/admin/tenants/[id]/use-tenant-wallet.js.map +0 -1
  255. package/dist/admin/tenants/[id]/verification/document-file.js +0 -78
  256. package/dist/admin/tenants/[id]/verification/document-file.js.map +0 -1
  257. package/dist/admin/tenants/[id]/verification/sent-files.js +0 -33
  258. package/dist/admin/tenants/[id]/verification/sent-files.js.map +0 -1
  259. package/dist/admin/verification/preview-dialog.js +0 -111
  260. package/dist/admin/verification/preview-dialog.js.map +0 -1
@@ -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={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</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={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":[]}
@@ -50,8 +50,8 @@ function TenantsWorkspace() {
50
50
  /* @__PURE__ */ jsx(
51
51
  PageHeader,
52
52
  {
53
- title: "Workspaces",
54
- description: "Every workspace on the platform, how it\u2019s doing and what it sells.",
53
+ title: "Merchants",
54
+ description: "Every business on the platform, how it\u2019s doing and what it sells.",
55
55
  actions: tab === "overview" && /* @__PURE__ */ jsxs("div", { className: "adm-toolbar", children: [
56
56
  /* @__PURE__ */ jsx(
57
57
  CurrencyFilter,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/tenants/tenants-workspace.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport {\n CurrencyFilter,\n PageHeader,\n PageTabs,\n PeriodSelector,\n customRange,\n focusCurrency,\n periodPhrase,\n rangeFromKey,\n useCurrencyParam,\n usePersistedDateRange,\n useTabParam,\n} from '../_ui';\nimport { usePlatformTenantsAnalytics } from '../hooks';\nimport { TenantsAnalytics } from './tenants-analytics';\nimport { TenantsTable } from './tenants-table';\n\nconst TABS = [\n { id: 'overview', label: 'Overview' },\n { id: 'all', label: 'All merchants' },\n] as const;\n\nconst KEYS = TABS.map((t) => t.id);\n\n/** Merchants: the period's picture on Overview, every business on its own tab. */\nexport function TenantsWorkspace() {\n const [tab, setTab] = useTabParam(KEYS);\n const {\n rangeKey,\n setRangeKey,\n customStart,\n customEnd,\n onCustomChange,\n compare,\n } = usePersistedDateRange();\n // Merchant GMV comes back once per currency; `?currency=` narrows it.\n const [currency, setCurrency] = useCurrencyParam();\n const range = useMemo(\n () =>\n rangeKey === 'custom'\n ? customRange(customStart, customEnd)\n : rangeFromKey(rangeKey),\n [rangeKey, customStart, customEnd],\n );\n const analytics = usePlatformTenantsAnalytics({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n\n const currencies = useMemo(\n () => analytics.data?.currencies ?? [],\n [analytics.data],\n );\n const span = periodPhrase(range);\n\n return (\n <div>\n <PageHeader\n title=\"Workspaces\"\n description=\"Every workspace on the platform, how it’s doing and what it sells.\"\n actions={\n tab === 'overview' && (\n <div className=\"adm-toolbar\">\n <CurrencyFilter\n value={currency}\n onChange={setCurrency}\n currencies={currencies}\n />\n <PeriodSelector\n value={rangeKey}\n onChange={setRangeKey}\n customStart={customStart}\n customEnd={customEnd}\n onCustomChange={onCustomChange}\n />\n </div>\n )\n }\n />\n <PageTabs tabs={TABS} active={tab} onChange={setTab} />\n\n {tab === 'overview' && (\n <TenantsAnalytics\n data={analytics.data}\n isLoading={analytics.isLoading}\n isError={analytics.isError}\n onRetry={() => void analytics.refetch()}\n currency={currency}\n focus={focusCurrency(currencies, currency)}\n caption={`${span[0].toUpperCase()}${span.slice(1)}`}\n span={span}\n compare={compare}\n />\n )}\n\n {tab === 'all' && <TenantsTable />}\n </div>\n );\n}\n"],"mappings":";AAiEY,SACE,KADF;AA/DZ,SAAS,eAAe;AACxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mCAAmC;AAC5C,SAAS,wBAAwB;AACjC,SAAS,oBAAoB;AAE7B,MAAM,OAAO;AAAA,EACX,EAAE,IAAI,YAAY,OAAO,WAAW;AAAA,EACpC,EAAE,IAAI,OAAO,OAAO,gBAAgB;AACtC;AAEA,MAAM,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE;AAG1B,SAAS,mBAAmB;AACjC,QAAM,CAAC,KAAK,MAAM,IAAI,YAAY,IAAI;AACtC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,sBAAsB;AAE1B,QAAM,CAAC,UAAU,WAAW,IAAI,iBAAiB;AACjD,QAAM,QAAQ;AAAA,IACZ,MACE,aAAa,WACT,YAAY,aAAa,SAAS,IAClC,aAAa,QAAQ;AAAA,IAC3B,CAAC,UAAU,aAAa,SAAS;AAAA,EACnC;AACA,QAAM,YAAY,4BAA4B;AAAA,IAC5C,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,EACjB,CAAC;AAED,QAAM,aAAa;AAAA,IACjB,MAAM,UAAU,MAAM,cAAc,CAAC;AAAA,IACrC,CAAC,UAAU,IAAI;AAAA,EACjB;AACA,QAAM,OAAO,aAAa,KAAK;AAE/B,SACE,qBAAC,SACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SACE,QAAQ,cACN,qBAAC,SAAI,WAAU,eACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU;AAAA,cACV;AAAA;AAAA,UACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU;AAAA,cACV;AAAA,cACA;AAAA,cACA;AAAA;AAAA,UACF;AAAA,WACF;AAAA;AAAA,IAGN;AAAA,IACA,oBAAC,YAAS,MAAM,MAAM,QAAQ,KAAK,UAAU,QAAQ;AAAA,IAEpD,QAAQ,cACP;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,UAAU;AAAA,QAChB,WAAW,UAAU;AAAA,QACrB,SAAS,UAAU;AAAA,QACnB,SAAS,MAAM,KAAK,UAAU,QAAQ;AAAA,QACtC;AAAA,QACA,OAAO,cAAc,YAAY,QAAQ;AAAA,QACzC,SAAS,GAAG,KAAK,CAAC,EAAE,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AAAA,QACjD;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAGD,QAAQ,SAAS,oBAAC,gBAAa;AAAA,KAClC;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/tenants/tenants-workspace.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\nimport {\n CurrencyFilter,\n PageHeader,\n PageTabs,\n PeriodSelector,\n customRange,\n focusCurrency,\n periodPhrase,\n rangeFromKey,\n useCurrencyParam,\n usePersistedDateRange,\n useTabParam,\n} from '../_ui';\nimport { usePlatformTenantsAnalytics } from '../hooks';\nimport { TenantsAnalytics } from './tenants-analytics';\nimport { TenantsTable } from './tenants-table';\n\nconst TABS = [\n { id: 'overview', label: 'Overview' },\n { id: 'all', label: 'All merchants' },\n] as const;\n\nconst KEYS = TABS.map((t) => t.id);\n\n/** Merchants: the period's picture on Overview, every business on its own tab. */\nexport function TenantsWorkspace() {\n const [tab, setTab] = useTabParam(KEYS);\n const {\n rangeKey,\n setRangeKey,\n customStart,\n customEnd,\n onCustomChange,\n compare,\n } = usePersistedDateRange();\n // Merchant GMV comes back once per currency; `?currency=` narrows it.\n const [currency, setCurrency] = useCurrencyParam();\n const range = useMemo(\n () =>\n rangeKey === 'custom'\n ? customRange(customStart, customEnd)\n : rangeFromKey(rangeKey),\n [rangeKey, customStart, customEnd],\n );\n const analytics = usePlatformTenantsAnalytics({\n startDate: range.startDate,\n endDate: range.endDate,\n });\n\n const currencies = useMemo(\n () => analytics.data?.currencies ?? [],\n [analytics.data],\n );\n const span = periodPhrase(range);\n\n return (\n <div>\n <PageHeader\n title=\"Merchants\"\n description=\"Every business on the platform, how it’s doing and what it sells.\"\n actions={\n tab === 'overview' && (\n <div className=\"adm-toolbar\">\n <CurrencyFilter\n value={currency}\n onChange={setCurrency}\n currencies={currencies}\n />\n <PeriodSelector\n value={rangeKey}\n onChange={setRangeKey}\n customStart={customStart}\n customEnd={customEnd}\n onCustomChange={onCustomChange}\n />\n </div>\n )\n }\n />\n <PageTabs tabs={TABS} active={tab} onChange={setTab} />\n\n {tab === 'overview' && (\n <TenantsAnalytics\n data={analytics.data}\n isLoading={analytics.isLoading}\n isError={analytics.isError}\n onRetry={() => void analytics.refetch()}\n currency={currency}\n focus={focusCurrency(currencies, currency)}\n caption={`${span[0].toUpperCase()}${span.slice(1)}`}\n span={span}\n compare={compare}\n />\n )}\n\n {tab === 'all' && <TenantsTable />}\n </div>\n );\n}\n"],"mappings":";AAiEY,SACE,KADF;AA/DZ,SAAS,eAAe;AACxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mCAAmC;AAC5C,SAAS,wBAAwB;AACjC,SAAS,oBAAoB;AAE7B,MAAM,OAAO;AAAA,EACX,EAAE,IAAI,YAAY,OAAO,WAAW;AAAA,EACpC,EAAE,IAAI,OAAO,OAAO,gBAAgB;AACtC;AAEA,MAAM,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE;AAG1B,SAAS,mBAAmB;AACjC,QAAM,CAAC,KAAK,MAAM,IAAI,YAAY,IAAI;AACtC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,sBAAsB;AAE1B,QAAM,CAAC,UAAU,WAAW,IAAI,iBAAiB;AACjD,QAAM,QAAQ;AAAA,IACZ,MACE,aAAa,WACT,YAAY,aAAa,SAAS,IAClC,aAAa,QAAQ;AAAA,IAC3B,CAAC,UAAU,aAAa,SAAS;AAAA,EACnC;AACA,QAAM,YAAY,4BAA4B;AAAA,IAC5C,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,EACjB,CAAC;AAED,QAAM,aAAa;AAAA,IACjB,MAAM,UAAU,MAAM,cAAc,CAAC;AAAA,IACrC,CAAC,UAAU,IAAI;AAAA,EACjB;AACA,QAAM,OAAO,aAAa,KAAK;AAE/B,SACE,qBAAC,SACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SACE,QAAQ,cACN,qBAAC,SAAI,WAAU,eACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU;AAAA,cACV;AAAA;AAAA,UACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU;AAAA,cACV;AAAA,cACA;AAAA,cACA;AAAA;AAAA,UACF;AAAA,WACF;AAAA;AAAA,IAGN;AAAA,IACA,oBAAC,YAAS,MAAM,MAAM,QAAQ,KAAK,UAAU,QAAQ;AAAA,IAEpD,QAAQ,cACP;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,UAAU;AAAA,QAChB,WAAW,UAAU;AAAA,QACrB,SAAS,UAAU;AAAA,QACnB,SAAS,MAAM,KAAK,UAAU,QAAQ;AAAA,QACtC;AAAA,QACA,OAAO,cAAc,YAAY,QAAQ;AAAA,QACzC,SAAS,GAAG,KAAK,CAAC,EAAE,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AAAA,QACjD;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAGD,QAAQ,SAAS,oBAAC,gBAAa;AAAA,KAClC;AAEJ;","names":[]}
@@ -1,31 +1,15 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useState } from "react";
4
- import { FilterSelect, Filters, PageHeader } from "../_ui";
3
+ import { PageHeader } from "../_ui";
5
4
  import { ReviewQueue } from "./review-queue";
6
5
  import { WaitingCases } from "./waiting-cases";
7
6
  import styles from "./verification.module.css";
8
- const SHOW = [
9
- { value: "businesses", label: "Businesses waiting for review" },
10
- { value: "screening", label: "Screening matches" }
11
- ];
12
7
  function VerificationPage() {
13
- const [show, setShow] = useState(SHOW[0].value);
14
8
  return /* @__PURE__ */ jsxs("div", { children: [
15
9
  /* @__PURE__ */ jsx(PageHeader, { title: "Verification" }),
16
10
  /* @__PURE__ */ jsxs("div", { className: styles.stack, children: [
17
- /* @__PURE__ */ jsx("div", { className: styles.show, children: /* @__PURE__ */ jsx(Filters, { label: "Choose which queue to show", children: /* @__PURE__ */ jsx(
18
- FilterSelect,
19
- {
20
- label: "Show",
21
- value: show,
22
- allValue: SHOW[0].value,
23
- onChange: setShow,
24
- options: SHOW,
25
- className: styles.showSelect
26
- }
27
- ) }) }),
28
- show === "businesses" ? /* @__PURE__ */ jsx(WaitingCases, {}) : /* @__PURE__ */ jsx(ReviewQueue, {})
11
+ /* @__PURE__ */ jsx(WaitingCases, {}),
12
+ /* @__PURE__ */ jsx(ReviewQueue, {})
29
13
  ] })
30
14
  ] });
31
15
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/verification/verification-page.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { FilterSelect, Filters, PageHeader } from '../_ui';\nimport { ReviewQueue } from './review-queue';\nimport { WaitingCases } from './waiting-cases';\nimport styles from './verification.module.css';\n\nconst SHOW = [\n { value: 'businesses', label: 'Businesses waiting for review' },\n { value: 'screening', label: 'Screening matches' },\n];\n\n/**\n * Verification: one queue at a time, chosen on the right, so a long list\n * never pushes the other down the page. The businesses waiting for a decision\n * (each opens on its merchant page), or the screening matches to clear or reject.\n */\nexport function VerificationPage() {\n const [show, setShow] = useState(SHOW[0].value);\n\n return (\n <div>\n <PageHeader title=\"Verification\" />\n <div className={styles.stack}>\n <div className={styles.show}>\n <Filters label=\"Choose which queue to show\">\n <FilterSelect\n label=\"Show\"\n value={show}\n allValue={SHOW[0].value}\n onChange={setShow}\n options={SHOW}\n className={styles.showSelect}\n />\n </Filters>\n </div>\n {show === 'businesses' ? <WaitingCases /> : <ReviewQueue />}\n </div>\n </div>\n );\n}\n"],"mappings":";AAuBM,cACA,YADA;AArBN,SAAS,gBAAgB;AACzB,SAAS,cAAc,SAAS,kBAAkB;AAClD,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B,OAAO,YAAY;AAEnB,MAAM,OAAO;AAAA,EACX,EAAE,OAAO,cAAc,OAAO,gCAAgC;AAAA,EAC9D,EAAE,OAAO,aAAa,OAAO,oBAAoB;AACnD;AAOO,SAAS,mBAAmB;AACjC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK,CAAC,EAAE,KAAK;AAE9C,SACE,qBAAC,SACC;AAAA,wBAAC,cAAW,OAAM,gBAAe;AAAA,IACjC,qBAAC,SAAI,WAAW,OAAO,OACrB;AAAA,0BAAC,SAAI,WAAW,OAAO,MACrB,8BAAC,WAAQ,OAAM,8BACb;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO;AAAA,UACP,UAAU,KAAK,CAAC,EAAE;AAAA,UAClB,UAAU;AAAA,UACV,SAAS;AAAA,UACT,WAAW,OAAO;AAAA;AAAA,MACpB,GACF,GACF;AAAA,MACC,SAAS,eAAe,oBAAC,gBAAa,IAAK,oBAAC,eAAY;AAAA,OAC3D;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/verification/verification-page.tsx"],"sourcesContent":["'use client';\n\nimport { PageHeader } from '../_ui';\nimport { ReviewQueue } from './review-queue';\nimport { WaitingCases } from './waiting-cases';\nimport styles from './verification.module.css';\n\n/**\n * Verification: the businesses waiting for a decision on their case (each\n * opens on its merchant page), and the screening matches to clear or reject.\n */\nexport function VerificationPage() {\n return (\n <div>\n <PageHeader title=\"Verification\" />\n <div className={styles.stack}>\n <WaitingCases />\n <ReviewQueue />\n </div>\n </div>\n );\n}\n"],"mappings":";AAcM,cACA,YADA;AAZN,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B,OAAO,YAAY;AAMZ,SAAS,mBAAmB;AACjC,SACE,qBAAC,SACC;AAAA,wBAAC,cAAW,OAAM,gBAAe;AAAA,IACjC,qBAAC,SAAI,WAAW,OAAO,OACrB;AAAA,0BAAC,gBAAa;AAAA,MACd,oBAAC,eAAY;AAAA,OACf;AAAA,KACF;AAEJ;","names":[]}
@@ -18,13 +18,3 @@
18
18
  justify-content: flex-end;
19
19
  gap: 8px;
20
20
  }
21
-
22
- /* The queue chooser, on the right above the list. */
23
- .show {
24
- display: flex;
25
- justify-content: flex-end;
26
- }
27
-
28
- .show .showSelect {
29
- width: 260px;
30
- }
@@ -0,0 +1,68 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { Check, X } from "lucide-react";
5
+ import {
6
+ OverflowItem,
7
+ OverflowMenu,
8
+ useConfirm,
9
+ useToast
10
+ } from "@withpotter/ui-kit";
11
+ import { useMoneyPermissions } from "../_money/permissions";
12
+ import rows from "../accounts/rows.module.css";
13
+ import { caseErrorText } from "../tenants/[id]/verification/case-rules";
14
+ import { DenyDialog } from "../tenants/[id]/verification/decision-dialogs";
15
+ import { useDecideCase } from "../tenants/[id]/verification/use-case";
16
+ function WaitingCaseActions({
17
+ tenantId,
18
+ businessName
19
+ }) {
20
+ const { toast } = useToast();
21
+ const confirm = useConfirm();
22
+ const { manageComplianceHint } = useMoneyPermissions();
23
+ const decide = useDecideCase(tenantId);
24
+ const [rejecting, setRejecting] = useState(false);
25
+ const business = businessName ?? "This business";
26
+ async function approve() {
27
+ const ok = await confirm({
28
+ title: `Approve ${business}?`,
29
+ description: ["Everyone listed is marked verified.", manageComplianceHint].filter(Boolean).join(" "),
30
+ confirmLabel: "Approve"
31
+ });
32
+ if (!ok) return;
33
+ decide.mutate(
34
+ { decision: "APPROVE" },
35
+ {
36
+ onSuccess: () => toast({ title: `${business} approved` }),
37
+ onError: (e) => toast({ title: caseErrorText(e, "decide"), variant: "destructive" })
38
+ }
39
+ );
40
+ }
41
+ return /* @__PURE__ */ jsxs("td", { className: rows.menuCell, children: [
42
+ /* @__PURE__ */ jsxs(OverflowMenu, { label: `Actions for ${business}`, children: [
43
+ /* @__PURE__ */ jsx(OverflowItem, { icon: /* @__PURE__ */ jsx(Check, {}), onClick: () => void approve(), children: "Approve" }),
44
+ /* @__PURE__ */ jsx(
45
+ OverflowItem,
46
+ {
47
+ icon: /* @__PURE__ */ jsx(X, {}),
48
+ destructive: true,
49
+ onClick: () => setRejecting(true),
50
+ children: "Reject"
51
+ }
52
+ )
53
+ ] }),
54
+ /* @__PURE__ */ jsx(
55
+ DenyDialog,
56
+ {
57
+ tenantId,
58
+ business,
59
+ open: rejecting,
60
+ onClose: () => setRejecting(false)
61
+ }
62
+ )
63
+ ] });
64
+ }
65
+ export {
66
+ WaitingCaseActions
67
+ };
68
+ //# sourceMappingURL=waiting-case-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/verification/waiting-case-actions.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Check, X } from 'lucide-react';\nimport {\n OverflowItem,\n OverflowMenu,\n useConfirm,\n useToast,\n} from '@withpotter/ui-kit';\nimport { useMoneyPermissions } from '../_money/permissions';\nimport rows from '../accounts/rows.module.css';\nimport { caseErrorText } from '../tenants/[id]/verification/case-rules';\nimport { DenyDialog } from '../tenants/[id]/verification/decision-dialogs';\nimport { useDecideCase } from '../tenants/[id]/verification/use-case';\n\n/**\n * Approve or reject a waiting business from the list, after checking its\n * BVN and NIN by hand. Reject asks for a reason and a note, the same form\n * as on the business's own page; the server checks the permission.\n */\nexport function WaitingCaseActions({\n tenantId,\n businessName,\n}: {\n tenantId: string;\n businessName: string | null;\n}) {\n const { toast } = useToast();\n const confirm = useConfirm();\n const { manageComplianceHint } = useMoneyPermissions();\n const decide = useDecideCase(tenantId);\n const [rejecting, setRejecting] = useState(false);\n const business = businessName ?? 'This business';\n\n async function approve() {\n const ok = await confirm({\n title: `Approve ${business}?`,\n description: ['Everyone listed is marked verified.', manageComplianceHint]\n .filter(Boolean)\n .join(' '),\n confirmLabel: 'Approve',\n });\n\n if (!ok) return;\n\n decide.mutate(\n { decision: 'APPROVE' },\n {\n onSuccess: () => toast({ title: `${business} approved` }),\n onError: (e) =>\n toast({ title: caseErrorText(e, 'decide'), variant: 'destructive' }),\n },\n );\n }\n\n return (\n <td className={rows.menuCell}>\n <OverflowMenu label={`Actions for ${business}`}>\n <OverflowItem icon={<Check />} onClick={() => void approve()}>\n Approve\n </OverflowItem>\n <OverflowItem\n icon={<X />}\n destructive\n onClick={() => setRejecting(true)}\n >\n Reject\n </OverflowItem>\n </OverflowMenu>\n <DenyDialog\n tenantId={tenantId}\n business={business}\n open={rejecting}\n onClose={() => setRejecting(false)}\n />\n </td>\n );\n}\n"],"mappings":";AA0DM,SACsB,KADtB;AAxDN,SAAS,gBAAgB;AACzB,SAAS,OAAO,SAAS;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,2BAA2B;AACpC,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAOvB,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AACF,GAGG;AACD,QAAM,EAAE,MAAM,IAAI,SAAS;AAC3B,QAAM,UAAU,WAAW;AAC3B,QAAM,EAAE,qBAAqB,IAAI,oBAAoB;AACrD,QAAM,SAAS,cAAc,QAAQ;AACrC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,WAAW,gBAAgB;AAEjC,iBAAe,UAAU;AACvB,UAAM,KAAK,MAAM,QAAQ;AAAA,MACvB,OAAO,WAAW,QAAQ;AAAA,MAC1B,aAAa,CAAC,uCAAuC,oBAAoB,EACtE,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MACX,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,CAAC,GAAI;AAET,WAAO;AAAA,MACL,EAAE,UAAU,UAAU;AAAA,MACtB;AAAA,QACE,WAAW,MAAM,MAAM,EAAE,OAAO,GAAG,QAAQ,YAAY,CAAC;AAAA,QACxD,SAAS,CAAC,MACR,MAAM,EAAE,OAAO,cAAc,GAAG,QAAQ,GAAG,SAAS,cAAc,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAEA,SACE,qBAAC,QAAG,WAAW,KAAK,UAClB;AAAA,yBAAC,gBAAa,OAAO,eAAe,QAAQ,IAC1C;AAAA,0BAAC,gBAAa,MAAM,oBAAC,SAAM,GAAI,SAAS,MAAM,KAAK,QAAQ,GAAG,qBAE9D;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,oBAAC,KAAE;AAAA,UACT,aAAW;AAAA,UACX,SAAS,MAAM,aAAa,IAAI;AAAA,UACjC;AAAA;AAAA,MAED;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,SAAS,MAAM,aAAa,KAAK;AAAA;AAAA,IACnC;AAAA,KACF;AAEJ;","names":[]}
@@ -1,16 +1,14 @@
1
1
  "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import Link from "next/link";
4
- import { useState } from "react";
5
4
  import { useQuery } from "@tanstack/react-query";
6
- import { Button, TableRow, Th } from "@withpotter/ui-kit";
5
+ import { TableRow, Th } from "@withpotter/ui-kit";
7
6
  import { adminCaseApi } from "@withpotter/lib/admin-case-api";
8
7
  import { EMPTY, ListCard } from "../_ui/list-card";
9
8
  import list from "../_ui/list-card.module.css";
10
- import rows from "../accounts/rows.module.css";
11
9
  import { flagWords, waited } from "../tenants/[id]/verification/case-words";
12
10
  import { caseErrorText } from "../tenants/[id]/verification/case-rules";
13
- import { PreviewDialog } from "./preview-dialog";
11
+ import { WaitingCaseActions } from "./waiting-case-actions";
14
12
  const WAITING_LIST_KEY = [
15
13
  "platform-admin",
16
14
  "compliance",
@@ -25,67 +23,51 @@ function WaitingCases() {
25
23
  retry: false
26
24
  });
27
25
  const items = data?.items ?? [];
28
- const [previewing, setPreviewing] = useState(null);
29
- return /* @__PURE__ */ jsxs(Fragment, { children: [
30
- /* @__PURE__ */ jsx(
31
- ListCard,
32
- {
33
- title: "Businesses waiting for review",
34
- count: data?.total,
35
- columns: COLUMNS,
36
- minWidth: 720,
37
- isLoading,
38
- isError,
39
- onRetry: () => void refetch(),
40
- errorTitle: caseErrorText(error, "load"),
41
- isEmpty: items.length === 0,
42
- emptyTitle: "No business is waiting for review.",
43
- head: /* @__PURE__ */ jsxs("tr", { children: [
44
- /* @__PURE__ */ jsx(Th, { children: "Business" }),
45
- /* @__PURE__ */ jsx(Th, { children: "People" }),
46
- /* @__PURE__ */ jsx(Th, { children: "Waiting" }),
47
- /* @__PURE__ */ jsx(Th, { children: "Flags" }),
48
- /* @__PURE__ */ jsx(Th, { align: "right", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Actions" }) })
49
- ] }),
50
- children: items.map((c) => {
51
- const flags = flagWords(c.flags);
52
- return /* @__PURE__ */ jsxs(TableRow, { children: [
53
- /* @__PURE__ */ jsx("td", { className: list.nowrap, children: /* @__PURE__ */ jsx(
54
- Link,
55
- {
56
- href: `/admin/tenants/${c.tenantId}?tab=verification`,
57
- className: "text-brand-500 hover:underline",
58
- children: c.businessName ?? "Unnamed business"
59
- }
60
- ) }),
61
- /* @__PURE__ */ jsx("td", { className: list.muted, children: c.peopleCount }),
62
- /* @__PURE__ */ jsx("td", { className: `${list.nowrap} ${list.muted}`, children: c.waitingSince ? waited(c.waitingSince) : EMPTY }),
63
- /* @__PURE__ */ jsx("td", { className: list.muted, children: flags.length ? flags.join(" \xB7 ") : EMPTY }),
64
- /* @__PURE__ */ jsx("td", { className: rows.menuCell, children: /* @__PURE__ */ jsx(
65
- Button,
66
- {
67
- size: "sm",
68
- variant: "secondary",
69
- onClick: () => setPreviewing({
70
- id: c.tenantId,
71
- name: c.businessName ?? "Unnamed business"
72
- }),
73
- children: "Preview"
74
- }
75
- ) })
76
- ] }, c.tenantId);
77
- })
78
- }
79
- ),
80
- previewing && /* @__PURE__ */ jsx(
81
- PreviewDialog,
82
- {
83
- tenantId: previewing.id,
84
- business: previewing.name,
85
- onClose: () => setPreviewing(null)
86
- }
87
- )
88
- ] });
26
+ return /* @__PURE__ */ jsx(
27
+ ListCard,
28
+ {
29
+ title: "Businesses waiting for review",
30
+ count: data?.total,
31
+ columns: COLUMNS,
32
+ minWidth: 720,
33
+ isLoading,
34
+ isError,
35
+ onRetry: () => void refetch(),
36
+ errorTitle: caseErrorText(error, "load"),
37
+ isEmpty: items.length === 0,
38
+ emptyTitle: "No business is waiting for review.",
39
+ head: /* @__PURE__ */ jsxs("tr", { children: [
40
+ /* @__PURE__ */ jsx(Th, { children: "Business" }),
41
+ /* @__PURE__ */ jsx(Th, { children: "People" }),
42
+ /* @__PURE__ */ jsx(Th, { children: "Waiting" }),
43
+ /* @__PURE__ */ jsx(Th, { children: "Flags" }),
44
+ /* @__PURE__ */ jsx(Th, { align: "right", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Actions" }) })
45
+ ] }),
46
+ children: items.map((c) => {
47
+ const flags = flagWords(c.flags);
48
+ return /* @__PURE__ */ jsxs(TableRow, { children: [
49
+ /* @__PURE__ */ jsx("td", { className: list.nowrap, children: /* @__PURE__ */ jsx(
50
+ Link,
51
+ {
52
+ href: `/admin/tenants/${c.tenantId}?tab=verification`,
53
+ className: "text-brand-500 hover:underline",
54
+ children: c.businessName ?? "Unnamed business"
55
+ }
56
+ ) }),
57
+ /* @__PURE__ */ jsx("td", { className: list.muted, children: c.peopleCount }),
58
+ /* @__PURE__ */ jsx("td", { className: `${list.nowrap} ${list.muted}`, children: c.waitingSince ? waited(c.waitingSince) : EMPTY }),
59
+ /* @__PURE__ */ jsx("td", { className: list.muted, children: flags.length ? flags.join(" \xB7 ") : EMPTY }),
60
+ /* @__PURE__ */ jsx(
61
+ WaitingCaseActions,
62
+ {
63
+ tenantId: c.tenantId,
64
+ businessName: c.businessName
65
+ }
66
+ )
67
+ ] }, c.tenantId);
68
+ })
69
+ }
70
+ );
89
71
  }
90
72
  export {
91
73
  WAITING_LIST_KEY,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/verification/waiting-cases.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { useState } from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { Button, TableRow, Th } from \"@withpotter/ui-kit\";\nimport { adminCaseApi } from \"@withpotter/lib/admin-case-api\";\nimport { EMPTY, ListCard } from \"../_ui/list-card\";\nimport list from \"../_ui/list-card.module.css\";\nimport rows from \"../accounts/rows.module.css\";\nimport { flagWords, waited } from \"../tenants/[id]/verification/case-words\";\nimport { caseErrorText } from \"../tenants/[id]/verification/case-rules\";\nimport { PreviewDialog } from \"./preview-dialog\";\n\nexport const WAITING_LIST_KEY = [\n \"platform-admin\",\n \"compliance\",\n \"cases\",\n \"waiting\",\n];\n\nconst COLUMNS = 5;\n\n/**\n * Businesses whose checks are back and wait for a decision, oldest first.\n * Preview opens a popup with what the merchant sent and Approve / Deny; the\n * business name opens its full Verification tab.\n */\nexport function WaitingCases() {\n const { data, isLoading, isError, error, refetch } = useQuery({\n queryKey: WAITING_LIST_KEY,\n queryFn: () => adminCaseApi.list({ status: \"WAITING_REVIEW\", limit: 100 }),\n retry: false,\n });\n const items = data?.items ?? [];\n const [previewing, setPreviewing] = useState<{\n id: string;\n name: string;\n } | null>(null);\n\n return (\n <>\n <ListCard\n title=\"Businesses waiting for review\"\n count={data?.total}\n columns={COLUMNS}\n minWidth={720}\n isLoading={isLoading}\n isError={isError}\n onRetry={() => void refetch()}\n errorTitle={caseErrorText(error, \"load\")}\n isEmpty={items.length === 0}\n emptyTitle=\"No business is waiting for review.\"\n head={\n <tr>\n <Th>Business</Th>\n <Th>People</Th>\n <Th>Waiting</Th>\n <Th>Flags</Th>\n <Th align=\"right\">\n <span className=\"sr-only\">Actions</span>\n </Th>\n </tr>\n }\n >\n {items.map((c) => {\n const flags = flagWords(c.flags);\n\n return (\n <TableRow key={c.tenantId}>\n <td className={list.nowrap}>\n <Link\n href={`/admin/tenants/${c.tenantId}?tab=verification`}\n className=\"text-brand-500 hover:underline\"\n >\n {c.businessName ?? \"Unnamed business\"}\n </Link>\n </td>\n <td className={list.muted}>{c.peopleCount}</td>\n <td className={`${list.nowrap} ${list.muted}`}>\n {c.waitingSince ? waited(c.waitingSince) : EMPTY}\n </td>\n <td className={list.muted}>\n {flags.length ? flags.join(\" · \") : EMPTY}\n </td>\n <td className={rows.menuCell}>\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() =>\n setPreviewing({\n id: c.tenantId,\n name: c.businessName ?? \"Unnamed business\",\n })\n }\n >\n Preview\n </Button>\n </td>\n </TableRow>\n );\n })}\n </ListCard>\n {previewing && (\n <PreviewDialog\n tenantId={previewing.id}\n business={previewing.name}\n onClose={() => setPreviewing(null)}\n />\n )}\n </>\n );\n}\n"],"mappings":";AAyCI,mBAcQ,KADF,YAbN;AAvCJ,OAAO,UAAU;AACjB,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,QAAQ,UAAU,UAAU;AACrC,SAAS,oBAAoB;AAC7B,SAAS,OAAO,gBAAgB;AAChC,OAAO,UAAU;AACjB,OAAO,UAAU;AACjB,SAAS,WAAW,cAAc;AAClC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAEvB,MAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,UAAU;AAOT,SAAS,eAAe;AAC7B,QAAM,EAAE,MAAM,WAAW,SAAS,OAAO,QAAQ,IAAI,SAAS;AAAA,IAC5D,UAAU;AAAA,IACV,SAAS,MAAM,aAAa,KAAK,EAAE,QAAQ,kBAAkB,OAAO,IAAI,CAAC;AAAA,IACzE,OAAO;AAAA,EACT,CAAC;AACD,QAAM,QAAQ,MAAM,SAAS,CAAC;AAC9B,QAAM,CAAC,YAAY,aAAa,IAAI,SAG1B,IAAI;AAEd,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,MAAM;AAAA,QACb,SAAS;AAAA,QACT,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA,SAAS,MAAM,KAAK,QAAQ;AAAA,QAC5B,YAAY,cAAc,OAAO,MAAM;AAAA,QACvC,SAAS,MAAM,WAAW;AAAA,QAC1B,YAAW;AAAA,QACX,MACE,qBAAC,QACC;AAAA,8BAAC,MAAG,sBAAQ;AAAA,UACZ,oBAAC,MAAG,oBAAM;AAAA,UACV,oBAAC,MAAG,qBAAO;AAAA,UACX,oBAAC,MAAG,mBAAK;AAAA,UACT,oBAAC,MAAG,OAAM,SACR,8BAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,WACF;AAAA,QAGD,gBAAM,IAAI,CAAC,MAAM;AAChB,gBAAM,QAAQ,UAAU,EAAE,KAAK;AAE/B,iBACE,qBAAC,YACC;AAAA,gCAAC,QAAG,WAAW,KAAK,QAClB;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,kBAAkB,EAAE,QAAQ;AAAA,gBAClC,WAAU;AAAA,gBAET,YAAE,gBAAgB;AAAA;AAAA,YACrB,GACF;AAAA,YACA,oBAAC,QAAG,WAAW,KAAK,OAAQ,YAAE,aAAY;AAAA,YAC1C,oBAAC,QAAG,WAAW,GAAG,KAAK,MAAM,IAAI,KAAK,KAAK,IACxC,YAAE,eAAe,OAAO,EAAE,YAAY,IAAI,OAC7C;AAAA,YACA,oBAAC,QAAG,WAAW,KAAK,OACjB,gBAAM,SAAS,MAAM,KAAK,QAAK,IAAI,OACtC;AAAA,YACA,oBAAC,QAAG,WAAW,KAAK,UAClB;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,SAAS,MACP,cAAc;AAAA,kBACZ,IAAI,EAAE;AAAA,kBACN,MAAM,EAAE,gBAAgB;AAAA,gBAC1B,CAAC;AAAA,gBAEJ;AAAA;AAAA,YAED,GACF;AAAA,eA7Ba,EAAE,QA8BjB;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH;AAAA,IACC,cACC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,WAAW;AAAA,QACrB,UAAU,WAAW;AAAA,QACrB,SAAS,MAAM,cAAc,IAAI;AAAA;AAAA,IACnC;AAAA,KAEJ;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/verification/waiting-cases.tsx"],"sourcesContent":["'use client';\n\nimport Link from 'next/link';\nimport { useQuery } from '@tanstack/react-query';\nimport { TableRow, Th } from '@withpotter/ui-kit';\nimport { adminCaseApi } from '@withpotter/lib/admin-case-api';\nimport { EMPTY, ListCard } from '../_ui/list-card';\nimport list from '../_ui/list-card.module.css';\nimport { flagWords, waited } from '../tenants/[id]/verification/case-words';\nimport { caseErrorText } from '../tenants/[id]/verification/case-rules';\nimport { WaitingCaseActions } from './waiting-case-actions';\n\nexport const WAITING_LIST_KEY = [\n 'platform-admin',\n 'compliance',\n 'cases',\n 'waiting',\n];\n\nconst COLUMNS = 5;\n\n/**\n * Businesses whose checks are back and wait for a decision, oldest first.\n * Each row approves or rejects the case in place.\n */\nexport function WaitingCases() {\n const { data, isLoading, isError, error, refetch } = useQuery({\n queryKey: WAITING_LIST_KEY,\n queryFn: () => adminCaseApi.list({ status: 'WAITING_REVIEW', limit: 100 }),\n retry: false,\n });\n const items = data?.items ?? [];\n\n return (\n <ListCard\n title=\"Businesses waiting for review\"\n count={data?.total}\n columns={COLUMNS}\n minWidth={720}\n isLoading={isLoading}\n isError={isError}\n onRetry={() => void refetch()}\n errorTitle={caseErrorText(error, 'load')}\n isEmpty={items.length === 0}\n emptyTitle=\"No business is waiting for review.\"\n head={\n <tr>\n <Th>Business</Th>\n <Th>People</Th>\n <Th>Waiting</Th>\n <Th>Flags</Th>\n <Th align=\"right\">\n <span className=\"sr-only\">Actions</span>\n </Th>\n </tr>\n }\n >\n {items.map((c) => {\n const flags = flagWords(c.flags);\n\n return (\n <TableRow key={c.tenantId}>\n <td className={list.nowrap}>\n <Link\n href={`/admin/tenants/${c.tenantId}?tab=verification`}\n className=\"text-brand-500 hover:underline\"\n >\n {c.businessName ?? 'Unnamed business'}\n </Link>\n </td>\n <td className={list.muted}>{c.peopleCount}</td>\n <td className={`${list.nowrap} ${list.muted}`}>\n {c.waitingSince ? waited(c.waitingSince) : EMPTY}\n </td>\n <td className={list.muted}>\n {flags.length ? flags.join(' · ') : EMPTY}\n </td>\n <WaitingCaseActions\n tenantId={c.tenantId}\n businessName={c.businessName}\n />\n </TableRow>\n );\n })}\n </ListCard>\n );\n}\n"],"mappings":";AA8CQ,SACE,KADF;AA5CR,OAAO,UAAU;AACjB,SAAS,gBAAgB;AACzB,SAAS,UAAU,UAAU;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,OAAO,gBAAgB;AAChC,OAAO,UAAU;AACjB,SAAS,WAAW,cAAc;AAClC,SAAS,qBAAqB;AAC9B,SAAS,0BAA0B;AAE5B,MAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,UAAU;AAMT,SAAS,eAAe;AAC7B,QAAM,EAAE,MAAM,WAAW,SAAS,OAAO,QAAQ,IAAI,SAAS;AAAA,IAC5D,UAAU;AAAA,IACV,SAAS,MAAM,aAAa,KAAK,EAAE,QAAQ,kBAAkB,OAAO,IAAI,CAAC;AAAA,IACzE,OAAO;AAAA,EACT,CAAC;AACD,QAAM,QAAQ,MAAM,SAAS,CAAC;AAE9B,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,YAAY,cAAc,OAAO,MAAM;AAAA,MACvC,SAAS,MAAM,WAAW;AAAA,MAC1B,YAAW;AAAA,MACX,MACE,qBAAC,QACC;AAAA,4BAAC,MAAG,sBAAQ;AAAA,QACZ,oBAAC,MAAG,oBAAM;AAAA,QACV,oBAAC,MAAG,qBAAO;AAAA,QACX,oBAAC,MAAG,mBAAK;AAAA,QACT,oBAAC,MAAG,OAAM,SACR,8BAAC,UAAK,WAAU,WAAU,qBAAO,GACnC;AAAA,SACF;AAAA,MAGD,gBAAM,IAAI,CAAC,MAAM;AAChB,cAAM,QAAQ,UAAU,EAAE,KAAK;AAE/B,eACE,qBAAC,YACC;AAAA,8BAAC,QAAG,WAAW,KAAK,QAClB;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,kBAAkB,EAAE,QAAQ;AAAA,cAClC,WAAU;AAAA,cAET,YAAE,gBAAgB;AAAA;AAAA,UACrB,GACF;AAAA,UACA,oBAAC,QAAG,WAAW,KAAK,OAAQ,YAAE,aAAY;AAAA,UAC1C,oBAAC,QAAG,WAAW,GAAG,KAAK,MAAM,IAAI,KAAK,KAAK,IACxC,YAAE,eAAe,OAAO,EAAE,YAAY,IAAI,OAC7C;AAAA,UACA,oBAAC,QAAG,WAAW,KAAK,OACjB,gBAAM,SAAS,MAAM,KAAK,QAAK,IAAI,OACtC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,UAAU,EAAE;AAAA,cACZ,cAAc,EAAE;AAAA;AAAA,UAClB;AAAA,aAnBa,EAAE,QAoBjB;AAAA,MAEJ,CAAC;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.124",
3
+ "version": "0.13.0-next.59",
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.124",
35
- "@withpotter/platform-admin": "^0.13.0-next.124",
36
- "@withpotter/ui-kit": "^0.13.0-next.124",
34
+ "@withpotter/lib": "^0.13.0-next.59",
35
+ "@withpotter/platform-admin": "^0.13.0-next.59",
36
+ "@withpotter/ui-kit": "^0.13.0-next.59",
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,40 +0,0 @@
1
- "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { useState } from "react";
4
- import { Button } from "@withpotter/ui-kit";
5
- import { oliveBalance } from "@withpotter/lib/admin-pos-olive";
6
- import { Panel } from "../_ui";
7
- import { OLIVE_NOTE, OliveProblem, naira } from "./olive-state";
8
- import { useOliveAccount } from "./use-pos";
9
- import pos from "./pos.module.css";
10
- function OliveBalance({ tenantId }) {
11
- const [asked, setAsked] = useState(false);
12
- const q = useOliveAccount(tenantId, asked);
13
- const account = oliveBalance(q.data);
14
- return /* @__PURE__ */ jsx(Panel, { title: "POS account balance", height: "auto", children: /* @__PURE__ */ jsx("div", { className: pos.stack, children: !asked ? /* @__PURE__ */ jsxs(Fragment, { children: [
15
- /* @__PURE__ */ jsx("span", { className: "adm-caption", children: OLIVE_NOTE }),
16
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
17
- Button,
18
- {
19
- size: "sm",
20
- variant: "secondary",
21
- onClick: () => setAsked(true),
22
- children: "Show balance"
23
- }
24
- ) })
25
- ] }) : q.isLoading ? /* @__PURE__ */ jsx("span", { className: "adm-caption", children: "Asking Olive\u2026" }) : q.isError ? /* @__PURE__ */ jsx(
26
- OliveProblem,
27
- {
28
- error: q.error,
29
- what: "balance",
30
- onRetry: () => void q.refetch()
31
- }
32
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
33
- /* @__PURE__ */ jsx("strong", { children: naira(account.balanceMinor) }),
34
- /* @__PURE__ */ jsx("span", { className: "adm-caption", children: [account.accountName, account.accountNumber].filter(Boolean).join(" \xB7 ") || "No account details" })
35
- ] }) }) });
36
- }
37
- export {
38
- OliveBalance
39
- };
40
- //# sourceMappingURL=olive-balance.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/admin/_pos/olive-balance.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Button } from '@withpotter/ui-kit';\nimport { oliveBalance } from '@withpotter/lib/admin-pos-olive';\nimport { Panel } from '../_ui';\nimport { OLIVE_NOTE, OliveProblem, naira } from './olive-state';\nimport { useOliveAccount } from './use-pos';\nimport pos from './pos.module.css';\n\n/**\n * The business's POS account balance, from Olive. Not fetched until asked for: every look is a call to\n * Olive under the merchant's login and a line in the audit log, so opening the tab alone does neither.\n */\nexport function OliveBalance({ tenantId }: { tenantId: string }) {\n const [asked, setAsked] = useState(false);\n const q = useOliveAccount(tenantId, asked);\n const account = oliveBalance(q.data);\n\n return (\n <Panel title=\"POS account balance\" height=\"auto\">\n <div className={pos.stack}>\n {!asked ? (\n <>\n <span className=\"adm-caption\">{OLIVE_NOTE}</span>\n <div>\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => setAsked(true)}\n >\n Show balance\n </Button>\n </div>\n </>\n ) : q.isLoading ? (\n <span className=\"adm-caption\">Asking Olive…</span>\n ) : q.isError ? (\n <OliveProblem\n error={q.error}\n what=\"balance\"\n onRetry={() => void q.refetch()}\n />\n ) : (\n <>\n <strong>{naira(account.balanceMinor)}</strong>\n <span className=\"adm-caption\">\n {[account.accountName, account.accountNumber]\n .filter(Boolean)\n .join(' · ') || 'No account details'}\n </span>\n </>\n )}\n </div>\n </Panel>\n );\n}\n"],"mappings":";AAuBU,mBACE,KADF;AArBV,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,aAAa;AACtB,SAAS,YAAY,cAAc,aAAa;AAChD,SAAS,uBAAuB;AAChC,OAAO,SAAS;AAMT,SAAS,aAAa,EAAE,SAAS,GAAyB;AAC/D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK;AACxC,QAAM,IAAI,gBAAgB,UAAU,KAAK;AACzC,QAAM,UAAU,aAAa,EAAE,IAAI;AAEnC,SACE,oBAAC,SAAM,OAAM,uBAAsB,QAAO,QACxC,8BAAC,SAAI,WAAW,IAAI,OACjB,WAAC,QACA,iCACE;AAAA,wBAAC,UAAK,WAAU,eAAe,sBAAW;AAAA,IAC1C,oBAAC,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,SAAS,MAAM,SAAS,IAAI;AAAA,QAC7B;AAAA;AAAA,IAED,GACF;AAAA,KACF,IACE,EAAE,YACJ,oBAAC,UAAK,WAAU,eAAc,gCAAa,IACzC,EAAE,UACJ;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE;AAAA,MACT,MAAK;AAAA,MACL,SAAS,MAAM,KAAK,EAAE,QAAQ;AAAA;AAAA,EAChC,IAEA,iCACE;AAAA,wBAAC,YAAQ,gBAAM,QAAQ,YAAY,GAAE;AAAA,IACrC,oBAAC,UAAK,WAAU,eACb,WAAC,QAAQ,aAAa,QAAQ,aAAa,EACzC,OAAO,OAAO,EACd,KAAK,QAAK,KAAK,sBACpB;AAAA,KACF,GAEJ,GACF;AAEJ;","names":[]}
@@ -1,23 +0,0 @@
1
- "use client";
2
- import { jsx } from "react/jsx-runtime";
3
- import { EmptyNote } from "@withpotter/ui-kit";
4
- import { formatMinor } from "@withpotter/lib/money-minor";
5
- import { LoadError } from "./pos-parts";
6
- import { isNotLinked } from "./pos-rules";
7
- const naira = (minor) => minor === null ? "\u2013" : formatMinor(String(Math.trunc(minor)), "NGN");
8
- function OliveProblem({
9
- error,
10
- what,
11
- onRetry
12
- }) {
13
- if (isNotLinked(error))
14
- return /* @__PURE__ */ jsx(EmptyNote, { well: true, children: `This business has not linked its Olive account, so its ${what} cannot be read yet.` });
15
- return /* @__PURE__ */ jsx(LoadError, { error, what: `its ${what}`, onRetry });
16
- }
17
- const OLIVE_NOTE = "Read live from Olive under the business\u2019s own login. Each view is recorded in the audit log.";
18
- export {
19
- OLIVE_NOTE,
20
- OliveProblem,
21
- naira
22
- };
23
- //# sourceMappingURL=olive-state.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/admin/_pos/olive-state.tsx"],"sourcesContent":["'use client';\n\nimport { EmptyNote } from '@withpotter/ui-kit';\nimport { formatMinor } from '@withpotter/lib/money-minor';\nimport { LoadError } from './pos-parts';\nimport { isNotLinked } from './pos-rules';\n\n/** Olive's amounts are kobo; the merchant's own POS page shows them as naira. */\nexport const naira = (minor: number | null) =>\n minor === null ? '–' : formatMinor(String(Math.trunc(minor)), 'NGN');\n\n/**\n * Why Olive's data is not on screen. A business that has not linked Olive is a state, not a fault, and\n * says so; anything else is a retry.\n */\nexport function OliveProblem({\n error,\n what,\n onRetry,\n}: {\n error: unknown;\n what: string;\n onRetry: () => void;\n}) {\n if (isNotLinked(error))\n return (\n <EmptyNote well>\n {`This business has not linked its Olive account, so its ${what} cannot be read yet.`}\n </EmptyNote>\n );\n\n return <LoadError error={error} what={`its ${what}`} onRetry={onRetry} />;\n}\n\nexport const OLIVE_NOTE =\n 'Read live from Olive under the business’s own login. Each view is recorded in the audit log.';\n"],"mappings":";AA0BM;AAxBN,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAGrB,MAAM,QAAQ,CAAC,UACpB,UAAU,OAAO,WAAM,YAAY,OAAO,KAAK,MAAM,KAAK,CAAC,GAAG,KAAK;AAM9D,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,YAAY,KAAK;AACnB,WACE,oBAAC,aAAU,MAAI,MACZ,oEAA0D,IAAI,wBACjE;AAGJ,SAAO,oBAAC,aAAU,OAAc,MAAM,OAAO,IAAI,IAAI,SAAkB;AACzE;AAEO,MAAM,aACX;","names":[]}
@@ -1,55 +0,0 @@
1
- import { formatMinor } from "@withpotter/lib/money-minor";
2
- const PAYMENT_STATUS_OPTIONS = [
3
- { value: "", label: "Any result" },
4
- { value: "SUCCEEDED", label: "Succeeded" },
5
- { value: "FAILED", label: "Failed" },
6
- { value: "PROCESSING", label: "Processing" },
7
- { value: "CREATED", label: "Created" },
8
- { value: "CANCELLED", label: "Cancelled" }
9
- ];
10
- const statusWord = (status) => status.charAt(0) + status.slice(1).toLowerCase();
11
- function matchesSearch(payment, business, search) {
12
- const words = search.toLowerCase().split(/\s+/).filter(Boolean);
13
- if (words.length === 0) return true;
14
- const haystack = [
15
- business,
16
- payment.deviceLabel,
17
- payment.reference,
18
- statusWord(payment.status),
19
- payment.currency,
20
- formatMinor(payment.amountMinor, payment.currency)
21
- ].filter(Boolean).join(" ").toLowerCase();
22
- return words.every((w) => haystack.includes(w));
23
- }
24
- const PAYMENTS_CSV_HEAD = [
25
- "When",
26
- "Business",
27
- "Terminal",
28
- "Reference",
29
- "Result",
30
- "Direction",
31
- "Currency",
32
- "Amount",
33
- "Amount (minor units)"
34
- ];
35
- function paymentRow(p, business) {
36
- return [
37
- p.at,
38
- business ?? "",
39
- p.deviceLabel ?? "",
40
- p.reference ?? "",
41
- statusWord(p.status),
42
- p.direction === "out" ? "Out" : "In",
43
- p.currency,
44
- formatMinor(p.amountMinor, p.currency),
45
- p.amountMinor
46
- ];
47
- }
48
- export {
49
- PAYMENTS_CSV_HEAD,
50
- PAYMENT_STATUS_OPTIONS,
51
- matchesSearch,
52
- paymentRow,
53
- statusWord
54
- };
55
- //# sourceMappingURL=payments-model.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/admin/_pos/payments-model.ts"],"sourcesContent":["import { formatMinor } from '@withpotter/lib/money-minor';\nimport type { PosPayment } from '@withpotter/lib/admin-pos-types';\n\n/** The results the API can filter on, in the words the table shows. */\nexport const PAYMENT_STATUS_OPTIONS = [\n { value: '', label: 'Any result' },\n { value: 'SUCCEEDED', label: 'Succeeded' },\n { value: 'FAILED', label: 'Failed' },\n { value: 'PROCESSING', label: 'Processing' },\n { value: 'CREATED', label: 'Created' },\n { value: 'CANCELLED', label: 'Cancelled' },\n] as const;\n\n/** \"SUCCEEDED\" as \"Succeeded\". */\nexport const statusWord = (status: string) =>\n status.charAt(0) + status.slice(1).toLowerCase();\n\n/**\n * Whether a payment matches a search: every word typed must appear in its business, terminal, reference, result or\n * amount, in any order and any case. An empty search matches everything.\n */\nexport function matchesSearch(\n payment: PosPayment,\n business: string | undefined,\n search: string,\n): boolean {\n const words = search.toLowerCase().split(/\\s+/).filter(Boolean);\n\n if (words.length === 0) return true;\n\n const haystack = [\n business,\n payment.deviceLabel,\n payment.reference,\n statusWord(payment.status),\n payment.currency,\n formatMinor(payment.amountMinor, payment.currency),\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n\n return words.every((w) => haystack.includes(w));\n}\n\nexport const PAYMENTS_CSV_HEAD = [\n 'When',\n 'Business',\n 'Terminal',\n 'Reference',\n 'Result',\n 'Direction',\n 'Currency',\n 'Amount',\n 'Amount (minor units)',\n];\n\n/** One CSV row per payment: the time as ISO text, the amount as shown and in minor units. */\nexport function paymentRow(\n p: PosPayment,\n business: string | undefined,\n): (string | number)[] {\n return [\n p.at,\n business ?? '',\n p.deviceLabel ?? '',\n p.reference ?? '',\n statusWord(p.status),\n p.direction === 'out' ? 'Out' : 'In',\n p.currency,\n formatMinor(p.amountMinor, p.currency),\n p.amountMinor,\n ];\n}\n"],"mappings":"AAAA,SAAS,mBAAmB;AAIrB,MAAM,yBAAyB;AAAA,EACpC,EAAE,OAAO,IAAI,OAAO,aAAa;AAAA,EACjC,EAAE,OAAO,aAAa,OAAO,YAAY;AAAA,EACzC,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,EACnC,EAAE,OAAO,cAAc,OAAO,aAAa;AAAA,EAC3C,EAAE,OAAO,WAAW,OAAO,UAAU;AAAA,EACrC,EAAE,OAAO,aAAa,OAAO,YAAY;AAC3C;AAGO,MAAM,aAAa,CAAC,WACzB,OAAO,OAAO,CAAC,IAAI,OAAO,MAAM,CAAC,EAAE,YAAY;AAM1C,SAAS,cACd,SACA,UACA,QACS;AACT,QAAM,QAAQ,OAAO,YAAY,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AAE9D,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,WAAW;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW,QAAQ,MAAM;AAAA,IACzB,QAAQ;AAAA,IACR,YAAY,QAAQ,aAAa,QAAQ,QAAQ;AAAA,EACnD,EACG,OAAO,OAAO,EACd,KAAK,GAAG,EACR,YAAY;AAEf,SAAO,MAAM,MAAM,CAAC,MAAM,SAAS,SAAS,CAAC,CAAC;AAChD;AAEO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,SAAS,WACd,GACA,UACqB;AACrB,SAAO;AAAA,IACL,EAAE;AAAA,IACF,YAAY;AAAA,IACZ,EAAE,eAAe;AAAA,IACjB,EAAE,aAAa;AAAA,IACf,WAAW,EAAE,MAAM;AAAA,IACnB,EAAE,cAAc,QAAQ,QAAQ;AAAA,IAChC,EAAE;AAAA,IACF,YAAY,EAAE,aAAa,EAAE,QAAQ;AAAA,IACrC,EAAE;AAAA,EACJ;AACF;","names":[]}
@@ -1,63 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { TableRow, Th } from "@withpotter/ui-kit";
4
- import { ListCard } from "../_ui/list-card";
5
- import list from "../_ui/list-card.module.css";
6
- import { LoadError } from "./pos-parts";
7
- import { isForbidden, posErrorText } from "./pos-rules";
8
- import { atTime } from "./pos-words";
9
- import { useTenantRoster } from "./use-pos";
10
- import pos from "./pos.module.css";
11
- const sentence = (s) => s ? s.charAt(0).toUpperCase() + s.slice(1).replace(/_/g, " ") : s;
12
- function shiftLimit(minutes) {
13
- if (!Number.isFinite(minutes) || minutes <= 0) return "\u2013";
14
- const h = Math.floor(minutes / 60);
15
- const m = minutes % 60;
16
- if (!h) return `${m} min`;
17
- return m ? `${h} h ${m} min` : `${h} h`;
18
- }
19
- function TenantOperators({ tenantId }) {
20
- const { data, isLoading, isError, error, refetch } = useTenantRoster(tenantId);
21
- if (isError && !data)
22
- return /* @__PURE__ */ jsx(
23
- LoadError,
24
- {
25
- error,
26
- what: "this business's operators",
27
- onRetry: () => void refetch()
28
- }
29
- );
30
- return /* @__PURE__ */ jsx(
31
- ListCard,
32
- {
33
- title: "Operators",
34
- count: data?.length,
35
- columns: 4,
36
- minWidth: 640,
37
- isLoading,
38
- errorTitle: isForbidden(error) ? "" : posErrorText(error, "Operators did not load."),
39
- isEmpty: data?.length === 0,
40
- emptyTitle: "Nobody can sign in at this business's terminals yet.",
41
- head: /* @__PURE__ */ jsxs("tr", { children: [
42
- /* @__PURE__ */ jsx(Th, { children: "Operator" }),
43
- /* @__PURE__ */ jsx(Th, { children: "Role" }),
44
- /* @__PURE__ */ jsx(Th, { children: "Shift limit" }),
45
- /* @__PURE__ */ jsx(Th, { children: "Updated" })
46
- ] }),
47
- children: data?.map((o) => /* @__PURE__ */ jsxs(TableRow, { children: [
48
- /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsxs("span", { className: pos.cellStack, children: [
49
- /* @__PURE__ */ jsx("span", { className: pos.clip, children: o.name }),
50
- /* @__PURE__ */ jsx("span", { className: pos.subtle, children: o.active ? o.signIn !== o.name ? `Signs in as ${o.signIn}` : "" : "Removed" })
51
- ] }) }),
52
- /* @__PURE__ */ jsx("td", { className: `${list.nowrap} ${list.muted}`, children: sentence(o.role) }),
53
- /* @__PURE__ */ jsx("td", { className: `${list.nowrap} ${list.muted}`, children: shiftLimit(o.shiftLimitMinutes) }),
54
- /* @__PURE__ */ jsx("td", { className: `${list.nowrap} ${list.muted}`, children: atTime(o.updatedAt) })
55
- ] }, o.id))
56
- }
57
- );
58
- }
59
- export {
60
- TenantOperators,
61
- shiftLimit
62
- };
63
- //# sourceMappingURL=tenant-operators.js.map