"use client"; import { useRouter } from "next/navigation"; import { useTheme } from "next-themes"; import { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { FlickeringGrid } from "@/components/ui/flickering-grid"; import { Input } from "@/components/ui/input"; import { getCsrfHeaders } from "@/core/api/fetcher"; import { useAuth } from "@/core/auth/AuthProvider"; import { parseAuthError } from "@/core/auth/types"; type SetupMode = "loading" | "init_admin" | "change_password"; export default function SetupPage() { const router = useRouter(); const { user, isAuthenticated } = useAuth(); const { theme, resolvedTheme } = useTheme(); const [mode, setMode] = useState("loading"); // --- Shared state --- const [email, setEmail] = useState(""); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); // --- Change-password mode only --- const [currentPassword, setCurrentPassword] = useState(""); useEffect(() => { let cancelled = false; if (isAuthenticated && user?.needs_setup) { setMode("change_password"); } else if (!isAuthenticated) { // Check if the system has no users yet void fetch("/api/v1/auth/setup-status") .then((r) => r.json()) .then((data: { needs_setup?: boolean }) => { if (cancelled) return; if (data.needs_setup) { setMode("init_admin"); } else { // System already set up and user is not logged in — go to login router.push("/login"); } }) .catch(() => { if (!cancelled) router.push("/login"); }); } else { // Authenticated but needs_setup is false — already set up router.push("/workspace"); } return () => { cancelled = true; }; }, [isAuthenticated, user, router]); // ── Init-admin handler ───────────────────────────────────────────── const handleInitAdmin = async (e: React.SubmitEvent) => { e.preventDefault(); setError(""); if (newPassword !== confirmPassword) { setError("Passwords do not match"); return; } setLoading(true); try { const res = await fetch("/api/v1/auth/initialize", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ email, password: newPassword, }), }); if (!res.ok) { const data = await res.json(); const authError = parseAuthError(data); setError(authError.message); return; } router.push("/workspace"); } catch { setError("Network error. Please try again."); } finally { setLoading(false); } }; // ── Change-password handler ──────────────────────────────────────── const handleChangePassword = async (e: React.SubmitEvent) => { e.preventDefault(); setError(""); if (newPassword !== confirmPassword) { setError("Passwords do not match"); return; } if (newPassword.length < 8) { setError("Password must be at least 8 characters"); return; } setLoading(true); try { const res = await fetch("/api/v1/auth/change-password", { method: "POST", headers: { "Content-Type": "application/json", ...getCsrfHeaders(), }, credentials: "include", body: JSON.stringify({ current_password: currentPassword, new_password: newPassword, new_email: email || undefined, }), }); if (!res.ok) { const data = await res.json(); const authError = parseAuthError(data); setError(authError.message); return; } router.push("/workspace"); } catch { setError("Network error. Please try again."); } finally { setLoading(false); } }; const actualTheme = theme === "system" ? resolvedTheme : theme; if (mode === "loading") { return (

Loading…

); } // ── Admin initialization form ────────────────────────────────────── if (mode === "init_admin") { return (

DeerFlow

Create admin account

Set up the administrator account to get started.

setEmail(e.target.value)} required />
setNewPassword(e.target.value)} required minLength={8} />
setConfirmPassword(e.target.value)} required minLength={8} />
{error &&

{error}

}
); } // ── Change-password form (needs_setup after login) ───────────────── return (

DeerFlow

Complete admin account setup

Set your real email and a new password.

setEmail(e.target.value)} required /> setCurrentPassword(e.target.value)} required /> setNewPassword(e.target.value)} required minLength={8} /> setConfirmPassword(e.target.value)} required minLength={8} /> {error &&

{error}

}
); }