/** * Admin > People > Users */ const { html } = window; const { useState, useEffect, useCallback } = hooks; export default function UsersSection() { const [users, setUsers] = useState([]); const [search, setSearch] = useState(''); const [loading, setLoading] = useState(true); const [showCreate, setShowCreate] = useState(false); const load = useCallback(async () => { try { const resp = await sw.api.admin.users.list(); setUsers(resp.data || []); } catch (e) { sw.toast(e.message, 'error'); } finally { setLoading(false); } }, []); useEffect(() => { load(); }, []); const filtered = users.filter(u => { if (!search) return true; const q = search.toLowerCase(); return u.username?.toLowerCase().includes(q) || u.email?.toLowerCase().includes(q); }); async function createUser(e) { e.preventDefault(); const form = e.target; const data = { username: form.username.value.trim(), email: form.email.value.trim(), password: form.password.value, is_admin: form.is_admin.checked, }; if (!data.username || !data.password) return sw.toast('Username and password required', 'error'); try { await sw.api.admin.users.create(data); sw.toast('User created', 'success'); setShowCreate(false); load(); } catch (e) { sw.toast(e.message, 'error'); } } async function toggleActive(id, active) { try { await sw.api.admin.users.toggleActive(id, active); sw.toast(`User ${active ? 'activated' : 'deactivated'}`, 'success'); load(); } catch (e) { sw.toast(e.message, 'error'); } } async function toggleAdmin(id, isAdmin) { try { await sw.api.admin.users.updateRole(id, isAdmin); sw.toast(isAdmin ? 'Admin granted' : 'Admin revoked', 'success'); load(); } catch (e) { sw.toast(e.message, 'error'); } } async function resetPassword(id, username) { const pw = await sw.prompt(`New password for "${username}":`, ''); if (!pw) return; try { await sw.api.admin.users.resetPassword(id, pw); sw.toast('Password reset', 'success'); } catch (e) { sw.toast(e.message, 'error'); } } async function approveUser(id) { try { await sw.api.admin.users.toggleActive(id, true); sw.toast('User approved', 'success'); load(); } catch (e) { sw.toast(e.message, 'error'); } } async function deleteUser(id, username) { const ok = await sw.confirm(`Delete user "${username}"? This is permanent and destroys their vault.`, true); if (!ok) return; try { await sw.api.admin.users.del(id); sw.toast('User deleted', 'success'); load(); } catch (e) { sw.toast(e.message, 'error'); } } function statusBadge(u) { if (u.status === 'pending') return html`pending`; if (!u.is_active) return html`inactive`; return html`active`; } if (loading) return html`
Loading\u2026
`; return html`
${showCreate && html`
`}
${filtered.length === 0 && html`
No users found
`} ${filtered.map(u => html`
${u.username} ${u.email || ''} ${' '}${statusBadge(u)}
${u.status === 'pending' && html` `} ${u.is_active ? html`` : html`` }
`)}
`; }