@wopr-network/platform-ui-core 1.27.7 → 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 +14 -17
  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
@@ -1,4 +1,5 @@
1
1
  import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { trpcVanillaProxy } from "./setup.js";
2
3
 
3
4
  const mockTestProviderKey = vi.fn();
4
5
  const mockSaveProviderKey = vi.fn();
@@ -30,7 +31,7 @@ vi.mock("@/lib/fetch-utils", () => ({
30
31
  }));
31
32
 
32
33
  vi.mock("@/lib/trpc", () => ({
33
- trpcVanilla: {},
34
+ trpcVanilla: trpcVanillaProxy,
34
35
  }));
35
36
 
36
37
  import { validateElevenLabsKey } from "@/lib/api";
@@ -22,12 +22,8 @@ vi.mock("better-auth/react", () => ({
22
22
 
23
23
  vi.mock("framer-motion", () => ({
24
24
  motion: {
25
- div: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => (
26
- <div {...props}>{children}</div>
27
- ),
28
- p: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => (
29
- <p {...props}>{children}</p>
30
- ),
25
+ div: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => <div {...props}>{children}</div>,
26
+ p: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => <p {...props}>{children}</p>,
31
27
  },
32
28
  }));
33
29
 
@@ -51,10 +47,7 @@ describe("VerifyPage", () => {
51
47
  expect(screen.getByText("Email verified")).toBeInTheDocument();
52
48
  expect(screen.getByText(/verified successfully/)).toBeInTheDocument();
53
49
  expect(screen.getByText(/\$5 signup credit/)).toBeInTheDocument();
54
- expect(screen.getByRole("link", { name: /Continue to setup/ })).toHaveAttribute(
55
- "href",
56
- "/onboarding",
57
- );
50
+ expect(screen.getByRole("link", { name: /Continue to setup/ })).toHaveAttribute("href", "/onboarding");
58
51
  });
59
52
 
60
53
  it("redirects to dashboard after countdown on success", async () => {
@@ -71,9 +64,7 @@ describe("VerifyPage", () => {
71
64
  });
72
65
 
73
66
  it("renders token-expired error with resend button when email param present", async () => {
74
- mockSearchParams = new URLSearchParams(
75
- "status=error&reason=token-expired&email=test@example.com",
76
- );
67
+ mockSearchParams = new URLSearchParams("status=error&reason=token-expired&email=test@example.com");
77
68
 
78
69
  const { default: VerifyPage } = await import("@/app/auth/verify/page");
79
70
  render(<VerifyPage />);
@@ -15,12 +15,8 @@ vi.mock("@/components/auth/resend-verification-button", () => ({
15
15
  }));
16
16
  vi.mock("framer-motion", () => ({
17
17
  motion: {
18
- div: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => (
19
- <div {...props}>{children}</div>
20
- ),
21
- p: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => (
22
- <p {...props}>{children}</p>
23
- ),
18
+ div: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => <div {...props}>{children}</div>,
19
+ p: ({ children, ...props }: React.PropsWithChildren<Record<string, unknown>>) => <p {...props}>{children}</p>,
24
20
  },
25
21
  }));
26
22
 
@@ -8,13 +8,7 @@ import { logger } from "@/lib/logger";
8
8
 
9
9
  const log = logger("error-boundary:auth");
10
10
 
11
- export default function AuthError({
12
- error,
13
- reset,
14
- }: {
15
- error: Error & { digest?: string };
16
- reset: () => void;
17
- }) {
11
+ export default function AuthError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
18
12
  const [showDetails, setShowDetails] = useState(false);
19
13
  const isDev = process.env.NODE_ENV === "development";
20
14
 
@@ -6,14 +6,7 @@ import { type FormEvent, useState } from "react";
6
6
  import { AuthError } from "@/components/auth/auth-error";
7
7
  import { AuthShell } from "@/components/auth/auth-shell";
8
8
  import { Button } from "@/components/ui/button";
9
- import {
10
- Card,
11
- CardContent,
12
- CardDescription,
13
- CardFooter,
14
- CardHeader,
15
- CardTitle,
16
- } from "@/components/ui/card";
9
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
17
10
  import { Input } from "@/components/ui/input";
18
11
  import { Label } from "@/components/ui/label";
19
12
  import { authClient } from "@/lib/auth-client";
@@ -69,15 +62,11 @@ export default function ForgotPasswordPage() {
69
62
  </CardHeader>
70
63
  <CardContent>
71
64
  <p className="text-sm text-muted-foreground">
72
- Click the link in the email to reset your password. If you don&apos;t see it, check
73
- your spam folder.
65
+ Click the link in the email to reset your password. If you don&apos;t see it, check your spam folder.
74
66
  </p>
75
67
  </CardContent>
76
68
  <CardFooter className="justify-center">
77
- <Link
78
- href="/login"
79
- className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal"
80
- >
69
+ <Link href="/login" className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal">
81
70
  Back to sign in
82
71
  </Link>
83
72
  </CardFooter>
@@ -124,10 +113,7 @@ export default function ForgotPasswordPage() {
124
113
  </form>
125
114
  </CardContent>
126
115
  <CardFooter className="justify-center">
127
- <Link
128
- href="/login"
129
- className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal"
130
- >
116
+ <Link href="/login" className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal">
131
117
  Back to sign in
132
118
  </Link>
133
119
  </CardFooter>
@@ -9,14 +9,7 @@ import { AuthShell } from "@/components/auth/auth-shell";
9
9
  import { ResendVerificationButton } from "@/components/auth/resend-verification-button";
10
10
  import { OAuthButtons } from "@/components/oauth-buttons";
11
11
  import { Button } from "@/components/ui/button";
12
- import {
13
- Card,
14
- CardContent,
15
- CardDescription,
16
- CardFooter,
17
- CardHeader,
18
- CardTitle,
19
- } from "@/components/ui/card";
12
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
20
13
  import { Input } from "@/components/ui/input";
21
14
  import { Label } from "@/components/ui/label";
22
15
  import { signIn } from "@/lib/auth-client";
@@ -28,9 +21,7 @@ function LoginForm() {
28
21
  const [email, setEmail] = useState("");
29
22
  const [password, setPassword] = useState("");
30
23
  const [error, setError] = useState<string | null>(null);
31
- const [errorType, setErrorType] = useState<
32
- "credentials" | "unverified" | "suspended" | "generic" | null
33
- >(null);
24
+ const [errorType, setErrorType] = useState<"credentials" | "unverified" | "suspended" | "generic" | null>(null);
34
25
  const [loading, setLoading] = useState(false);
35
26
 
36
27
  const searchParams = useSearchParams();
@@ -80,9 +71,7 @@ function LoginForm() {
80
71
  <AuthShell>
81
72
  <Card className="crt-scanlines border-terminal/20 bg-black/80 shadow-[0_0_30px_rgba(0,255,65,0.08)]">
82
73
  <CardHeader>
83
- <CardTitle className="text-sm font-medium uppercase tracking-widest text-terminal">
84
- Sign in
85
- </CardTitle>
74
+ <CardTitle className="text-sm font-medium uppercase tracking-widest text-terminal">Sign in</CardTitle>
86
75
  <CardDescription>Access your {productName()} terminal</CardDescription>
87
76
  </CardHeader>
88
77
  <CardContent>
@@ -108,10 +97,7 @@ function LoginForm() {
108
97
  <div className="flex flex-col gap-2">
109
98
  <div className="flex items-center justify-between">
110
99
  <Label htmlFor="password">Password</Label>
111
- <Link
112
- href="/forgot-password"
113
- className="text-xs text-terminal-dim hover:text-terminal"
114
- >
100
+ <Link href="/forgot-password" className="text-xs text-terminal-dim hover:text-terminal">
115
101
  Forgot password?
116
102
  </Link>
117
103
  </div>
@@ -165,10 +151,7 @@ function LoginForm() {
165
151
  <CardFooter className="justify-center">
166
152
  <p className="text-sm text-muted-foreground">
167
153
  Don&apos;t have an account?{" "}
168
- <Link
169
- href="/signup"
170
- className="text-terminal-dim underline underline-offset-4 hover:text-terminal"
171
- >
154
+ <Link href="/signup" className="text-terminal-dim underline underline-offset-4 hover:text-terminal">
172
155
  Sign up
173
156
  </Link>
174
157
  </p>
@@ -6,14 +6,7 @@ import { type FormEvent, Suspense, useState } from "react";
6
6
  import { AuthError } from "@/components/auth/auth-error";
7
7
  import { AuthShell } from "@/components/auth/auth-shell";
8
8
  import { Button } from "@/components/ui/button";
9
- import {
10
- Card,
11
- CardContent,
12
- CardDescription,
13
- CardFooter,
14
- CardHeader,
15
- CardTitle,
16
- } from "@/components/ui/card";
9
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
17
10
  import { Input } from "@/components/ui/input";
18
11
  import { Label } from "@/components/ui/label";
19
12
  import { authClient } from "@/lib/auth-client";
@@ -148,10 +141,7 @@ function ResetPasswordForm() {
148
141
  </form>
149
142
  </CardContent>
150
143
  <CardFooter className="justify-center">
151
- <Link
152
- href="/login"
153
- className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal"
154
- >
144
+ <Link href="/login" className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal">
155
145
  Back to sign in
156
146
  </Link>
157
147
  </CardFooter>
@@ -10,14 +10,7 @@ import { AuthShell } from "@/components/auth/auth-shell";
10
10
  import { ResendVerificationButton } from "@/components/auth/resend-verification-button";
11
11
  import { OAuthButtons } from "@/components/oauth-buttons";
12
12
  import { Button } from "@/components/ui/button";
13
- import {
14
- Card,
15
- CardContent,
16
- CardDescription,
17
- CardFooter,
18
- CardHeader,
19
- CardTitle,
20
- } from "@/components/ui/card";
13
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
21
14
  import { Checkbox } from "@/components/ui/checkbox";
22
15
  import { Input } from "@/components/ui/input";
23
16
  import { Label } from "@/components/ui/label";
@@ -37,13 +30,7 @@ function getPasswordStrength(password: string): { score: number; label: string }
37
30
  return { score, label: labels[Math.min(score, labels.length) - 1] ?? "" };
38
31
  }
39
32
 
40
- const strengthColors = [
41
- "bg-red-500",
42
- "bg-red-500",
43
- "bg-amber-500",
44
- "bg-terminal",
45
- "bg-terminal-dim",
46
- ];
33
+ const strengthColors = ["bg-red-500", "bg-red-500", "bg-amber-500", "bg-terminal", "bg-terminal-dim"];
47
34
 
48
35
  const strengthLabelColors = [
49
36
  "text-destructive",
@@ -141,10 +128,7 @@ function SignupForm() {
141
128
  <ResendVerificationButton email={email} />
142
129
  </CardContent>
143
130
  <CardFooter className="justify-center">
144
- <Link
145
- href="/login"
146
- className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal"
147
- >
131
+ <Link href="/login" className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal">
148
132
  Back to sign in
149
133
  </Link>
150
134
  </CardFooter>
@@ -157,9 +141,7 @@ function SignupForm() {
157
141
  <AuthShell>
158
142
  <Card className="crt-scanlines border-terminal/20 bg-black/80 shadow-[0_0_30px_rgba(0,255,65,0.08)]">
159
143
  <CardHeader>
160
- <CardTitle className="text-sm font-medium uppercase tracking-widest text-terminal">
161
- Create account
162
- </CardTitle>
144
+ <CardTitle className="text-sm font-medium uppercase tracking-widest text-terminal">Create account</CardTitle>
163
145
  <CardDescription>Register for {productName()} access</CardDescription>
164
146
  </CardHeader>
165
147
  <CardContent>
@@ -210,18 +192,14 @@ function SignupForm() {
210
192
  <div
211
193
  key={seg.key}
212
194
  className={`h-1 flex-1 rounded-full ${
213
- seg.index < strength.score
214
- ? strengthColors[strength.score - 1]
215
- : "bg-terminal/20"
195
+ seg.index < strength.score ? strengthColors[strength.score - 1] : "bg-terminal/20"
216
196
  }`}
217
197
  />
218
198
  ))}
219
199
  </div>
220
200
  <span
221
201
  className={`text-xs ${
222
- strength.score > 0
223
- ? strengthLabelColors[strength.score - 1]
224
- : "text-muted-foreground"
202
+ strength.score > 0 ? strengthLabelColors[strength.score - 1] : "text-muted-foreground"
225
203
  }`}
226
204
  >
227
205
  {strength.label}
@@ -249,22 +227,13 @@ function SignupForm() {
249
227
  onCheckedChange={(checked) => setAgreedToTerms(checked === true)}
250
228
  className="mt-0.5 data-[state=checked]:border-terminal data-[state=checked]:bg-terminal"
251
229
  />
252
- <Label
253
- htmlFor="agree-terms"
254
- className="text-muted-foreground font-normal cursor-pointer"
255
- >
230
+ <Label htmlFor="agree-terms" className="text-muted-foreground font-normal cursor-pointer">
256
231
  I agree to the{" "}
257
- <Link
258
- href="/terms"
259
- className="text-terminal-dim underline underline-offset-4 hover:text-terminal"
260
- >
232
+ <Link href="/terms" className="text-terminal-dim underline underline-offset-4 hover:text-terminal">
261
233
  Terms of Service
262
234
  </Link>{" "}
263
235
  and{" "}
264
- <Link
265
- href="/privacy"
266
- className="text-terminal-dim underline underline-offset-4 hover:text-terminal"
267
- >
236
+ <Link href="/privacy" className="text-terminal-dim underline underline-offset-4 hover:text-terminal">
268
237
  Privacy Policy
269
238
  </Link>
270
239
  </Label>
@@ -286,10 +255,7 @@ function SignupForm() {
286
255
  <CardFooter className="justify-center">
287
256
  <p className="text-sm text-muted-foreground">
288
257
  Already have an account?{" "}
289
- <Link
290
- href="/login"
291
- className="text-terminal-dim underline underline-offset-4 hover:text-terminal"
292
- >
258
+ <Link href="/login" className="text-terminal-dim underline underline-offset-4 hover:text-terminal">
293
259
  Sign in
294
260
  </Link>
295
261
  </p>
@@ -0,0 +1,47 @@
1
+ import { CheckCircle2, XCircle } from "lucide-react";
2
+ import Link from "next/link";
3
+
4
+ export default async function VerifyPage({
5
+ searchParams,
6
+ }: {
7
+ searchParams: Promise<{ status?: string; reason?: string }>;
8
+ }) {
9
+ const { status, reason } = await searchParams;
10
+ const success = status === "success";
11
+
12
+ return (
13
+ <div className="flex flex-col items-center gap-4 text-center">
14
+ {success ? (
15
+ <>
16
+ <CheckCircle2 className="size-12 text-terminal" />
17
+ <h1 className="text-2xl font-bold tracking-tight">Email verified</h1>
18
+ <p className="text-sm text-muted-foreground">
19
+ Your account is active and you&apos;ve been granted $5.00 in free credits.
20
+ </p>
21
+ <Link
22
+ href="/login"
23
+ className="mt-2 inline-flex items-center justify-center rounded-md bg-terminal px-6 py-2 text-sm font-medium text-terminal-foreground hover:bg-terminal/90 transition-colors"
24
+ >
25
+ Sign in
26
+ </Link>
27
+ </>
28
+ ) : (
29
+ <>
30
+ <XCircle className="size-12 text-destructive" />
31
+ <h1 className="text-2xl font-bold tracking-tight">Verification failed</h1>
32
+ <p className="text-sm text-muted-foreground">
33
+ {reason === "missing_token"
34
+ ? "No verification token provided."
35
+ : "This link is invalid or has expired. Please request a new one."}
36
+ </p>
37
+ <Link
38
+ href="/login"
39
+ className="mt-2 inline-flex items-center justify-center rounded-md bg-terminal px-6 py-2 text-sm font-medium text-terminal-foreground hover:bg-terminal/90 transition-colors"
40
+ >
41
+ Back to login
42
+ </Link>
43
+ </>
44
+ )}
45
+ </div>
46
+ );
47
+ }
@@ -1,37 +1,27 @@
1
1
  "use client";
2
2
 
3
- import { Clock } from "lucide-react";
4
- import { usePathname, useRouter, useSearchParams } from "next/navigation";
5
3
  import { Suspense, useEffect, useState } from "react";
6
- import { AutoTopupCard } from "@/components/billing/auto-topup-card";
7
- import { BuyCreditsPanel } from "@/components/billing/buy-credits-panel";
8
- import { CouponInput } from "@/components/billing/coupon-input";
9
4
  import { CreditBalance } from "@/components/billing/credit-balance";
10
- import { CryptoCheckout } from "@/components/billing/crypto-checkout";
11
5
  import { DividendBanner } from "@/components/billing/dividend-banner";
12
6
  import { DividendEligibility } from "@/components/billing/dividend-eligibility";
13
7
  import { DividendPoolStats } from "@/components/billing/dividend-pool-stats";
14
8
  import { FirstDividendDialog } from "@/components/billing/first-dividend-dialog";
15
9
  import { LowBalanceBanner } from "@/components/billing/low-balance-banner";
16
- import { OrgBillingPage } from "@/components/billing/org-billing-page";
17
10
  import { TransactionHistory } from "@/components/billing/transaction-history";
11
+ import { UnifiedCheckout } from "@/components/billing/unified-checkout";
18
12
  import { Button } from "@/components/ui/button";
19
13
  import { Skeleton } from "@/components/ui/skeleton";
20
- import type { CreditBalance as CreditBalanceData, DividendWalletStats } from "@/lib/api";
14
+ import { useCreditBalance } from "@/hooks/use-credit-balance";
15
+ import type { DividendWalletStats } from "@/lib/api";
21
16
  import { getDividendStats } from "@/lib/api";
22
17
  import { useSession } from "@/lib/auth-client";
23
18
  import { getBrandConfig } from "@/lib/brand-config";
24
19
  import { getOrganization } from "@/lib/org-api";
25
- import { trpc } from "@/lib/trpc";
26
20
 
27
21
  function CreditsContent() {
28
- const searchParams = useSearchParams();
29
- const pathname = usePathname();
30
- const router = useRouter();
31
- const cryptoPending = searchParams.get("crypto") === "pending";
32
22
  const { data: session } = useSession();
33
23
 
34
- const [orgContext, setOrgContext] = useState<{
24
+ const [_orgContext, setOrgContext] = useState<{
35
25
  orgId: string;
36
26
  orgName: string;
37
27
  isAdmin: boolean;
@@ -56,40 +46,20 @@ function CreditsContent() {
56
46
  .finally(() => setOrgChecked(true));
57
47
  }, [session?.user?.email, session?.user?.id]);
58
48
 
59
- const [showCryptoPending, setShowCryptoPending] = useState(cryptoPending);
60
49
  const showDividends = getBrandConfig().dividendsEnabled;
61
50
  const [dividendStats, setDividendStats] = useState<DividendWalletStats | null>(null);
62
51
  const [todayDividendCents, setTodayDividendCents] = useState(0);
63
52
 
64
- useEffect(() => {
65
- if (cryptoPending) {
66
- setShowCryptoPending(true);
67
- router.replace(pathname);
68
- }
69
- }, [cryptoPending, pathname, router]);
70
-
71
53
  const {
72
- data: rawBalance,
54
+ balance: balanceNum,
55
+ dailyBurn,
56
+ runway,
73
57
  isLoading: loading,
74
58
  error: balanceError,
75
59
  refetch,
76
- } = trpc.billing.creditsBalance.useQuery({});
77
-
78
- const balance: CreditBalanceData | null = rawBalance
79
- ? {
80
- balance:
81
- ((rawBalance as { balance_credits?: number; balance_cents?: number }).balance_credits ??
82
- (rawBalance as { balance_cents?: number }).balance_cents ??
83
- 0) / 100,
84
- dailyBurn:
85
- ((rawBalance as { daily_burn_credits?: number; daily_burn_cents?: number })
86
- .daily_burn_credits ??
87
- (rawBalance as { daily_burn_cents?: number }).daily_burn_cents ??
88
- 0) / 100,
89
- runway: (rawBalance as { runway_days?: number | null }).runway_days ?? null,
90
- }
91
- : null;
60
+ } = useCreditBalance();
92
61
 
62
+ const balance = balanceNum != null ? { balance: balanceNum, dailyBurn: dailyBurn ?? 0, runway } : null;
93
63
  const error = balanceError ? "Failed to load credit balance." : null;
94
64
 
95
65
  useEffect(() => {
@@ -115,15 +85,8 @@ function CreditsContent() {
115
85
  );
116
86
  }
117
87
 
118
- if (orgContext) {
119
- return (
120
- <OrgBillingPage
121
- orgId={orgContext.orgId}
122
- orgName={orgContext.orgName}
123
- isAdmin={orgContext.isAdmin}
124
- />
125
- );
126
- }
88
+ // Org billing view disabled — single-user mode for now.
89
+ // When org features are re-enabled, restore: OrgBillingPage render here.
127
90
 
128
91
  if (loading) {
129
92
  return (
@@ -169,18 +132,7 @@ function CreditsContent() {
169
132
 
170
133
  <LowBalanceBanner balance={balance.balance} runway={balance.runway} />
171
134
 
172
- {showDividends && dividendStats && (
173
- <DividendBanner todayAmountCents={todayDividendCents} stats={dividendStats} />
174
- )}
175
-
176
- {showCryptoPending && (
177
- <div className="rounded-md border border-amber-500/25 bg-amber-500/5 p-4">
178
- <p className="flex items-center gap-2 text-sm font-medium">
179
- <Clock className="h-4 w-4 text-amber-500" />
180
- Crypto payment pending — credits will appear once confirmed on-chain.
181
- </p>
182
- </div>
183
- )}
135
+ {showDividends && dividendStats && <DividendBanner todayAmountCents={todayDividendCents} stats={dividendStats} />}
184
136
 
185
137
  <CreditBalance data={balance} />
186
138
 
@@ -199,15 +151,10 @@ function CreditsContent() {
199
151
  />
200
152
  )}
201
153
 
202
- <BuyCreditsPanel />
203
- <CouponInput />
204
- <CryptoCheckout />
205
- <AutoTopupCard />
154
+ <UnifiedCheckout />
206
155
  <TransactionHistory />
207
156
 
208
- {showDividends && dividendStats && (
209
- <FirstDividendDialog todayAmountCents={todayDividendCents} />
210
- )}
157
+ {showDividends && dividendStats && <FirstDividendDialog todayAmountCents={todayDividendCents} />}
211
158
  </div>
212
159
  );
213
160
  }
@@ -8,13 +8,7 @@ import { logger } from "@/lib/logger";
8
8
 
9
9
  const log = logger("error-boundary:billing");
10
10
 
11
- export default function BillingError({
12
- error,
13
- reset,
14
- }: {
15
- error: Error & { digest?: string };
16
- reset: () => void;
17
- }) {
11
+ export default function BillingError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
18
12
  const [showDetails, setShowDetails] = useState(false);
19
13
  const isDev = process.env.NODE_ENV === "development";
20
14
 
@@ -32,9 +26,7 @@ export default function BillingError({
32
26
  </div>
33
27
  </CardHeader>
34
28
  <CardContent className="space-y-4">
35
- <p className="text-muted-foreground">
36
- Something went wrong loading billing. This may be a temporary issue.
37
- </p>
29
+ <p className="text-muted-foreground">Something went wrong loading billing. This may be a temporary issue.</p>
38
30
  {isDev && (
39
31
  <Button
40
32
  type="button"
@@ -1,73 +1,23 @@
1
- "use client";
2
-
3
1
  import Link from "next/link";
4
- import { usePathname } from "next/navigation";
5
- import { useEffect, useState } from "react";
6
- import type { InferenceMode } from "@/lib/api";
7
- import { getInferenceMode } from "@/lib/api";
8
- import { cn } from "@/lib/utils";
9
-
10
- const billingNav = [
11
- { label: "Your Plan", href: "/billing/plans", hostedOnly: false },
12
- { label: "Credits", href: "/billing/credits", hostedOnly: false },
13
- { label: "Usage", href: "/billing/usage", hostedOnly: false },
14
- { label: "Hosted Usage", href: "/billing/usage/hosted", hostedOnly: true },
15
- { label: "Payment", href: "/billing/payment", hostedOnly: false },
16
- { label: "Refer & Earn", href: "/billing/referrals", hostedOnly: false },
17
- ];
18
2
 
19
3
  export default function BillingLayout({
20
4
  children,
21
5
  }: Readonly<{
22
6
  children: React.ReactNode;
23
7
  }>) {
24
- const pathname = usePathname();
25
- const [mode, setMode] = useState<InferenceMode | null>(null);
26
-
27
- useEffect(() => {
28
- getInferenceMode()
29
- .then(setMode)
30
- .catch(() => setMode("hosted"));
31
- }, []);
32
-
33
8
  return (
34
- <div className="flex h-full">
35
- <nav className="w-48 shrink-0 border-r p-4">
36
- <h2 className="mb-4 text-sm font-semibold text-muted-foreground">Billing</h2>
37
- <ul className="space-y-1">
38
- {billingNav.map((item) => {
39
- if (item.hostedOnly && mode === "byok") return null;
40
- return (
41
- <li key={item.href} className={cn(item.hostedOnly && mode === null && "hidden")}>
42
- <Link
43
- href={item.href}
44
- className={cn(
45
- "block rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground",
46
- pathname === item.href
47
- ? "bg-accent text-accent-foreground"
48
- : "text-muted-foreground",
49
- )}
50
- >
51
- {item.label}
52
- </Link>
53
- </li>
54
- );
55
- })}
56
- </ul>
57
- </nav>
58
- <div className="flex-1 overflow-auto p-6">
59
- {children}
60
- <footer className="mt-8 border-t pt-4 text-xs text-muted-foreground">
61
- <div className="flex gap-4">
62
- <Link href="/terms" className="underline underline-offset-4 hover:text-foreground">
63
- Terms of Service
64
- </Link>
65
- <Link href="/privacy" className="underline underline-offset-4 hover:text-foreground">
66
- Privacy Policy
67
- </Link>
68
- </div>
69
- </footer>
70
- </div>
9
+ <div className="flex-1 overflow-auto p-6">
10
+ {children}
11
+ <footer className="mt-8 border-t pt-4 text-xs text-muted-foreground">
12
+ <div className="flex gap-4">
13
+ <Link href="/terms" className="underline underline-offset-4 hover:text-foreground">
14
+ Terms of Service
15
+ </Link>
16
+ <Link href="/privacy" className="underline underline-offset-4 hover:text-foreground">
17
+ Privacy Policy
18
+ </Link>
19
+ </div>
20
+ </footer>
71
21
  </div>
72
22
  );
73
23
  }