130 lines
4.2 KiB
HTML
130 lines
4.2 KiB
HTML
|
|
{% extends "v2/base.html" %}
|
||
|
|
|
||
|
|
{% block title %}Abo-Verwaltung — GWÖ-Antragsprüfer{% endblock %}
|
||
|
|
|
||
|
|
{% set v2_active_nav = "admin_abos" %}
|
||
|
|
|
||
|
|
{% block main %}
|
||
|
|
<div style="padding:0 0 1.5rem;">
|
||
|
|
<h1 style="font-family:var(--font-display);font-size:22px;color:var(--ecg-teal);margin:0 0 4px;">Abo-Verwaltung</h1>
|
||
|
|
<p style="font-size:12px;font-family:var(--font-mono);color:var(--ecg-dark);opacity:0.6;">
|
||
|
|
E-Mail-Abonnements aller Nutzer*innen · nur für Admins
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div id="loading" style="font-family:var(--font-mono);font-size:12px;opacity:0.5;padding:16px 0;">
|
||
|
|
Lade Abonnements …
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div id="empty" class="v2-kasten outline-green" style="display:none;">
|
||
|
|
<h4>Keine Abonnements vorhanden</h4>
|
||
|
|
<p>Es wurden noch keine E-Mail-Abonnements eingerichtet.</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div id="error" class="v2-kasten outline-blue" style="display:none;">
|
||
|
|
<h4>Fehler beim Laden</h4>
|
||
|
|
<p id="error-msg"></p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div id="table-wrap" style="display:none;">
|
||
|
|
<div id="abo-count" style="font-family:var(--font-mono);font-size:11px;opacity:0.5;margin-bottom:10px;"></div>
|
||
|
|
<table class="v2-admin-table">
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>ID</th>
|
||
|
|
<th>E-Mail</th>
|
||
|
|
<th>Bundesland</th>
|
||
|
|
<th>Partei</th>
|
||
|
|
<th>Rhythmus</th>
|
||
|
|
<th>Zuletzt gesendet</th>
|
||
|
|
<th></th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody id="abo-rows"></tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
{% endblock %}
|
||
|
|
|
||
|
|
{% block body_scripts %}
|
||
|
|
<script>
|
||
|
|
(async function () {
|
||
|
|
const loadingEl = document.getElementById('loading');
|
||
|
|
const emptyEl = document.getElementById('empty');
|
||
|
|
const errorEl = document.getElementById('error');
|
||
|
|
const errorMsgEl = document.getElementById('error-msg');
|
||
|
|
const tableEl = document.getElementById('table-wrap');
|
||
|
|
const tbodyEl = document.getElementById('abo-rows');
|
||
|
|
const countEl = document.getElementById('abo-count');
|
||
|
|
|
||
|
|
function showError(msg) {
|
||
|
|
loadingEl.style.display = 'none';
|
||
|
|
errorMsgEl.textContent = msg;
|
||
|
|
errorEl.style.display = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function fmtDate(ts) {
|
||
|
|
if (!ts) return '—';
|
||
|
|
try { return new Date(ts).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }); }
|
||
|
|
catch (_) { return ts; }
|
||
|
|
}
|
||
|
|
|
||
|
|
async function deleteAbo(subId, btn) {
|
||
|
|
if (!confirm('Abo #' + subId + ' wirklich löschen?')) return;
|
||
|
|
btn.disabled = true;
|
||
|
|
btn.textContent = '…';
|
||
|
|
try {
|
||
|
|
const resp = await fetch('/api/subscriptions/' + subId, { method: 'DELETE' });
|
||
|
|
if (!resp.ok) {
|
||
|
|
const data = await resp.json().catch(() => ({}));
|
||
|
|
btn.textContent = 'Fehler: ' + (data.detail || resp.status);
|
||
|
|
btn.disabled = false;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const row = btn.closest('tr');
|
||
|
|
if (row) {
|
||
|
|
row.style.opacity = '0.3';
|
||
|
|
row.style.transition = 'opacity .3s';
|
||
|
|
setTimeout(() => row.remove(), 350);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
btn.textContent = 'Fehler';
|
||
|
|
btn.disabled = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const resp = await fetch('/api/subscriptions');
|
||
|
|
if (resp.status === 403) { showError('Zugriff verweigert (kein Admin).'); return; }
|
||
|
|
if (!resp.ok) { showError('HTTP ' + resp.status); return; }
|
||
|
|
const abos = await resp.json();
|
||
|
|
loadingEl.style.display = 'none';
|
||
|
|
|
||
|
|
if (!abos.length) { emptyEl.style.display = ''; return; }
|
||
|
|
|
||
|
|
countEl.textContent = abos.length + ' Abonnement' + (abos.length !== 1 ? 'e' : '');
|
||
|
|
|
||
|
|
tbodyEl.innerHTML = abos.map(a => `
|
||
|
|
<tr id="abo-${a.id}">
|
||
|
|
<td style="font-family:var(--font-mono);font-size:11px;opacity:0.6;">${a.id}</td>
|
||
|
|
<td style="font-size:12px;">${a.email || a.user_id || '—'}</td>
|
||
|
|
<td>${a.bundesland || '<span style="opacity:.4">alle</span>'}</td>
|
||
|
|
<td>${a.partei || '<span style="opacity:.4">alle</span>'}</td>
|
||
|
|
<td style="font-family:var(--font-mono);font-size:11px;">${a.frequency || 'weekly'}</td>
|
||
|
|
<td style="font-family:var(--font-mono);font-size:11px;">${fmtDate(a.last_sent_at)}</td>
|
||
|
|
<td>
|
||
|
|
<button class="v2-admin-btn danger" onclick="deleteAboRow(${a.id}, this)">
|
||
|
|
Löschen
|
||
|
|
</button>
|
||
|
|
</td>
|
||
|
|
</tr>`).join('');
|
||
|
|
|
||
|
|
tableEl.style.display = '';
|
||
|
|
} catch (e) {
|
||
|
|
showError(e.message);
|
||
|
|
}
|
||
|
|
|
||
|
|
window.deleteAboRow = deleteAbo;
|
||
|
|
})();
|
||
|
|
</script>
|
||
|
|
{% endblock %}
|