diff --git a/data/events.json b/data/events.json index c09641e..fb162e7 100644 --- a/data/events.json +++ b/data/events.json @@ -4,11 +4,11 @@ "title": "Italienische Tavolata", "location": "Luzern", "address": "Pilatusstrasse 18, 6003 Luzern", - "date": "11. APR. 2026", + "date": "22. APR. 2026", "time": "15:30 UHR", "category": "Dinner", "diet": "Vegetarisch", - "spots": 6, + "spots": 8, "host": { "name": "Ferdinando", "initial": "F" @@ -45,7 +45,7 @@ "title": "Noche Peruana", "location": "Chur", "address": "Obere Gasse 41, 7000 Chur", - "date": "16. Juni 2026", + "date": "12. April 2026", "time": "19:00 UHR", "category": "Dinner", "diet": "Omnivore", diff --git a/js/event_detail.js b/js/event_detail.js index 838675a..4a2d5b9 100644 --- a/js/event_detail.js +++ b/js/event_detail.js @@ -1,6 +1,7 @@ document.addEventListener('DOMContentLoaded', async () => { const EVENTS_STORAGE_KEY = 'socialCookingEvents'; const CURRENT_USER_KEY = 'socialCookingCurrentUser'; + const USERS_STORAGE_KEY = 'socialCookingUsers'; const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations'; // ------------------------------------------------------------- // DOM entry point and shared asset path. @@ -50,6 +51,57 @@ } } + function getStoredUsers() { + try { + const stored = localStorage.getItem(USERS_STORAGE_KEY); + return stored ? JSON.parse(stored) : []; + } catch (error) { + console.error('Benutzerdaten konnten nicht gelesen werden.', error); + return []; + } + } + + function getUserDisplayName(user) { + if (!user) { + return ''; + } + + const firstName = String(user.vorname || '').trim(); + const lastName = String(user.nachname || '').trim(); + + return (firstName || `${firstName} ${lastName}`.trim() || String(user.email || '').trim()).trim(); + } + + function getResolvedParticipants(event, registrationMap) { + const baseParticipants = Array.isArray(event.participants) + ? event.participants.map(name => String(name || '').trim()).filter(Boolean) + : []; + const usersByEmail = new Map( + getStoredUsers().map(user => [String(user.email || '').trim().toLowerCase(), user]) + ); + const participantLookup = new Set(baseParticipants.map(name => name.toLowerCase())); + + Object.entries(registrationMap || {}).forEach(([email, ids]) => { + const isRegisteredForEvent = Array.isArray(ids) + && ids.map(id => Number(id)).includes(Number(event.id)); + + if (!isRegisteredForEvent) { + return; + } + + const user = usersByEmail.get(String(email || '').trim().toLowerCase()); + const displayName = getUserDisplayName(user) || String(email || '').trim(); + const normalizedName = displayName.toLowerCase(); + + if (displayName && !participantLookup.has(normalizedName)) { + baseParticipants.push(displayName); + participantLookup.add(normalizedName); + } + }); + + return baseParticipants; + } + function setRegistrationMap(registrationMap) { localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap)); } @@ -114,7 +166,7 @@ } const msUntilStart = eventDateTime.getTime() - Date.now(); - const twentyfourHoursInMs = 12 * 60 * 60 * 1000; + const twentyfourHoursInMs = 24 * 60 * 60 * 1000; return msUntilStart <= twentyfourHoursInMs; } @@ -138,7 +190,7 @@ return { daysLeft, isClosed: false }; } - // Adresse ist nur im 12h-Fenster VOR Eventstart sichtbar. + // Adresse ist nur im 24h-Fenster VOR Eventstart sichtbar. function isAddressVisibleWindow(event) { const eventDateTime = parseEventDateTime(event); if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) { @@ -146,7 +198,7 @@ } const msUntilStart = eventDateTime.getTime() - Date.now(); - const twentyfourHoursInMs = 12 * 60 * 60 * 1000; + const twentyfourHoursInMs = 24 * 60 * 60 * 1000; return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs; } @@ -283,16 +335,26 @@ 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 registrationMap = getRegistrationMap(); - const extraRegistrations = countRegistrationsForEvent(registrationMap, event.id); - const remainingParticipants = Math.max(0, participants.length + extraRegistrations - visibleParticipants.length); + const participants = getResolvedParticipants(event, registrationMap); + const galleryImages = Array.isArray(event.gallery) + ? event.gallery.filter(Boolean) + : []; + const galleryMarkup = galleryImages.length > 0 + ? ` + + ` + : ''; + 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 + extraRegistrations; + const confirmedGuests = participants.length; const freePlaces = Math.max(0, totalGuests - confirmedGuests); const isFull = freePlaces === 0; const isRegistrationClosed = isRegistrationClosedForEvent(event); @@ -331,7 +393,12 @@

${event.address}

` - : ''; + : ` +
+

Adresse

+

Vielen Dank für die Anmeldung! Die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.

+
+ `; const detailChips = [ `${eventCategory}`, ...event.diet.split(', ').filter(d => d.trim() && d !== 'Keine Angabe').map(d => `${getDietLabel(d.trim())}`), @@ -401,13 +468,7 @@ ${addressPanelMarkup} - + ${galleryMarkup}
diff --git a/js/event_overview.js b/js/event_overview.js index c5b1e66..5ecbb4c 100644 --- a/js/event_overview.js +++ b/js/event_overview.js @@ -1,6 +1,7 @@ document.addEventListener('DOMContentLoaded', () => { const EVENTS_STORAGE_KEY = 'socialCookingEvents'; const CURRENT_USER_KEY = 'socialCookingCurrentUser'; + const USERS_STORAGE_KEY = 'socialCookingUsers'; const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations'; const INFO_MODAL_SHOWN_KEY = 'infoModalShownOnFirstLogin'; // ------------------------------------------------------------- @@ -73,6 +74,57 @@ } } + function getStoredUsers() { + try { + const stored = localStorage.getItem(USERS_STORAGE_KEY); + return stored ? JSON.parse(stored) : []; + } catch (error) { + console.error('Benutzerdaten konnten nicht gelesen werden.', error); + return []; + } + } + + function getUserDisplayName(user) { + if (!user) { + return ''; + } + + const firstName = String(user.vorname || '').trim(); + const lastName = String(user.nachname || '').trim(); + + return (firstName || `${firstName} ${lastName}`.trim() || String(user.email || '').trim()).trim(); + } + + function getResolvedParticipants(event, registrationMap) { + const baseParticipants = Array.isArray(event.participants) + ? event.participants.map(name => String(name || '').trim()).filter(Boolean) + : []; + const usersByEmail = new Map( + getStoredUsers().map(user => [String(user.email || '').trim().toLowerCase(), user]) + ); + const participantLookup = new Set(baseParticipants.map(name => name.toLowerCase())); + + Object.entries(registrationMap || {}).forEach(([email, ids]) => { + const isRegisteredForEvent = Array.isArray(ids) + && ids.map(id => Number(id)).includes(Number(event.id)); + + if (!isRegisteredForEvent) { + return; + } + + const user = usersByEmail.get(String(email || '').trim().toLowerCase()); + const displayName = getUserDisplayName(user) || String(email || '').trim(); + const normalizedName = displayName.toLowerCase(); + + if (displayName && !participantLookup.has(normalizedName)) { + baseParticipants.push(displayName); + participantLookup.add(normalizedName); + } + }); + + return baseParticipants; + } + function setRegistrationMap(registrationMap) { localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap)); } @@ -392,10 +444,9 @@ const displayTime = formatEventTime(event.time); // Capacity logic: - // spots = total capacity, participants.length = booked seats. - const baseParticipants = Array.isArray(event.participants) ? event.participants.length : 0; - const extraRegistrations = countRegistrationsForEvent(registrationMap, event.id); - const bookedSeats = baseParticipants + extraRegistrations; + // spots = total capacity, resolved participants = booked seats. + const resolvedParticipants = getResolvedParticipants(event, registrationMap); + const bookedSeats = resolvedParticipants.length; const totalCapacity = event.spots; const freePlaces = Math.max(0, totalCapacity - bookedSeats); const isFull = freePlaces === 0; diff --git a/js/my_profil.js b/js/my_profil.js index 0874f61..b367de4 100644 --- a/js/my_profil.js +++ b/js/my_profil.js @@ -538,7 +538,7 @@ }); } - // Gibt true zurück, wenn ein Event innerhalb der nächsten 12 Stunden startet. + // Gibt true zurück, wenn ein Event innerhalb der nächsten 24 Stunden startet. function isAddressVisibleWindow(event) { const eventDateTime = parseEventDateTime(event); if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) { @@ -546,7 +546,7 @@ } const msUntilStart = eventDateTime.getTime() - Date.now(); - const twentyfourHoursInMs = 12 * 60 * 60 * 1000; + const twentyfourHoursInMs = 24 * 60 * 60 * 1000; return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs; }