import React, { useState, useEffect } from "react"; import { Link } from "react-router-dom"; import { supabase } from "../lib/supabaseClient"; import { BrainCircuit, Mail, ArrowLeft, Loader2, CheckCircle2, ShieldCheck, Lock, KeyRound, AlertCircle } from "lucide-react"; import { motion, AnimatePresence } from "framer-motion"; function ForgotPassword() { const [step, setStep] = useState(1); const [email, setEmail] = useState(""); const [otp, setOtp] = useState(""); const [newPassword, setNewPassword] = useState(""); const [loading, setLoading] = useState(false); const [message, setMessage] = useState(""); const [error, setError] = useState(""); const [timeLeft, setTimeLeft] = useState(900); const [timerExpired, setTimerExpired] = useState(false); // Only re-run when step changes. DO NOT add timeLeft to deps array. useEffect(() => { if (step !== 2) return; setTimerExpired(false); setTimeLeft(900); const timer = setInterval(() => { setTimeLeft((prev) => { if (prev <= 1) { clearInterval(timer); setTimerExpired(true); return 0; } return prev - 1; }); }, 1000); return () => clearInterval(timer); }, [step]); const formatTime = (seconds) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs.toString().padStart(2, '0')}`; }; const handleSendOtp = async (e) => { e.preventDefault(); if (!email) { setError("Please enter your email address"); return; } setLoading(true); setError(""); try { // With Email OTP enabled in Supabase, resetPasswordForEmail sends // a 6-digit numeric OTP instead of a magic link. const { error } = await supabase.auth.resetPasswordForEmail(email); if (error) throw error; setMessage("Check your email for the 6-digit recovery code!"); setStep(2); } catch (err) { console.error("Password reset error:", err); setError(err.message || "An error occurred. Please try again."); } finally { setLoading(false); } }; const handleVerifyOtp = async (e) => { e.preventDefault(); if (!otp || otp.length !== 6) { setError("Please enter the 6-digit code"); return; } if (timerExpired) { setError("Your code has expired. Please request a new one."); return; } setLoading(true); setError(""); try { const { error } = await supabase.auth.verifyOtp({ email, token: otp, type: 'recovery' }); if (error) throw error; setStep(3); setMessage("Code verified. Please enter your new password."); } catch (err) { console.error("OTP verification error:", err); setError("Invalid or expired code. Please check your email and try again."); } finally { setLoading(false); } }; const handleUpdatePassword = async (e) => { e.preventDefault(); if (!newPassword || newPassword.length < 6) { setError("Password must be at least 6 characters long."); return; } setLoading(true); setError(""); try { const { error } = await supabase.auth.updateUser({ password: newPassword }); if (error) throw error; setStep(4); } catch (err) { console.error("Update password error:", err); setError(err.message || "Failed to update password."); } finally { setLoading(false); } }; return (
{/* Background Patterns */}
{/* Logo Header */}
HelpDesk.ai
{/* Header Decoration */}

{step === 1 ? "Recovery Access" : step === 2 ? "Verify Identity" : "Secure Protocol"}

{step === 1 ? "Enter your email to initiate recovery." : step === 2 ? "Enter the 6-digit code sent to your email." : "Set a new high-security password."}

{step === 4 ? (

Sync Successful

Your security credentials have been updated across all nodes.

Proceed to Terminal
) : (
{error && (

{error}

)} {message && step !== 1 && (

{message}

)} {/* STEP 1: Email */} {step === 1 && (
setEmail(e.target.value)} required />
)} {/* STEP 2: OTP */} {step === 2 && (
setOtp(e.target.value.replace(/[^0-9]/g, ''))} autoFocus />

{timerExpired ? '⚠ Code expired — request a new one below' : `Expires in ${formatTime(timeLeft)}`}

{timerExpired && ( )}
)} {/* STEP 3: New Password */} {step === 3 && (
setNewPassword(e.target.value)} required />
)}
Return to Secure Gate
)}
); } export default ForgotPassword;