tahamajs/IE / Projects /front /src /components /auth /PasswordResetModal.tsx
tahamajs's picture
download
raw
7.52 kB
"use client";
import { usePasswordReset } from "@/hooks/usePasswordReset";
import { motion, AnimatePresence } from "framer-motion";
import { X, AlertCircle, CheckCircle, ArrowLeft } from "lucide-react";
interface PasswordResetModalProps {
isOpen: boolean;
onClose: () => void;
onLoginClick?: () => void;
}
export function PasswordResetModal({ isOpen, onClose, onLoginClick }: PasswordResetModalProps) {
const {
step,
username,
setUsername,
question,
answer,
setAnswer,
newPassword,
setNewPassword,
confirmPassword,
setConfirmPassword,
error,
success,
loading,
requestSecurityQuestion,
submitAnswer,
resetPassword,
goBack,
} = usePasswordReset();
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4" onClick={onClose}>
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
className="bg-white dark:bg-gray-800 rounded-2xl max-w-md w-full shadow-xl"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center p-5 border-b dark:border-gray-700">
<h2 className="text-xl font-bold text-gray-900 dark:text-white">Reset Password</h2>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
<X className="w-5 h-5" />
</button>
</div>
<div className="p-6">
<AnimatePresence mode="wait">
{success ? (
<motion.div
key="success"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="space-y-4"
>
<div className="bg-green-50 dark:bg-green-900/30 p-4 rounded-xl text-green-700 dark:text-green-400 text-center">
<CheckCircle className="w-12 h-12 mx-auto mb-2" />
<p className="font-medium">Password reset successful!</p>
<p className="text-sm mt-1">You can now log in with your new password.</p>
</div>
<button
onClick={onLoginClick || onClose}
className="w-full py-2 bg-primary text-white rounded-lg font-medium hover:bg-primary/90 transition"
>
Go to Login
</button>
</motion.div>
) : (
<motion.div key={step} initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="space-y-4">
{step === "ask" && (
<>
<p className="text-sm text-gray-600 dark:text-gray-400">
Enter your username to receive your security question.
</p>
<input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
className="w-full px-4 py-2 border rounded-xl dark:bg-gray-700 dark:border-gray-600 focus:ring-2 focus:ring-primary"
disabled={loading}
autoFocus
/>
</>
)}
{step === "question" && (
<>
<div className="bg-gray-50 dark:bg-gray-700/50 p-4 rounded-xl">
<p className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Security question:</p>
<p className="text-gray-900 dark:text-white font-mono text-sm break-words">{question}</p>
</div>
<input
type="text"
placeholder="Your answer"
value={answer}
onChange={(e) => setAnswer(e.target.value)}
className="w-full px-4 py-2 border rounded-xl dark:bg-gray-700 dark:border-gray-600 focus:ring-2 focus:ring-primary"
autoFocus
/>
</>
)}
{step === "reset" && (
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
New password
</label>
<input
type="password"
placeholder="Min 6 characters"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
className="w-full px-4 py-2 border rounded-xl dark:bg-gray-700 dark:border-gray-600 focus:ring-2 focus:ring-primary"
autoFocus
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Confirm new password
</label>
<input
type="password"
placeholder="Confirm"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="w-full px-4 py-2 border rounded-xl dark:bg-gray-700 dark:border-gray-600 focus:ring-2 focus:ring-primary"
/>
</div>
</div>
)}
{error && (
<div className="flex items-center gap-2 p-3 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-lg text-sm">
<AlertCircle className="w-4 h-4" />
<span>{error}</span>
</div>
)}
<div className="flex gap-3 pt-2">
{step !== "ask" && (
<button
onClick={goBack}
disabled={loading}
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition"
>
<ArrowLeft className="w-4 h-4 inline mr-1" /> Back
</button>
)}
<button
onClick={
step === "ask"
? requestSecurityQuestion
: step === "question"
? submitAnswer
: resetPassword
}
disabled={loading}
className={`${step === "ask" ? "flex-1" : "flex-1"} py-2 bg-primary text-white rounded-lg font-medium hover:bg-primary/90 transition disabled:opacity-50`}
>
{loading ? (
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin mx-auto" />
) : step === "reset" ? (
"Reset Password"
) : (
"Next"
)}
</button>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
</motion.div>
</div>
);
}

Xet Storage Details

Size:
7.52 kB
·
Xet hash:
43f93e113a56022eb54508e2677bc20fae10948f19b017faa3ca43f699210539

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.