+
+
+ Event erstellen | Invité
+
+
+
+
+
+
+
+
+
+
+ Abbrechen
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/event-create.js b/event-create.js
new file mode 100644
index 0000000..5735a3f
--- /dev/null
+++ b/event-create.js
@@ -0,0 +1,443 @@
+// =============================
+// SETUP: Wichtige HTML-Elemente holen
+// Diese Konstanten verbinden unser JavaScript mit dem HTML.
+// So können wir später Buttons, Formularfelder und Bereiche steuern.
+// =============================
+const form = document.getElementById("eventForm");
+const steps = Array.from(document.querySelectorAll(".step"));
+const backButton = document.getElementById("backButton");
+const nextButton = document.getElementById("nextButton");
+const progressBar = document.getElementById("progressBar");
+const errorMessage = document.getElementById("errorMessage");
+const usernameElement = document.getElementById("username");
+const flowFooter = document.getElementById("flowFooter");
+
+// =============================
+// STATE: aktueller Schritt im Flow
+// currentStep merkt sich, auf welchem Schritt der User gerade ist.
+// lastStep ist der letzte Schritt im Formular.
+// =============================
+let currentStep = 0;
+const lastStep = steps.length - 1;
+
+// Text für den Weiter-Button je nach Schritt
+const nextLabels = {
+ 0: "Weiter",
+ 1: "Weiter",
+ 2: "Weiter",
+ 3: "Weiter",
+ 4: "Weiter",
+ 5: "Event veröffentlichen"
+};
+
+// Demo-Wert: Später könnte der Name z. B. aus einem User-Profil kommen
+usernameElement.textContent = "Mia";
+
+
+// =============================
+// STEP 1: Kleine Hilfsfunktionen
+// Diese Funktionen helfen uns später an mehreren Stellen im Code.
+// =============================
+
+/**
+ * Gibt alle Eingabefelder eines bestimmten Schritts zurück.
+ * Rückgabe: Array mit input-, textarea- und select-Feldern.
+ */
+function getStepFields(stepIndex) {
+ return Array.from(
+ steps[stepIndex].querySelectorAll("input, textarea, select")
+ );
+}
+
+/**
+ * Zeigt eine Fehlermeldung im Formular an.
+ * Wenn keine Nachricht übergeben wird, wird die Meldung geleert.
+ */
+function setErrorMessage(message = "") {
+ errorMessage.textContent = message;
+}
+
+
+// =============================
+// STEP 2: Schritt anzeigen & Oberfläche aktualisieren
+// showStep() ist eine der wichtigsten Funktionen:
+// Sie bestimmt, welcher Schritt sichtbar ist,
+// und aktualisiert gleichzeitig die restliche Oberfläche.
+// =============================
+
+/**
+ * Zeigt den gewünschten Schritt an.
+ * Dabei werden auch Buttons, Progress Bar und Review aktualisiert.
+ */
+function showStep(index) {
+ currentStep = index;
+
+ // Nur der aktuelle Schritt soll sichtbar sein
+ steps.forEach((step, stepIndex) => {
+ step.classList.toggle("step--active", stepIndex === index);
+ });
+
+ updateFlowVisibility(index);
+ updateReviewIfNeeded(index);
+ updateProgressBar(index, lastStep);
+ setErrorMessage("");
+
+ // Für bessere UX: bei jedem Schritt wieder nach oben scrollen
+ window.scrollTo({ top: 0, behavior: "smooth" });
+}
+
+/**
+ * Steuert Sichtbarkeit von Footer und Buttons.
+ * Im Intro-Schritt werden Footer und Zurück-Button versteckt.
+ * Zusätzlich bekommt der Weiter-Button je nach Schritt ein anderes Label.
+ */
+function updateFlowVisibility(stepIndex) {
+ const isIntroStep = stepIndex === 0;
+
+ flowFooter.hidden = isIntroStep;
+ backButton.hidden = isIntroStep;
+ nextButton.textContent = nextLabels[stepIndex];
+}
+
+
+// =============================
+// STEP 3: Fortschrittsanzeige
+// Die Progress Bar zeigt, wie weit der User im Flow ist.
+// Das Intro zählt noch nicht als eigentlicher Formularschritt.
+// =============================
+
+/**
+ * Berechnet den Fortschritt in Prozent und setzt die Breite der Progress Bar.
+ * Beispiel:
+ * - Intro = 0%
+ * - erster echter Formularschritt = 0%
+ * - letzter Schritt = 100%
+ */
+function updateProgressBar(stepIndex, totalStepIndex) {
+ let progress = 0;
+
+ if (stepIndex > 0) {
+ progress = ((stepIndex - 1) / (totalStepIndex - 1)) * 100;
+ }
+
+ progressBar.style.width = `${progress}%`;
+}
+
+
+// =============================
+// STEP 4: Review-Daten vorbereiten
+// Im letzten Schritt werden alle eingegebenen Daten nochmals angezeigt.
+// Dafür brauchen wir Funktionen, die Feldwerte sauber auslesen und formatieren.
+// =============================
+
+/**
+ * Führt das Update der Review nur aus,
+ * wenn wirklich der letzte Schritt geöffnet ist.
+ */
+function updateReviewIfNeeded(stepIndex) {
+ if (stepIndex === lastStep) {
+ updateReview();
+ }
+}
+
+/**
+ * Gibt den Wert eines Formularfeldes zurück.
+ * Rückgabe:
+ * - eingegebener Text / ausgewählte Option
+ * - oder "–", falls nichts vorhanden ist
+ */
+function getFieldValue(name) {
+ const field = form.elements[name];
+
+ if (!field) return "–";
+
+ // Spezialfall: Radio-Gruppen verhalten sich anders als normale Inputs
+ if (field instanceof RadioNodeList) {
+ return field.value || "–";
+ }
+
+ return field.value.trim() || "–";
+}
+
+/**
+ * Gibt alle ausgewählten Checkbox-Werte als Text zurück.
+ * Beispiel: "Vegetarisch, Vegan"
+ * Falls nichts ausgewählt wurde: "Keine Angabe"
+ */
+function getCheckboxValues(name) {
+ const checked = Array.from(
+ form.querySelectorAll(`input[name="${name}"]:checked`)
+ );
+
+ return checked.length
+ ? checked.map(item => item.value).join(", ")
+ : "Keine Angabe";
+}
+
+/**
+ * Formatiert ein Datum für die Review-Anzeige.
+ * Beispiel: aus "2026-03-26" wird "26.03.2026"
+ */
+function formatDate(value) {
+ if (!value || value === "–") return "–";
+
+ const date = new Date(value);
+ if (Number.isNaN(date.getTime())) return value;
+
+ return new Intl.DateTimeFormat("de-CH", {
+ day: "2-digit",
+ month: "2-digit",
+ year: "numeric"
+ }).format(date);
+}
+
+/**
+ * Schreibt einen Wert in das passende Feld der Review-Ansicht.
+ * Gesucht wird ein HTML-Element mit data-review="..."
+ */
+function updateReviewField(fieldName, value) {
+ const target = document.querySelector(`[data-review="${fieldName}"]`);
+
+ if (target) {
+ target.textContent = value;
+ }
+}
+
+/**
+ * Baut den Text für Allergien / Hinweise zusammen.
+ * Dabei werden Checkboxen und zusätzliches Freitextfeld kombiniert.
+ */
+function buildAllergiesReviewValue() {
+ const selected = getCheckboxValues("allergies");
+ const notes = getFieldValue("allergiesOther");
+
+ if (selected === "Keine Angabe" && notes === "–") return "Keine Angabe";
+
+ if (selected !== "Keine Angabe" && notes !== "–") {
+ return `${selected}, ${notes}`;
+ }
+
+ return selected !== "Keine Angabe" ? selected : notes;
+}
+
+/**
+ * Liest alle wichtigen Formularwerte aus
+ * und schreibt sie gesammelt in die Review-Ansicht.
+ */
+function updateReview() {
+ const reviewValues = {
+ eventTitle: getFieldValue("eventTitle"),
+ eventType: getFieldValue("eventType"),
+ menuDescription: getFieldValue("menuDescription"),
+ eventDescription: getFieldValue("eventDescription"),
+ maxGuests: getFieldValue("maxGuests"),
+ dietType: getFieldValue("dietType"),
+ allergies: buildAllergiesReviewValue(),
+ eventDate: formatDate(getFieldValue("eventDate")),
+ eventTime: getFieldValue("eventTime"),
+ eventAddress: getFieldValue("eventAddress"),
+ eventCity: getFieldValue("eventCity")
+ };
+
+ Object.entries(reviewValues).forEach(([key, value]) => {
+ updateReviewField(key, value);
+ });
+}
+
+
+// =============================
+// STEP 5: Validierung
+// Bevor der User weitergehen darf, prüfen wir:
+// 1. Sind Pflichtfelder ausgefüllt?
+// 2. Wurde bei Pflicht-Radios etwas ausgewählt?
+// =============================
+
+/**
+ * Prüft, ob der aktuelle Schritt gültig ist.
+ * Rückgabe:
+ * - true = alles okay
+ * - false = es gibt einen Fehler
+ */
+function validateCurrentStep() {
+ // Intro und Review müssen nicht validiert werden
+ if (currentStep === 0 || currentStep === lastStep) return true;
+
+ const fields = getStepFields(currentStep);
+
+ // Zuerst Radio-Gruppen prüfen
+ const radioCheck = validateRadioGroups(fields);
+ if (!radioCheck.isValid) {
+ setErrorMessage(radioCheck.message);
+ return false;
+ }
+
+ // Danach normale Pflichtfelder prüfen
+ const requiredCheck = validateRequiredFields(fields);
+ if (!requiredCheck.isValid) {
+ setErrorMessage(requiredCheck.message);
+ return false;
+ }
+
+ setErrorMessage("");
+ return true;
+}
+
+/**
+ * Prüft alle Radio-Gruppen eines Schritts.
+ * Rückgabe:
+ * - Objekt mit isValid: true/false
+ * - bei Fehler zusätzlich eine passende Meldung
+ */
+function validateRadioGroups(fields) {
+ const names = [...new Set(fields.filter(f => f.type === "radio").map(f => f.name))];
+
+ for (const name of names) {
+ const group = Array.from(form.querySelectorAll(`input[name="${name}"]`));
+ const required = group.some(f => f.required);
+ const selected = group.some(f => f.checked);
+
+ if (required && !selected) {
+ return {
+ isValid: false,
+ message: "Bitte wähle eine Option aus."
+ };
+ }
+ }
+
+ return { isValid: true };
+}
+
+/**
+ * Prüft alle Pflichtfelder ausser Radios und Checkboxen.
+ * Rückgabe:
+ * - Objekt mit isValid: true/false
+ * - bei Fehler zusätzlich eine passende Meldung
+ */
+function validateRequiredFields(fields) {
+ for (const field of fields) {
+ if (field.type === "radio" || field.type === "checkbox") continue;
+
+ if (!field.checkValidity()) {
+ return {
+ isValid: false,
+ message: "Bitte fülle alle Pflichtfelder aus."
+ };
+ }
+ }
+
+ return { isValid: true };
+}
+
+
+// =============================
+// STEP 6: Navigation mit Zurück / Weiter
+// Diese Funktionen bestimmen, was beim Klicken auf die Buttons passiert.
+// =============================
+
+/**
+ * Einen Schritt zurückgehen.
+ * Wenn der User im ersten Formularschritt ist, geht es zurück zum Intro.
+ */
+function handleBackClick() {
+ if (currentStep > 1) {
+ showStep(currentStep - 1);
+ } else {
+ showStep(0);
+ }
+}
+
+/**
+ * Einen Schritt weitergehen.
+ * Vorher wird geprüft, ob der aktuelle Schritt gültig ist.
+ * Im letzten Schritt wird stattdessen das Formular abgeschickt.
+ */
+function handleNextClick() {
+ if (!validateCurrentStep()) return;
+
+ if (currentStep < lastStep) {
+ showStep(currentStep + 1);
+ } else {
+ form.requestSubmit();
+ }
+}
+
+
+// =============================
+// STEP 7: Submit
+// Aktuell ist das nur eine Demo.
+// Später könnte hier ein API-Call oder Speichern in einer Datenbank passieren.
+// =============================
+
+/**
+ * Reagiert auf das Absenden des Formulars.
+ * preventDefault verhindert, dass die Seite neu lädt.
+ */
+function handleFormSubmit(event) {
+ event.preventDefault();
+ alert("Event würde jetzt veröffentlicht werden.");
+}
+
+
+// =============================
+// STEP 8: Counter-Felder (+ / -)
+// Für Zahlenfelder wie z. B. Anzahl Gäste.
+// =============================
+
+/**
+ * Sucht alle Counter-Komponenten
+ * und verbindet die Plus-/Minus-Buttons mit den passenden Funktionen.
+ */
+function registerCounterHandlers() {
+ document.querySelectorAll("[data-counter]").forEach(counter => {
+ const input = counter.querySelector("input[type='number']");
+ const dec = counter.querySelector("[data-counter-action='decrease']");
+ const inc = counter.querySelector("[data-counter-action='increase']");
+
+ dec.addEventListener("click", () => updateCounterValue(input, -1));
+ inc.addEventListener("click", () => updateCounterValue(input, 1));
+ });
+}
+
+/**
+ * Erhöht oder verringert den Wert eines Zahlenfelds.
+ * Der Wert darf dabei nie kleiner als das definierte Minimum werden.
+ */
+function updateCounterValue(input, change) {
+ const min = Number(input.min || 1);
+ const currentValue = Number(input.value || min);
+ input.value = Math.max(min, currentValue + change);
+}
+
+
+// =============================
+// STEP 9: Alles starten
+// Hier werden alle Event Listener registriert
+// und der Flow startet mit dem Intro-Schritt.
+// =============================
+
+/**
+ * Initialisiert den kompletten Event-Erstellungs-Flow.
+ * Diese Funktion wird einmal beim Laden der Seite aufgerufen.
+ */
+function initEventCreationFlow() {
+ // Buttons, die den Flow starten
+ document.querySelectorAll("[data-start-flow]").forEach(btn => {
+ btn.addEventListener("click", () => showStep(1));
+ });
+
+ // Navigation
+ backButton.addEventListener("click", handleBackClick);
+ nextButton.addEventListener("click", handleNextClick);
+
+ // Formular absenden
+ form.addEventListener("submit", handleFormSubmit);
+
+ // Counter aktivieren
+ registerCounterHandlers();
+
+ // Startzustand: Intro anzeigen
+ showStep(0);
+}
+
+// Startpunkt des Skripts
+initEventCreationFlow();
\ No newline at end of file
diff --git a/event_detail.html b/event_detail.html
new file mode 100644
index 0000000..22044dd
--- /dev/null
+++ b/event_detail.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+ Event-Detail
+
+
+
+
+
+
SOCIAL COOKING
+
+
+
+
+
+
Lädt Event-Details...
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/event_overview.html b/event_overview.html
new file mode 100644
index 0000000..0fdc248
--- /dev/null
+++ b/event_overview.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+ Event-Overview
+
+
+
+
+
SOCIAL COOKING
+
+
+
+
+
Invité Events
+
+
+
WORAUF HAST DU LUST
+
+
BRUNCH
+
LUNCH
+
DINNER
+
COFFEE
+
ALLE
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/js/event_detail.js b/js/event_detail.js
new file mode 100644
index 0000000..e34ebc6
--- /dev/null
+++ b/js/event_detail.js
@@ -0,0 +1,47 @@
+document.addEventListener('DOMContentLoaded', async () => {
+ const detailContainer = document.getElementById('detail-view');
+
+ // 1. ID aus der URL lesen (z.B. detail.html?id=1)
+ const params = new URLSearchParams(window.location.search);
+ const eventId = parseInt(params.get('id'));
+
+ if (!eventId) {
+ window.location.href = 'event_overview.html';
+ return;
+ }
+
+ // 2. Daten laden und das richtige Event suchen
+ try {
+ const response = await fetch('data/events.json');
+ const allEvents = await response.json();
+ const event = allEvents.find(e => e.id === eventId);
+
+ if (event) {
+ renderDetailPage(event);
+ } else {
+ detailContainer.innerHTML = "
Event wurde nicht gefunden.
Zurück zur Übersicht";
+ }
+ } catch (error) {
+ console.error("Fehler beim Laden der Details:", error);
+ }
+
+ function renderDetailPage(event) {
+ //Layout Deatilseite der Events mit Rücklink zur Übersicht, Eventtitel, Infos und Bild
+ detailContainer.innerHTML = `
+
📍 ${event.location} | 📅 ${event.date} | 👤 Max. ${event.spots} Personen
+
+
Hier kommen die detaillierten Infos zu ${event.title} hin...
+
+
+
+
+
+ `;
+ }
+});
\ No newline at end of file
diff --git a/js/event_overview_script.js b/js/event_overview_script.js
new file mode 100644
index 0000000..4aa3c77
--- /dev/null
+++ b/js/event_overview_script.js
@@ -0,0 +1,109 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const eventGrid = document.getElementById('event-grid');
+ const filterButtons = document.querySelectorAll('.category-item');
+ let allEvents = [];
+
+ // 1. Daten laden aus JSOn file
+ async function fetchEvents() {
+ try {
+ // Pfad zu JSON File angepasst an lokale Ordnerstruktur
+ const response = await fetch('data/events.json');
+ allEvents = await response.json();
+ renderEvents(allEvents);
+
+ // Beim Laden prüfen, ob ein Filter gespeichert war
+ const savedFilter = sessionStorage.getItem('activeFilter') || 'ALLE';
+ applyFilter(savedFilter);
+
+ //checked ob Fehler beim Laden oder Parsen der Daten auftreten
+ } catch (error) {
+ console.error("Fehler:", error);
+ eventGrid.innerHTML = "
Events konnten nicht geladen werden.
";
+ }
+ }
+ // Funktion um Filter anzuwenden und gleichzeitig UI zu aktualisieren
+ function applyFilter(category) {
+
+ // UI: Aktiven Button stylen
+ filterButtons.forEach(btn => {
+ if (btn.getAttribute('data-cat') === category) {
+ btn.classList.add('active');
+ } else {
+ btn.classList.remove('active');
+ }
+ });
+
+ // Daten filtern
+ const filtered = category === 'ALLE'
+ ? allEvents
+ : allEvents.filter(e => e.category === category);
+
+ renderEvents(filtered);
+
+ //Filter im Browser merken
+ sessionStorage.setItem('activeFilter', category);
+
+ }
+ // 2. Events rendern + "Empty State" Logik
+ function renderEvents(events) {
+ eventGrid.innerHTML = '';
+
+ // PRÜFUNG: Wenn keine Events vorhanden sind zeigt folgende Nachricht
+ if (events.length === 0) {
+ eventGrid.innerHTML = `
+
+
Schade! Aktuell gibt es hier keine Events.
+
Möchtest du vielleicht selbst Gastgeber sein?
+
+
+ `;
+ return;
+ }
+
+ // Wenn Events da sind, Karten bauen
+ events.forEach(event => {
+ const card = document.createElement('article');
+ card.className = 'event-card';
+
+ //Klick auf die gesamte Karte leitet zur Detailseite weiter
+ card.style.cursor = "pointer";
+ card.onclick = () => {
+ window.location.href = `event_detail.html?id=${event.id}`;
+ };
+
+ //internes HTML im Js zur Styling der Event-Karte (HIER CHECKEN OB SO OK NACH CLEAN CODE)
+ card.innerHTML = `
+
+
+ 📍 ${event.location}
+
${event.title}
+
+ ${event.cuisine}
+ ${event.category}
+
+
+
+ ${event.date}
+ 🕒 ${event.time}
+
+
+
🥗 ${event.diet}
+
+
${event.spots} PLÄTZE FREI
+
+
❤️
+ `;
+ eventGrid.appendChild(card);
+ });
+ }
+
+ // 3. Filter-Logik basic anhand der Kategorien im JSON File
+ filterButtons.forEach(button => {
+ button.addEventListener('click', () => {
+ const selectedCat = button.getAttribute('data-cat');
+ applyFilter(selectedCat);
+ });
+ });
+
+ fetchEvents();
+});
\ No newline at end of file
diff --git a/js/javascript.js b/js/javascript.js
new file mode 100644
index 0000000..e69de29
diff --git a/kontakt.html b/kontakt.html
new file mode 100644
index 0000000..87907ad
--- /dev/null
+++ b/kontakt.html
@@ -0,0 +1,573 @@
+
+
+
+
+
+ Kontaktseite - Invité
+
+
+
+
+
+
+