import { apiAction, toast } from './api.js'; import { initUserPanel } from './ui-user.js'; import { mountLogoutButton, ensureFloatingLogout } from './ui-auth.js'; const state = { counts: { templates: 0, sections: 0, blocks: 0, snippets: 0, renders_total: 0 }, usage: [], }; async function ensureAuthenticated() { try { const me = await apiAction('auth.me', { method: 'GET' }); if (!me?.ok || !me?.user) { if (!window.DISABLE_AUTH_REDIRECT) { window.location.href = '/login.php'; } return false; } window.__currentUser = me.user; document.documentElement.classList.remove('auth-pending'); return true; } catch { return false; } } function ensureAccess() { const role = (window.__currentUser?.role || '').toLowerCase(); if (role !== 'owner' && role !== 'admin') { toast('Kein Zugriff auf das Dashboard', false); window.location.href = '/admin/profile.php'; return false; } return true; } function renderCounts(counts) { const mapping = { templates: 'count-templates', sections: 'count-sections', blocks: 'count-blocks', snippets: 'count-snippets', renders_total: 'count-usage', }; Object.entries(mapping).forEach(([key, id]) => { const el = document.getElementById(id); if (!el) return; const value = counts[key] ?? 0; el.textContent = typeof value === 'number' ? value.toLocaleString('de-DE') : value; }); } function formatDate(value) { if (!value) return '–'; try { const date = new Date(value); if (Number.isNaN(date.getTime())) return value; return date.toLocaleString('de-DE'); } catch { return value; } } function renderUsage(list) { const table = document.getElementById('usageTable'); if (!table) return; const tbody = table.querySelector('tbody'); if (!tbody) return; if (!list.length) { tbody.innerHTML = 'Noch keine Daten vorhanden.'; return; } tbody.innerHTML = list.map(item => ` ${escapeHtml(item.name)} ${item.render_count.toLocaleString('de-DE')} ${escapeHtml(formatDate(item.last_rendered_at || item.updated_at))} `).join(''); } function escapeHtml(str) { return String(str ?? '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } async function loadMetrics() { try { const res = await apiAction('dashboard.metrics', { method: 'GET' }); if (!res?.ok) throw new Error(res?.error || 'Dashboard konnte nicht geladen werden'); state.counts = res.counts || state.counts; state.usage = Array.isArray(res.usage) ? res.usage : []; renderCounts(state.counts); renderUsage(state.usage); } catch (err) { toast(err.message || 'Fehler beim Laden', false); } } async function resetUsage(templateId) { try { await apiAction('dashboard.reset_usage', { method: 'POST', data: { template_id: templateId } }); toast('Zähler zurückgesetzt', true); await loadMetrics(); } catch (err) { toast(err.message || 'Zurücksetzen fehlgeschlagen', false); } } function bindEvents() { const refresh = document.getElementById('btn-refresh-dashboard'); refresh?.addEventListener('click', () => loadMetrics()); const table = document.getElementById('usageTable'); table?.addEventListener('click', ev => { const btn = ev.target.closest('button[data-reset]'); if (!btn) return; const id = Number(btn.getAttribute('data-reset')); if (!id) return; if (confirm('Zähler für dieses Template wirklich löschen?')) { resetUsage(id); } }); } document.addEventListener('DOMContentLoaded', async () => { const ok = await ensureAuthenticated(); if (!ok) return; if (!ensureAccess()) return; initUserPanel(); bindEvents(); await loadMetrics(); mountLogoutButton('#btn-logout', { redirect: '/login.php' }); ensureFloatingLogout({ redirect: '/login.php' }); });