From 905e1d1d6bf666b4cfbba23922ef717a84d95cf4 Mon Sep 17 00:00:00 2001 From: yashksaini-coder <ys3853428@gmail.com> Date: Fri, 4 Apr 2025 15:29:40 +0530 Subject: [PATCH 1/2] feat: Add Forgot Password and Reset Password pages with functionality --- app/auth/forgot-password/page.tsx | 65 +++++++++++++++++++++++ app/auth/reset-password/page.tsx | 68 +++++++++++++++++++++++++ components/AuthComponent/SigninForm.tsx | 5 ++ 3 files changed, 138 insertions(+) create mode 100644 app/auth/forgot-password/page.tsx create mode 100644 app/auth/reset-password/page.tsx diff --git a/app/auth/forgot-password/page.tsx b/app/auth/forgot-password/page.tsx new file mode 100644 index 0000000..0a2c155 --- /dev/null +++ b/app/auth/forgot-password/page.tsx @@ -0,0 +1,65 @@ +'use client' + +import { useState } from 'react' +import { Button } from '@/components/ui/button' +import { Alert, AlertDescription } from '@/components/ui/alert' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { supabase } from '@/lib/supabaseClient' + +export default function ForgotPasswordPage() { + const [email, setEmail] = useState('') + const [status, setStatus] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle') + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setStatus('sending') + + const { error } = await supabase.auth.resetPasswordForEmail(email, { + redirectTo: `${window.location.origin}/auth/reset-password` + }) + + if (error) { + setStatus('error') + console.error('Error sending reset email:', error.message) + } else { + setStatus('sent') + } + } + + return ( + <main className="flex min-h-screen items-center justify-center px-4"> + <Card className="w-full max-w-md rounded-2xl"> + <CardHeader> + <CardTitle className="text-center text-2xl">Forgot Password</CardTitle> + </CardHeader> + <CardContent className='space-y-4 align-center'> + <form onSubmit={handleSubmit} className="space-y-4"> + <input + type="email" + placeholder="you@example.com" + value={email} + onChange={(e) => setEmail(e.target.value)} + required + className="w-full p-2 border rounded" + /> + <div className="flex justify-center"> + <Button type="submit" disabled={status === 'sending'}> + {status === 'sending' ? 'Sending...' : 'Send Reset Link'} + </Button> + </div> + </form> + {status === 'sent' && ( + <Alert variant="default" className="mt-4"> + <AlertDescription>Check your email for the reset link.</AlertDescription> + </Alert> + )} + {status === 'error' && ( + <Alert variant="destructive" className="mt-4"> + <AlertDescription>Failed to send reset link. Please try again.</AlertDescription> + </Alert> + )} + </CardContent> + </Card> + </main> + ) +} \ No newline at end of file diff --git a/app/auth/reset-password/page.tsx b/app/auth/reset-password/page.tsx new file mode 100644 index 0000000..75f5158 --- /dev/null +++ b/app/auth/reset-password/page.tsx @@ -0,0 +1,68 @@ +'use client' + +import { useState } from 'react' +import { useRouter } from 'next/navigation' +import { Button } from '@/components/ui/button' +import { Alert, AlertDescription } from '@/components/ui/alert' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { supabase } from '@/lib/supabaseClient' + +export default function ResetPasswordPage() { + const router = useRouter() + const [newPassword, setNewPassword] = useState('') + const [status, setStatus] = useState<'idle' | 'updating' | 'updated' | 'error'>('idle') + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setStatus('updating') + + // Use the access token to update the user's password + const { data, error } = await supabase.auth.updateUser({ password: newPassword }) + + if (error) { + setStatus('error') + console.error('Error updating password:', error.message) + } else { + setStatus('updated') + // Redirect to login or another page after successful password update + setTimeout(() => { + router.push('/auth/signin') + }, 2000) + } + } + + return ( + <main className="flex min-h-screen items-center justify-center px-4"> + <Card className="w-full max-w-md rounded-2xl"> + <CardHeader> + <CardTitle className="text-center text-2xl">Set New Password</CardTitle> + </CardHeader> + <CardContent> + <form onSubmit={handleSubmit} className="space-y-4"> + <input + type="password" + placeholder="New Password" + value={newPassword} + onChange={(e) => setNewPassword(e.target.value)} + required + className="w-full p-2 border rounded" + /> + <Button type="submit" disabled={status === 'updating'}> + {status === 'updating' ? 'Updating...' : 'Set New Password'} + </Button> + </form> + {status === 'updated' && ( + <Alert variant="default" className="mt-4"> + <AlertDescription>Password updated successfully! Redirecting to sign in...</AlertDescription> + </Alert> + )} + {status === 'error' && ( + <Alert variant="destructive" className="mt-4"> + <AlertDescription>Failed to update password. Please try again.</AlertDescription> + </Alert> + )} + </CardContent> + </Card> + </main> + ) +} \ No newline at end of file diff --git a/components/AuthComponent/SigninForm.tsx b/components/AuthComponent/SigninForm.tsx index 9732907..d3dcce1 100644 --- a/components/AuthComponent/SigninForm.tsx +++ b/components/AuthComponent/SigninForm.tsx @@ -128,6 +128,11 @@ export default function SigninForm() { title="Sign in" type="submit" /> + <div className="flex justify-center mt-4"> + <a href="/auth/forgot-password" className="text-blue-600 hover:underline"> + Forgot Password? + </a> + </div> </form> </Form> </CardContent> From 937e7d2a218f28a44da7202ac4071b462025180f Mon Sep 17 00:00:00 2001 From: yashksaini-coder <ys3853428@gmail.com> Date: Fri, 4 Apr 2025 15:31:54 +0530 Subject: [PATCH 2/2] feat: Add password confirmation field and error handling to Reset Password page --- app/auth/reset-password/page.tsx | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/app/auth/reset-password/page.tsx b/app/auth/reset-password/page.tsx index 75f5158..19f9067 100644 --- a/app/auth/reset-password/page.tsx +++ b/app/auth/reset-password/page.tsx @@ -10,10 +10,19 @@ import { supabase } from '@/lib/supabaseClient' export default function ResetPasswordPage() { const router = useRouter() const [newPassword, setNewPassword] = useState('') + const [confirmPassword, setConfirmPassword] = useState('') const [status, setStatus] = useState<'idle' | 'updating' | 'updated' | 'error'>('idle') + const [errorMessage, setErrorMessage] = useState('') const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() + setErrorMessage('') + + if (newPassword !== confirmPassword) { + setErrorMessage('Passwords do not match.') + return + } + setStatus('updating') // Use the access token to update the user's password @@ -47,6 +56,19 @@ export default function ResetPasswordPage() { required className="w-full p-2 border rounded" /> + <input + type="password" + placeholder="Confirm Password" + value={confirmPassword} + onChange={(e) => setConfirmPassword(e.target.value)} + required + className="w-full p-2 border rounded" + /> + {errorMessage && ( + <Alert variant="destructive" className="mt-2"> + <AlertDescription>{errorMessage}</AlertDescription> + </Alert> + )} <Button type="submit" disabled={status === 'updating'}> {status === 'updating' ? 'Updating...' : 'Set New Password'} </Button> @@ -65,4 +87,4 @@ export default function ResetPasswordPage() { </Card> </main> ) -} \ No newline at end of file +} \ No newline at end of file