221 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* eventCard.js Erstellt interaktive Event-Karten als DOM-Elemente.
* Jede Karte zeigt Titel, Datum, Veranstaltungsort sowie Speichern- und Einladen-Buttons.
*/
/**
* Erstellt eine vollständige Event-Karte als <article>-Element.
* @param {Object} event - Event-Objekt mit id, name, date, time, venue, category
* @returns {HTMLElement} Fertig aufgebautes Karten-Element
*/
export function createEventCard(event) {
const article = document.createElement("article");
article.className = "event-card";
// --- TITEL ---
const title = document.createElement("h3");
title.className = "event-card__title";
title.textContent = event.name;
// --- DATUM & UHRZEIT formatieren (Schweizer Format: dd.mm.yyyy) ---
const formattedDate = event.date
? new Date(event.date).toLocaleDateString("de-CH", {
day: "2-digit",
month: "2-digit",
year: "numeric"
})
: "Datum unbekannt";
const formattedTime = event.time ? event.time.slice(0, 5) : "";
const dateTime = formattedTime ? `${formattedDate}, ${formattedTime}` : formattedDate;
const date = document.createElement("p");
date.className = "event-card__date";
date.textContent = dateTime;
// --- VERANSTALTUNGSORT ---
const venue = document.createElement("p");
venue.className = "event-card__venue";
venue.textContent = event.venue || "Ort unbekannt";
article.append(title, date, venue);
if (event.url) {
const link = document.createElement("a");
link.href = event.url;
link.target = "_blank";
link.rel = "noopener noreferrer";
link.className = "btn btn-outline-secondary btn-sm mt-2";
link.textContent = "Event ansehen";
article.appendChild(link);
}
// Gäste sehen nur Event-Informationen. Speichern und Einladen sind Login-Funktionen.
if (!window.currentUser) {
return article;
}
// --- BUTTON-GRUPPE ---
const buttonContainer = document.createElement("div");
buttonContainer.className = "d-flex gap-2 mt-2 flex-wrap";
// =========================
// SPEICHERN-BUTTON
// Speichert das Event im localStorage, verhindert Duplikate
// =========================
const saveBtn = document.createElement("button");
saveBtn.type = "button";
saveBtn.className = "btn btn-outline-primary btn-sm";
// Prüfen ob bereits gespeichert → Button-Text entsprechend setzen
const alreadySaved = isAlreadySaved(event.id);
saveBtn.textContent = alreadySaved ? "Gespeichert ✓" : "Speichern";
if (alreadySaved) saveBtn.disabled = true;
saveBtn.addEventListener("click", () => {
const saved = JSON.parse(localStorage.getItem("savedEvents") || "[]");
// Duplikat-Schutz
if (saved.find(e => e.id === event.id)) {
saveBtn.textContent = "Gespeichert ✓";
saveBtn.disabled = true;
return;
}
saved.push(event);
localStorage.setItem("savedEvents", JSON.stringify(saved));
// Visuelles Feedback statt alert()
saveBtn.textContent = "Gespeichert ✓";
saveBtn.disabled = true;
saveBtn.classList.replace("btn-outline-primary", "btn-success");
});
// =========================
// EINLADEN-BUTTON
// Zeigt ein Inline-Formular an (kein browser-prompt())
// =========================
const inviteBtn = document.createElement("button");
inviteBtn.type = "button";
inviteBtn.textContent = "Einladen";
inviteBtn.className = "btn btn-primary btn-sm";
inviteBtn.disabled = false;
inviteBtn.addEventListener("click", () => {
if (!window.currentUser) {
showCardMessage(article, "Bitte einloggen um Einladungen zu senden.", "warning");
return;
}
// Formular ein-/ausblenden (Toggle)
const existing = article.querySelector(".invite-form");
if (existing) {
existing.remove();
} else {
article.appendChild(createInviteForm(event, article));
}
});
buttonContainer.append(saveBtn, inviteBtn);
article.appendChild(buttonContainer);
return article;
}
// =========================
// HILFSFUNKTION Einladungsformular
// Erstellt ein kleines Inline-Formular mit Benutzername-Eingabe
// =========================
function createInviteForm(event, card) {
const form = document.createElement("div");
form.className = "invite-form mt-2 d-flex gap-2 align-items-center flex-wrap";
const input = document.createElement("input");
input.type = "text";
input.className = "form-control form-control-sm";
input.placeholder = "Benutzername eingeben";
input.setAttribute("aria-label", "Benutzername für Einladung");
const sendBtn = document.createElement("button");
sendBtn.type = "button";
sendBtn.textContent = "Senden";
sendBtn.className = "btn btn-primary btn-sm";
const cancelBtn = document.createElement("button");
cancelBtn.type = "button";
cancelBtn.textContent = "Abbrechen";
cancelBtn.className = "btn btn-outline-secondary btn-sm";
cancelBtn.addEventListener("click", () => form.remove());
sendBtn.addEventListener("click", async () => {
const toUser = input.value.trim();
if (!toUser) {
input.classList.add("is-invalid");
return;
}
input.classList.remove("is-invalid");
sendBtn.disabled = true;
sendBtn.textContent = "Sende...";
try {
const res = await fetch("http://localhost:3000/api/invitation", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Username": window.currentUser
},
body: JSON.stringify({
toUser,
eventId: event.id,
eventName: event.name,
eventUrl: event.url || null
})
});
if (!res.ok) {
// Fehlermeldung vom Server auslesen (z.B. "Nutzer nicht registriert")
const errData = await res.json().catch(() => ({}));
throw new Error(errData.message || `Fehler ${res.status}`);
}
// Formular entfernen und Erfolgsmeldung anzeigen
form.remove();
showCardMessage(card, `Einladung an "${toUser}" gesendet.`, "success");
} catch (err) {
sendBtn.disabled = false;
sendBtn.textContent = "Senden";
showCardMessage(card, err.message || "Fehler beim Senden der Einladung.", "danger");
}
});
form.append(input, sendBtn, cancelBtn);
return form;
}
// =========================
// HILFSFUNKTION Status-Nachricht in Karte anzeigen
// Zeigt eine kurze Meldung innerhalb der Karte an und blendet sie nach 3s aus
// =========================
function showCardMessage(card, message, type) {
// Alte Nachrichten entfernen
card.querySelectorAll(".card-message").forEach(el => el.remove());
const msg = document.createElement("p");
msg.className = `card-message text-${type} mt-1 mb-0`;
msg.textContent = message;
card.appendChild(msg);
setTimeout(() => msg.remove(), 3000);
}
// =========================
// HILFSFUNKTION Prüft ob Event bereits gespeichert ist
// =========================
function isAlreadySaved(eventId) {
const saved = JSON.parse(localStorage.getItem("savedEvents") || "[]");
return saved.some(e => e.id === eventId);
}