Skip to content

Commit d9d8c77

Browse files
committed
[Feat] Add Forgot Password page for user password recovery
1 parent c7abf06 commit d9d8c77

2 files changed

Lines changed: 453 additions & 0 deletions

File tree

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { useRouter } from 'next/navigation';
5+
import Link from 'next/link';
6+
import { authService } from '../authService';
7+
8+
export default function ForgotPasswordPage() {
9+
const [email, setEmail] = useState('');
10+
const [isLoading, setIsLoading] = useState(false);
11+
const [message, setMessage] = useState('');
12+
const [error, setError] = useState('');
13+
const [isSubmitted, setIsSubmitted] = useState(false);
14+
const router = useRouter();
15+
16+
const handleSubmit = async (e: React.FormEvent) => {
17+
e.preventDefault();
18+
setIsLoading(true);
19+
setError('');
20+
setMessage('');
21+
22+
try {
23+
const response = await authService.forgotPassword({ email });
24+
setMessage(response.message);
25+
setIsSubmitted(true);
26+
} catch (err: any) {
27+
setError(err.message || 'An error occurred. Please try again.');
28+
} finally {
29+
setIsLoading(false);
30+
}
31+
};
32+
33+
if (isSubmitted) {
34+
return (
35+
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 px-4">
36+
<div className="max-w-md w-full space-y-8">
37+
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8">
38+
<div className="text-center">
39+
<div className="mx-auto flex items-center justify-center h-16 w-16 rounded-full bg-green-100 dark:bg-green-900 mb-6">
40+
<svg className="h-8 w-8 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
41+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
42+
</svg>
43+
</div>
44+
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
45+
Check Your Email
46+
</h2>
47+
<p className="text-gray-600 dark:text-gray-400 mb-6">
48+
{message}
49+
</p>
50+
<div className="space-y-4">
51+
<button
52+
onClick={() => {
53+
setIsSubmitted(false);
54+
setEmail('');
55+
setMessage('');
56+
}}
57+
className="w-full flex justify-center py-3 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200"
58+
>
59+
Send Another Email
60+
</button>
61+
<Link
62+
href="/auth/login"
63+
className="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200"
64+
>
65+
Back to Login
66+
</Link>
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
</div>
72+
);
73+
}
74+
75+
return (
76+
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 px-4">
77+
<div className="max-w-md w-full space-y-8">
78+
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8">
79+
<div className="text-center">
80+
<div className="mx-auto flex items-center justify-center h-16 w-16 rounded-full bg-blue-100 dark:bg-blue-900 mb-6">
81+
<svg className="h-8 w-8 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
82+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-3a1 1 0 011-1h2.586l6.414-6.414a6 6 0 015.743-7.743z" />
83+
</svg>
84+
</div>
85+
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-2">
86+
Forgot Password?
87+
</h2>
88+
<p className="text-gray-600 dark:text-gray-400 mb-8">
89+
No worries! Enter your email address and we'll send you a link to reset your password.
90+
</p>
91+
</div>
92+
93+
<form onSubmit={handleSubmit} className="space-y-6">
94+
{error && (
95+
<div className="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4">
96+
<div className="flex">
97+
<div className="flex-shrink-0">
98+
<svg className="h-5 w-5 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
99+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
100+
</svg>
101+
</div>
102+
<div className="ml-3">
103+
<p className="text-sm text-red-600 dark:text-red-400">{error}</p>
104+
</div>
105+
</div>
106+
</div>
107+
)}
108+
109+
<div>
110+
<label htmlFor="email" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
111+
Email Address
112+
</label>
113+
<input
114+
id="email"
115+
name="email"
116+
type="email"
117+
autoComplete="email"
118+
required
119+
value={email}
120+
onChange={(e) => setEmail(e.target.value)}
121+
className="appearance-none relative block w-full px-4 py-3 border border-gray-300 dark:border-gray-600 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white bg-white dark:bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors duration-200"
122+
placeholder="Enter your email address"
123+
/>
124+
</div>
125+
126+
<div>
127+
<button
128+
type="submit"
129+
disabled={isLoading || !email.trim()}
130+
className="group relative w-full flex justify-center py-3 px-4 border border-transparent text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200"
131+
>
132+
{isLoading ? (
133+
<div className="flex items-center">
134+
<svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
135+
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
136+
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
137+
</svg>
138+
Sending...
139+
</div>
140+
) : (
141+
'Send Reset Link'
142+
)}
143+
</button>
144+
</div>
145+
146+
<div className="text-center">
147+
<Link
148+
href="/auth/login"
149+
className="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300 transition-colors duration-200"
150+
>
151+
← Back to Login
152+
</Link>
153+
</div>
154+
</form>
155+
</div>
156+
157+
<div className="text-center">
158+
<p className="text-sm text-gray-600 dark:text-gray-400">
159+
Don't have an account?{' '}
160+
<Link
161+
href="/auth/signup"
162+
className="font-medium text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300 transition-colors duration-200"
163+
>
164+
Sign up here
165+
</Link>
166+
</p>
167+
</div>
168+
</div>
169+
</div>
170+
);
171+
}

0 commit comments

Comments
 (0)