document.addEventListener('DOMContentLoaded', async () => { const EVENTS_STORAGE_KEY = 'socialCookingEvents'; const CURRENT_USER_KEY = 'socialCookingCurrentUser'; const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations'; // ------------------------------------------------------------- // DOM entry point and shared asset path. // ------------------------------------------------------------- const detailContainer = document.getElementById('detail-view'); const locationIconPath = 'assets/location-pin.svg'; const currentUser = getCurrentUser(); // Read event id from query string (detail page deep-link support). const params = new URLSearchParams(window.location.search); const eventId = parseInt(params.get('id')); if (!eventId) { window.location.href = 'event_overview.html'; return; } function getStoredEvents() { try { const stored = localStorage.getItem(EVENTS_STORAGE_KEY); return stored ? JSON.parse(stored) : []; } catch (error) { console.error('Lokale Events konnten nicht gelesen werden.', error); return []; } } function getCurrentUser() { try { const stored = localStorage.getItem(CURRENT_USER_KEY); return stored ? JSON.parse(stored) : null; } catch (error) { console.error('Aktueller Benutzer konnte nicht gelesen werden.', error); return null; } } function getRegistrationMap() { try { const stored = localStorage.getItem(REGISTRATION_STORAGE_KEY); return stored ? JSON.parse(stored) : {}; } catch (error) { console.error('Anmeldedaten konnten nicht gelesen werden.', error); return {}; } } function setRegistrationMap(registrationMap) { localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap)); } // Ermittelt, ob das Event vom aktuell eingeloggten Benutzer erstellt wurde. function isEventOwnedByCurrentUser(event, user) { if (!event || !user) { return false; } const userEmail = String(user.email || '').trim().toLowerCase(); const hostEmail = String(event.hostEmail || '').trim().toLowerCase(); if (userEmail && hostEmail) { return userEmail === hostEmail; } // Fallback fuer aeltere Datensaetze ohne hostEmail. const userFirstName = String(user.vorname || '').trim().toLowerCase(); const hostName = String(event.host?.name || '').trim().toLowerCase(); return Boolean(userFirstName && hostName && userFirstName === hostName); } // Fetch data source and resolve the matching event record. try { const response = await fetch('data/events.json'); const apiEvents = await response.json(); const allEvents = [...getStoredEvents(), ...apiEvents]; 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); } // Format localized date token into full readable date. function formatEventDate(dateString) { const labels = { JAN: 'Januar', FEB: 'Februar', 'MÄR': 'März', MRZ: 'März', APR: 'April', MAI: 'Mai', JUN: 'Juni', JUL: 'Juli', AUG: 'August', SEP: 'September', OKT: 'Oktober', NOV: 'November', DEZ: 'Dezember' }; const match = dateString.match(/^(\d{1,2})\.\s*([A-ZÄÖÜ]{3})\.\s*(\d{4})$/); if (!match) { return dateString; } const day = Number(match[1]); const monthLabel = labels[match[2]]; const year = match[3]; return monthLabel ? `${day}. ${monthLabel} ${year}` : dateString; } // Normalize time casing for UI consistency. function formatEventTime(timeString) { return timeString.replace('UHR', 'Uhr').trim(); } // Map diet keys to readable labels while keeping unknown values untouched. function getDietLabel(diet) { const labels = { VEGGIE: 'Vegetarisch', VEGAN: 'Vegan', FLEISCH: 'Fleisch', FISCH: 'Fisch' }; return labels[diet] || diet; } // Compose and inject the full detail UI for a single event. function renderDetailPage(event) { // Core display values and resilient fallbacks for optional data fields. const displayDate = formatEventDate(event.date); const displayTime = formatEventTime(event.time); const dietLabel = getDietLabel(event.diet); const eventCategory = event.category || 'EVENT'; const hostName = event.host?.name || 'Host'; const hostInitial = (event.host?.initial || hostName.charAt(0) || 'H').charAt(0).toUpperCase(); const hostMessage = Array.isArray(event.hostMessage) && event.hostMessage.length > 0 ? event.hostMessage : ['Der Host hat für dieses Event noch keine Nachricht hinterlegt.']; const menuItems = Array.isArray(event.menu) && event.menu.length > 0 ? event.menu : ['Menü wird in Kuerze bekannt gegeben.']; const specifications = Array.isArray(event.specifications) && event.specifications.length > 0 ? event.specifications : []; const participants = Array.isArray(event.participants) ? event.participants : []; const galleryImages = Array.isArray(event.gallery) && event.gallery.length > 0 ? event.gallery : [event.image, event.image, event.image]; const visibleParticipants = participants.slice(0, 6); const remainingParticipants = Math.max(0, participants.length - visibleParticipants.length); const totalGuests = Number.isFinite(event.spots) ? event.spots : 0; const confirmedGuests = participants.length; const freePlaces = Math.max(0, totalGuests - confirmedGuests); const isFull = freePlaces === 0; const isOwnEvent = isEventOwnedByCurrentUser(event, currentUser); const registrationMap = getRegistrationMap(); const userRegistrations = currentUser?.email && Array.isArray(registrationMap[currentUser.email]) ? registrationMap[currentUser.email].map(id => Number(id)) : []; const isRegistered = userRegistrations.includes(Number(event.id)); const actionButtonLabel = isOwnEvent ? 'Dein Event' : !currentUser ? 'Einloggen' : isRegistered ? 'Abmelden' : 'Anmelden'; const actionButtonDisabled = isOwnEvent || (!isRegistered && isFull); const detailChips = [ `${eventCategory}`, `${dietLabel}`, ...specifications.map(item => `${item}`) ].join(''); // Render complete detail page layout including: // hero metadata, host card, menu, participants, gallery and sticky action bar. detailContainer.innerHTML = `
Alle Events
${event.location}

${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gaeste

${event.title}

${detailChips}
${hostInitial} ${hostName} Host
${hostMessage.map(paragraph => `

${paragraph}

`).join('')}

Menue

    ${menuItems.map(item => `
  • ${item}
  • `).join('')}

Teilnehmer

Alle ansehen
${visibleParticipants.map(name => `${name.charAt(0).toUpperCase()}`).join('')} ${remainingParticipants > 0 ? `+${remainingParticipants}` : ''}
${event.location} | ${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gaeste ${event.title}
${isFull ? 'AUSGEBUCHT' : `${freePlaces} Plaetze frei`}
`; // --------------------------------------------------------- // Lightbox behavior for gallery images: // open on image click, close via backdrop, close button or ESC. // --------------------------------------------------------- const lightbox = detailContainer.querySelector('.detail-lightbox'); const lightboxImage = detailContainer.querySelector('.detail-lightbox-image'); const lightboxClose = detailContainer.querySelector('.detail-lightbox-close'); const galleryButtons = detailContainer.querySelectorAll('.detail-gallery-item'); const registerButton = detailContainer.querySelector('[data-register-button]'); // Anmeldung toggeln und im lokalen Registrierungs-Store persistieren. if (registerButton) { registerButton.addEventListener('click', () => { if (isOwnEvent) { return; } if (!currentUser || !currentUser.email) { window.location.href = 'login.html'; return; } const nextRegistrationMap = getRegistrationMap(); const currentList = Array.isArray(nextRegistrationMap[currentUser.email]) ? nextRegistrationMap[currentUser.email].map(id => Number(id)) : []; const registrationSet = new Set(currentList); if (registrationSet.has(Number(event.id))) { registrationSet.delete(Number(event.id)); } else if (!isFull) { registrationSet.add(Number(event.id)); } nextRegistrationMap[currentUser.email] = Array.from(registrationSet); setRegistrationMap(nextRegistrationMap); // Re-Render aktualisiert Buttonzustand und CTA ohne Seitenreload. renderDetailPage(event); }); } // Central close helper to keep all close paths consistent. function closeLightbox() { if (!lightbox) { return; } lightbox.classList.remove('is-open'); lightbox.setAttribute('aria-hidden', 'true'); } if (lightbox && lightboxImage) { // Open with selected image source. galleryButtons.forEach(button => { button.addEventListener('click', () => { const imageSrc = button.getAttribute('data-fullsrc'); if (!imageSrc) { return; } lightboxImage.src = imageSrc; lightbox.classList.add('is-open'); lightbox.setAttribute('aria-hidden', 'false'); }); }); // Close when user clicks on backdrop. lightbox.addEventListener('click', event => { const target = event.target; if (target instanceof HTMLElement && target.hasAttribute('data-close-lightbox')) { closeLightbox(); } }); // Close via dedicated icon/button. lightboxClose?.addEventListener('click', closeLightbox); // Close with keyboard for accessibility. document.addEventListener('keydown', event => { if (event.key === 'Escape') { closeLightbox(); } }); } } });