206 lines
6.6 KiB
JavaScript
206 lines
6.6 KiB
JavaScript
(function () {
|
|
const loginView = document.getElementById("loginView");
|
|
const adminView = document.getElementById("adminView");
|
|
const loginForm = document.getElementById("loginForm");
|
|
const passwordInput = document.getElementById("passwordInput");
|
|
const loginMessage = document.getElementById("loginMessage");
|
|
const addDateForm = document.getElementById("addDateForm");
|
|
const dateInput = document.getElementById("dateInput");
|
|
const addDateMessage = document.getElementById("addDateMessage");
|
|
const datesList = document.getElementById("datesList");
|
|
const dateCount = document.getElementById("dateCount");
|
|
const emptyDates = document.getElementById("emptyDates");
|
|
const logoutBtn = document.getElementById("logoutBtn");
|
|
|
|
let dates = [];
|
|
|
|
function setMessage(element, message, success) {
|
|
element.textContent = message;
|
|
element.classList.toggle("is-success", Boolean(success));
|
|
}
|
|
|
|
function todayKey() {
|
|
const today = new Date();
|
|
const year = today.getFullYear();
|
|
const month = String(today.getMonth() + 1).padStart(2, "0");
|
|
const day = String(today.getDate()).padStart(2, "0");
|
|
return `${year}-${month}-${day}`;
|
|
}
|
|
|
|
function formatDate(date) {
|
|
return new Date(`${date}T00:00:00`).toLocaleDateString("de-DE", {
|
|
weekday: "short",
|
|
day: "2-digit",
|
|
month: "2-digit",
|
|
year: "numeric",
|
|
});
|
|
}
|
|
|
|
async function request(path, options) {
|
|
const response = await fetch(path, {
|
|
...options,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...(options && options.headers),
|
|
},
|
|
});
|
|
const data = await response.json().catch(() => ({}));
|
|
if (!response.ok) {
|
|
const error = new Error(data.message || "Die Anfrage ist fehlgeschlagen.");
|
|
error.status = response.status;
|
|
throw error;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function showLogin(message) {
|
|
adminView.classList.add("hidden");
|
|
loginView.classList.remove("hidden");
|
|
if (message) {
|
|
setMessage(loginMessage, message, false);
|
|
}
|
|
passwordInput.focus();
|
|
}
|
|
|
|
function renderDates() {
|
|
datesList.innerHTML = "";
|
|
dateCount.textContent = `${dates.length} ${dates.length === 1 ? "Termin" : "Termine"}`;
|
|
emptyDates.classList.toggle("hidden", dates.length !== 0);
|
|
|
|
dates.forEach((date) => {
|
|
const row = document.createElement("li");
|
|
row.className = "date-row";
|
|
|
|
const label = document.createElement("span");
|
|
label.className = "date-label";
|
|
label.textContent = formatDate(date.date);
|
|
|
|
const typeSelect = document.createElement("select");
|
|
typeSelect.className = "date-type-select";
|
|
typeSelect.setAttribute("aria-label", `Tagestyp für ${formatDate(date.date)}`);
|
|
[["short", "Kurz"], ["long", "Lang"]].forEach(([value, text]) => {
|
|
const option = document.createElement("option");
|
|
option.value = value;
|
|
option.textContent = text;
|
|
option.selected = date.type === value;
|
|
typeSelect.appendChild(option);
|
|
});
|
|
typeSelect.addEventListener("change", async () => {
|
|
typeSelect.disabled = true;
|
|
try {
|
|
await request("/api/admin/dates", {
|
|
method: "PUT",
|
|
body: JSON.stringify({ date: date.date, type: typeSelect.value }),
|
|
});
|
|
date.type = typeSelect.value;
|
|
setMessage(addDateMessage, "Tagestyp aktualisiert.", true);
|
|
} catch (error) {
|
|
if (error.status === 401) {
|
|
showLogin("Deine Anmeldung ist abgelaufen.");
|
|
return;
|
|
}
|
|
typeSelect.value = date.type;
|
|
setMessage(addDateMessage, error.message, false);
|
|
} finally {
|
|
typeSelect.disabled = false;
|
|
}
|
|
});
|
|
|
|
const deleteButton = document.createElement("button");
|
|
deleteButton.className = "delete-date-btn";
|
|
deleteButton.type = "button";
|
|
deleteButton.textContent = "Löschen";
|
|
deleteButton.addEventListener("click", async () => {
|
|
if (!window.confirm(`${formatDate(date.date)} wirklich löschen?`)) {
|
|
return;
|
|
}
|
|
deleteButton.disabled = true;
|
|
try {
|
|
await request("/api/admin/dates", {
|
|
method: "DELETE",
|
|
body: JSON.stringify({ date: date.date }),
|
|
});
|
|
dates = dates.filter((item) => item.date !== date.date);
|
|
renderDates();
|
|
setMessage(addDateMessage, "Datum gelöscht.", true);
|
|
} catch (error) {
|
|
if (error.status === 401) {
|
|
showLogin("Deine Anmeldung ist abgelaufen.");
|
|
return;
|
|
}
|
|
setMessage(addDateMessage, error.message, false);
|
|
deleteButton.disabled = false;
|
|
}
|
|
});
|
|
|
|
row.append(label, typeSelect, deleteButton);
|
|
datesList.appendChild(row);
|
|
});
|
|
}
|
|
|
|
async function loadDates() {
|
|
try {
|
|
dates = await request("/api/admin/dates", { method: "GET" });
|
|
dates.sort((first, second) => first.date.localeCompare(second.date));
|
|
loginView.classList.add("hidden");
|
|
adminView.classList.remove("hidden");
|
|
renderDates();
|
|
} catch (error) {
|
|
if (error.status === 401) {
|
|
showLogin();
|
|
return;
|
|
}
|
|
showLogin("Die Termine konnten nicht geladen werden.");
|
|
}
|
|
}
|
|
|
|
loginForm.addEventListener("submit", async (event) => {
|
|
event.preventDefault();
|
|
setMessage(loginMessage, "", false);
|
|
try {
|
|
await request("/api/admin/login", {
|
|
method: "POST",
|
|
body: JSON.stringify({ password: passwordInput.value }),
|
|
});
|
|
passwordInput.value = "";
|
|
await loadDates();
|
|
} catch (error) {
|
|
setMessage(loginMessage, error.message, false);
|
|
}
|
|
});
|
|
|
|
addDateForm.addEventListener("submit", async (event) => {
|
|
event.preventDefault();
|
|
const type = addDateForm.elements.dateType.value;
|
|
setMessage(addDateMessage, "", false);
|
|
try {
|
|
await request("/api/admin/dates", {
|
|
method: "POST",
|
|
body: JSON.stringify({ date: dateInput.value, type }),
|
|
});
|
|
dates.push({ date: dateInput.value, type });
|
|
dates.sort((first, second) => first.date.localeCompare(second.date));
|
|
renderDates();
|
|
setMessage(addDateMessage, "Datum hinzugefügt.", true);
|
|
addDateForm.reset();
|
|
dateInput.min = todayKey();
|
|
} catch (error) {
|
|
if (error.status === 401) {
|
|
showLogin("Deine Anmeldung ist abgelaufen.");
|
|
return;
|
|
}
|
|
setMessage(addDateMessage, error.message, false);
|
|
}
|
|
});
|
|
|
|
logoutBtn.addEventListener("click", async () => {
|
|
try {
|
|
await request("/api/admin/logout", { method: "POST" });
|
|
} finally {
|
|
showLogin();
|
|
}
|
|
});
|
|
|
|
dateInput.min = todayKey();
|
|
loadDates();
|
|
})(); |