import { useEffect, useMemo, useState } from 'react' import api from '@/services/api' import { useAuth } from '@/hooks/useAuth' import type { User } from '@/types' interface UserCreatePayload { username: string email: string full_name: string password: string is_admin: boolean } interface UserUpdatePayload { email?: string full_name?: string | null password?: string is_admin?: boolean is_active?: boolean } export default function UsersPage() { const { user } = useAuth() const isAdmin = user?.is_admin === true const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [message, setMessage] = useState('') const [selectedId, setSelectedId] = useState(null) const [createForm, setCreateForm] = useState({ username: '', email: '', full_name: '', password: '', is_admin: false, }) const [editForm, setEditForm] = useState({ email: '', full_name: '', password: '', is_admin: false, is_active: true, }) const selectedUser = useMemo( () => users.find((u) => u.id === selectedId) ?? null, [users, selectedId], ) useEffect(() => { if (!isAdmin) { setLoading(false) return } fetchUsers() }, [isAdmin]) useEffect(() => { if (!selectedUser) return setEditForm({ email: selectedUser.email, full_name: selectedUser.full_name || '', password: '', is_admin: selectedUser.is_admin, is_active: selectedUser.is_active, }) }, [selectedUser]) const fetchUsers = async () => { try { const { data } = await api.get('/users') setUsers(data) if (!selectedId && data.length > 0) { setSelectedId(data[0].id) } else if (selectedId && !data.some((u) => u.id === selectedId)) { setSelectedId(data[0]?.id ?? null) } } catch (err: any) { setMessage(err.response?.data?.detail || 'Failed to load users') } finally { setLoading(false) } } const handleCreateUser = async () => { if (!createForm.username.trim() || !createForm.email.trim() || !createForm.password.trim()) return setSaving(true) setMessage('') try { const payload = { username: createForm.username.trim(), email: createForm.email.trim(), full_name: createForm.full_name.trim() || null, password: createForm.password, is_admin: createForm.is_admin, } const { data } = await api.post('/users', payload) setCreateForm({ username: '', email: '', full_name: '', password: '', is_admin: false }) setMessage('User created successfully') await fetchUsers() setSelectedId(data.id) } catch (err: any) { setMessage(err.response?.data?.detail || 'Failed to create user') } finally { setSaving(false) } } const handleSaveUser = async () => { if (!selectedUser) return setSaving(true) setMessage('') try { const payload: UserUpdatePayload = { email: editForm.email.trim(), full_name: editForm.full_name.trim() || null, is_admin: editForm.is_admin, is_active: editForm.is_active, } if (editForm.password.trim()) { payload.password = editForm.password } await api.patch(`/users/${selectedUser.id}`, payload) setMessage('User updated successfully') await fetchUsers() setEditForm((prev) => ({ ...prev, password: '' })) } catch (err: any) { setMessage(err.response?.data?.detail || 'Failed to update user') } finally { setSaving(false) } } const handleDeleteUser = async () => { if (!selectedUser) return if (!confirm(`Delete user ${selectedUser.username}? This cannot be undone.`)) return setSaving(true) setMessage('') try { await api.delete(`/users/${selectedUser.id}`) setMessage('User deleted successfully') await fetchUsers() } catch (err: any) { setMessage(err.response?.data?.detail || 'Failed to delete user') } finally { setSaving(false) } } if (loading) return
Loading users...
if (!isAdmin) { return (

👥 User Management

Admin access required.

) } return (

👥 User Management

Create, edit, activate, and remove HarborForge users.
{message && (
{message}
)}

Create User

Users

{users.map((u) => ( ))}
{selectedUser ? ( <>

{selectedUser.username}

Created at {new Date(selectedUser.created_at).toLocaleString()}
) : (
No user selected.
)}
) }