diff --git a/packages/frontend/src/pages/AdminUsers.tsx b/packages/frontend/src/pages/AdminUsers.tsx new file mode 100644 index 0000000..a5834f4 --- /dev/null +++ b/packages/frontend/src/pages/AdminUsers.tsx @@ -0,0 +1,121 @@ +import { useEffect, useState } from 'react'; +import { adminUsersApi, type ListUsersResponse } from '../api/admin-users.js'; +import type { User } from '@flashcard/shared'; +import { ApiClientError } from '../api/client.js'; + +export function AdminUsersPage() { + const [data, setData] = useState({ rows: [], total: 0 }); + const [q, setQ] = useState(''); + const [busy, setBusy] = useState(false); + + const [inviteEmail, setInviteEmail] = useState(''); + const [inviteRole, setInviteRole] = useState<'user' | 'sysadmin'>('user'); + const [inviteMsg, setInviteMsg] = useState(null); + + async function refresh() { + setBusy(true); + try { setData(await adminUsersApi.list({ q: q.trim() || undefined })); } + finally { setBusy(false); } + } + useEffect(() => { refresh(); }, []); + + async function invite(e: React.FormEvent) { + e.preventDefault(); + setInviteMsg(null); + try { + await adminUsersApi.invite({ email: inviteEmail, role: inviteRole }); + setInviteMsg('Uitnodiging verstuurd.'); + setInviteEmail(''); + await refresh(); + } catch (err) { + setInviteMsg(err instanceof ApiClientError ? err.message : 'Uitnodigen mislukt.'); + } + } + + async function setActive(u: User, isActive: boolean) { + try { await adminUsersApi.update(u.id, { isActive }); await refresh(); } + catch (err) { alert(err instanceof ApiClientError ? err.message : 'Bijwerken mislukt.'); } + } + + async function setRole(u: User, role: 'user' | 'sysadmin') { + try { await adminUsersApi.update(u.id, { role }); await refresh(); } + catch (err) { alert(err instanceof ApiClientError ? err.message : 'Bijwerken mislukt.'); } + } + + async function sendReset(u: User) { + if (!confirm(`Reset/uitnodigingsmail sturen naar ${u.email}?`)) return; + try { await adminUsersApi.sendReset(u.id); alert('Mail verstuurd.'); } + catch (err) { alert(err instanceof ApiClientError ? err.message : 'Versturen mislukt.'); } + } + + return ( +
+
+

👑 Gebruikersbeheer

+

{data.total} gebruiker(s) totaal

+
+ +
+ + + +
+ {inviteMsg &&

{inviteMsg}

} + +
+
+ setQ(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && refresh()} /> + +
+ + + + + + + + + + + + {data.rows.map((u) => ( + + + + + + + + ))} + +
EmailNaamRolStatus
{u.email}{u.displayName} + + + {u.isActive ? ( + actief + ) : ( + uit + )} + {!u.emailVerifiedAt && ( + onbevestigd + )} + + + +
+
+
+ ); +}