// register.jsx — Everest new account registration function RegisterForm({ onLogin, onBack }) { const [step, setStep] = React.useState("register"); // "register" | "totp" const [name, setName] = React.useState(""); const [email, setEmail] = React.useState(""); const [password, setPassword] = React.useState(""); const [error, setError] = React.useState(null); const [totpData, setTotpData] = React.useState(null); // {token, totp_secret, totp_qr} const [code, setCode] = React.useState(""); const [loading, setLoading] = React.useState(false); async function handleRegister(e) { e.preventDefault(); setError(null); setLoading(true); try { const res = await fetch("/api/v1/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, email, password }), }); const data = await res.json(); if (!res.ok) throw new Error(data.detail || "Registration failed"); setTotpData(data); setStep("totp"); } catch (err) { setError(err.message); } finally { setLoading(false); } } async function handleTotp(e) { e.preventDefault(); setError(null); setLoading(true); try { const res = await fetch("/api/v1/auth/verify-totp", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: totpData.token, code }), }); const data = await res.json(); if (!res.ok) throw new Error(data.detail || "Invalid code"); onLogin(); } catch (err) { setError(err.message); } finally { setLoading(false); } } if (step === "totp") { return (
Everest

Set up authenticator

Scan this QR code with your authenticator app

{totpData?.totp_qr && ( TOTP QR )} {totpData?.totp_secret && (
Manual key {totpData.totp_secret}
)}
setCode(e.target.value.replace(/\D/g, ""))} autoFocus maxLength={6} required /> {error &&

{error}

}
); } return (
Everest

Create account

Mission Control — new expedition member

setName(e.target.value)} required autoFocus /> setEmail(e.target.value)} required /> setPassword(e.target.value)} required /> {error &&

{error}

}

Already have an account?{" "}

); }