registerPage('users', async (content, params = {}) => { document.getElementById('topbar-title').textContent = 'Users'; let userTypes = [], clients = []; async function preload() { const [tr, cr] = await Promise.all([ api('users.php', { action: 'user_types' }), api('clients.php', { action: 'list' }), ]); userTypes = tr.user_types || []; clients = cr.clients || []; } async function render(search = '') { const r = await api('users.php', { action: 'list', search }); if (!r.success) { document.getElementById('users-table').innerHTML = emptyHTML(); return; } const rows = r.users; document.getElementById('users-table').innerHTML = rows.length === 0 ? emptyHTML('No users found') : `
${rows.map(u => ``).join('')}
UsernameFull NameEmailTypeAssessor #ClientsActions
${u.safesure_users_name} ${u.name || '—'} ${u.email || '—'} ${typeBadge(u.user_type_name)} ${u.assessor_number || '—'} ${u.clients_multi || '—'}
`; } content.innerHTML = `
${loadingHTML()}
`; await preload(); const typeSel = document.getElementById('uf-type'); userTypes.forEach(t => typeSel.innerHTML += ``); function renderClientCheckboxes(selectedIds = []) { const selected = typeof selectedIds === 'string' ? selectedIds.split(',').map(s => s.trim()) : selectedIds; document.getElementById('uf-clients').innerHTML = clients.map(c => ` `).join(''); } window.syncClientHidden = () => { const checked = [...document.querySelectorAll('#uf-clients input:checked')].map(c => c.value); document.getElementById('uf-clients-hidden').value = checked.join(','); }; document.getElementById('user-search').addEventListener('input', e => render(e.target.value)); render(); window.userAdd = () => { document.getElementById('user-modal-title').textContent = 'New User'; document.getElementById('uf-id').value = ''; document.getElementById('uf-username').value = ''; document.getElementById('uf-name').value = ''; document.getElementById('uf-email').value = ''; document.getElementById('uf-password').value = ''; document.getElementById('uf-assessor').value = ''; document.getElementById('uf-moderator').value = ''; document.getElementById('uf-type').value = '2'; document.getElementById('pw-hint').textContent = '(required)'; renderClientCheckboxes([]); openModal('user-modal'); }; window.userEdit = async (id) => { const r = await api('users.php', { action: 'get', id }); if (!r.success) { toast('Failed', 'error'); return; } const u = r.user; document.getElementById('user-modal-title').textContent = 'Edit User'; document.getElementById('uf-id').value = u.record_id; document.getElementById('uf-username').value = u.safesure_users_name; document.getElementById('uf-name').value = u.name || ''; document.getElementById('uf-email').value = u.email || ''; document.getElementById('uf-password').value = ''; document.getElementById('uf-assessor').value = u.assessor_number || ''; document.getElementById('uf-moderator').value = u.moderator_number || ''; document.getElementById('uf-type').value = u.user_type_id; document.getElementById('pw-hint').textContent = '(leave blank to keep)'; renderClientCheckboxes(u.clients_multi || ''); syncClientHidden(); openModal('user-modal'); }; window.userSave = async () => { const id = document.getElementById('uf-id').value; syncClientHidden(); const params = { action: id ? 'update' : 'create', id, safesure_users_name: document.getElementById('uf-username').value, name: document.getElementById('uf-name').value, email: document.getElementById('uf-email').value, password: document.getElementById('uf-password').value, user_type_id: document.getElementById('uf-type').value, assessor_number: document.getElementById('uf-assessor').value, moderator_number: document.getElementById('uf-moderator').value, clients_multi: document.getElementById('uf-clients-hidden').value, }; const r = await api('users.php', params, 'POST'); if (r.success) { toast(r.message, 'success'); closeModal('user-modal'); render(); } else toast(r.error, 'error'); }; window.userDelete = async (id) => { if (!confirm('Delete this user? Their active session token will also be revoked.')) return; const r = await api('users.php', { action: 'delete', id }, 'POST'); if (r.success) { toast('User deleted', 'success'); render(); } else toast(r.error, 'error'); }; });