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) {