Skip to content

Commit a0a1c2f

Browse files
committed
feat(auth): add email verification flow for signup
- Show 'Check your email' screen after signup instead of redirecting - Handle email_not_confirmed error gracefully in login form - Show helpful error messages for common auth issues - Prevent fake email signups by requiring verification
1 parent 3f597d2 commit a0a1c2f

2 files changed

Lines changed: 64 additions & 18 deletions

File tree

frontend/src/components/auth/LoginForm.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ export function LoginForm() {
2626
await signIn(email, password)
2727
navigate('/dashboard')
2828
} catch (err: any) {
29-
setError(err.message || 'Login failed')
29+
const message = err.message?.toLowerCase() || ''
30+
if (message.includes('email not confirmed') || message.includes('not confirmed')) {
31+
setError('Please verify your email before logging in. Check your inbox for the verification link.')
32+
} else if (message.includes('invalid login credentials')) {
33+
setError('Invalid email or password. Please try again.')
34+
} else {
35+
setError(err.message || 'Login failed')
36+
}
3037
} finally {
3138
setLoading(false)
3239
}

frontend/src/components/auth/SignupForm.tsx

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Input } from '@/components/ui/input'
66
import { Label } from '@/components/ui/label'
77
import { Alert, AlertDescription } from '@/components/ui/alert'
88
import { Navbar } from '@/components/landing'
9-
import { Github, Loader2, Mail, Lock } from 'lucide-react'
9+
import { Github, Loader2, Mail, Lock, CheckCircle2 } from 'lucide-react'
1010

1111
export function SignupForm() {
1212
const [email, setEmail] = useState('')
@@ -15,6 +15,7 @@ export function SignupForm() {
1515
const [error, setError] = useState('')
1616
const [loading, setLoading] = useState(false)
1717
const [oauthLoading, setOauthLoading] = useState<'github' | 'google' | null>(null)
18+
const [emailSent, setEmailSent] = useState(false)
1819
const { signUp, signInWithGitHub, signInWithGoogle } = useAuth()
1920
const navigate = useNavigate()
2021

@@ -35,7 +36,7 @@ export function SignupForm() {
3536
setLoading(true)
3637
try {
3738
await signUp(email, password)
38-
navigate('/dashboard')
39+
setEmailSent(true)
3940
} catch (err: any) {
4041
setError(err.message || 'Signup failed')
4142
} finally {
@@ -73,22 +74,58 @@ export function SignupForm() {
7374

7475
<div className="flex-1 flex items-center justify-center px-6 py-12">
7576
<div className="w-full max-w-sm">
76-
<div className="text-center mb-8">
77-
<h1 className="text-2xl font-semibold text-foreground mb-2">
78-
Create your account
79-
</h1>
80-
<p className="text-sm text-muted-foreground">
81-
Free for open source projects
82-
</p>
83-
</div>
77+
{/* Email Verification Sent */}
78+
{emailSent ? (
79+
<div className="text-center">
80+
<div className="w-16 h-16 mx-auto mb-6 rounded-full bg-green-500/10 border border-green-500/20 flex items-center justify-center">
81+
<CheckCircle2 className="w-8 h-8 text-green-500" />
82+
</div>
83+
<h1 className="text-2xl font-semibold text-foreground mb-2">
84+
Check your email
85+
</h1>
86+
<p className="text-sm text-muted-foreground mb-6">
87+
We sent a verification link to<br />
88+
<span className="font-medium text-foreground">{email}</span>
89+
</p>
90+
<div className="bg-card rounded-lg border border-border p-4 text-sm text-muted-foreground">
91+
<p className="mb-2">
92+
Click the link in the email to verify your account and get started.
93+
</p>
94+
<p>
95+
Didn't receive it? Check your spam folder or{' '}
96+
<button
97+
onClick={() => setEmailSent(false)}
98+
className="text-primary hover:underline"
99+
>
100+
try again
101+
</button>
102+
</p>
103+
</div>
104+
<Link
105+
to="/login"
106+
className="inline-block mt-6 text-sm text-muted-foreground hover:text-foreground"
107+
>
108+
← Back to login
109+
</Link>
110+
</div>
111+
) : (
112+
<>
113+
<div className="text-center mb-8">
114+
<h1 className="text-2xl font-semibold text-foreground mb-2">
115+
Create your account
116+
</h1>
117+
<p className="text-sm text-muted-foreground">
118+
Free for open source projects
119+
</p>
120+
</div>
84121

85-
<div className="bg-card rounded-lg border border-border p-6">
86-
<form onSubmit={handleSubmit} className="space-y-4">
87-
{error && (
88-
<Alert variant="destructive" className="bg-destructive/10 border-destructive/20">
89-
<AlertDescription>{error}</AlertDescription>
90-
</Alert>
91-
)}
122+
<div className="bg-card rounded-lg border border-border p-6">
123+
<form onSubmit={handleSubmit} className="space-y-4">
124+
{error && (
125+
<Alert variant="destructive" className="bg-destructive/10 border-destructive/20">
126+
<AlertDescription>{error}</AlertDescription>
127+
</Alert>
128+
)}
92129

93130
<div className="space-y-2">
94131
<Label htmlFor="email">Email</Label>
@@ -242,6 +279,8 @@ export function SignupForm() {
242279
Sign in
243280
</Link>
244281
</p>
282+
</>
283+
)}
245284
</div>
246285
</div>
247286
</div>

0 commit comments

Comments
 (0)