@wopr-network/platform-ui-core 1.27.8 → 1.27.9

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 (353) hide show
  1. package/next.config.ts +1 -2
  2. package/package.json +17 -17
  3. package/src/__tests__/account-switcher.test.tsx +21 -20
  4. package/src/__tests__/activity-page.test.tsx +2 -6
  5. package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
  6. package/src/__tests__/admin-api.test.ts +1 -6
  7. package/src/__tests__/admin-gpu-api.test.ts +1 -3
  8. package/src/__tests__/admin-marketplace-api.test.ts +1 -4
  9. package/src/__tests__/admin-middleware.test.ts +76 -83
  10. package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
  11. package/src/__tests__/api-401-redirect.test.ts +46 -9
  12. package/src/__tests__/api-client.test.ts +3 -5
  13. package/src/__tests__/api-config.test.ts +22 -42
  14. package/src/__tests__/api-fleet-resources.test.ts +1 -2
  15. package/src/__tests__/api-fleet-trpc.test.ts +2 -8
  16. package/src/__tests__/api-null-guards.test.ts +3 -1
  17. package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
  18. package/src/__tests__/auth-password-reset.test.tsx +7 -21
  19. package/src/__tests__/auth-redirect.test.tsx +8 -2
  20. package/src/__tests__/auth.test.tsx +25 -23
  21. package/src/__tests__/auto-topup-card.test.tsx +4 -12
  22. package/src/__tests__/backups-tab.test.tsx +3 -4
  23. package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
  24. package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
  25. package/src/__tests__/billing.test.tsx +8 -39
  26. package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
  27. package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
  28. package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
  29. package/src/__tests__/bot-settings-restart.test.tsx +1 -3
  30. package/src/__tests__/bot-settings.test.tsx +2 -6
  31. package/src/__tests__/brand.test.ts +6 -26
  32. package/src/__tests__/buy-credits-panel.test.tsx +1 -3
  33. package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
  34. package/src/__tests__/capability-conflicts.test.ts +2 -8
  35. package/src/__tests__/capability-resolver.test.tsx +2 -12
  36. package/src/__tests__/channel-wizard.test.tsx +4 -17
  37. package/src/__tests__/chat/chat-panel.test.tsx +1 -4
  38. package/src/__tests__/chat-store.test.ts +5 -15
  39. package/src/__tests__/command-center.test.tsx +10 -12
  40. package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
  41. package/src/__tests__/confirmation-tracker.test.tsx +3 -18
  42. package/src/__tests__/coupon-input.test.tsx +1 -3
  43. package/src/__tests__/create-instance.test.tsx +1 -3
  44. package/src/__tests__/credit-balance.test.tsx +4 -12
  45. package/src/__tests__/credits.test.tsx +32 -85
  46. package/src/__tests__/email-verification-banner.test.tsx +2 -6
  47. package/src/__tests__/error-boundaries.test.tsx +0 -1
  48. package/src/__tests__/fetch-pricing.test.ts +2 -1
  49. package/src/__tests__/field-oauth.test.tsx +2 -6
  50. package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
  51. package/src/__tests__/fixtures/mock-manifests.ts +2 -4
  52. package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
  53. package/src/__tests__/fleet-health-update.test.tsx +1 -8
  54. package/src/__tests__/gpu-dashboard.test.tsx +2 -6
  55. package/src/__tests__/instance-detail.test.tsx +3 -9
  56. package/src/__tests__/instance-list.test.tsx +1 -5
  57. package/src/__tests__/layout-snapshots.test.tsx +64 -11
  58. package/src/__tests__/marketplace-admin.test.tsx +2 -6
  59. package/src/__tests__/marketplace.test.tsx +11 -35
  60. package/src/__tests__/merge-api-rates.test.ts +1 -6
  61. package/src/__tests__/middleware.test.ts +32 -219
  62. package/src/__tests__/next-config-headers.test.ts +1 -3
  63. package/src/__tests__/notifications.test.tsx +4 -11
  64. package/src/__tests__/oauth-buttons.test.tsx +36 -59
  65. package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
  66. package/src/__tests__/observability.test.tsx +23 -36
  67. package/src/__tests__/onboarding-page.test.tsx +4 -6
  68. package/src/__tests__/org-billing-api.test.tsx +1 -6
  69. package/src/__tests__/plugin-install-flow.test.tsx +28 -58
  70. package/src/__tests__/plugin-registry.test.tsx +3 -11
  71. package/src/__tests__/plugin-tool-sync.test.ts +1 -3
  72. package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
  73. package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
  74. package/src/__tests__/portfolio-chart.test.tsx +2 -6
  75. package/src/__tests__/promotion-form.test.tsx +2 -6
  76. package/src/__tests__/promotions-list.test.tsx +1 -3
  77. package/src/__tests__/provider-key-api.test.ts +2 -1
  78. package/src/__tests__/resend-verification-button.test.tsx +8 -24
  79. package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
  80. package/src/__tests__/settings.test.tsx +11 -21
  81. package/src/__tests__/setup-checklist.test.tsx +3 -9
  82. package/src/__tests__/setup.ts +25 -6
  83. package/src/__tests__/snapshot-api.test.ts +2 -1
  84. package/src/__tests__/step-superpowers.test.tsx +1 -3
  85. package/src/__tests__/tenant-context.test.tsx +1 -6
  86. package/src/__tests__/tenant-keys-api.test.ts +3 -4
  87. package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
  88. package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
  89. package/src/__tests__/transaction-history.test.tsx +190 -238
  90. package/src/__tests__/trpc-types.test.ts +2 -6
  91. package/src/__tests__/use-chat.test.ts +1 -3
  92. package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
  93. package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
  94. package/src/__tests__/use-webmcp.test.ts +1 -3
  95. package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
  96. package/src/__tests__/verify-page.test.tsx +4 -13
  97. package/src/__tests__/verify-redirect.test.tsx +2 -6
  98. package/src/app/(auth)/error.tsx +1 -7
  99. package/src/app/(auth)/forgot-password/page.tsx +4 -18
  100. package/src/app/(auth)/login/page.tsx +5 -22
  101. package/src/app/(auth)/reset-password/page.tsx +2 -12
  102. package/src/app/(auth)/signup/page.tsx +10 -44
  103. package/src/app/(auth)/verify/page.tsx +47 -0
  104. package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
  105. package/src/app/(dashboard)/billing/error.tsx +2 -10
  106. package/src/app/(dashboard)/billing/layout.tsx +12 -62
  107. package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
  108. package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
  109. package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
  110. package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
  111. package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
  112. package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
  113. package/src/app/(dashboard)/changesets/error.tsx +1 -7
  114. package/src/app/(dashboard)/chat/page.tsx +2 -6
  115. package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
  116. package/src/app/(dashboard)/error.tsx +1 -7
  117. package/src/app/(dashboard)/layout.tsx +15 -36
  118. package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
  119. package/src/app/(dashboard)/marketplace/error.tsx +1 -7
  120. package/src/app/(dashboard)/marketplace/page.tsx +6 -27
  121. package/src/app/(dashboard)/not-found.tsx +2 -5
  122. package/src/app/(dashboard)/onboarding/page.tsx +5 -22
  123. package/src/app/(dashboard)/settings/account/page.tsx +1 -6
  124. package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
  125. package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
  126. package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
  127. package/src/app/(dashboard)/settings/error.tsx +2 -10
  128. package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
  129. package/src/app/(dashboard)/settings/org/page.tsx +13 -56
  130. package/src/app/(dashboard)/settings/page.tsx +1 -0
  131. package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
  132. package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
  133. package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
  134. package/src/app/(dashboard)/settings/security/page.tsx +31 -111
  135. package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
  136. package/src/app/admin/error.tsx +1 -7
  137. package/src/app/admin/fleet-updates/error.tsx +1 -7
  138. package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
  139. package/src/app/admin/layout.tsx +4 -0
  140. package/src/app/admin/payment-methods/page.tsx +9 -38
  141. package/src/app/admin/products/error.tsx +2 -7
  142. package/src/app/admin/products/page.tsx +1 -4
  143. package/src/app/admin/promotions/[id]/page.tsx +9 -38
  144. package/src/app/admin/promotions/page.tsx +9 -36
  145. package/src/app/admin/rate-overrides/page.tsx +9 -45
  146. package/src/app/auth/callback/[provider]/page.tsx +1 -8
  147. package/src/app/auth/verify/page.tsx +9 -36
  148. package/src/app/channels/error.tsx +2 -10
  149. package/src/app/channels/layout.tsx +9 -0
  150. package/src/app/channels/page.tsx +8 -20
  151. package/src/app/channels/setup/[plugin]/page.tsx +3 -5
  152. package/src/app/error.tsx +1 -7
  153. package/src/app/fleet/error.tsx +1 -7
  154. package/src/app/fleet/layout.tsx +5 -0
  155. package/src/app/fleet/settings/page.tsx +1 -3
  156. package/src/app/global-error.tsx +2 -10
  157. package/src/app/globals.css +1 -4
  158. package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
  159. package/src/app/instances/error.tsx +2 -10
  160. package/src/app/instances/instance-list-client.tsx +20 -69
  161. package/src/app/instances/layout.tsx +9 -0
  162. package/src/app/instances/new/create-instance-client.tsx +10 -31
  163. package/src/app/layout.tsx +2 -10
  164. package/src/app/not-found.tsx +1 -3
  165. package/src/app/page.tsx +1 -2
  166. package/src/app/plugins/error.tsx +2 -10
  167. package/src/app/plugins/layout.tsx +5 -0
  168. package/src/app/plugins/page.tsx +16 -48
  169. package/src/app/pricing/error.tsx +1 -7
  170. package/src/app/privacy/page.tsx +93 -150
  171. package/src/app/status/error.tsx +1 -7
  172. package/src/app/terms/page.tsx +89 -144
  173. package/src/components/account-switcher.tsx +25 -52
  174. package/src/components/admin/accounting-dashboard.tsx +1 -3
  175. package/src/components/admin/admin-guard.tsx +1 -3
  176. package/src/components/admin/admin-nav.tsx +1 -3
  177. package/src/components/admin/affiliate-dashboard.tsx +25 -94
  178. package/src/components/admin/audit-log-table.tsx +13 -49
  179. package/src/components/admin/billing-health-dashboard.tsx +7 -25
  180. package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
  181. package/src/components/admin/bulk-actions-bar.tsx +1 -3
  182. package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
  183. package/src/components/admin/bulk-export-dialog.tsx +6 -32
  184. package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
  185. package/src/components/admin/bulk-grant-dialog.tsx +4 -15
  186. package/src/components/admin/bulk-preview-dialog.tsx +3 -12
  187. package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
  188. package/src/components/admin/bulk-select-all-banner.tsx +1 -6
  189. package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
  190. package/src/components/admin/bulk-undo-toast.tsx +1 -2
  191. package/src/components/admin/compliance-dashboard.tsx +31 -101
  192. package/src/components/admin/gpu-dashboard.tsx +21 -70
  193. package/src/components/admin/grant-credits-dialog.tsx +4 -17
  194. package/src/components/admin/incident-dashboard.tsx +10 -25
  195. package/src/components/admin/inference-dashboard.tsx +14 -54
  196. package/src/components/admin/marketplace-admin.tsx +18 -60
  197. package/src/components/admin/migrations-dashboard.tsx +9 -42
  198. package/src/components/admin/onboarding-dashboard.tsx +14 -64
  199. package/src/components/admin/pool-config-dashboard.tsx +4 -10
  200. package/src/components/admin/products/fleet-form.tsx +2 -11
  201. package/src/components/admin/products/nav-editor.tsx +3 -10
  202. package/src/components/admin/promotions/promotion-form.tsx +9 -42
  203. package/src/components/admin/roles-dashboard.tsx +7 -34
  204. package/src/components/admin/suspend-dialog.tsx +4 -11
  205. package/src/components/admin/tenant-notes-panel.tsx +1 -3
  206. package/src/components/admin/tenant-row-actions.tsx +4 -20
  207. package/src/components/admin/tenant-table.tsx +12 -49
  208. package/src/components/auth/auth-redirect.tsx +11 -3
  209. package/src/components/auth/email-verification-result-banner.tsx +1 -3
  210. package/src/components/auth/resend-verification-button.tsx +2 -10
  211. package/src/components/auth/wopr-wordmark.tsx +1 -3
  212. package/src/components/billing/add-payment-method-dialog.tsx +1 -2
  213. package/src/components/billing/affiliate-dashboard.tsx +4 -16
  214. package/src/components/billing/amount-selector.tsx +1 -3
  215. package/src/components/billing/auto-topup-card.tsx +2 -11
  216. package/src/components/billing/buy-credits-panel.tsx +4 -14
  217. package/src/components/billing/byok-callout.tsx +6 -8
  218. package/src/components/billing/confirmation-tracker.tsx +4 -14
  219. package/src/components/billing/credit-balance-badge.tsx +22 -0
  220. package/src/components/billing/credit-balance.tsx +3 -9
  221. package/src/components/billing/crypto-checkout.tsx +5 -24
  222. package/src/components/billing/degraded-state-banner.tsx +1 -3
  223. package/src/components/billing/deposit-view.tsx +301 -41
  224. package/src/components/billing/dividend-banner.tsx +1 -3
  225. package/src/components/billing/dividend-eligibility.tsx +3 -12
  226. package/src/components/billing/dividend-pool-stats.tsx +6 -20
  227. package/src/components/billing/first-dividend-dialog.tsx +2 -2
  228. package/src/components/billing/org-billing-page.tsx +8 -31
  229. package/src/components/billing/payment-method-picker.tsx +2 -10
  230. package/src/components/billing/suspension-banner.tsx +2 -7
  231. package/src/components/billing/transaction-history.tsx +10 -58
  232. package/src/components/billing/unified-checkout.tsx +547 -0
  233. package/src/components/bot-settings/backups-tab.tsx +9 -33
  234. package/src/components/bot-settings/bot-settings-client.tsx +32 -134
  235. package/src/components/bot-settings/resources-tab.tsx +2 -9
  236. package/src/components/bot-settings/storage-tab.tsx +19 -48
  237. package/src/components/bot-settings/vps-info-panel.tsx +3 -11
  238. package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
  239. package/src/components/brand-hydrator.tsx +13 -0
  240. package/src/components/channel-wizard/field-interactive.tsx +1 -3
  241. package/src/components/channel-wizard/field-qr.tsx +10 -39
  242. package/src/components/channel-wizard/step-renderer.tsx +5 -28
  243. package/src/components/channel-wizard/wizard.tsx +6 -31
  244. package/src/components/chat/chat-message.tsx +1 -4
  245. package/src/components/chat/chat-panel.tsx +4 -18
  246. package/src/components/chat/chat-widget.tsx +3 -14
  247. package/src/components/dashboard/command-center.tsx +15 -61
  248. package/src/components/fleet/update-settings-card.tsx +7 -23
  249. package/src/components/instance-update-banner.tsx +130 -0
  250. package/src/components/instances/friends-tab.test.tsx +2 -9
  251. package/src/components/instances/friends-tab.tsx +18 -74
  252. package/src/components/instances/update-available-badge.tsx +2 -11
  253. package/src/components/landing/hero.tsx +3 -9
  254. package/src/components/landing/landing-page.tsx +1 -3
  255. package/src/components/landing/portfolio-chart.tsx +4 -9
  256. package/src/components/landing/story-sections.tsx +1 -3
  257. package/src/components/landing/terminal-sequence.tsx +4 -17
  258. package/src/components/marketplace/empty-state.tsx +2 -6
  259. package/src/components/marketplace/first-visit-hero.tsx +1 -3
  260. package/src/components/marketplace/install-wizard.tsx +20 -77
  261. package/src/components/marketplace/marketplace-tabs.tsx +1 -4
  262. package/src/components/marketplace/plugin-card.tsx +2 -9
  263. package/src/components/marketplace/superpower-content.tsx +1 -3
  264. package/src/components/marketplace/terminal-search.tsx +2 -8
  265. package/src/components/oauth-buttons.tsx +29 -14
  266. package/src/components/observability/fleet-health.tsx +5 -18
  267. package/src/components/observability/health-overview.tsx +7 -20
  268. package/src/components/observability/logs-viewer.tsx +8 -32
  269. package/src/components/observability/metrics-dashboard.tsx +2 -15
  270. package/src/components/onboarding/fallback-setup.tsx +6 -25
  271. package/src/components/onboarding/setup-checklist.tsx +18 -51
  272. package/src/components/onboarding/step-superpowers.tsx +1 -4
  273. package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
  274. package/src/components/pricing/dividend-calculator.tsx +6 -12
  275. package/src/components/pricing/dividend-stats.tsx +5 -17
  276. package/src/components/pricing/pricing-page.tsx +17 -36
  277. package/src/components/settings/create-org-wizard.tsx +2 -5
  278. package/src/components/sidebar.tsx +7 -42
  279. package/src/components/sidecar-frame.tsx +78 -0
  280. package/src/components/status/status-page.tsx +6 -28
  281. package/src/components/ui/alert-dialog.tsx +8 -25
  282. package/src/components/ui/badge.tsx +2 -8
  283. package/src/components/ui/banner.tsx +1 -6
  284. package/src/components/ui/card.tsx +5 -24
  285. package/src/components/ui/checkbox.tsx +1 -5
  286. package/src/components/ui/collapsible.tsx +3 -8
  287. package/src/components/ui/dialog.tsx +4 -10
  288. package/src/components/ui/dropdown-menu.tsx +9 -18
  289. package/src/components/ui/form.tsx +2 -16
  290. package/src/components/ui/popover.tsx +3 -23
  291. package/src/components/ui/progress.tsx +1 -5
  292. package/src/components/ui/radio-group.tsx +3 -15
  293. package/src/components/ui/select.tsx +4 -17
  294. package/src/components/ui/sheet.tsx +5 -19
  295. package/src/components/ui/skeleton.tsx +1 -7
  296. package/src/components/ui/table.tsx +5 -22
  297. package/src/components/ui/tabs.tsx +3 -13
  298. package/src/components/ui/tooltip.tsx +1 -1
  299. package/src/components/unified-sidebar.tsx +493 -0
  300. package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
  301. package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
  302. package/src/hooks/use-credit-balance.ts +27 -0
  303. package/src/hooks/use-my-org-role.ts +1 -3
  304. package/src/hooks/use-plugin-registry.ts +8 -14
  305. package/src/hooks/use-plugin-setup-chat.ts +2 -5
  306. package/src/hooks/use-sidecar-bridge.tsx +148 -0
  307. package/src/hooks/use-webmcp.ts +1 -4
  308. package/src/lib/__tests__/admin-api.test.ts +1 -3
  309. package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
  310. package/src/lib/__tests__/api-fetch.test.ts +4 -16
  311. package/src/lib/__tests__/org-billing-api.test.ts +1 -3
  312. package/src/lib/__tests__/pricing-data.test.ts +0 -8
  313. package/src/lib/__tests__/settings-api.test.ts +1 -3
  314. package/src/lib/admin-affiliate-api.ts +2 -7
  315. package/src/lib/admin-api.ts +6 -26
  316. package/src/lib/admin-incident-api.ts +11 -19
  317. package/src/lib/admin-marketplace-api.ts +1 -5
  318. package/src/lib/api-config.test.ts +5 -50
  319. package/src/lib/api.ts +143 -122
  320. package/src/lib/auth-client.ts +1 -2
  321. package/src/lib/bot-settings-data.ts +11 -36
  322. package/src/lib/brand-config.ts +56 -115
  323. package/src/lib/brand.ts +2 -15
  324. package/src/lib/chat/use-chat.ts +2 -7
  325. package/src/lib/cost-comparison-data.test.ts +1 -3
  326. package/src/lib/cost-comparison-data.ts +1 -4
  327. package/src/lib/errors.ts +1 -4
  328. package/src/lib/fetch-utils.test.ts +26 -9
  329. package/src/lib/fetch-utils.ts +40 -11
  330. package/src/lib/logger.ts +2 -0
  331. package/src/lib/marketplace-data.ts +3 -11
  332. package/src/lib/oauth-errors.ts +2 -4
  333. package/src/lib/onboarding-data.ts +3 -11
  334. package/src/lib/org-api.ts +2 -10
  335. package/src/lib/org-billing-api.ts +5 -19
  336. package/src/lib/plugin/tool-definitions.ts +1 -2
  337. package/src/lib/require-auth.ts +57 -0
  338. package/src/lib/settings-api.ts +1 -4
  339. package/src/lib/sidecar-routes.ts +43 -0
  340. package/src/lib/trpc-server.ts +49 -0
  341. package/src/lib/trpc-types.ts +4 -6
  342. package/src/lib/trpc.tsx +12 -4
  343. package/src/lib/validate-redirect-url.ts +1 -4
  344. package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
  345. package/src/lib/webmcp/register.ts +1 -4
  346. package/src/lib/webmcp/tools.ts +2 -9
  347. package/src/proxy.ts +35 -212
  348. package/src/types/missing-deps.d.ts +2 -8
  349. package/tsconfig.json +1 -8
  350. package/biome.json +0 -52
  351. package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
  352. package/src/__tests__/billing-byok-callout.test.tsx +0 -76
  353. package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +0 -112
@@ -8,14 +8,7 @@ import { toast } from "sonner";
8
8
  import { Badge } from "@/components/ui/badge";
9
9
  import { Button } from "@/components/ui/button";
10
10
  import { Skeleton } from "@/components/ui/skeleton";
11
- import {
12
- Table,
13
- TableBody,
14
- TableCell,
15
- TableHead,
16
- TableHeader,
17
- TableRow,
18
- } from "@/components/ui/table";
11
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
19
12
  import {
20
13
  blockAffiliateFingerprint,
21
14
  type FingerprintCluster,
@@ -89,25 +82,14 @@ function SuppressionFeed() {
89
82
  <Table>
90
83
  <TableHeader>
91
84
  <TableRow className="bg-secondary crt-scanlines">
92
- <TableHead className="text-xs font-medium uppercase tracking-wider">
93
- Referrer
94
- </TableHead>
95
- <TableHead className="text-xs font-medium uppercase tracking-wider">
96
- Referred
97
- </TableHead>
98
- <TableHead className="text-xs font-medium uppercase tracking-wider">
99
- Signals
100
- </TableHead>
85
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Referrer</TableHead>
86
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Referred</TableHead>
87
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Signals</TableHead>
101
88
  <TableHead className="text-xs font-medium uppercase tracking-wider">Phase</TableHead>
102
89
  <TableHead className="text-xs font-medium uppercase tracking-wider">When</TableHead>
103
90
  </TableRow>
104
91
  </TableHeader>
105
- <TableBody
106
- className={cn(
107
- "transition-opacity duration-150",
108
- loading && events.length > 0 && "opacity-60",
109
- )}
110
- >
92
+ <TableBody className={cn("transition-opacity duration-150", loading && events.length > 0 && "opacity-60")}>
111
93
  {loading && events.length === 0 ? (
112
94
  Array.from({ length: 5 }).map((_, i) => (
113
95
  // biome-ignore lint/suspicious/noArrayIndexKey: skeleton rows
@@ -142,9 +124,7 @@ function SuppressionFeed() {
142
124
  events.map((e) => (
143
125
  <TableRow key={e.id} className="h-10 hover:bg-secondary/50">
144
126
  <TableCell className="font-mono text-sm cursor-pointer hover:text-terminal hover:underline">
145
- <Link href={`/admin/tenants?search=${e.referrerTenantId}`}>
146
- {e.referrerTenantId}
147
- </Link>
127
+ <Link href={`/admin/tenants?search=${e.referrerTenantId}`}>{e.referrerTenantId}</Link>
148
128
  </TableCell>
149
129
  <TableCell className="font-mono text-sm">{e.referredTenantId}</TableCell>
150
130
  <TableCell>
@@ -227,24 +207,13 @@ function VelocityPanel() {
227
207
  <Table>
228
208
  <TableHeader>
229
209
  <TableRow className="bg-secondary crt-scanlines">
230
- <TableHead className="text-xs font-medium uppercase tracking-wider">
231
- Referrer
232
- </TableHead>
233
- <TableHead className="text-xs font-medium uppercase tracking-wider">
234
- 30d Payouts
235
- </TableHead>
236
- <TableHead className="text-xs font-medium uppercase tracking-wider">
237
- 30d Total
238
- </TableHead>
210
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Referrer</TableHead>
211
+ <TableHead className="text-xs font-medium uppercase tracking-wider">30d Payouts</TableHead>
212
+ <TableHead className="text-xs font-medium uppercase tracking-wider">30d Total</TableHead>
239
213
  <TableHead className="text-xs font-medium uppercase tracking-wider">Status</TableHead>
240
214
  </TableRow>
241
215
  </TableHeader>
242
- <TableBody
243
- className={cn(
244
- "transition-opacity duration-150",
245
- loading && referrers.length > 0 && "opacity-60",
246
- )}
247
- >
216
+ <TableBody className={cn("transition-opacity duration-150", loading && referrers.length > 0 && "opacity-60")}>
248
217
  {loading && referrers.length === 0 ? (
249
218
  Array.from({ length: 3 }).map((_, i) => (
250
219
  // biome-ignore lint/suspicious/noArrayIndexKey: skeleton rows
@@ -279,22 +248,13 @@ function VelocityPanel() {
279
248
  const atCap = payoutRatio >= 1 || creditRatio >= 1;
280
249
  const nearCap = !atCap && (payoutRatio >= 0.8 || creditRatio >= 0.8);
281
250
 
282
- const countColor = atCap
283
- ? "text-red-400"
284
- : nearCap
285
- ? "text-amber-400"
286
- : "text-terminal";
251
+ const countColor = atCap ? "text-red-400" : nearCap ? "text-amber-400" : "text-terminal";
287
252
  const rowBg = atCap ? "bg-red-500/5" : nearCap ? "bg-amber-500/5" : "";
288
253
 
289
254
  return (
290
- <TableRow
291
- key={r.referrerTenantId}
292
- className={cn("h-10 hover:bg-secondary/50", rowBg)}
293
- >
255
+ <TableRow key={r.referrerTenantId} className={cn("h-10 hover:bg-secondary/50", rowBg)}>
294
256
  <TableCell className="font-mono text-sm cursor-pointer hover:text-terminal hover:underline">
295
- <Link href={`/admin/tenants?search=${r.referrerTenantId}`}>
296
- {r.referrerTenantId}
297
- </Link>
257
+ <Link href={`/admin/tenants?search=${r.referrerTenantId}`}>{r.referrerTenantId}</Link>
298
258
  </TableCell>
299
259
  <TableCell className={cn("font-mono text-sm", countColor)}>
300
260
  {r.payoutCount30d} / {CAP_REFERRALS}
@@ -304,9 +264,7 @@ function VelocityPanel() {
304
264
  </TableCell>
305
265
  <TableCell>
306
266
  {atCap && (
307
- <Badge className="bg-red-500/15 text-red-400 border border-red-500/20 text-xs">
308
- AT CAP
309
- </Badge>
267
+ <Badge className="bg-red-500/15 text-red-400 border border-red-500/20 text-xs">AT CAP</Badge>
310
268
  )}
311
269
  {nearCap && (
312
270
  <Badge className="bg-amber-500/15 text-amber-400 border border-amber-500/20 text-xs">
@@ -314,9 +272,7 @@ function VelocityPanel() {
314
272
  </Badge>
315
273
  )}
316
274
  {!atCap && !nearCap && (
317
- <Badge className="bg-terminal/15 text-terminal border border-terminal/20 text-xs">
318
- NORMAL
319
- </Badge>
275
+ <Badge className="bg-terminal/15 text-terminal border border-terminal/20 text-xs">NORMAL</Badge>
320
276
  )}
321
277
  </TableCell>
322
278
  </TableRow>
@@ -373,31 +329,18 @@ function FingerprintPanel() {
373
329
  <div className="space-y-3">
374
330
  <div>
375
331
  <h2 className="text-lg font-semibold text-foreground">Same-Card Clusters</h2>
376
- <p className="text-xs text-muted-foreground">
377
- Accounts sharing the same Stripe card fingerprint
378
- </p>
332
+ <p className="text-xs text-muted-foreground">Accounts sharing the same Stripe card fingerprint</p>
379
333
  </div>
380
334
  <div className="rounded-sm border border-terminal/10">
381
335
  <Table>
382
336
  <TableHeader>
383
337
  <TableRow className="bg-secondary crt-scanlines">
384
- <TableHead className="text-xs font-medium uppercase tracking-wider">
385
- Fingerprint
386
- </TableHead>
387
- <TableHead className="text-xs font-medium uppercase tracking-wider">
388
- Accounts
389
- </TableHead>
390
- <TableHead className="text-xs font-medium uppercase tracking-wider">
391
- Actions
392
- </TableHead>
338
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Fingerprint</TableHead>
339
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Accounts</TableHead>
340
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Actions</TableHead>
393
341
  </TableRow>
394
342
  </TableHeader>
395
- <TableBody
396
- className={cn(
397
- "transition-opacity duration-150",
398
- loading && clusters.length > 0 && "opacity-60",
399
- )}
400
- >
343
+ <TableBody className={cn("transition-opacity duration-150", loading && clusters.length > 0 && "opacity-60")}>
401
344
  {loading && clusters.length === 0 ? (
402
345
  Array.from({ length: 3 }).map((_, i) => (
403
346
  // biome-ignore lint/suspicious/noArrayIndexKey: skeleton rows
@@ -417,18 +360,13 @@ function FingerprintPanel() {
417
360
  &gt; No same-card clusters detected
418
361
  <span className="animate-ellipsis" />
419
362
  </p>
420
- <p className="text-xs text-muted-foreground mt-1">
421
- All payment fingerprints map to unique accounts
422
- </p>
363
+ <p className="text-xs text-muted-foreground mt-1">All payment fingerprints map to unique accounts</p>
423
364
  </TableCell>
424
365
  </TableRow>
425
366
  ) : (
426
367
  clusters.map((c) => (
427
368
  <TableRow key={c.stripeFingerprint} className="h-10 hover:bg-secondary/50">
428
- <TableCell
429
- className="font-mono text-sm text-muted-foreground"
430
- title={c.stripeFingerprint}
431
- >
369
+ <TableCell className="font-mono text-sm text-muted-foreground" title={c.stripeFingerprint}>
432
370
  {c.stripeFingerprint.substring(0, 10)}...
433
371
  </TableCell>
434
372
  <TableCell>
@@ -465,15 +403,9 @@ function FingerprintPanel() {
465
403
  disabled={blockingFingerprint === c.stripeFingerprint}
466
404
  onClick={() => handleBlock(c.stripeFingerprint)}
467
405
  >
468
- {blockingFingerprint === c.stripeFingerprint
469
- ? "Blocking..."
470
- : "Confirm Block?"}
406
+ {blockingFingerprint === c.stripeFingerprint ? "Blocking..." : "Confirm Block?"}
471
407
  </Button>
472
- <Button
473
- variant="ghost"
474
- size="sm"
475
- onClick={() => setConfirmingFingerprint(null)}
476
- >
408
+ <Button variant="ghost" size="sm" onClick={() => setConfirmingFingerprint(null)}>
477
409
  Cancel
478
410
  </Button>
479
411
  </>
@@ -543,8 +475,7 @@ export function AffiliateDashboard() {
543
475
  AFFILIATE OPS
544
476
  </h1>
545
477
  <p className="text-sm text-muted-foreground font-mono mt-1">
546
- {summary.suppressions} suppressions | {summary.nearCap} referrers near cap |{" "}
547
- {summary.clusters} card clusters
478
+ {summary.suppressions} suppressions | {summary.nearCap} referrers near cap | {summary.clusters} card clusters
548
479
  </p>
549
480
  </div>
550
481
 
@@ -5,22 +5,9 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation";
5
5
  import { useCallback, useEffect, useMemo, useState } from "react";
6
6
  import { Button } from "@/components/ui/button";
7
7
  import { Input } from "@/components/ui/input";
8
- import {
9
- Select,
10
- SelectContent,
11
- SelectItem,
12
- SelectTrigger,
13
- SelectValue,
14
- } from "@/components/ui/select";
8
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
15
9
  import { Skeleton } from "@/components/ui/skeleton";
16
- import {
17
- Table,
18
- TableBody,
19
- TableCell,
20
- TableHead,
21
- TableHeader,
22
- TableRow,
23
- } from "@/components/ui/table";
10
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
24
11
  import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
25
12
  import type { AuditLogResponse } from "@/lib/api";
26
13
  import { fetchAuditLog } from "@/lib/api";
@@ -65,11 +52,9 @@ function relativeTime(iso: string): string {
65
52
  function actionBadgeClasses(action: string): string {
66
53
  if (action.startsWith("admin.suspend") || action.startsWith("admin.ban"))
67
54
  return "bg-destructive/15 text-red-400 border border-destructive/20";
68
- if (action.startsWith("admin.reactivate"))
69
- return "bg-terminal/15 text-terminal border border-terminal/20";
55
+ if (action.startsWith("admin.reactivate")) return "bg-terminal/15 text-terminal border border-terminal/20";
70
56
  if (action.startsWith("billing")) return "bg-chart-3/15 text-amber-400 border border-chart-3/20";
71
- if (action.startsWith("security"))
72
- return "bg-destructive/15 text-red-400 border border-destructive/20";
57
+ if (action.startsWith("security")) return "bg-destructive/15 text-red-400 border border-destructive/20";
73
58
  return "bg-secondary text-muted-foreground border border-border";
74
59
  }
75
60
 
@@ -96,9 +81,7 @@ export function AuditLogTable() {
96
81
  setLoadError(false);
97
82
  try {
98
83
  const since =
99
- dateRange === "all"
100
- ? undefined
101
- : new Date(Date.now() - Number(dateRange) * 86400000).toISOString();
84
+ dateRange === "all" ? undefined : new Date(Date.now() - Number(dateRange) * 86400000).toISOString();
102
85
  const result = await fetchAuditLog({
103
86
  limit: PAGE_SIZE,
104
87
  offset: newOffset,
@@ -171,9 +154,7 @@ export function AuditLogTable() {
171
154
  <h1 className="text-xl font-bold uppercase tracking-wider text-terminal [text-shadow:0_0_10px_rgba(0,255,65,0.25)]">
172
155
  AUDIT LOG
173
156
  </h1>
174
- <span className="text-sm text-muted-foreground font-mono">
175
- {data ? `${data.total} events` : "Loading..."}
176
- </span>
157
+ <span className="text-sm text-muted-foreground font-mono">{data ? `${data.total} events` : "Loading..."}</span>
177
158
  </div>
178
159
 
179
160
  {/* Filters */}
@@ -218,21 +199,13 @@ export function AuditLogTable() {
218
199
  <Table>
219
200
  <TableHeader>
220
201
  <TableRow className="bg-secondary crt-scanlines">
221
- <TableHead className="text-xs font-medium uppercase tracking-wider w-[100px]">
222
- Time
223
- </TableHead>
202
+ <TableHead className="text-xs font-medium uppercase tracking-wider w-[100px]">Time</TableHead>
224
203
  <TableHead className="text-xs font-medium uppercase tracking-wider">Action</TableHead>
225
- <TableHead className="text-xs font-medium uppercase tracking-wider">
226
- Resource
227
- </TableHead>
228
- <TableHead className="text-xs font-medium uppercase tracking-wider">
229
- Details
230
- </TableHead>
204
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Resource</TableHead>
205
+ <TableHead className="text-xs font-medium uppercase tracking-wider">Details</TableHead>
231
206
  </TableRow>
232
207
  </TableHeader>
233
- <TableBody
234
- className={cn("transition-opacity duration-150", loading && data && "opacity-60")}
235
- >
208
+ <TableBody className={cn("transition-opacity duration-150", loading && data && "opacity-60")}>
236
209
  {loading && !data ? (
237
210
  ["s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8"].map((rowKey, i) => (
238
211
  <TableRow key={rowKey} className="h-10">
@@ -274,12 +247,8 @@ export function AuditLogTable() {
274
247
  </span>
275
248
  </TableCell>
276
249
  <TableCell className="text-sm">
277
- <span className="text-xs uppercase tracking-wide text-muted-foreground">
278
- {event.resourceType}
279
- </span>{" "}
280
- <span className="font-mono text-xs">
281
- {event.resourceName ?? event.resourceId}
282
- </span>
250
+ <span className="text-xs uppercase tracking-wide text-muted-foreground">{event.resourceType}</span>{" "}
251
+ <span className="font-mono text-xs">{event.resourceName ?? event.resourceId}</span>
283
252
  </TableCell>
284
253
  <TableCell className="text-xs text-muted-foreground max-w-[300px] truncate">
285
254
  {event.details ?? "\u2014"}
@@ -309,12 +278,7 @@ export function AuditLogTable() {
309
278
  >
310
279
  Previous
311
280
  </Button>
312
- <Button
313
- variant="ghost"
314
- size="xs"
315
- disabled={!data.hasMore}
316
- onClick={() => load(offset + PAGE_SIZE)}
317
- >
281
+ <Button variant="ghost" size="xs" disabled={!data.hasMore} onClick={() => load(offset + PAGE_SIZE)}>
318
282
  Next
319
283
  </Button>
320
284
  <Button
@@ -79,9 +79,7 @@ function CheckRow({ ok, label, detail }: { ok: boolean; label: string; detail?:
79
79
  return (
80
80
  <div className="flex items-center justify-between py-2 border-b border-border/50 last:border-0">
81
81
  <div className="flex items-center gap-2">
82
- <div
83
- className={cn("w-2 h-2 rounded-full flex-shrink-0", ok ? "bg-green-500" : "bg-red-500")}
84
- />
82
+ <div className={cn("w-2 h-2 rounded-full flex-shrink-0", ok ? "bg-green-500" : "bg-red-500")} />
85
83
  <span className="text-sm">{label}</span>
86
84
  </div>
87
85
  {detail && <span className="text-xs text-muted-foreground">{detail}</span>}
@@ -131,9 +129,7 @@ export function BillingHealthDashboard() {
131
129
 
132
130
  async function poll() {
133
131
  try {
134
- const result = (await trpcVanilla.admin.billingHealth.query(
135
- undefined,
136
- )) as BillingHealthData;
132
+ const result = (await trpcVanilla.admin.billingHealth.query(undefined)) as BillingHealthData;
137
133
  if (active) {
138
134
  setData(result);
139
135
  setError(null);
@@ -184,9 +180,7 @@ export function BillingHealthDashboard() {
184
180
  <div className="flex items-center justify-between">
185
181
  <div className="flex items-center gap-3">
186
182
  <StatusBadge status={data.overall} />
187
- {data.severity && (
188
- <span className="text-sm text-muted-foreground font-medium">{data.severity}</span>
189
- )}
183
+ {data.severity && <span className="text-sm text-muted-foreground font-medium">{data.severity}</span>}
190
184
  </div>
191
185
  {lastUpdated && (
192
186
  <span className="text-xs text-muted-foreground">
@@ -230,9 +224,7 @@ export function BillingHealthDashboard() {
230
224
  label="Revenue (24h)"
231
225
  value={formatCents(data.business.revenueToday)}
232
226
  sub={
233
- data.business.activeTenantCount !== null
234
- ? `${data.business.activeTenantCount} active tenants`
235
- : undefined
227
+ data.business.activeTenantCount !== null ? `${data.business.activeTenantCount} active tenants` : undefined
236
228
  }
237
229
  />
238
230
  </div>
@@ -298,12 +290,7 @@ export function BillingHealthDashboard() {
298
290
  </CardHeader>
299
291
  <CardContent>
300
292
  {data.alerts.map((alert) => (
301
- <CheckRow
302
- key={alert.name}
303
- ok={!alert.firing}
304
- label={alert.name}
305
- detail={alert.message}
306
- />
293
+ <CheckRow key={alert.name} ok={!alert.firing} label={alert.name} detail={alert.message} />
307
294
  ))}
308
295
  </CardContent>
309
296
  </Card>
@@ -319,11 +306,7 @@ export function BillingHealthDashboard() {
319
306
  <div>
320
307
  <div className="text-xs text-muted-foreground mb-1">CPU</div>
321
308
  <div className="text-lg font-medium">
322
- {(data.system.cpuCount > 0
323
- ? (data.system.cpuLoad1m / data.system.cpuCount) * 100
324
- : 0
325
- ).toFixed(0)}
326
- %
309
+ {(data.system.cpuCount > 0 ? (data.system.cpuLoad1m / data.system.cpuCount) * 100 : 0).toFixed(0)}%
327
310
  </div>
328
311
  <div className="text-xs text-muted-foreground">
329
312
  Load {data.system.cpuLoad1m.toFixed(2)} / {data.system.cpuCount} cores
@@ -339,8 +322,7 @@ export function BillingHealthDashboard() {
339
322
  %
340
323
  </div>
341
324
  <div className="text-xs text-muted-foreground">
342
- {formatBytes(data.system.memoryUsedBytes)} /{" "}
343
- {formatBytes(data.system.memoryTotalBytes)}
325
+ {formatBytes(data.system.memoryUsedBytes)} / {formatBytes(data.system.memoryTotalBytes)}
344
326
  </div>
345
327
  </div>
346
328
  <div>
@@ -79,13 +79,7 @@ describe("BulkActionsBar", () => {
79
79
  it("fires onReactivate when Reactivate clicked", async () => {
80
80
  const user = userEvent.setup();
81
81
  const onReactivate = vi.fn();
82
- render(
83
- <BulkActionsBar
84
- {...defaultProps}
85
- hasSuspendedInSelection={true}
86
- onReactivate={onReactivate}
87
- />,
88
- );
82
+ render(<BulkActionsBar {...defaultProps} hasSuspendedInSelection={true} onReactivate={onReactivate} />);
89
83
  await user.click(screen.getByText("Reactivate"));
90
84
  expect(onReactivate).toHaveBeenCalledOnce();
91
85
  });
@@ -37,9 +37,7 @@ function BulkActionsBar({
37
37
  >
38
38
  <div className="flex items-center gap-2">
39
39
  <span className="text-lg font-semibold text-terminal">{selectedCount} selected</span>
40
- {allMatchingSelected && (
41
- <span className="text-sm text-muted-foreground">(all matching filters)</span>
42
- )}
40
+ {allMatchingSelected && <span className="text-sm text-muted-foreground">(all matching filters)</span>}
43
41
  </div>
44
42
 
45
43
  <div className="flex items-center gap-2">
@@ -47,13 +47,7 @@ describe("BulkExportDialog", () => {
47
47
  it("disables Generate export when all fields unchecked", async () => {
48
48
  const user = userEvent.setup();
49
49
  render(<BulkExportDialog {...defaultProps} />);
50
- for (const label of [
51
- "Account info",
52
- "Credit balance",
53
- "Monthly products",
54
- "Lifetime spend",
55
- "Last seen",
56
- ]) {
50
+ for (const label of ["Account info", "Credit balance", "Monthly products", "Lifetime spend", "Last seen"]) {
57
51
  await user.click(screen.getByLabelText(label));
58
52
  }
59
53
  expect(screen.getByText("Generate export").closest("button")).toBeDisabled();
@@ -14,13 +14,7 @@ import {
14
14
  DialogTitle,
15
15
  } from "@/components/ui/dialog";
16
16
  import { Label } from "@/components/ui/label";
17
- import {
18
- Select,
19
- SelectContent,
20
- SelectItem,
21
- SelectTrigger,
22
- SelectValue,
23
- } from "@/components/ui/select";
17
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
24
18
  import { Separator } from "@/components/ui/separator";
25
19
 
26
20
  type ExportFieldKey =
@@ -55,13 +49,7 @@ interface BulkExportDialogProps {
55
49
  isLoading?: boolean;
56
50
  }
57
51
 
58
- function BulkExportDialog({
59
- open,
60
- onOpenChange,
61
- selectedCount,
62
- onConfirm,
63
- isLoading,
64
- }: BulkExportDialogProps) {
52
+ function BulkExportDialog({ open, onOpenChange, selectedCount, onConfirm, isLoading }: BulkExportDialogProps) {
65
53
  const [enabledFields, setEnabledFields] = useState<Set<ExportFieldKey>>(
66
54
  new Set(["account_info", "credit_balance", "monthly_products", "lifetime_spend", "last_seen"]),
67
55
  );
@@ -85,15 +73,7 @@ function BulkExportDialog({
85
73
 
86
74
  const handleOpenChange = (next: boolean) => {
87
75
  if (!next) {
88
- setEnabledFields(
89
- new Set([
90
- "account_info",
91
- "credit_balance",
92
- "monthly_products",
93
- "lifetime_spend",
94
- "last_seen",
95
- ]),
96
- );
76
+ setEnabledFields(new Set(["account_info", "credit_balance", "monthly_products", "lifetime_spend", "last_seen"]));
97
77
  }
98
78
  onOpenChange(next);
99
79
  };
@@ -125,9 +105,7 @@ function BulkExportDialog({
125
105
  <Label htmlFor={`export-${field.key}`} className="cursor-pointer">
126
106
  {field.label}
127
107
  </Label>
128
- {field.description && (
129
- <span className="text-xs text-muted-foreground">{field.description}</span>
130
- )}
108
+ {field.description && <span className="text-xs text-muted-foreground">{field.description}</span>}
131
109
  </div>
132
110
  </div>
133
111
  ))}
@@ -170,11 +148,7 @@ function BulkExportDialog({
170
148
  <Button variant="outline" onClick={() => handleOpenChange(false)} disabled={isLoading}>
171
149
  Cancel
172
150
  </Button>
173
- <Button
174
- variant="terminal"
175
- onClick={handleConfirm}
176
- disabled={enabledFields.size === 0 || isLoading}
177
- >
151
+ <Button variant="terminal" onClick={handleConfirm} disabled={enabledFields.size === 0 || isLoading}>
178
152
  <Download className="size-4" />
179
153
  Generate export
180
154
  <ArrowRight className="size-4" />
@@ -185,5 +159,5 @@ function BulkExportDialog({
185
159
  );
186
160
  }
187
161
 
188
- export { BulkExportDialog };
189
162
  export type { ExportFieldKey };
163
+ export { BulkExportDialog };
@@ -21,9 +21,7 @@ describe("BulkGrantDialog", () => {
21
21
  it("confirm button is disabled when amount is 0", () => {
22
22
  render(<BulkGrantDialog {...defaultProps} />);
23
23
  const buttons = screen.getAllByRole("button");
24
- const confirmBtn = buttons.find(
25
- (b) => b.textContent?.includes("Grant") && b.textContent?.includes("="),
26
- );
24
+ const confirmBtn = buttons.find((b) => b.textContent?.includes("Grant") && b.textContent?.includes("="));
27
25
  expect(confirmBtn).toBeDisabled();
28
26
  });
29
27
 
@@ -32,9 +30,7 @@ describe("BulkGrantDialog", () => {
32
30
  render(<BulkGrantDialog {...defaultProps} />);
33
31
  await user.type(screen.getByLabelText("Amount per tenant"), "5");
34
32
  const buttons = screen.getAllByRole("button");
35
- const confirmBtn = buttons.find(
36
- (b) => b.textContent?.includes("Grant") && b.textContent?.includes("="),
37
- );
33
+ const confirmBtn = buttons.find((b) => b.textContent?.includes("Grant") && b.textContent?.includes("="));
38
34
  expect(confirmBtn).toBeDisabled();
39
35
  });
40
36
 
@@ -25,13 +25,7 @@ interface BulkGrantDialogProps {
25
25
  isLoading?: boolean;
26
26
  }
27
27
 
28
- function BulkGrantDialog({
29
- open,
30
- onOpenChange,
31
- selectedCount,
32
- onConfirm,
33
- isLoading,
34
- }: BulkGrantDialogProps) {
28
+ function BulkGrantDialog({ open, onOpenChange, selectedCount, onConfirm, isLoading }: BulkGrantDialogProps) {
35
29
  const [amount, setAmount] = useState("");
36
30
  const [reason, setReason] = useState("");
37
31
  const [notifyByEmail, setNotifyByEmail] = useState(false);
@@ -66,21 +60,16 @@ function BulkGrantDialog({
66
60
  <DialogHeader>
67
61
  <DialogTitle className="flex items-center gap-2">
68
62
  <Gift className="size-5 text-terminal" />
69
- Grant credits to <span className="text-terminal font-semibold">{selectedCount}</span>{" "}
70
- tenants
63
+ Grant credits to <span className="text-terminal font-semibold">{selectedCount}</span> tenants
71
64
  </DialogTitle>
72
- <DialogDescription>
73
- Grant a fixed amount to each selected tenant account.
74
- </DialogDescription>
65
+ <DialogDescription>Grant a fixed amount to each selected tenant account.</DialogDescription>
75
66
  </DialogHeader>
76
67
 
77
68
  <div className="flex flex-col gap-4">
78
69
  <div className="space-y-2">
79
70
  <Label htmlFor="grant-amount">Amount per tenant</Label>
80
71
  <div className="relative">
81
- <span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">
82
- $
83
- </span>
72
+ <span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">$</span>
84
73
  <Input
85
74
  id="grant-amount"
86
75
  type="number"
@@ -9,14 +9,7 @@ import {
9
9
  DialogHeader,
10
10
  DialogTitle,
11
11
  } from "@/components/ui/dialog";
12
- import {
13
- Table,
14
- TableBody,
15
- TableCell,
16
- TableHead,
17
- TableHeader,
18
- TableRow,
19
- } from "@/components/ui/table";
12
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
20
13
 
21
14
  interface PreviewTenant {
22
15
  tenantId: string;
@@ -51,9 +44,7 @@ function BulkPreviewDialog({
51
44
  <DialogContent className="sm:max-w-2xl">
52
45
  <DialogHeader>
53
46
  <DialogTitle>Preview: {tenants.length} tenants will be affected</DialogTitle>
54
- <DialogDescription>
55
- Review the list of tenants before executing the operation.
56
- </DialogDescription>
47
+ <DialogDescription>Review the list of tenants before executing the operation.</DialogDescription>
57
48
  </DialogHeader>
58
49
 
59
50
  <div className="max-h-80 overflow-y-auto rounded-sm border border-border">
@@ -102,5 +93,5 @@ function BulkPreviewDialog({
102
93
  );
103
94
  }
104
95
 
105
- export { BulkPreviewDialog };
106
96
  export type { PreviewTenant };
97
+ export { BulkPreviewDialog };
@@ -19,13 +19,7 @@ interface BulkReactivateDialogProps {
19
19
  isLoading?: boolean;
20
20
  }
21
21
 
22
- function BulkReactivateDialog({
23
- open,
24
- onOpenChange,
25
- selectedCount,
26
- onConfirm,
27
- isLoading,
28
- }: BulkReactivateDialogProps) {
22
+ function BulkReactivateDialog({ open, onOpenChange, selectedCount, onConfirm, isLoading }: BulkReactivateDialogProps) {
29
23
  return (
30
24
  <Dialog open={open} onOpenChange={onOpenChange}>
31
25
  <DialogContent className="sm:max-w-sm">
@@ -10,12 +10,7 @@ interface BulkSelectAllBannerProps {
10
10
  onSelectAllMatching: () => void;
11
11
  }
12
12
 
13
- function BulkSelectAllBanner({
14
- visible,
15
- pageCount,
16
- totalMatching,
17
- onSelectAllMatching,
18
- }: BulkSelectAllBannerProps) {
13
+ function BulkSelectAllBanner({ visible, pageCount, totalMatching, onSelectAllMatching }: BulkSelectAllBannerProps) {
19
14
  return (
20
15
  <AnimatePresence>
21
16
  {visible && (