chore: move js to single file
This commit is contained in:
+2
-133
@@ -178,140 +178,9 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="assets/js/nav.js"></script>
|
||||
<script src="assets/js/app.js"></script>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
// ─── Load admin state ────────────────────────────────────────────────────────
|
||||
|
||||
async function loadAdmin() {
|
||||
try {
|
||||
const r = await fetch('/api/admin.php', { redirect: 'manual' });
|
||||
if (r.type === 'opaqueredirect') { window.location.reload(); return; }
|
||||
if (!r.ok) { window.location.replace('index.html'); return; }
|
||||
const data = await r.json();
|
||||
|
||||
if (!data.is_admin) {
|
||||
window.location.replace('index.html');
|
||||
return;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.admin-nav-link').forEach(el => el.classList.remove('d-none'));
|
||||
const name = data.name || data.username;
|
||||
if (name) {
|
||||
document.querySelectorAll('.nav-username').forEach(el => { el.textContent = name; });
|
||||
}
|
||||
|
||||
document.getElementById('sandboxToggle').checked = data.sandbox_mode;
|
||||
document.getElementById('sandboxBanner').style.display = data.sandbox_mode ? '' : 'none';
|
||||
|
||||
document.getElementById('count-log').textContent = data.delivery_log_total ?? '—';
|
||||
document.getElementById('count-attendees').textContent = data.attendees ?? '—';
|
||||
document.getElementById('count-templates').textContent = data.templates ?? '—';
|
||||
document.getElementById('count-schedules').textContent = data.schedules ?? '—';
|
||||
} catch (e) {
|
||||
showResult('Failed to load admin data: ' + e.message, 'danger');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Sandbox toggle ──────────────────────────────────────────────────────────
|
||||
|
||||
document.getElementById('sandboxToggle').addEventListener('change', async () => {
|
||||
try {
|
||||
const data = await fetch('/api/admin.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action: 'toggle_sandbox' }),
|
||||
}).then(r => r.json());
|
||||
document.getElementById('sandboxToggle').checked = data.sandbox_mode;
|
||||
document.getElementById('sandboxBanner').style.display = data.sandbox_mode ? '' : 'none';
|
||||
showResult(`Sandbox mode ${data.sandbox_mode ? 'enabled' : 'disabled'}.`, 'success');
|
||||
} catch (e) {
|
||||
showResult('Failed to toggle sandbox mode: ' + e.message, 'danger');
|
||||
await loadAdmin(); // revert toggle visual state
|
||||
}
|
||||
});
|
||||
|
||||
// ─── Mark all as sandbox ─────────────────────────────────────────────────────
|
||||
|
||||
async function markAllSandbox() {
|
||||
if (!confirm('Mark ALL existing delivery log entries as sandbox?\n\nThey will be excluded from cost calculations and success rate on the dashboard.')) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await fetch('/api/admin.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action: 'mark_all_sandbox' }),
|
||||
});
|
||||
if (!res.ok) throw new Error((await res.json()).error ?? 'Failed');
|
||||
showResult('All sends marked as sandbox.', 'success');
|
||||
loadAdmin();
|
||||
} catch (e) {
|
||||
showResult('Failed: ' + e.message, 'danger');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Purge ───────────────────────────────────────────────────────────────────
|
||||
|
||||
const PURGE_LABELS = {
|
||||
delivery_log: 'all delivery log entries',
|
||||
attendees: 'all attendees, registrations and workshops',
|
||||
templates: 'all SMS templates',
|
||||
schedules: 'all scheduled rules',
|
||||
};
|
||||
|
||||
async function purge(target, useDateFilter = false) {
|
||||
const body = { action: 'purge', target };
|
||||
|
||||
if (useDateFilter) {
|
||||
const before = document.getElementById('purgeBefore').value;
|
||||
if (!before) {
|
||||
alert('Please select a date first.');
|
||||
return;
|
||||
}
|
||||
if (!confirm(`Purge all delivery log entries before ${before}?\n\nThis cannot be undone.`)) {
|
||||
return;
|
||||
}
|
||||
body.before = before;
|
||||
} else {
|
||||
if (!confirm(`This will permanently delete ${PURGE_LABELS[target]}.\n\nThis cannot be undone. Are you sure?`)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/admin.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) throw new Error(data.error ?? 'Purge failed');
|
||||
const n = typeof data.purged === 'number' ? ` (${data.purged} rows)` : '';
|
||||
showResult(`Purge completed successfully${n}.`, 'success');
|
||||
loadAdmin();
|
||||
} catch (e) {
|
||||
showResult('Purge failed: ' + e.message, 'danger');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Toast/alert helper ──────────────────────────────────────────────────────
|
||||
|
||||
function showResult(msg, type) {
|
||||
const el = document.getElementById('adminResult');
|
||||
el.className = `alert alert-${type}`;
|
||||
el.textContent = msg;
|
||||
el.style.display = '';
|
||||
clearTimeout(el._timer);
|
||||
el._timer = setTimeout(() => { el.style.display = 'none'; }, 6000);
|
||||
}
|
||||
|
||||
// ─── Init ────────────────────────────────────────────────────────────────────
|
||||
|
||||
loadAdmin();
|
||||
document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') loadAdmin(); });
|
||||
</script>
|
||||
|
||||
<nav class="bottom-nav" aria-label="Navigation">
|
||||
<a href="index.html" class="bottom-nav-item">
|
||||
<i class="fa-solid fa-house"></i>
|
||||
|
||||
Reference in New Issue
Block a user