Quran_Tech_Server / F_Pro /src /components /auth /ResetPassword.tsx
aboalaa147's picture
Initial deployment
eb6a2f9
Raw
History Blame Contribute Delete
6.87 kB
// 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>
);
}