Skip to content

Commit 3ee7a0e

Browse files
Merge pull request #426 from mftee/main
implemented and validated the details for a forgot password page
2 parents 4ba949f + 9e9e520 commit 3ee7a0e

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import { useForm } from "react-hook-form";
5+
import { zodResolver } from "@hookform/resolvers/zod";
6+
import { z } from "zod";
7+
import Link from "next/link";
8+
import { useRouter } from "next/navigation";
9+
10+
const forgotPasswordSchema = z.object({
11+
email: z.string().email("Please enter a valid email address"),
12+
});
13+
14+
type ForgotPasswordForm = z.infer<typeof forgotPasswordSchema>;
15+
16+
export default function ForgotPasswordPage() {
17+
const [isLoading, setIsLoading] = useState(false);
18+
const [isSuccess, setIsSuccess] = useState(false);
19+
const [submittedEmail, setSubmittedEmail] = useState("");
20+
const [countdown, setCountdown] = useState(5);
21+
const router = useRouter();
22+
23+
const {
24+
register,
25+
handleSubmit,
26+
formState: { errors },
27+
} = useForm<ForgotPasswordForm>({
28+
resolver: zodResolver(forgotPasswordSchema),
29+
});
30+
31+
const onSubmit = async (data: ForgotPasswordForm) => {
32+
setIsLoading(true);
33+
34+
try {
35+
const response = await fetch("/api/v1/auth/forgot-password", {
36+
method: "POST",
37+
headers: {
38+
"Content-Type": "application/json",
39+
},
40+
body: JSON.stringify(data),
41+
});
42+
43+
if (!response.ok) {
44+
throw new Error("Failed to send reset email");
45+
}
46+
47+
setSubmittedEmail(data.email);
48+
setIsSuccess(true);
49+
50+
// Start countdown and redirect
51+
let timeLeft = 5;
52+
const timer = setInterval(() => {
53+
timeLeft -= 1;
54+
setCountdown(timeLeft);
55+
if (timeLeft === 0) {
56+
clearInterval(timer);
57+
router.push("/login");
58+
}
59+
}, 1000);
60+
} catch (error) {
61+
alert("Failed to send reset email. Please try again.");
62+
} finally {
63+
setIsLoading(false);
64+
}
65+
};
66+
67+
if (isSuccess) {
68+
return (
69+
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4 sm:px-6 lg:px-8">
70+
<div className="max-w-md w-full space-y-8 animate-fade-in">
71+
<div className="text-center">
72+
<div className="mx-auto flex items-center justify-center h-16 w-16 rounded-full bg-green-100 mb-4">
73+
<svg
74+
className="h-10 w-10 text-green-600"
75+
fill="none"
76+
stroke="currentColor"
77+
viewBox="0 0 24 24"
78+
>
79+
<path
80+
strokeLinecap="round"
81+
strokeLinejoin="round"
82+
strokeWidth={2}
83+
d="M5 13l4 4L19 7"
84+
/>
85+
</svg>
86+
</div>
87+
<h2 className="text-3xl font-bold text-gray-900">
88+
Check Your Email
89+
</h2>
90+
<p className="mt-4 text-base text-gray-600">
91+
We've sent password reset instructions to
92+
</p>
93+
<p className="mt-2 text-sm font-medium text-emerald-600">
94+
{submittedEmail}
95+
</p>
96+
<p className="mt-6 text-sm text-gray-500">
97+
Didn't receive the email? Check your spam folder or{" "}
98+
<button
99+
onClick={() => setIsSuccess(false)}
100+
className="text-emerald-600 hover:text-emerald-500 font-medium"
101+
>
102+
try again
103+
</button>
104+
</p>
105+
</div>
106+
107+
<div className="space-y-4">
108+
<Link
109+
href="/login"
110+
className="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-emerald-500 transition-colors"
111+
>
112+
Back to Login
113+
</Link>
114+
<p className="text-center text-sm text-gray-500">
115+
Redirecting in {countdown} seconds...
116+
</p>
117+
</div>
118+
</div>
119+
</div>
120+
);
121+
}
122+
123+
return (
124+
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4 sm:px-6 lg:px-8">
125+
<div className="max-w-md w-full space-y-8">
126+
<div className="text-center">
127+
<h2 className="text-3xl font-bold text-gray-900">
128+
Reset Your Password
129+
</h2>
130+
<p className="mt-2 text-sm text-gray-600">
131+
Enter your email and we'll send you a reset link
132+
</p>
133+
</div>
134+
135+
<form className="mt-8 space-y-6" onSubmit={handleSubmit(onSubmit)}>
136+
<div>
137+
<label
138+
htmlFor="email"
139+
className="block text-sm font-medium text-gray-700"
140+
>
141+
Email address
142+
</label>
143+
<div className="mt-1">
144+
<input
145+
{...register("email")}
146+
id="email"
147+
type="email"
148+
autoComplete="email"
149+
className={`appearance-none block w-full px-3 py-3 border ${
150+
errors.email ? "border-red-300" : "border-gray-300"
151+
} rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-emerald-500 focus:border-emerald-500 sm:text-sm`}
152+
placeholder="[email protected]"
153+
/>
154+
{errors.email && (
155+
<p className="mt-2 text-sm text-red-600">
156+
{errors.email.message}
157+
</p>
158+
)}
159+
</div>
160+
</div>
161+
162+
<div>
163+
<button
164+
type="submit"
165+
disabled={isLoading}
166+
className="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-emerald-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
167+
>
168+
{isLoading ? (
169+
<div className="flex items-center">
170+
<svg
171+
className="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
172+
xmlns="http://www.w3.org/2000/svg"
173+
fill="none"
174+
viewBox="0 0 24 24"
175+
>
176+
<circle
177+
className="opacity-25"
178+
cx="12"
179+
cy="12"
180+
r="10"
181+
stroke="currentColor"
182+
strokeWidth="4"
183+
></circle>
184+
<path
185+
className="opacity-75"
186+
fill="currentColor"
187+
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"
188+
></path>
189+
</svg>
190+
Sending...
191+
</div>
192+
) : (
193+
"Send Reset Link"
194+
)}
195+
</button>
196+
</div>
197+
198+
<div className="text-center">
199+
<Link
200+
href="/login"
201+
className="text-sm font-medium text-emerald-600 hover:text-emerald-500"
202+
>
203+
← Back to Login
204+
</Link>
205+
</div>
206+
</form>
207+
</div>
208+
</div>
209+
);
210+
}

0 commit comments

Comments
 (0)