// admin.js — admin user management page
let resetTargetId = null;
let deleteTargetId = null;
let currentAdminId = null;
document.addEventListener('DOMContentLoaded', async () => {
// Verify admin access
const user = Auth.getUser();
if (!user || !user.is_admin) {
window.location.href = '/';
return;
}
currentAdminId = parseInt(user.sub);
await loadUsers();
});
async function loadUsers() {
try {
const users = await API.get('/api/admin/users');
renderUsers(users);
} catch (err) {
showMessage(document.getElementById('msg'), err.message, 'error');
}
}
function renderUsers(users) {
const tbody = document.getElementById('users-body');
if (!users.length) {
tbody.innerHTML = '
| No users found. |
';
return;
}
tbody.innerHTML = users.map(u => {
const isSelf = u.id === currentAdminId;
const roleLabel = u.is_admin
? 'Admin'
: 'User';
const statusLabel = u.is_disabled
? 'Disabled'
: 'Active';
const created = new Date(u.created_at).toLocaleDateString();
const toggleBtn = u.is_disabled
? ``
: ``;
const impersonateBtn = !isSelf
? ``
: '';
const deleteBtn = !isSelf
? ``
: '';
return `
| ${escHtml(u.username)} |
${roleLabel} |
${statusLabel} |
${created} |
${toggleBtn}
${impersonateBtn}
${deleteBtn}
|
`;
}).join('');
}
function showResetModal(id, username) {
resetTargetId = id;
document.getElementById('reset-username').textContent = username;
document.getElementById('reset-password').value = '';
document.getElementById('reset-msg').className = 'message';
document.getElementById('reset-modal').style.display = 'flex';
document.getElementById('reset-password').focus();
}
function hideResetModal() {
document.getElementById('reset-modal').style.display = 'none';
resetTargetId = null;
}
async function submitReset() {
const password = document.getElementById('reset-password').value;
const msgEl = document.getElementById('reset-msg');
if (password.length < 6) {
msgEl.textContent = 'Password must be at least 6 characters';
msgEl.className = 'message error visible';
return;
}
try {
await API.post(`/api/admin/users/${resetTargetId}/reset-password`, { new_password: password });
msgEl.textContent = 'Password reset successfully.';
msgEl.className = 'message success visible';
setTimeout(hideResetModal, 1200);
} catch (err) {
msgEl.textContent = err.message;
msgEl.className = 'message error visible';
}
}
async function toggleUser(id, disable) {
const action = disable ? 'disable' : 'enable';
try {
await API.post(`/api/admin/users/${id}/${action}`, {});
await loadUsers();
} catch (err) {
showMessage(document.getElementById('msg'), err.message, 'error');
}
}
async function impersonateUser(id) {
try {
const data = await API.post(`/api/admin/users/${id}/impersonate`, {});
Auth.setToken(data.user);
window.location.href = '/';
} catch (err) {
showMessage(document.getElementById('msg'), err.message, 'error');
}
}
function showDeleteModal(id, username) {
deleteTargetId = id;
document.getElementById('delete-username').textContent = username;
document.getElementById('delete-modal').style.display = 'flex';
}
function hideDeleteModal() {
document.getElementById('delete-modal').style.display = 'none';
deleteTargetId = null;
}
async function submitDelete() {
try {
await API.del(`/api/admin/users/${deleteTargetId}`);
hideDeleteModal();
showMessage(document.getElementById('msg'), 'User deleted.');
await loadUsers();
} catch (err) {
hideDeleteModal();
showMessage(document.getElementById('msg'), err.message, 'error');
}
}
// Close modals on overlay click
document.addEventListener('click', (e) => {
if (e.target.id === 'reset-modal') hideResetModal();
if (e.target.id === 'delete-modal') hideDeleteModal();
});