import { useState } from 'react'; import { Alert } from '@/components/ui/Alert'; import { Button } from '@/components/ui/Button'; import { Card } from '@/components/ui/Card'; import { SectionHeader } from '@/components/ui/SectionHeader'; import { Tag } from '@/components/ui/Tag'; import { TextField } from '@/components/ui/TextField'; import { ApiError, apiPost } from '@/lib/api'; import { useAuth } from '@/lib/auth'; export function ProfilePage() { const { state, logout } = useAuth(); const user = state.user!; const [current, setCurrent] = useState(''); const [next, setNext] = useState(''); const [confirm, setConfirm] = useState(''); const [busy, setBusy] = useState(false); const [msg, setMsg] = useState<{ kind: 'ok' | 'err'; text: string } | null>(null); async function handleChangePassword(e: React.FormEvent) { e.preventDefault(); setMsg(null); if (next !== confirm) { setMsg({ kind: 'err', text: 'New passwords do not match.' }); return; } if (next.length < 8) { setMsg({ kind: 'err', text: 'New password must be at least 8 characters.' }); return; } setBusy(true); try { await apiPost('/auth/change-password', { current_password: current, new_password: next, }); setMsg({ kind: 'ok', text: 'Password updated. You will be signed out for security.' }); setCurrent(''); setNext(''); setConfirm(''); setTimeout(() => logout(), 1500); } catch (err) { if (err instanceof ApiError) { const payload = err.payload as { error?: string; message?: string } | null; setMsg({ kind: 'err', text: payload?.message ?? payload?.error ?? `HTTP ${err.status}`, }); } else { setMsg({ kind: 'err', text: err instanceof Error ? err.message : 'Update failed.' }); } } finally { setBusy(false); } } return ( <>

email  {user.email}

display  {user.display_name ?? '—'}

locale  {user.locale}

{user.groups.length === 0 &&

No groups yet.

} {user.groups.map((g) => ( {g} ))}
{user.is_admin && ADMIN — bypasses checks} {user.permissions.map((p) => ( {p} ))}
setCurrent(e.target.value)} required /> setNext(e.target.value)} required hint="Min 8 characters." /> setConfirm(e.target.value)} required /> {msg && {msg.text}}
); }