Update event dates and participant handling; adjust visibility window to 24 hours

This commit is contained in:
viiivo 2026-04-21 19:51:13 +02:00
parent fa8a7f1fc2
commit e3ac1a11f0
4 changed files with 140 additions and 28 deletions

View File

@ -4,11 +4,11 @@
"title": "Italienische Tavolata", "title": "Italienische Tavolata",
"location": "Luzern", "location": "Luzern",
"address": "Pilatusstrasse 18, 6003 Luzern", "address": "Pilatusstrasse 18, 6003 Luzern",
"date": "11. APR. 2026", "date": "22. APR. 2026",
"time": "15:30 UHR", "time": "15:30 UHR",
"category": "Dinner", "category": "Dinner",
"diet": "Vegetarisch", "diet": "Vegetarisch",
"spots": 6, "spots": 8,
"host": { "host": {
"name": "Ferdinando", "name": "Ferdinando",
"initial": "F" "initial": "F"
@ -45,7 +45,7 @@
"title": "Noche Peruana", "title": "Noche Peruana",
"location": "Chur", "location": "Chur",
"address": "Obere Gasse 41, 7000 Chur", "address": "Obere Gasse 41, 7000 Chur",
"date": "16. Juni 2026", "date": "12. April 2026",
"time": "19:00 UHR", "time": "19:00 UHR",
"category": "Dinner", "category": "Dinner",
"diet": "Omnivore", "diet": "Omnivore",

View File

@ -1,6 +1,7 @@
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
const EVENTS_STORAGE_KEY = 'socialCookingEvents'; const EVENTS_STORAGE_KEY = 'socialCookingEvents';
const CURRENT_USER_KEY = 'socialCookingCurrentUser'; const CURRENT_USER_KEY = 'socialCookingCurrentUser';
const USERS_STORAGE_KEY = 'socialCookingUsers';
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations'; const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
// ------------------------------------------------------------- // -------------------------------------------------------------
// DOM entry point and shared asset path. // 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) { function setRegistrationMap(registrationMap) {
localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap)); localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap));
} }
@ -114,7 +166,7 @@
} }
const msUntilStart = eventDateTime.getTime() - Date.now(); const msUntilStart = eventDateTime.getTime() - Date.now();
const twentyfourHoursInMs = 12 * 60 * 60 * 1000; const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
return msUntilStart <= twentyfourHoursInMs; return msUntilStart <= twentyfourHoursInMs;
} }
@ -138,7 +190,7 @@
return { daysLeft, isClosed: false }; 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) { function isAddressVisibleWindow(event) {
const eventDateTime = parseEventDateTime(event); const eventDateTime = parseEventDateTime(event);
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) { if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
@ -146,7 +198,7 @@
} }
const msUntilStart = eventDateTime.getTime() - Date.now(); const msUntilStart = eventDateTime.getTime() - Date.now();
const twentyfourHoursInMs = 12 * 60 * 60 * 1000; const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs; return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs;
} }
@ -283,16 +335,26 @@
const specifications = Array.isArray(event.specifications) && event.specifications.length > 0 const specifications = Array.isArray(event.specifications) && event.specifications.length > 0
? event.specifications ? 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 registrationMap = getRegistrationMap();
const extraRegistrations = countRegistrationsForEvent(registrationMap, event.id); const participants = getResolvedParticipants(event, registrationMap);
const remainingParticipants = Math.max(0, participants.length + extraRegistrations - visibleParticipants.length); const galleryImages = Array.isArray(event.gallery)
? event.gallery.filter(Boolean)
: [];
const galleryMarkup = galleryImages.length > 0
? `
<div class="detail-gallery detail-gallery-large">
${galleryImages.slice(0, 9).map((img, index) => `
<button class="detail-gallery-item" type="button" aria-label="Bild ${index + 1} gross anzeigen" data-fullsrc="${img}">
<img src="${img}" alt="${event.title} Bild ${index + 1}" class="detail-gallery-image">
</button>
`).join('')}
</div>
`
: '';
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 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 freePlaces = Math.max(0, totalGuests - confirmedGuests);
const isFull = freePlaces === 0; const isFull = freePlaces === 0;
const isRegistrationClosed = isRegistrationClosedForEvent(event); const isRegistrationClosed = isRegistrationClosedForEvent(event);
@ -331,7 +393,12 @@
<p>${event.address}</p> <p>${event.address}</p>
</article> </article>
` `
: ''; : `
<article class="detail-panel">
<h2 class="detail-section-title">Adresse</h2>
<p>Vielen Dank für die Anmeldung! Die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.</p>
</article>
`;
const detailChips = [ const detailChips = [
`<span class="event-tag">${eventCategory}</span>`, `<span class="event-tag">${eventCategory}</span>`,
...event.diet.split(', ').filter(d => d.trim() && d !== 'Keine Angabe').map(d => `<span class="event-tag">${getDietLabel(d.trim())}</span>`), ...event.diet.split(', ').filter(d => d.trim() && d !== 'Keine Angabe').map(d => `<span class="event-tag">${getDietLabel(d.trim())}</span>`),
@ -401,13 +468,7 @@
${addressPanelMarkup} ${addressPanelMarkup}
</div> </div>
<div class="detail-gallery detail-gallery-large"> ${galleryMarkup}
${galleryImages.slice(0, 9).map((img, index) => `
<button class="detail-gallery-item" type="button" aria-label="Bild ${index + 1} gross anzeigen" data-fullsrc="${img}">
<img src="${img}" alt="${event.title} Bild ${index + 1}" class="detail-gallery-image">
</button>
`).join('')}
</div>
</section> </section>
<section class="detail-action-bar"> <section class="detail-action-bar">

View File

@ -1,6 +1,7 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const EVENTS_STORAGE_KEY = 'socialCookingEvents'; const EVENTS_STORAGE_KEY = 'socialCookingEvents';
const CURRENT_USER_KEY = 'socialCookingCurrentUser'; const CURRENT_USER_KEY = 'socialCookingCurrentUser';
const USERS_STORAGE_KEY = 'socialCookingUsers';
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations'; const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
const INFO_MODAL_SHOWN_KEY = 'infoModalShownOnFirstLogin'; 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) { function setRegistrationMap(registrationMap) {
localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap)); localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap));
} }
@ -392,10 +444,9 @@
const displayTime = formatEventTime(event.time); const displayTime = formatEventTime(event.time);
// Capacity logic: // Capacity logic:
// spots = total capacity, participants.length = booked seats. // spots = total capacity, resolved participants = booked seats.
const baseParticipants = Array.isArray(event.participants) ? event.participants.length : 0; const resolvedParticipants = getResolvedParticipants(event, registrationMap);
const extraRegistrations = countRegistrationsForEvent(registrationMap, event.id); const bookedSeats = resolvedParticipants.length;
const bookedSeats = baseParticipants + extraRegistrations;
const totalCapacity = event.spots; const totalCapacity = event.spots;
const freePlaces = Math.max(0, totalCapacity - bookedSeats); const freePlaces = Math.max(0, totalCapacity - bookedSeats);
const isFull = freePlaces === 0; const isFull = freePlaces === 0;

View File

@ -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) { function isAddressVisibleWindow(event) {
const eventDateTime = parseEventDateTime(event); const eventDateTime = parseEventDateTime(event);
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) { if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
@ -546,7 +546,7 @@
} }
const msUntilStart = eventDateTime.getTime() - Date.now(); const msUntilStart = eventDateTime.getTime() - Date.now();
const twentyfourHoursInMs = 12 * 60 * 60 * 1000; const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs; return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs;
} }