import axios from "axios"; import { FormEvent, useEffect, useState } from "react"; import { checkEmailStatus, registerRequest } from "../api/auth"; import { useAuthStore } from "../store/authStore"; type Step = "email" | "password" | "register" | "otp"; const AUTH_NOTICE_KEY = "bm_auth_notice"; export function AuthPanel() { const login = useAuthStore((s) => s.login); const loading = useAuthStore((s) => s.loading); const [step, setStep] = useState("email"); const [email, setEmail] = useState(""); const [name, setName] = useState(""); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [otpCode, setOtpCode] = useState(""); const [recoveryCode, setRecoveryCode] = useState(""); const [useRecoveryCode, setUseRecoveryCode] = useState(false); const [checkingEmail, setCheckingEmail] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); useEffect(() => { const notice = window.localStorage.getItem(AUTH_NOTICE_KEY); if (!notice) { return; } setSuccess(notice); window.localStorage.removeItem(AUTH_NOTICE_KEY); }, []); async function onSubmit(event: FormEvent) { event.preventDefault(); setError(null); setSuccess(null); try { if (step === "email") { const normalizedEmail = email.trim().toLowerCase(); if (!normalizedEmail) { setError("Enter email."); return; } setCheckingEmail(true); try { const status = await checkEmailStatus(normalizedEmail); setEmail(normalizedEmail); setStep(status.registered ? "password" : "register"); } finally { setCheckingEmail(false); } return; } if (step === "register") { await registerRequest(email, name, username, password); setSuccess("Account created. Verify email and continue login."); setStep("password"); return; } if (step === "password") { await login(email, password); return; } await login( email, password, useRecoveryCode ? undefined : (otpCode.trim() || undefined), useRecoveryCode ? (recoveryCode.trim() || undefined) : undefined ); } catch (err) { const message = getErrorMessage(err); if (step === "password" && message.toLowerCase().includes("2fa code required")) { setStep("otp"); setError(null); setSuccess("Enter 2FA code or use a recovery code."); return; } setError(message); setSuccess(null); } } function resetToEmail() { setStep("email"); setPassword(""); setOtpCode(""); setRecoveryCode(""); setUseRecoveryCode(false); setName(""); setUsername(""); setError(null); setSuccess(null); } const submitLabel = step === "email" ? "Continue" : step === "register" ? "Create account" : step === "password" ? "Next" : "Sign in"; const isBusy = loading || checkingEmail; return (

{step === "email" ? "Sign in to BenyaMessenger" : step === "register" ? "Create account" : "Enter credentials"}

{step === "email" ? "Enter your email to continue" : step === "register" ? "This email is not registered yet. Complete registration." : step === "password" ? "Enter your password" : "Two-factor authentication is enabled"}

setEmail(e.target.value)} /> {step !== "email" ? ( ) : null}
{step === "register" ? ( <> setName(e.target.value)} /> setUsername(e.target.value.replace("@", ""))} /> ) : null} {step === "password" || step === "register" || step === "otp" ? ( setPassword(e.target.value)} /> ) : null} {step === "otp" ? ( <> {useRecoveryCode ? ( setRecoveryCode(e.target.value.toUpperCase().replace(/[^A-Z0-9-]/g, "").slice(0, 24))} /> ) : ( setOtpCode(e.target.value.replace(/\D/g, "").slice(0, 8))} /> )} ) : null}
{error ?

{error}

: null} {success ?

{success}

: null}
); } function getErrorMessage(err: unknown): string { if (axios.isAxiosError(err)) { const detail = err.response?.data?.detail; if (typeof detail === "string" && detail.trim()) { return detail; } if (typeof err.message === "string" && err.message.trim()) { return err.message; } } if (err instanceof Error && err.message) { return err.message; } return "Auth request failed."; }