Spaces:
Sleeping
Sleeping
| // src/pages/ForgotPassword/ResetPassword.tsx | |
| import { useState, useEffect } from 'react'; | |
| import { useNavigate, Link } from 'react-router-dom'; | |
| import { Button } from '../../components/ui/button'; | |
| import { Input } from '../../components/ui/input'; | |
| import { Label } from '../../components/ui/label'; | |
| import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../components/ui/card'; | |
| import { Lock, Eye, EyeOff, ArrowLeft, CheckCircle } from 'lucide-react'; | |
| import { forgotPasswordApi } from '../../lib/api/forgotPasswordApi'; | |
| export function ResetPassword() { | |
| const [newPassword, setNewPassword] = useState(''); | |
| const [confirmPassword, setConfirmPassword] = useState(''); | |
| const [showPassword, setShowPassword] = useState(false); | |
| const [showConfirmPassword, setShowConfirmPassword] = useState(false); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState<string | null>(null); | |
| const [success, setSuccess] = useState(false); | |
| const navigate = useNavigate(); | |
| const email = sessionStorage.getItem('resetEmail'); | |
| const otp = sessionStorage.getItem('resetOtp'); | |
| useEffect(() => { | |
| if (!email || !otp) { | |
| navigate('/forgot-password'); | |
| } | |
| }, [email, otp, navigate]); | |
| const validatePassword = (password: string): string | null => { | |
| if (password.length < 6) { | |
| return 'Password must be at least 6 characters long'; | |
| } | |
| return null; | |
| }; | |
| const handleSubmit = async (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| const passwordError = validatePassword(newPassword); | |
| if (passwordError) { | |
| setError(passwordError); | |
| return; | |
| } | |
| if (newPassword !== confirmPassword) { | |
| setError('Passwords do not match'); | |
| return; | |
| } | |
| if (!email || !otp) return; | |
| setLoading(true); | |
| setError(null); | |
| try { | |
| await forgotPasswordApi.resetPassword({ | |
| email, | |
| otp, | |
| newPassword, | |
| confirmNewPassword: confirmPassword, | |
| }); | |
| setSuccess(true); | |
| // Clear sensitive data from session storage | |
| sessionStorage.removeItem('resetEmail'); | |
| sessionStorage.removeItem('resetOtp'); | |
| // Redirect to sign in after 3 seconds | |
| setTimeout(() => { | |
| navigate('/signin'); | |
| }, 3000); | |
| } catch (err) { | |
| console.error('Password reset error:', err); | |
| setError(err instanceof Error ? err.message : 'Failed to reset password'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| if (success) { | |
| return ( | |
| <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-emerald-50 to-teal-50 p-4"> | |
| <Card className="w-full max-w-md"> | |
| <CardHeader className="text-center"> | |
| <div className="flex justify-center mb-4"> | |
| <div className="w-16 h-16 bg-emerald-600 rounded-full flex items-center justify-center"> | |
| <CheckCircle className="h-8 w-8 text-white" /> | |
| </div> | |
| </div> | |
| <CardTitle>Password Reset Successful!</CardTitle> | |
| <CardDescription> | |
| Your password has been changed successfully. | |
| </CardDescription> | |
| </CardHeader> | |
| <CardContent> | |
| <Button | |
| onClick={() => navigate('/signin')} | |
| className="w-full bg-emerald-600" | |
| > | |
| Go to Sign In | |
| </Button> | |
| </CardContent> | |
| </Card> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-emerald-50 to-teal-50 p-4"> | |
| <Card className="w-full max-w-md"> | |
| <CardHeader> | |
| <Link to="/verify-otp" className="text-emerald-600 hover:text-emerald-700 mb-2 inline-flex items-center gap-1"> | |
| <ArrowLeft className="h-4 w-4" /> | |
| Back | |
| </Link> | |
| <CardTitle className="text-center">Reset Password</CardTitle> | |
| <CardDescription className="text-center"> | |
| Create a new password for your account | |
| </CardDescription> | |
| </CardHeader> | |
| <CardContent> | |
| <form onSubmit={handleSubmit} className="space-y-4"> | |
| <div className="space-y-2"> | |
| <Label htmlFor="newPassword">New Password</Label> | |
| <div className="relative"> | |
| <Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> | |
| <Input | |
| id="newPassword" | |
| type={showPassword ? 'text' : 'password'} | |
| value={newPassword} | |
| onChange={(e) => setNewPassword(e.target.value)} | |
| placeholder="Enter new password" | |
| className="pl-10 pr-10" | |
| required | |
| /> | |
| <button | |
| type="button" | |
| onClick={() => setShowPassword(!showPassword)} | |
| className="absolute right-3 top-3 text-muted-foreground hover:text-gray-600" | |
| > | |
| {showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />} | |
| </button> | |
| </div> | |
| <p className="text-xs text-muted-foreground"> | |
| Password must be at least 6 characters long | |
| </p> | |
| </div> | |
| <div className="space-y-2"> | |
| <Label htmlFor="confirmPassword">Confirm New Password</Label> | |
| <div className="relative"> | |
| <Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> | |
| <Input | |
| id="confirmPassword" | |
| type={showConfirmPassword ? 'text' : 'password'} | |
| value={confirmPassword} | |
| onChange={(e) => setConfirmPassword(e.target.value)} | |
| placeholder="Confirm new password" | |
| className="pl-10 pr-10" | |
| required | |
| /> | |
| <button | |
| type="button" | |
| onClick={() => setShowConfirmPassword(!showConfirmPassword)} | |
| className="absolute right-3 top-3 text-muted-foreground hover:text-gray-600" | |
| > | |
| {showConfirmPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />} | |
| </button> | |
| </div> | |
| </div> | |
| {error && ( | |
| <div className="bg-red-50 border border-red-200 rounded-lg p-3"> | |
| <p className="text-red-600 text-sm text-center">{error}</p> | |
| </div> | |
| )} | |
| <Button | |
| type="submit" | |
| className="w-full bg-emerald-600" | |
| disabled={loading} | |
| > | |
| {loading ? 'Resetting...' : 'Reset Password'} | |
| </Button> | |
| </form> | |
| </CardContent> | |
| </Card> | |
| </div> | |
| ); | |
| } |