Add protected date management admin
This commit is contained in:
+206
@@ -0,0 +1,206 @@
|
||||
(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();
|
||||
})();
|
||||
Reference in New Issue
Block a user