'use client' import { useEffect, useState } from 'react' import { useRouter } from 'next/navigation' import AdminShell from '../../ui/AdminShell' import { authFetch, clearToken, getApiBase, getToken } from '../../lib/auth' type Profile = { id: number name: string description?: string | null role: 'user' | 'admin' auto_search_enabled: boolean account_expires_days?: number | null is_active: boolean assigned_users?: number assigned_invites?: number } type ProfileForm = { name: string description: string role: 'user' | 'admin' auto_search_enabled: boolean account_expires_days: string is_active: boolean } const defaultForm = (): ProfileForm => ({ name: '', description: '', role: 'user', auto_search_enabled: true, account_expires_days: '', is_active: true, }) export default function AdminProfilesPage() { const router = useRouter() const [profiles, setProfiles] = useState([]) const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [error, setError] = useState(null) const [status, setStatus] = useState(null) const [editingId, setEditingId] = useState(null) const [form, setForm] = useState(defaultForm()) const handleAuthResponse = (response: Response) => { if (response.status === 401) { clearToken() router.push('/login') return true } if (response.status === 403) { router.push('/') return true } return false } const loadProfiles = async () => { if (!getToken()) { router.push('/login') return } setLoading(true) setError(null) try { const baseUrl = getApiBase() const response = await authFetch(`${baseUrl}/admin/profiles`) if (!response.ok) { if (handleAuthResponse(response)) return throw new Error(`Failed to load profiles (${response.status})`) } const data = await response.json() setProfiles(Array.isArray(data?.profiles) ? data.profiles : []) } catch (err) { console.error(err) setError('Could not load profiles.') } finally { setLoading(false) } } useEffect(() => { void loadProfiles() }, []) const resetEditor = () => { setEditingId(null) setForm(defaultForm()) } const editProfile = (profile: Profile) => { setEditingId(profile.id) setForm({ name: profile.name ?? '', description: profile.description ?? '', role: profile.role ?? 'user', auto_search_enabled: Boolean(profile.auto_search_enabled), account_expires_days: typeof profile.account_expires_days === 'number' ? String(profile.account_expires_days) : '', is_active: profile.is_active !== false, }) setStatus(null) setError(null) } const saveProfile = async (event: React.FormEvent) => { event.preventDefault() setSaving(true) setError(null) setStatus(null) try { const baseUrl = getApiBase() const payload = { name: form.name, description: form.description || null, role: form.role, auto_search_enabled: form.auto_search_enabled, account_expires_days: form.account_expires_days || null, is_active: form.is_active, } const url = editingId == null ? `${baseUrl}/admin/profiles` : `${baseUrl}/admin/profiles/${editingId}` const response = await authFetch(url, { method: editingId == null ? 'POST' : 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }) if (!response.ok) { if (handleAuthResponse(response)) return const text = await response.text() throw new Error(text || 'Save failed') } setStatus(editingId == null ? 'Profile created.' : 'Profile updated.') resetEditor() await loadProfiles() } catch (err) { console.error(err) setError(err instanceof Error ? err.message : 'Could not save profile.') } finally { setSaving(false) } } const deleteProfile = async (profile: Profile) => { if (!window.confirm(`Delete profile "${profile.name}"?`)) return setError(null) setStatus(null) try { const baseUrl = getApiBase() const response = await authFetch(`${baseUrl}/admin/profiles/${profile.id}`, { method: 'DELETE', }) if (!response.ok) { if (handleAuthResponse(response)) return const text = await response.text() throw new Error(text || 'Delete failed') } if (editingId === profile.id) resetEditor() setStatus(`Deleted profile "${profile.name}".`) await loadProfiles() } catch (err) { console.error(err) setError(err instanceof Error ? err.message : 'Could not delete profile.') } } return ( } >
{error &&
{error}
} {status &&
{status}
}

{editingId == null ? 'Create profile' : 'Edit profile'}

Profiles define defaults applied when a user signs up using an invite.