diff --git a/data/events.json b/data/events.json index 088ffe1..e4e2249 100644 --- a/data/events.json +++ b/data/events.json @@ -121,5 +121,39 @@ "https://i.pinimg.com/1200x/b1/fb/3a/b1fb3a7809f4046843904ac8800daacc.jpg", "https://i.pinimg.com/1200x/c6/93/42/c69342ec621333e853c35bda891d8bc6.jpg" ] + }, + { + "id": 4, + "title": "Mexican Fiesta", + "location": "Basel", + "address": "Münsterplatz 10, 4051 Basel", + "date": "28. April. 2026", + "time": "18:00 UHR", + "category": "Dinner", + "diet": "Omnivore", + "spots": 6, + "status": "canceled", + "host": { + "name": "Carlos", + "initial": "C" + }, + "hostMessage": [ + "Hallo zusammen! Leider muss ich dieses Event absagen, da mir etwas Wichtiges dazwischengekommen ist.", + "Ich hoffe, wir können das bald nachholen!" + ], + "menu": [ + "Guacamole & Nachos", + "Tacos al Pastor", + "Churros" + ], + "specifications": [], + "participants": [ + "Carlos", + "Vivien", + "Test" + ], + "gallery": [ + "https://i.pinimg.com/1200x/e2/6a/f5/e26af5c24b805081a3f304d240818302.jpg" + ] } ] \ No newline at end of file diff --git a/js/event_detail.js b/js/event_detail.js index 6899f74..dc11b9a 100644 --- a/js/event_detail.js +++ b/js/event_detail.js @@ -345,29 +345,34 @@ const isRegistered = userRegistrations.includes(Number(event.id)); const isListedParticipant = isUserListedInEventParticipants(event, currentUser); const hasAddressAccess = isRegistered || isListedParticipant || isOwnEvent; + const isCanceled = event.status === 'canceled'; - const actionButtonLabel = isOwnEvent ? 'Dein Event!' + const actionButtonLabel = isCanceled ? 'Abgesagt' + : isOwnEvent ? 'Dein Event!' : !currentUser ? 'Einloggen' : isRegistered ? (deregInfo.isClosed ? 'Abmeldung geschlossen' : 'Abmelden') : isRegistrationClosed ? 'Anmeldung geschlossen' : 'Anmelden'; - const actionButtonDisabled = isOwnEvent + const actionButtonDisabled = isCanceled + || isOwnEvent || (!isRegistered && (isFull || isRegistrationClosed)) || (isRegistered && deregInfo.isClosed); const actionButtonVariantClass = isOwnEvent ? ' button-primary-eigener-event' - : isRegistered ? ' button-primary-abmelden ' + : (isRegistered || isRegistrationClosed) ? ' button-primary-abmelden ' : ' button-primary '; const shouldRevealAddress = Boolean(event.address) && isAddressVisibleWindow(event) && hasAddressAccess; let addressMessage = 'Wenn du dich anmeldest, wird die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.'; - if (isOwnEvent) { + if (isCanceled) { + addressMessage = 'Dieses Event wurde leider vom Gastgeber abgesagt.'; + } else if (isOwnEvent) { addressMessage = 'Deine Adresse für diesen Event wird 24 Stunden vorher genau hier für alle Teilnehmer sichtbar sein'; } else if (hasAddressAccess) { addressMessage = 'Vielen Dank für die Anmeldung! Die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.'; } - if (isEventPastAddressWindow(event)) { + if (!isCanceled && isEventPastAddressWindow(event)) { addressMessage = 'Vielen Dank, dass du an diesem Event teilgenommen hast.'; } diff --git a/js/event_overview.js b/js/event_overview.js index 3f638cc..26119a7 100644 --- a/js/event_overview.js +++ b/js/event_overview.js @@ -397,23 +397,24 @@ }); const filtered = allEvents.filter(event => { + if (event.status === 'canceled') return false; + const categoryMatch = activeCategory === 'ALLE' || event.category === activeCategory; - + // Diet filter: if no diets selected, show all. Otherwise, event MUST have at least one selected diet. - const dietMatch = activeDiets.size === 0 || + const dietMatch = activeDiets.size === 0 || (event.diet && event.diet.split(', ').some(d => activeDiets.has(d.trim()))); - + // Allergie filter: if no allergies selected, show all. Otherwise, event MUST have at least one selected allergie. - const allergieMatch = activeAllergies.size === 0 || + const allergieMatch = activeAllergies.size === 0 || (event.specifications && event.specifications.some(spec => activeAllergies.has(spec))); - + const locationMatch = selectedLocation === 'ALLE_ORTE' || event.location === selectedLocation; const eventDateIso = parseEventDateToIso(event.date); const dateMatch = !selectedDate || eventDateIso === selectedDate; return categoryMatch && dietMatch && allergieMatch && locationMatch && dateMatch; }); - renderEvents(filtered); sessionStorage.setItem('activeFilter', activeCategory); @@ -473,6 +474,11 @@ const isOwnEvent = isEventOwnedByCurrentUser(event, currentUser); const isRegistered = userRegistrationSet.has(Number(event.id)); const isRegistrationClosed = isRegistrationClosedForEvent(event); + const isCanceled = event.status === 'canceled'; + + if (isCanceled) { + card.style.opacity = '0.6'; + } // Build optional specification chips only when data exists. const specsChips = event.specifications && event.specifications.length > 0 @@ -484,19 +490,31 @@ ? event.diet.split(', ').map(d => `${d.trim()}`).join('') : ''; - const actionMarkup = isOwnEvent - ? '' - : isRegistered - ? (isRegistrationClosed - ? '' - : '') - : isRegistrationClosed - ? '' - : isFull - ? '' - : !currentUser - ? '' - : ''; + let actionMarkup = ''; + if (isCanceled) { + actionMarkup = ''; + } else if (isOwnEvent) { + actionMarkup = ''; + } else if (isRegistered) { + actionMarkup = isRegistrationClosed + ? '' + : ''; + } else if (isRegistrationClosed) { + actionMarkup = ''; + } else if (!isFull) { + if (!currentUser) { + actionMarkup = ''; + } else { + actionMarkup = ''; + } + } + + let sideInfoMarkup = ''; + if (isCanceled) { + sideInfoMarkup = 'Event abgesagt'; + } else if (!isRegistrationClosed) { + sideInfoMarkup = `${isFull ? 'Ausgebucht' : `${freePlaces} Plätze frei`}`; + } card.innerHTML = `
@@ -517,7 +535,7 @@
- ${isRegistrationClosed ? '' : `${isFull ? 'Ausgebucht' : `${freePlaces} Plätze frei`}`} + ${sideInfoMarkup} ${actionMarkup}
`; diff --git a/js/my_profil.js b/js/my_profil.js index a4d1b9b..ff4c7f6 100644 --- a/js/my_profil.js +++ b/js/my_profil.js @@ -457,13 +457,27 @@ }); } - // Ermittelt angemeldete Events über die Registration-Map. + // Ermittelt angemeldete Events über die Registration-Map und participants-Liste. function getMyRegisteredEvents(events, user) { const registrationMap = getRegistrationMap(); const registeredIds = Array.isArray(registrationMap[user.email]) ? registrationMap[user.email] : []; const idSet = new Set(registeredIds.map(id => Number(id))); - return events.filter(event => idSet.has(Number(event.id))); + const userFirstName = String(user.vorname || '').trim().toLowerCase(); + const userFullName = `${String(user.vorname || '').trim()} ${String(user.nachname || '').trim()}`.trim().toLowerCase(); + + return events.filter(event => { + if (idSet.has(Number(event.id))) { + return true; + } + if (Array.isArray(event.participants)) { + const participantSet = new Set(event.participants.map(name => String(name || '').trim().toLowerCase()).filter(Boolean)); + if ((userFirstName && participantSet.has(userFirstName)) || (userFullName && participantSet.has(userFullName))) { + return true; + } + } + return false; + }); } // Rendert angemeldete Events inkl. Zähler. @@ -584,46 +598,81 @@ const card = document.createElement('article'); card.className = 'profile-event-card profile-event-card-clickable'; card.setAttribute('data-event-id', String(event.id)); + + const isCanceled = event.status === 'canceled'; + if (isCanceled) { + card.style.opacity = '0.6'; + } + let addressMessage = 'Vielen Dank für die Anmeldung! Die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.'; if (isEventPastAddressWindow(event)) { addressMessage = 'Vielen Dank, dass du an diesem Event teilgenommen hast.'; } - const addressMarkup = mode === 'registrations' && event.address - ? (isAddressVisibleWindow(event) - ? ` + let addressMarkup = ''; + if (mode === 'registrations' && event.address) { + if (isCanceled) { + addressMarkup = ` +
+

Adresse

+

Dieses Event wurde leider vom Gastgeber abgesagt.

+
+ `; + } else if (isAddressVisibleWindow(event)) { + addressMarkup = `

Adresse

${event.address}

- ` - : ` + `; + } else { + addressMarkup = `

Adresse

${addressMessage}

- `) - : ''; + `; + } + } const isDeregClosed = isDeregistrationClosed(event); - const actionMarkup = mode === 'registrations' - ? (isDeregClosed - ? ` + let actionMarkup = ''; + if (mode === 'registrations') { + if (isCanceled) { + actionMarkup = ` +
+ +
+ `; + } else if (isDeregClosed) { + actionMarkup = `
- ` - : ` + `; + } else { + actionMarkup = `
- `) - : ` + `; + } + } else { + if (isCanceled) { + actionMarkup = ` +
+ +
+ `; + } else { + actionMarkup = `
- `; + `; + } + } card.innerHTML = `
@@ -640,6 +689,7 @@ // Gibt true zurück, wenn die Adresse sichtbar sein soll (24h vor bis 1h nach Start). function isAddressVisibleWindow(event) { + if (event.status === 'canceled') return false; const eventDateTime = parseEventDateTime(event); if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) return false; const now = Date.now(); diff --git a/js/navigation.js b/js/navigation.js index 2ac6878..eb957bb 100644 --- a/js/navigation.js +++ b/js/navigation.js @@ -74,6 +74,7 @@ document.addEventListener('DOMContentLoaded', () => { } function isAddressVisibleWindow(event) { + if (event.status === 'canceled') return false; const eventDateTime = parseEventDateTime(event); if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) return false; const now = Date.now();