"use client" import { useEffect, useState } from "react" import { useRouter } from "next/navigation" import { Button } from "@/components/ui/button" export default function LoginPage() { const router = useRouter() const [mode, setMode] = useState<"login" | "register">("login") const [name, setName] = useState("") const [email, setEmail] = useState("") const [password, setPassword] = useState("") const [rememberMe, setRememberMe] = useState(true) const [isSubmitting, setIsSubmitting] = useState(false) const [error, setError] = useState(null) const [resetSent, setResetSent] = useState(false) const [showForgot, setShowForgot] = useState(false) useEffect(() => { let isMounted = true const check = async () => { try { const res = await fetch("/api/auth/session", { cache: "no-store" }) if (res.ok && isMounted) { router.replace("/") } } catch { // ignore and stay on login } } check() return () => { isMounted = false } }, [router]) const submit = async () => { setError(null) if (!email.trim() || !password) { setError("Email and password are required") return } if (mode === "register" && !name.trim()) { setError("Name is required") return } setIsSubmitting(true) try { const endpoint = mode === "login" ? "/api/auth/login" : "/api/auth/register" const res = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, email, password, rememberMe }), }) const data = await res.json() if (!res.ok) { setError(data.error || "Authentication failed") return } router.replace("/") } catch { setError("Authentication failed") } finally { setIsSubmitting(false) } } return (

OpenClaw Task Hub

Sign in to continue.

{mode === "register" && (
setName(event.target.value)} className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white" placeholder="Your display name" />
)}
setEmail(event.target.value)} className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white" placeholder="you@example.com" />
{mode === "login" && ( )}
setPassword(event.target.value)} className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white" placeholder="At least 8 characters" />
{error &&

{error}

}
{/* Forgot Password Modal */} {showForgot && ( setShowForgot(false)} onSent={() => setResetSent(true)} /> )} {/* Reset Success Message */} {resetSent && (

✓ Password reset link sent! Check your email.

)}
) } function ForgotPasswordModal({ email, setEmail, onClose, onSent, }: { email: string setEmail: (email: string) => void onClose: () => void onSent: () => void }) { const [isSubmitting, setIsSubmitting] = useState(false) const [error, setError] = useState(null) const handleSubmit = async () => { setError(null) if (!email.trim()) { setError("Email is required") return } setIsSubmitting(true) try { const res = await fetch("/api/auth/forgot-password", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email }), }) const data = await res.json() if (!res.ok) { setError(data.error || "Failed to send reset link") return } onSent() onClose() } catch { setError("Failed to send reset link") } finally { setIsSubmitting(false) } } return (

Reset Password

Enter your email and we'll send you a link to reset your password.

setEmail(e.target.value)} className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white" placeholder="you@example.com" />
{error &&

{error}

}
) }