"use client"; import { useState } from "react"; import { Mail, Lock, User2, ArrowRight, ArrowLeft, AlertCircle, CheckCircle, KeyRound, ShieldCheck, } from "lucide-react"; import { type SupportedLanguage } from "@/lib/i18n"; type AuthFlow = "login" | "register" | "verify" | "forgot" | "reset"; interface LoginViewProps { onLogin: (email: string, password: string) => Promise<{ ok: boolean; error?: string }>; onRegister: ( email: string, password: string, opts?: { displayName?: string }, ) => Promise<{ ok: boolean; error?: string; needsVerification?: boolean }>; onVerifyEmail: (code: string) => Promise<{ ok: boolean; error?: string }>; onResendVerification: () => Promise; onForgotPassword: (email: string) => Promise<{ ok: boolean; message?: string }>; onResetPassword: ( email: string, code: string, newPassword: string, ) => Promise<{ ok: boolean; error?: string }>; language: SupportedLanguage; /** * Which tab to open on mount. Defaults to "login". Pass "register" from * call-sites that represent a clear sign-up intent (e.g. the sidebar's * "Create account" entry) so the user lands directly on the right form. * Pass "reset" from the password-reset email deep link so the user * drops straight into the "set new password" step with email + code * pre-filled. */ initialFlow?: AuthFlow; initialEmail?: string; initialCode?: string; } export function LoginView({ onLogin, onRegister, onVerifyEmail, onResendVerification, onForgotPassword, onResetPassword, initialFlow = "login", initialEmail = "", initialCode = "", }: LoginViewProps) { const [flow, setFlow] = useState(initialFlow); const [email, setEmail] = useState(initialEmail); const [password, setPassword] = useState(""); const [displayName, setDisplayName] = useState(""); const [code, setCode] = useState(initialCode); const [newPassword, setNewPassword] = useState(""); const [error, setError] = useState(""); const [success, setSuccess] = useState(""); const [loading, setLoading] = useState(false); const clearMessages = () => { setError(""); setSuccess(""); }; const handleLogin = async () => { if (!email || !password) { setError("Email and password required"); return; } setLoading(true); clearMessages(); const res = await onLogin(email, password); setLoading(false); if (!res.ok) setError(res.error || "Login failed"); }; const handleRegister = async () => { if (!email || !password) { setError("Email and password required"); return; } setLoading(true); clearMessages(); const res = await onRegister(email, password, { displayName: displayName || undefined }); setLoading(false); if (!res.ok) { setError(res.error || "Registration failed"); return; } if (res.needsVerification) { setSuccess("Account created! Check your email for a verification code."); setFlow("verify"); } }; const handleVerify = async () => { if (!code || code.length !== 6) { setError("Enter the 6-digit code from your email"); return; } setLoading(true); clearMessages(); const res = await onVerifyEmail(code); setLoading(false); if (res.ok) setSuccess("Email verified! You're all set."); else setError(res.error || "Invalid code"); }; const handleForgot = async () => { if (!email) { setError("Enter your email address"); return; } setLoading(true); clearMessages(); const res = await onForgotPassword(email); setLoading(false); setSuccess(res.message || "If that email is registered, a reset code has been sent."); setFlow("reset"); }; const handleReset = async () => { if (!code || !newPassword) { setError("Enter the code and your new password"); return; } setLoading(true); clearMessages(); const res = await onResetPassword(email, code, newPassword); setLoading(false); if (res.ok) setSuccess("Password reset! You're now logged in."); else setError(res.error || "Reset failed"); }; return (
{/* Header */}
{flow === "verify" ? ( ) : flow === "forgot" || flow === "reset" ? ( ) : ( )}

{flow === "login" && "Welcome back"} {flow === "register" && "Create your account"} {flow === "verify" && "Verify your email"} {flow === "forgot" && "Forgot password"} {flow === "reset" && "Reset password"}

{flow === "login" && "Log in to sync your health data across devices"} {flow === "register" && "Free forever. Your data stays private."} {flow === "verify" && "Enter the 6-digit code we sent to your email"} {flow === "forgot" && "We'll send a reset code to your email"} {flow === "reset" && "Enter the code from your email and your new password"}

{/* Status messages */} {error && (
{error}
)} {success && (
{success}
)}
{/* === LOGIN === */} {flow === "login" && ( <>
)} {/* === REGISTER === */} {flow === "register" && ( <> { setFlow("login"); clearMessages(); }} label="Already have an account? Log in" /> )} {/* === VERIFY EMAIL === */} {flow === "verify" && ( <>
setCode(e.target.value.replace(/\D/g, "").slice(0, 6))} placeholder="000000" className="w-full bg-surface-2 border border-line/60 text-ink-base rounded-xl px-4 py-4 text-center text-2xl font-black tracking-[0.5em] focus:outline-none focus:ring-2 focus:ring-brand-500/30 focus:border-brand-500" onKeyDown={(e) => e.key === "Enter" && handleVerify()} />
{ setFlow("login"); clearMessages(); }} label="Skip for now" /> )} {/* === FORGOT PASSWORD === */} {flow === "forgot" && ( <> { setFlow("login"); clearMessages(); }} label="Back to login" /> )} {/* === RESET PASSWORD === */} {flow === "reset" && ( <>
setCode(e.target.value.replace(/\D/g, "").slice(0, 6))} placeholder="000000" className="w-full bg-surface-2 border border-line/60 text-ink-base rounded-xl px-4 py-4 text-center text-2xl font-black tracking-[0.5em] focus:outline-none focus:ring-2 focus:ring-brand-500/30 focus:border-brand-500" />
{ setFlow("login"); clearMessages(); }} label="Back to login" /> )}

Account is optional. MedOS works fully without login.
Creating an account syncs health data across devices.

); } function Field({ icon: Icon, type, value, onChange, placeholder, label, autoComplete, onEnter, }: { icon: any; type: string; value: string; onChange: (v: string) => void; placeholder: string; label: string; autoComplete?: string; onEnter?: () => void; }) { return (
onChange(e.target.value)} placeholder={placeholder} autoComplete={autoComplete} className="w-full bg-surface-2 border border-line/60 text-ink-base rounded-xl pl-10 pr-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-brand-500/30 focus:border-brand-500" onKeyDown={(e) => e.key === "Enter" && onEnter?.()} />
); } function PrimaryButton({ loading, onClick, label }: { loading: boolean; onClick: () => void; label: string }) { return ( ); } function BackLink({ onClick, label }: { onClick: () => void; label: string }) { return (
); }