From a41e28c4205537ddba340b5af59d1482d2b70a31 Mon Sep 17 00:00:00 2001 From: "yves.gugger" Date: Wed, 10 Dec 2025 16:23:16 +0100 Subject: [PATCH] fix: Seamless user journey for register/login/Stripe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PROBLEM: Redirect parameters were getting lost during user flows FIXES APPLIED: 1. Register Page: - Default redirect: /command/dashboard (was /dashboard) - Stores redirect in localStorage before email verification - Preserves redirect when linking to login page 2. Login Page: - Checks localStorage for stored redirect (from registration) - Clears stored redirect after successful login - Uses useState for dynamic redirect handling 3. OAuth Callback: - Default redirect: /command/dashboard (was /dashboard) - Backend OAuth endpoints also updated 4. Fixed all /dashboard → /command/dashboard links: - pricing/page.tsx - page.tsx (landing page) - AdminLayout.tsx - DomainChecker.tsx - command/dashboard/page.tsx - Header.tsx (simplified check) 5. Backend OAuth: - Default redirect_path: /command/dashboard NEW USER JOURNEY: Pricing → Register → Email Verify → Login → Pricing → Stripe ↓ Welcome Page ↓ Dashboard The redirect is preserved throughout: - Query param ?redirect=/pricing passed through register/login - Stored in localStorage during email verification gap - Cleaned up after successful login STRIPE FLOW CLARIFICATION: - Stripe does NOT create users - Users must register FIRST with email/password - Then they can upgrade via Stripe checkout - This is by design for security and flexibility --- backend/app/api/oauth.py | 4 ++-- frontend/src/app/command/dashboard/page.tsx | 2 +- frontend/src/app/login/page.tsx | 16 ++++++++++++++-- frontend/src/app/oauth/callback/page.tsx | 2 +- frontend/src/app/page.tsx | 4 ++-- frontend/src/app/pricing/page.tsx | 2 +- frontend/src/app/register/page.tsx | 11 +++++++++-- frontend/src/components/AdminLayout.tsx | 2 +- frontend/src/components/DomainChecker.tsx | 4 ++-- frontend/src/components/Header.tsx | 4 +--- 10 files changed, 34 insertions(+), 17 deletions(-) diff --git a/backend/app/api/oauth.py b/backend/app/api/oauth.py index 0c03e50..68598f7 100644 --- a/backend/app/api/oauth.py +++ b/backend/app/api/oauth.py @@ -203,7 +203,7 @@ async def google_callback( ) # Parse redirect from state - redirect_path = "/dashboard" + redirect_path = "/command/dashboard" if ":" in state: _, redirect_path = state.split(":", 1) @@ -312,7 +312,7 @@ async def github_callback( ) # Parse redirect from state - redirect_path = "/dashboard" + redirect_path = "/command/dashboard" if ":" in state: _, redirect_path = state.split(":", 1) diff --git a/frontend/src/app/command/dashboard/page.tsx b/frontend/src/app/command/dashboard/page.tsx index b7b4d13..8cdd5be 100644 --- a/frontend/src/app/command/dashboard/page.tsx +++ b/frontend/src/app/command/dashboard/page.tsx @@ -63,7 +63,7 @@ export default function DashboardPage() { useEffect(() => { if (searchParams.get('upgraded') === 'true') { showToast('Welcome to your upgraded plan! 🎉', 'success') - window.history.replaceState({}, '', '/dashboard') + window.history.replaceState({}, '', '/command/dashboard') } }, [searchParams]) diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx index 30b5018..c803cf3 100644 --- a/frontend/src/app/login/page.tsx +++ b/frontend/src/app/login/page.tsx @@ -54,8 +54,17 @@ function LoginForm() { const [oauthProviders, setOauthProviders] = useState({ google_enabled: false, github_enabled: false }) const [verified, setVerified] = useState(false) - // Get redirect URL from query params - const redirectTo = searchParams.get('redirect') || '/command/dashboard' + // Get redirect URL from query params or localStorage (set during registration) + const paramRedirect = searchParams.get('redirect') + const [redirectTo, setRedirectTo] = useState(paramRedirect || '/command/dashboard') + + // Check localStorage for redirect (set during registration before email verification) + useEffect(() => { + const storedRedirect = localStorage.getItem('pounce_redirect_after_login') + if (storedRedirect && !paramRedirect) { + setRedirectTo(storedRedirect) + } + }, [paramRedirect]) // Check for verified status useEffect(() => { @@ -88,6 +97,9 @@ function LoginForm() { return } + // Clear stored redirect (was set during registration) + localStorage.removeItem('pounce_redirect_after_login') + // Redirect to intended destination or dashboard router.push(redirectTo) } catch (err: unknown) { diff --git a/frontend/src/app/oauth/callback/page.tsx b/frontend/src/app/oauth/callback/page.tsx index 0125153..c5d39d0 100644 --- a/frontend/src/app/oauth/callback/page.tsx +++ b/frontend/src/app/oauth/callback/page.tsx @@ -12,7 +12,7 @@ function OAuthCallbackContent() { useEffect(() => { const token = searchParams.get('token') - const redirect = searchParams.get('redirect') || '/dashboard' + const redirect = searchParams.get('redirect') || '/command/dashboard' const isNew = searchParams.get('new') === 'true' const error = searchParams.get('error') diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index a1f5ab6..1876447 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -768,7 +768,7 @@ export default function HomePage() { {isAuthenticated ? "Go to Dashboard" : "Start Free"} @@ -789,7 +789,7 @@ export default function HomePage() { Track your first domain in under a minute. Free forever, no credit card.

{isAuthenticated ? "Command Center" : "Join the Hunt"} diff --git a/frontend/src/app/register/page.tsx b/frontend/src/app/register/page.tsx index 0367038..298afdb 100644 --- a/frontend/src/app/register/page.tsx +++ b/frontend/src/app/register/page.tsx @@ -62,7 +62,7 @@ function RegisterForm() { const [registered, setRegistered] = useState(false) // Get redirect URL from query params - const redirectTo = searchParams.get('redirect') || '/dashboard' + const redirectTo = searchParams.get('redirect') || '/command/dashboard' // Load OAuth providers useEffect(() => { @@ -76,6 +76,13 @@ function RegisterForm() { try { await register(email, password) + + // Store redirect URL for after email verification + // This will be picked up by the login page after verification + if (redirectTo !== '/command/dashboard') { + localStorage.setItem('pounce_redirect_after_login', redirectTo) + } + // Show verification message setRegistered(true) } catch (err) { @@ -86,7 +93,7 @@ function RegisterForm() { } // Generate login link with redirect preserved - const loginLink = redirectTo !== '/dashboard' + const loginLink = redirectTo !== '/command/dashboard' ? `/login?redirect=${encodeURIComponent(redirectTo)}` : '/login' diff --git a/frontend/src/components/AdminLayout.tsx b/frontend/src/components/AdminLayout.tsx index 151f6b3..d376cd6 100644 --- a/frontend/src/components/AdminLayout.tsx +++ b/frontend/src/components/AdminLayout.tsx @@ -286,7 +286,7 @@ function AdminSidebar({
{/* Back to User Dashboard */} We'll alert you the moment it drops.
pathname.startsWith(path) - ) + const isCommandCenterPage = pathname.startsWith('/command') || pathname.startsWith('/admin') // If logged in and on Command Center page, don't render this header if (isAuthenticated && isCommandCenterPage) {