@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.
- package/next.config.ts +1 -2
- package/package.json +17 -17
- package/src/__tests__/account-switcher.test.tsx +21 -20
- package/src/__tests__/activity-page.test.tsx +2 -6
- package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
- package/src/__tests__/admin-api.test.ts +1 -6
- package/src/__tests__/admin-gpu-api.test.ts +1 -3
- package/src/__tests__/admin-marketplace-api.test.ts +1 -4
- package/src/__tests__/admin-middleware.test.ts +76 -83
- package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
- package/src/__tests__/api-401-redirect.test.ts +46 -9
- package/src/__tests__/api-client.test.ts +3 -5
- package/src/__tests__/api-config.test.ts +22 -42
- package/src/__tests__/api-fleet-resources.test.ts +1 -2
- package/src/__tests__/api-fleet-trpc.test.ts +2 -8
- package/src/__tests__/api-null-guards.test.ts +3 -1
- package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
- package/src/__tests__/auth-password-reset.test.tsx +7 -21
- package/src/__tests__/auth-redirect.test.tsx +8 -2
- package/src/__tests__/auth.test.tsx +25 -23
- package/src/__tests__/auto-topup-card.test.tsx +4 -12
- package/src/__tests__/backups-tab.test.tsx +3 -4
- package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
- package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
- package/src/__tests__/billing.test.tsx +8 -39
- package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
- package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
- package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
- package/src/__tests__/bot-settings-restart.test.tsx +1 -3
- package/src/__tests__/bot-settings.test.tsx +2 -6
- package/src/__tests__/brand.test.ts +6 -26
- package/src/__tests__/buy-credits-panel.test.tsx +1 -3
- package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
- package/src/__tests__/capability-conflicts.test.ts +2 -8
- package/src/__tests__/capability-resolver.test.tsx +2 -12
- package/src/__tests__/channel-wizard.test.tsx +4 -17
- package/src/__tests__/chat/chat-panel.test.tsx +1 -4
- package/src/__tests__/chat-store.test.ts +5 -15
- package/src/__tests__/command-center.test.tsx +10 -12
- package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
- package/src/__tests__/confirmation-tracker.test.tsx +3 -18
- package/src/__tests__/coupon-input.test.tsx +1 -3
- package/src/__tests__/create-instance.test.tsx +1 -3
- package/src/__tests__/credit-balance.test.tsx +4 -12
- package/src/__tests__/credits.test.tsx +32 -85
- package/src/__tests__/email-verification-banner.test.tsx +2 -6
- package/src/__tests__/error-boundaries.test.tsx +0 -1
- package/src/__tests__/fetch-pricing.test.ts +2 -1
- package/src/__tests__/field-oauth.test.tsx +2 -6
- package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
- package/src/__tests__/fixtures/mock-manifests.ts +2 -4
- package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
- package/src/__tests__/fleet-health-update.test.tsx +1 -8
- package/src/__tests__/gpu-dashboard.test.tsx +2 -6
- package/src/__tests__/instance-detail.test.tsx +3 -9
- package/src/__tests__/instance-list.test.tsx +1 -5
- package/src/__tests__/layout-snapshots.test.tsx +64 -11
- package/src/__tests__/marketplace-admin.test.tsx +2 -6
- package/src/__tests__/marketplace.test.tsx +11 -35
- package/src/__tests__/merge-api-rates.test.ts +1 -6
- package/src/__tests__/middleware.test.ts +32 -219
- package/src/__tests__/next-config-headers.test.ts +1 -3
- package/src/__tests__/notifications.test.tsx +4 -11
- package/src/__tests__/oauth-buttons.test.tsx +36 -59
- package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
- package/src/__tests__/observability.test.tsx +23 -36
- package/src/__tests__/onboarding-page.test.tsx +4 -6
- package/src/__tests__/org-billing-api.test.tsx +1 -6
- package/src/__tests__/plugin-install-flow.test.tsx +28 -58
- package/src/__tests__/plugin-registry.test.tsx +3 -11
- package/src/__tests__/plugin-tool-sync.test.ts +1 -3
- package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
- package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
- package/src/__tests__/portfolio-chart.test.tsx +2 -6
- package/src/__tests__/promotion-form.test.tsx +2 -6
- package/src/__tests__/promotions-list.test.tsx +1 -3
- package/src/__tests__/provider-key-api.test.ts +2 -1
- package/src/__tests__/resend-verification-button.test.tsx +8 -24
- package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
- package/src/__tests__/settings.test.tsx +11 -21
- package/src/__tests__/setup-checklist.test.tsx +3 -9
- package/src/__tests__/setup.ts +25 -6
- package/src/__tests__/snapshot-api.test.ts +2 -1
- package/src/__tests__/step-superpowers.test.tsx +1 -3
- package/src/__tests__/tenant-context.test.tsx +1 -6
- package/src/__tests__/tenant-keys-api.test.ts +3 -4
- package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
- package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
- package/src/__tests__/transaction-history.test.tsx +190 -238
- package/src/__tests__/trpc-types.test.ts +2 -6
- package/src/__tests__/use-chat.test.ts +1 -3
- package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
- package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
- package/src/__tests__/use-webmcp.test.ts +1 -3
- package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
- package/src/__tests__/verify-page.test.tsx +4 -13
- package/src/__tests__/verify-redirect.test.tsx +2 -6
- package/src/app/(auth)/error.tsx +1 -7
- package/src/app/(auth)/forgot-password/page.tsx +4 -18
- package/src/app/(auth)/login/page.tsx +5 -22
- package/src/app/(auth)/reset-password/page.tsx +2 -12
- package/src/app/(auth)/signup/page.tsx +10 -44
- package/src/app/(auth)/verify/page.tsx +47 -0
- package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
- package/src/app/(dashboard)/billing/error.tsx +2 -10
- package/src/app/(dashboard)/billing/layout.tsx +12 -62
- package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
- package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
- package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
- package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
- package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
- package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
- package/src/app/(dashboard)/changesets/error.tsx +1 -7
- package/src/app/(dashboard)/chat/page.tsx +2 -6
- package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
- package/src/app/(dashboard)/error.tsx +1 -7
- package/src/app/(dashboard)/layout.tsx +15 -36
- package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
- package/src/app/(dashboard)/marketplace/error.tsx +1 -7
- package/src/app/(dashboard)/marketplace/page.tsx +6 -27
- package/src/app/(dashboard)/not-found.tsx +2 -5
- package/src/app/(dashboard)/onboarding/page.tsx +5 -22
- package/src/app/(dashboard)/settings/account/page.tsx +1 -6
- package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
- package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
- package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
- package/src/app/(dashboard)/settings/error.tsx +2 -10
- package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
- package/src/app/(dashboard)/settings/org/page.tsx +13 -56
- package/src/app/(dashboard)/settings/page.tsx +1 -0
- package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
- package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
- package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
- package/src/app/(dashboard)/settings/security/page.tsx +31 -111
- package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
- package/src/app/admin/error.tsx +1 -7
- package/src/app/admin/fleet-updates/error.tsx +1 -7
- package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
- package/src/app/admin/layout.tsx +4 -0
- package/src/app/admin/payment-methods/page.tsx +9 -38
- package/src/app/admin/products/error.tsx +2 -7
- package/src/app/admin/products/page.tsx +1 -4
- package/src/app/admin/promotions/[id]/page.tsx +9 -38
- package/src/app/admin/promotions/page.tsx +9 -36
- package/src/app/admin/rate-overrides/page.tsx +9 -45
- package/src/app/auth/callback/[provider]/page.tsx +1 -8
- package/src/app/auth/verify/page.tsx +9 -36
- package/src/app/channels/error.tsx +2 -10
- package/src/app/channels/layout.tsx +9 -0
- package/src/app/channels/page.tsx +8 -20
- package/src/app/channels/setup/[plugin]/page.tsx +3 -5
- package/src/app/error.tsx +1 -7
- package/src/app/fleet/error.tsx +1 -7
- package/src/app/fleet/layout.tsx +5 -0
- package/src/app/fleet/settings/page.tsx +1 -3
- package/src/app/global-error.tsx +2 -10
- package/src/app/globals.css +1 -4
- package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
- package/src/app/instances/error.tsx +2 -10
- package/src/app/instances/instance-list-client.tsx +20 -69
- package/src/app/instances/layout.tsx +9 -0
- package/src/app/instances/new/create-instance-client.tsx +10 -31
- package/src/app/layout.tsx +2 -10
- package/src/app/not-found.tsx +1 -3
- package/src/app/page.tsx +1 -2
- package/src/app/plugins/error.tsx +2 -10
- package/src/app/plugins/layout.tsx +5 -0
- package/src/app/plugins/page.tsx +16 -48
- package/src/app/pricing/error.tsx +1 -7
- package/src/app/privacy/page.tsx +93 -150
- package/src/app/status/error.tsx +1 -7
- package/src/app/terms/page.tsx +89 -144
- package/src/components/account-switcher.tsx +25 -52
- package/src/components/admin/accounting-dashboard.tsx +1 -3
- package/src/components/admin/admin-guard.tsx +1 -3
- package/src/components/admin/admin-nav.tsx +1 -3
- package/src/components/admin/affiliate-dashboard.tsx +25 -94
- package/src/components/admin/audit-log-table.tsx +13 -49
- package/src/components/admin/billing-health-dashboard.tsx +7 -25
- package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
- package/src/components/admin/bulk-actions-bar.tsx +1 -3
- package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
- package/src/components/admin/bulk-export-dialog.tsx +6 -32
- package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
- package/src/components/admin/bulk-grant-dialog.tsx +4 -15
- package/src/components/admin/bulk-preview-dialog.tsx +3 -12
- package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
- package/src/components/admin/bulk-select-all-banner.tsx +1 -6
- package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
- package/src/components/admin/bulk-undo-toast.tsx +1 -2
- package/src/components/admin/compliance-dashboard.tsx +31 -101
- package/src/components/admin/gpu-dashboard.tsx +21 -70
- package/src/components/admin/grant-credits-dialog.tsx +4 -17
- package/src/components/admin/incident-dashboard.tsx +10 -25
- package/src/components/admin/inference-dashboard.tsx +14 -54
- package/src/components/admin/marketplace-admin.tsx +18 -60
- package/src/components/admin/migrations-dashboard.tsx +9 -42
- package/src/components/admin/onboarding-dashboard.tsx +14 -64
- package/src/components/admin/pool-config-dashboard.tsx +4 -10
- package/src/components/admin/products/fleet-form.tsx +2 -11
- package/src/components/admin/products/nav-editor.tsx +3 -10
- package/src/components/admin/promotions/promotion-form.tsx +9 -42
- package/src/components/admin/roles-dashboard.tsx +7 -34
- package/src/components/admin/suspend-dialog.tsx +4 -11
- package/src/components/admin/tenant-notes-panel.tsx +1 -3
- package/src/components/admin/tenant-row-actions.tsx +4 -20
- package/src/components/admin/tenant-table.tsx +12 -49
- package/src/components/auth/auth-redirect.tsx +11 -3
- package/src/components/auth/email-verification-result-banner.tsx +1 -3
- package/src/components/auth/resend-verification-button.tsx +2 -10
- package/src/components/auth/wopr-wordmark.tsx +1 -3
- package/src/components/billing/add-payment-method-dialog.tsx +1 -2
- package/src/components/billing/affiliate-dashboard.tsx +4 -16
- package/src/components/billing/amount-selector.tsx +1 -3
- package/src/components/billing/auto-topup-card.tsx +2 -11
- package/src/components/billing/buy-credits-panel.tsx +4 -14
- package/src/components/billing/byok-callout.tsx +6 -8
- package/src/components/billing/confirmation-tracker.tsx +4 -14
- package/src/components/billing/credit-balance-badge.tsx +22 -0
- package/src/components/billing/credit-balance.tsx +3 -9
- package/src/components/billing/crypto-checkout.tsx +5 -24
- package/src/components/billing/degraded-state-banner.tsx +1 -3
- package/src/components/billing/deposit-view.tsx +301 -41
- package/src/components/billing/dividend-banner.tsx +1 -3
- package/src/components/billing/dividend-eligibility.tsx +3 -12
- package/src/components/billing/dividend-pool-stats.tsx +6 -20
- package/src/components/billing/first-dividend-dialog.tsx +2 -2
- package/src/components/billing/org-billing-page.tsx +8 -31
- package/src/components/billing/payment-method-picker.tsx +2 -10
- package/src/components/billing/suspension-banner.tsx +2 -7
- package/src/components/billing/transaction-history.tsx +10 -58
- package/src/components/billing/unified-checkout.tsx +547 -0
- package/src/components/bot-settings/backups-tab.tsx +9 -33
- package/src/components/bot-settings/bot-settings-client.tsx +32 -134
- package/src/components/bot-settings/resources-tab.tsx +2 -9
- package/src/components/bot-settings/storage-tab.tsx +19 -48
- package/src/components/bot-settings/vps-info-panel.tsx +3 -11
- package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
- package/src/components/brand-hydrator.tsx +13 -0
- package/src/components/channel-wizard/field-interactive.tsx +1 -3
- package/src/components/channel-wizard/field-qr.tsx +10 -39
- package/src/components/channel-wizard/step-renderer.tsx +5 -28
- package/src/components/channel-wizard/wizard.tsx +6 -31
- package/src/components/chat/chat-message.tsx +1 -4
- package/src/components/chat/chat-panel.tsx +4 -18
- package/src/components/chat/chat-widget.tsx +3 -14
- package/src/components/dashboard/command-center.tsx +15 -61
- package/src/components/fleet/update-settings-card.tsx +7 -23
- package/src/components/instance-update-banner.tsx +130 -0
- package/src/components/instances/friends-tab.test.tsx +2 -9
- package/src/components/instances/friends-tab.tsx +18 -74
- package/src/components/instances/update-available-badge.tsx +2 -11
- package/src/components/landing/hero.tsx +3 -9
- package/src/components/landing/landing-page.tsx +1 -3
- package/src/components/landing/portfolio-chart.tsx +4 -9
- package/src/components/landing/story-sections.tsx +1 -3
- package/src/components/landing/terminal-sequence.tsx +4 -17
- package/src/components/marketplace/empty-state.tsx +2 -6
- package/src/components/marketplace/first-visit-hero.tsx +1 -3
- package/src/components/marketplace/install-wizard.tsx +20 -77
- package/src/components/marketplace/marketplace-tabs.tsx +1 -4
- package/src/components/marketplace/plugin-card.tsx +2 -9
- package/src/components/marketplace/superpower-content.tsx +1 -3
- package/src/components/marketplace/terminal-search.tsx +2 -8
- package/src/components/oauth-buttons.tsx +29 -14
- package/src/components/observability/fleet-health.tsx +5 -18
- package/src/components/observability/health-overview.tsx +7 -20
- package/src/components/observability/logs-viewer.tsx +8 -32
- package/src/components/observability/metrics-dashboard.tsx +2 -15
- package/src/components/onboarding/fallback-setup.tsx +6 -25
- package/src/components/onboarding/setup-checklist.tsx +18 -51
- package/src/components/onboarding/step-superpowers.tsx +1 -4
- package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
- package/src/components/pricing/dividend-calculator.tsx +6 -12
- package/src/components/pricing/dividend-stats.tsx +5 -17
- package/src/components/pricing/pricing-page.tsx +17 -36
- package/src/components/settings/create-org-wizard.tsx +2 -5
- package/src/components/sidebar.tsx +7 -42
- package/src/components/sidecar-frame.tsx +78 -0
- package/src/components/status/status-page.tsx +6 -28
- package/src/components/ui/alert-dialog.tsx +8 -25
- package/src/components/ui/badge.tsx +2 -8
- package/src/components/ui/banner.tsx +1 -6
- package/src/components/ui/card.tsx +5 -24
- package/src/components/ui/checkbox.tsx +1 -5
- package/src/components/ui/collapsible.tsx +3 -8
- package/src/components/ui/dialog.tsx +4 -10
- package/src/components/ui/dropdown-menu.tsx +9 -18
- package/src/components/ui/form.tsx +2 -16
- package/src/components/ui/popover.tsx +3 -23
- package/src/components/ui/progress.tsx +1 -5
- package/src/components/ui/radio-group.tsx +3 -15
- package/src/components/ui/select.tsx +4 -17
- package/src/components/ui/sheet.tsx +5 -19
- package/src/components/ui/skeleton.tsx +1 -7
- package/src/components/ui/table.tsx +5 -22
- package/src/components/ui/tabs.tsx +3 -13
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/components/unified-sidebar.tsx +493 -0
- package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
- package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
- package/src/hooks/use-credit-balance.ts +27 -0
- package/src/hooks/use-my-org-role.ts +1 -3
- package/src/hooks/use-plugin-registry.ts +8 -14
- package/src/hooks/use-plugin-setup-chat.ts +2 -5
- package/src/hooks/use-sidecar-bridge.tsx +148 -0
- package/src/hooks/use-webmcp.ts +1 -4
- package/src/lib/__tests__/admin-api.test.ts +1 -3
- package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
- package/src/lib/__tests__/api-fetch.test.ts +4 -16
- package/src/lib/__tests__/org-billing-api.test.ts +1 -3
- package/src/lib/__tests__/pricing-data.test.ts +0 -8
- package/src/lib/__tests__/settings-api.test.ts +1 -3
- package/src/lib/admin-affiliate-api.ts +2 -7
- package/src/lib/admin-api.ts +6 -26
- package/src/lib/admin-incident-api.ts +11 -19
- package/src/lib/admin-marketplace-api.ts +1 -5
- package/src/lib/api-config.test.ts +5 -50
- package/src/lib/api.ts +143 -122
- package/src/lib/auth-client.ts +1 -2
- package/src/lib/bot-settings-data.ts +11 -36
- package/src/lib/brand-config.ts +56 -115
- package/src/lib/brand.ts +2 -15
- package/src/lib/chat/use-chat.ts +2 -7
- package/src/lib/cost-comparison-data.test.ts +1 -3
- package/src/lib/cost-comparison-data.ts +1 -4
- package/src/lib/errors.ts +1 -4
- package/src/lib/fetch-utils.test.ts +26 -9
- package/src/lib/fetch-utils.ts +40 -11
- package/src/lib/logger.ts +2 -0
- package/src/lib/marketplace-data.ts +3 -11
- package/src/lib/oauth-errors.ts +2 -4
- package/src/lib/onboarding-data.ts +3 -11
- package/src/lib/org-api.ts +2 -10
- package/src/lib/org-billing-api.ts +5 -19
- package/src/lib/plugin/tool-definitions.ts +1 -2
- package/src/lib/require-auth.ts +57 -0
- package/src/lib/settings-api.ts +1 -4
- package/src/lib/sidecar-routes.ts +43 -0
- package/src/lib/trpc-server.ts +49 -0
- package/src/lib/trpc-types.ts +4 -6
- package/src/lib/trpc.tsx +12 -4
- package/src/lib/validate-redirect-url.ts +1 -4
- package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
- package/src/lib/webmcp/register.ts +1 -4
- package/src/lib/webmcp/tools.ts +2 -9
- package/src/proxy.ts +35 -212
- package/src/types/missing-deps.d.ts +2 -8
- package/tsconfig.json +1 -8
- package/biome.json +0 -52
- package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
- package/src/__tests__/billing-byok-callout.test.tsx +0 -76
- 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
|
-
|
|
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
|
-
|
|
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
|
|
package/src/app/(auth)/error.tsx
CHANGED
|
@@ -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't see it, check
|
|
73
|
-
your spam folder.
|
|
65
|
+
Click the link in the email to reset your password. If you don'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'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'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
|
|
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 [
|
|
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
|
-
|
|
54
|
+
balance: balanceNum,
|
|
55
|
+
dailyBurn,
|
|
56
|
+
runway,
|
|
73
57
|
isLoading: loading,
|
|
74
58
|
error: balanceError,
|
|
75
59
|
refetch,
|
|
76
|
-
} =
|
|
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
|
-
|
|
119
|
-
|
|
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
|
-
<
|
|
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
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
}
|