Skip to content

Commit ea9c304

Browse files
Implement forgot password page
Implement the forgot password page, accessible from the login page, to allow users to reset their passwords.
1 parent 8562171 commit ea9c304

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
import { Toaster } from "@/components/ui/toaster";
23
import { Toaster as Sonner } from "@/components/ui/sonner";
34
import { TooltipProvider } from "@/components/ui/tooltip";
@@ -10,6 +11,7 @@ import AuthWrapper from "./components/AuthWrapper";
1011
import Index from "./pages/Index";
1112
import Login from "./pages/Login";
1213
import Register from "./pages/Register";
14+
import ForgotPassword from "./pages/ForgotPassword";
1315
import Dashboard from "./pages/Dashboard";
1416
import Community from "./pages/Community";
1517
import Meditations from "./pages/Meditations";
@@ -38,6 +40,7 @@ const App = () => (
3840
<Route path="/" element={<Index />} />
3941
<Route path="/login" element={<Login />} />
4042
<Route path="/register" element={<Register />} />
43+
<Route path="/forgot-password" element={<ForgotPassword />} />
4144

4245
{/* Protected member routes */}
4346
<Route

src/pages/ForgotPassword.tsx

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
2+
import React, { useState } from 'react';
3+
import { Link } from 'react-router-dom';
4+
import { sendPasswordResetEmail } from 'firebase/auth';
5+
import { auth } from '../utils/firebase';
6+
import { Button } from '@/components/ui/button';
7+
import { Input } from '@/components/ui/input';
8+
import { Label } from '@/components/ui/label';
9+
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
10+
import { motion } from 'framer-motion';
11+
import { toast } from 'sonner';
12+
import { Mail, ArrowLeft } from 'lucide-react';
13+
14+
const ForgotPassword: React.FC = () => {
15+
const [email, setEmail] = useState('');
16+
const [isLoading, setIsLoading] = useState(false);
17+
const [isEmailSent, setIsEmailSent] = useState(false);
18+
19+
const handleSubmit = async (e: React.FormEvent) => {
20+
e.preventDefault();
21+
setIsLoading(true);
22+
23+
try {
24+
await sendPasswordResetEmail(auth, email);
25+
setIsEmailSent(true);
26+
toast.success('Password reset email sent');
27+
} catch (error: any) {
28+
console.error('Error sending password reset email:', error);
29+
30+
// Handle specific error codes
31+
if (error.code === 'auth/user-not-found') {
32+
toast.error('No account found with this email address');
33+
} else if (error.code === 'auth/invalid-email') {
34+
toast.error('Please enter a valid email address');
35+
} else {
36+
toast.error('Failed to send reset email: ' + error.message);
37+
}
38+
} finally {
39+
setIsLoading(false);
40+
}
41+
};
42+
43+
return (
44+
<div className="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
45+
<div className="w-full max-w-md">
46+
<motion.div
47+
initial={{ opacity: 0, y: 20 }}
48+
animate={{ opacity: 1, y: 0 }}
49+
transition={{ duration: 0.5 }}
50+
>
51+
<Card className="glass-card">
52+
<CardHeader className="space-y-1">
53+
<CardTitle className="text-2xl font-bold text-center">Reset Password</CardTitle>
54+
<CardDescription className="text-center">
55+
{!isEmailSent ?
56+
"Enter your email to receive a password reset link" :
57+
"Check your email for a reset link"}
58+
</CardDescription>
59+
</CardHeader>
60+
<CardContent>
61+
{!isEmailSent ? (
62+
<form onSubmit={handleSubmit} className="space-y-4">
63+
<div className="space-y-2">
64+
<Label htmlFor="email">Email</Label>
65+
<div className="relative">
66+
<Mail className="absolute left-3 top-2.5 h-5 w-5 text-muted-foreground" />
67+
<Input
68+
id="email"
69+
type="email"
70+
placeholder="[email protected]"
71+
value={email}
72+
onChange={(e) => setEmail(e.target.value)}
73+
required
74+
className="pl-10 bg-background"
75+
/>
76+
</div>
77+
</div>
78+
79+
<Button
80+
type="submit"
81+
className="w-full"
82+
disabled={isLoading}
83+
>
84+
{isLoading ? 'Sending...' : 'Send Reset Link'}
85+
</Button>
86+
</form>
87+
) : (
88+
<div className="text-center space-y-4">
89+
<div className="p-2 bg-green-50 text-green-600 rounded-full w-12 h-12 flex items-center justify-center mx-auto">
90+
<Mail className="h-6 w-6" />
91+
</div>
92+
<p className="text-sm text-muted-foreground">
93+
We've sent a password reset link to <span className="font-medium">{email}</span>.
94+
Please check your inbox and spam folder.
95+
</p>
96+
<Button
97+
variant="outline"
98+
className="w-full mt-4"
99+
onClick={() => setIsEmailSent(false)}
100+
>
101+
Try a different email
102+
</Button>
103+
</div>
104+
)}
105+
</CardContent>
106+
<CardFooter className="flex flex-col">
107+
<div className="text-center text-sm text-muted-foreground mt-2">
108+
<Link to="/login" className="text-primary hover:underline inline-flex items-center">
109+
<ArrowLeft className="mr-2 h-4 w-4" />
110+
Back to Sign In
111+
</Link>
112+
</div>
113+
</CardFooter>
114+
</Card>
115+
</motion.div>
116+
</div>
117+
</div>
118+
);
119+
};
120+
121+
export default ForgotPassword;

0 commit comments

Comments
 (0)