import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "react-toastify"; import { account, auth as authApi } from "../api/client"; import { useAuth } from "../context/AuthContext"; import { Button, Card, Input, PageHeader, Toggle } from "../components/ui"; import { Modal } from "../components/Modal"; import { CodeBlock } from "../components/CodeBlock"; function Section({ title, description, children }: { title: string; description?: string; children: React.ReactNode }) { return (

{title}

{description &&

{description}

}
{children}
); } export function SettingsPage() { const { user, refresh } = useAuth(); const navigate = useNavigate(); // Profile const [displayName, setDisplayName] = useState(user?.display_name ?? ""); // Password const [curPw, setCurPw] = useState(""); const [newPw, setNewPw] = useState(""); // Auto-delete const [autoDelete, setAutoDelete] = useState(user?.auto_delete_enabled ?? false); const [autoDeleteDays, setAutoDeleteDays] = useState(user?.auto_delete_days ?? 30); // 2FA const [setup, setSetup] = useState<{ secret: string; otpauth_url: string } | null>(null); const [totp, setTotp] = useState(""); const [disable2faOpen, setDisable2faOpen] = useState(false); const [disablePw, setDisablePw] = useState(""); // Delete account const [deleteOpen, setDeleteOpen] = useState(false); const [deletePw, setDeletePw] = useState(""); const saveProfile = async () => { try { await account.updateProfile(displayName); toast.success("Profile updated"); refresh(); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); } }; const savePassword = async () => { try { await account.changePassword(curPw, newPw); toast.success("Password changed"); setCurPw(""); setNewPw(""); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); } }; const saveAutoDelete = async (enabled: boolean, days: number) => { try { const res = await account.updateSettings({ auto_delete_enabled: enabled, auto_delete_days: days }); setAutoDelete(res.auto_delete_enabled); setAutoDeleteDays(res.auto_delete_days); toast.success("Settings saved"); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); } }; const begin2fa = async () => { try { setSetup(await authApi.setup2fa()); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); } }; const confirm2fa = async () => { try { await authApi.enable2fa(totp); toast.success("2FA enabled"); setSetup(null); setTotp(""); refresh(); } catch (e) { toast.error(e instanceof Error ? e.message : "Invalid code"); } }; const disable2fa = async () => { try { await authApi.disable2fa(disablePw); toast.success("2FA disabled"); setDisable2faOpen(false); setDisablePw(""); refresh(); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); } }; const deleteAccount = async () => { try { await account.deleteAccount(deletePw); toast.success("Account deleted"); navigate("/login", { replace: true }); window.location.reload(); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); } }; return (
setDisplayName(e.target.value)} />
setCurPw(e.target.value)} /> setNewPw(e.target.value)} hint="At least 8 characters." />
{user?.totp_enabled ? (
✓ 2FA is enabled
) : setup ? (

Add this secret to your authenticator app, then enter the 6-digit code.

setTotp(e.target.value.replace(/\D/g, "").slice(0, 6))} placeholder="123456" inputMode="numeric" />
) : ( )}
saveAutoDelete(v, autoDeleteDays)} label="Enable auto-delete" /> {autoDelete && (
Retention window {autoDeleteDays} days
setAutoDeleteDays(Number(e.target.value))} onMouseUp={() => saveAutoDelete(true, autoDeleteDays)} onTouchEnd={() => saveAutoDelete(true, autoDeleteDays)} className="w-full accent-[var(--color-primary)]" />
)}
setDisable2faOpen(false)} onSubmit={disable2fa} title="Disable 2FA" footer={ <> } > setDisablePw(e.target.value)} /> setDeleteOpen(false)} onSubmit={deleteAccount} title="Delete account" footer={ <> } >

This deletes your account and cascades to all your agents, change requests, and notifications. This action is irreversible.

setDeletePw(e.target.value)} />
); }