"use client" import { useState, useEffect } from "react" import { Loader2 } from "lucide-react" import { authClient } from "@/lib/auth-client" import { loginEmailSchema, loginSchema, } from "@/lib/auth/validation" import SocialButtons from "./social-buttons" import Link from "next/link" import { useRouter } from "next/navigation" export default function LoginForm() { const router = useRouter() const [phase, setPhase] = useState<"email" | "password">("email") const [email, setEmail] = useState("") const [password, setPassword] = useState("") const [error, setError] = useState("") const [isLoading, setIsLoading] = useState(false) // Preload passkeys for conditional UI useEffect(() => { if (phase === "password" && "PublicKeyCredential" in window) { authClient.signIn.passkey({ autoFill: true }) } }, [phase]) const handleEmailSubmit = async (e: React.FormEvent) => { e.preventDefault() setError("") const result = loginEmailSchema.safeParse({ email }) if (!result.success) { setError(result.error.issues[0].message) return } // Check if email exists by attempting sign-in with empty password setIsLoading(true) const { error } = await authClient.signIn.email( { email, password: "" }, { onError: () => { // Silently handle - we check the error type below }, }, ) setIsLoading(false) if (error) { // If error is about invalid credentials, email exists but password is wrong // If error is about user not found, email doesn't exist if ( error.message?.toLowerCase().includes("not found") || error.message?.toLowerCase().includes("invalid email") || error.status === 404 ) { setError( "No account found with this email.", ) return } // Email exists, move to password phase setPhase("password") return } // Shouldn't reach here with empty password, but handle it setPhase("password") } const handleLogin = async (e: React.FormEvent) => { e.preventDefault() setError("") const result = loginSchema.safeParse({ email, password }) if (!result.success) { setError(result.error.issues[0].message) return } setIsLoading(true) const { error } = await authClient.signIn.email({ email, password }) setIsLoading(false) if (error) { setError(error.message || "Invalid credentials. Please try again.") return } router.push("/") } const handleChangeEmail = () => { setPhase("email") setPassword("") setError("") } return (

Welcome back

{phase === "email" ? "Sign in to DeckyVault" : `Signing in as `} {phase === "password" && ( <> {email} {" "} )}

or continue with email
{error && (
{error} {error.includes("No account found") && ( <> {" "} Create one → )}
)} {phase === "email" ? (
setEmail(e.target.value)} placeholder="you@example.com" autoComplete="username webauthn" className="w-full px-3 py-2.5 rounded-lg border border-white/10 bg-white/[0.03] text-[#ebe4f1] text-sm placeholder:text-[#ebe4f1]/40 outline-none focus:border-[#eb3779] focus:ring-2 focus:ring-[#eb3779]/50 transition-colors" />
) : (
setPassword(e.target.value)} placeholder="Enter your password" autoComplete="current-password webauthn" autoFocus className="w-full px-3 py-2.5 rounded-lg border border-white/10 bg-white/[0.03] text-[#ebe4f1] text-sm placeholder:text-[#ebe4f1]/40 outline-none focus:border-[#eb3779] focus:ring-2 focus:ring-[#eb3779]/50 transition-colors" />
Forgot password?
{/* Passkey hint */}

Your browser may offer to sign in with a passkey

)}

Don't have an account?{" "} Create one

) }