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')); }