skydesportensdag/wwwroot/admin.js

116 lines
4.0 KiB
JavaScript

const tableBody = document.querySelector("#visitors");
const count = document.querySelector("#count");
const message = document.querySelector("#message");
const csvButton = document.querySelector("#export-csv");
const printButton = document.querySelector("#print-list");
let visitors = [];
function formatDateTime(value) {
return new Intl.DateTimeFormat("da-DK", {
dateStyle: "short",
timeStyle: "short"
}).format(new Date(value));
}
function showError(text) {
message.textContent = text;
message.className = "notice error";
message.hidden = false;
}
function escapeHtml(value) {
return String(value ?? "")
.replaceAll("&", "&")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#039;");
}
async function loadVisitors() {
csvButton.disabled = true;
printButton.disabled = true;
try {
const response = await fetch("/api/visitors");
if (!response.ok) {
showError("Listen kunne ikke hentes. Tjek admin-login og databaseforbindelse.");
count.textContent = "Fejl";
return;
}
visitors = await response.json();
updateParticipantMap(visitors);
message.hidden = true;
csvButton.disabled = false;
printButton.disabled = false;
count.textContent = `${visitors.length} registreret`;
if (visitors.length === 0) {
tableBody.innerHTML = '<tr><td colspan="8" class="empty">Ingen besøgende registreret endnu.</td></tr>';
return;
}
tableBody.innerHTML = visitors.map((visitor) => `
<tr>
<td>${escapeHtml(visitor.name)}</td>
<td>${escapeHtml(visitor.streetAddress)}</td>
<td>${escapeHtml(visitor.postalCode)}</td>
<td>${escapeHtml(visitor.city)}</td>
<td>${escapeHtml(visitor.birthday)}</td>
<td><a href="mailto:${escapeHtml(visitor.email)}">${escapeHtml(visitor.email)}</a></td>
<td>${escapeHtml(formatDateTime(visitor.createdAt))}</td>
<td class="no-print"><button type="button" class="delete-button" data-id="${visitor.id}" aria-label="Slet ${escapeHtml(visitor.name)}">Slet</button></td>
</tr>
`).join("");
} catch {
showError("Der er ikke forbindelse til besøgslisten lige nu.");
count.textContent = "Fejl";
}
}
tableBody.addEventListener("click", async (event) => {
const button = event.target.closest("button[data-id]");
if (!button || button.disabled) return;
const visitor = visitors.find((item) => String(item.id) === button.dataset.id);
if (!visitor || !window.confirm(`Slet registreringen for ${visitor.name}? Dette kan ikke fortrydes.`)) return;
button.disabled = true;
csvButton.disabled = true;
printButton.disabled = true;
try {
const response = await fetch(`/api/visitors/${visitor.id}`, { method: "DELETE" });
if (!response.ok && response.status !== 404) throw new Error("Sletning mislykkedes.");
await loadVisitors();
} catch {
showError("Registreringen kunne ikke slettes. Prøv igen.");
button.disabled = false;
csvButton.disabled = false;
printButton.disabled = false;
}
});
function csvCell(value) {
let text = String(value ?? "");
// Prevent spreadsheet programs from evaluating visitor input as formulas.
if (/^[\s]*[=+@-]/.test(text)) text = "'" + text;
return `"${text.replaceAll('"', '""')}"`;
}
csvButton.addEventListener("click", () => {
const rows = [
["Navn", "Vejnavn og husnummer", "Postnummer", "Postby", "Fødselsdag", "Email", "Registreret"],
...visitors.map((visitor) => [visitor.name, visitor.streetAddress, visitor.postalCode,
visitor.city, visitor.birthday, visitor.email, formatDateTime(visitor.createdAt)])
];
const csv = "\uFEFF" + rows.map((row) => row.map(csvCell).join(";")).join("\r\n") + "\r\n";
const url = URL.createObjectURL(new Blob([csv], { type: "text/csv;charset=utf-8" }));
const link = document.createElement("a");
link.href = url;
link.download = "skydesportens-dag-besogende.csv";
link.click();
setTimeout(() => URL.revokeObjectURL(url), 1000);
});
printButton.addEventListener("click", () => window.print());
loadVisitors();