let currentUser = null;
let users = [];
// Auth check
fetch('/api/auth/me').then(r => r.ok ? r.json() : null).then(u => {
currentUser = u;
updateNavbar();
updateSidebar();
if (!u || u.role !== 'admin') {
document.getElementById('usersTable').innerHTML =
'
| Zugriff verweigert |
';
return;
}
loadUsers();
});
function updateNavbar() {
if (currentUser) {
document.getElementById('userName').textContent = currentUser.name;
document.getElementById('userMenu').classList.remove('d-none');
document.getElementById('loginBtn').classList.add('d-none');
} else {
document.getElementById('userMenu').classList.add('d-none');
document.getElementById('loginBtn').classList.remove('d-none');
}
}
function updateSidebar() {
const isAdmin = currentUser && currentUser.role === 'admin';
document.querySelectorAll('.sidebar-admin').forEach(el => {
el.style.display = isAdmin ? '' : 'none';
});
}
async function loadUsers() {
try {
const resp = await fetch('/api/admin/users');
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
users = await resp.json();
renderUsers();
} catch (e) {
document.getElementById('usersTable').innerHTML =
'| Fehler beim Laden |
';
}
}
function renderUsers() {
const tbody = document.getElementById('usersTable');
if (users.length === 0) {
tbody.innerHTML = '| Keine Benutzer |
';
return;
}
tbody.innerHTML = users.map(user => {
const roleBadge = user.role === 'admin'
? 'Admin'
: 'User';
const verifiedIcon = user.is_verified
? ''
: '';
const created = user.created_at ? new Date(user.created_at * 1000).toLocaleDateString('de-DE') : '-';
const isSelf = currentUser && currentUser.id === user.id;
let actions = '';
if (!isSelf) {
const newRole = user.role === 'admin' ? 'user' : 'admin';
const roleLabel = user.role === 'admin' ? 'User' : 'Admin';
actions += ``;
if (!user.is_verified) {
actions += ``;
}
actions += ``;
} else {
actions = 'Du';
}
return `
| ${escapeHtml(user.name)} |
${escapeHtml(user.email)} |
${roleBadge} |
${verifiedIcon} |
${created} |
${actions} |
`;
}).join('');
}
async function changeRole(id, role) {
try {
const resp = await fetch(`/api/admin/users/${id}/role`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ role })
});
if (resp.ok) { users = await resp.json(); renderUsers(); }
} catch (e) { console.error('Role change failed:', e); }
}
async function verifyUser(id) {
try {
const resp = await fetch(`/api/admin/users/${id}/verify`, { method: 'POST' });
if (resp.ok) { users = await resp.json(); renderUsers(); }
} catch (e) { console.error('Verify failed:', e); }
}
async function deleteUser(id, name) {
if (!confirm(`Benutzer "${name}" wirklich loeschen?`)) return;
try {
const resp = await fetch(`/api/admin/users/${id}`, { method: 'DELETE' });
if (resp.ok) { users = await resp.json(); renderUsers(); }
} catch (e) { console.error('Delete failed:', e); }
}
function escapeHtml(str) {
if (!str) return '';
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
// Theme toggle
const themeToggle = document.getElementById('themeToggle');
const themeIcon = document.getElementById('themeIcon');
function applyTheme(theme) {
document.documentElement.setAttribute('data-bs-theme', theme);
themeIcon.className = theme === 'dark' ? 'bi bi-sun-fill' : 'bi bi-moon-fill';
localStorage.setItem('theme', theme);
}
applyTheme(localStorage.getItem('theme') || 'dark');
themeToggle.addEventListener('click', () => {
const current = document.documentElement.getAttribute('data-bs-theme');
applyTheme(current === 'dark' ? 'light' : 'dark');
});
// Sidebar toggle (mobile)
const sidebarToggle = document.getElementById('sidebarToggle');
const sidebar = document.getElementById('sidebar');
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
if (sidebarToggle) {
sidebarToggle.addEventListener('click', () => sidebar.classList.toggle('open'));
sidebarBackdrop.addEventListener('click', () => sidebar.classList.remove('open'));
}