Files
emailtemplate.it/public/assets/js/dashboard.js
2025-12-08 00:03:23 +01:00

141 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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) {
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 = '/account.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 = '<tr><td colspan="4" class="text-sm text-slate-500">Noch keine Daten vorhanden.</td></tr>';
return;
}
tbody.innerHTML = list.map(item => `
<tr data-template-id="${item.template_id}">
<td>${escapeHtml(item.name)}</td>
<td>${item.render_count.toLocaleString('de-DE')}</td>
<td>${escapeHtml(formatDate(item.last_rendered_at || item.updated_at))}</td>
<td class="text-right">
<button type="button" class="btn" data-reset="${item.template_id}">Zähler zurücksetzen</button>
</td>
</tr>
`).join('');
}
function escapeHtml(str) {
return String(str ?? '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
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' });
});