@@ -91,44 +91,129 @@
+
-
+
+
+
+ 142
+ 18
+
+
+
-
+
+
+
+ 89
+ 5
+
+
+
-
+
+
+
+ 215
+ 32
+
+
+
-
+
+
+
+ 304
+ 41
+
+
+
-
+
+
+
+ 178
+ 12
+
+
+
-
+
+
+
+ 95
+ 8
+
+
+
-
+
+
+
+ 420
+ 55
+
+
+
-
+
+
+
+ 267
+ 29
+
+
+
-
+
+
+
+ 112
+ 4
+
+
+
-
+
+
+
+ 389
+ 47
+
+
+
-
+
+
+
+ 156
+ 11
+
+
+
-
+
+
+
+ 234
+ 21
+
+
+
-
+
diff --git a/js/event_detail.js b/js/event_detail.js
index a7082ad..a2ec1c1 100644
--- a/js/event_detail.js
+++ b/js/event_detail.js
@@ -3,16 +3,13 @@
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
const USERS_STORAGE_KEY = 'socialCookingUsers';
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
- // -------------------------------------------------------------
- // DOM entry point and shared asset path.
- // -------------------------------------------------------------
+
const detailcontainer = document.getElementById('detail-view');
const locationIconPath = 'assets/icon_location.svg';
const calendarIconPath = 'assets/icon_calendar.svg';
const gastIconPath = 'assets/icon_gast.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'));
@@ -62,14 +59,10 @@
}
function getUserDisplayName(user) {
- if (!user) {
- return '';
- }
-
+ if (!user) return '';
const firstName = String(user.vorname || '').trim();
const lastName = String(user.nachname || '').trim();
const fullName = `${firstName} ${lastName}`.trim();
-
return (fullName || firstName || String(user.email || '').trim()).trim();
}
@@ -85,10 +78,7 @@
Object.entries(registrationMap || {}).forEach(([email, ids]) => {
const isRegisteredForEvent = Array.isArray(ids)
&& ids.map(id => Number(id)).includes(Number(event.id));
-
- if (!isRegisteredForEvent) {
- return;
- }
+ if (!isRegisteredForEvent) return;
const user = usersByEmail.get(String(email || '').trim().toLowerCase());
const displayName = getUserDisplayName(user) || String(email || '').trim();
@@ -105,19 +95,9 @@
function getParticipantNameForViewer(name, canSeeLastName) {
const rawName = String(name || '').trim();
- if (!rawName) {
- return '';
- }
-
- if (canSeeLastName) {
- return rawName;
- }
-
- // Bei E-Mail-Fallback nur den lokalen Teil anzeigen.
- if (rawName.includes('@')) {
- return rawName.split('@')[0].trim() || rawName;
- }
-
+ if (!rawName) return '';
+ if (canSeeLastName) return rawName;
+ if (rawName.includes('@')) return rawName.split('@')[0].trim() || rawName;
return rawName.split(/\s+/)[0];
}
@@ -126,153 +106,98 @@
}
function parseEventDateTime(event) {
- if (!event?.date) {
- return null;
- }
-
+ if (!event?.date) return null;
const dateValue = String(event.date).trim();
const isoDateMatch = dateValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
- let year;
- let month;
- let day;
+ let year, month, day;
if (isoDateMatch) {
year = Number(isoDateMatch[1]);
month = Number(isoDateMatch[2]);
day = Number(isoDateMatch[3]);
} else {
- const monthMap = {
- JAN: 1,
- FEB: 2,
- 'MÄR': 3,
- MRZ: 3,
- APR: 4,
- MAI: 5,
- JUN: 6,
- JUL: 7,
- AUG: 8,
- SEP: 9,
- OKT: 10,
- NOV: 11,
- DEZ: 12
- };
+ const monthMap = { JAN:1, FEB:2, 'MÄR':3, MRZ:3, APR:4, MAI:5, JUN:6, JUL:7, AUG:8, SEP:9, OKT:10, NOV:11, DEZ:12 };
const localizedMatch = dateValue.match(/^(\d{1,2})\.\s*([A-ZÄÖÜ]{3})\.\s*(\d{4})$/);
-
- if (!localizedMatch) {
- return null;
- }
-
+ if (!localizedMatch) return null;
day = Number(localizedMatch[1]);
month = monthMap[localizedMatch[2]];
year = Number(localizedMatch[3]);
-
- if (!month) {
- return null;
- }
+ if (!month) return null;
}
const timeMatch = String(event.time || '').match(/(\d{1,2}):(\d{2})/);
const hours = timeMatch ? Number(timeMatch[1]) : 0;
const minutes = timeMatch ? Number(timeMatch[2]) : 0;
-
return new Date(year, month - 1, day, hours, minutes, 0, 0);
}
function isRegistrationClosedForEvent(event) {
const eventDateTime = parseEventDateTime(event);
- if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
- return false;
- }
-
+ if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) return false;
const msUntilStart = eventDateTime.getTime() - Date.now();
- const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
-
- return msUntilStart <= twentyfourHoursInMs;
+ return msUntilStart <= 24 * 60 * 60 * 1000;
}
- // Abmeldefrist: 1 Tag (24 h) vor Eventstart.
function getDeregistrationInfo(event) {
const eventDateTime = parseEventDateTime(event);
- if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
- return { daysLeft: null, isClosed: false };
- }
-
+ if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) return { daysLeft: null, isClosed: false };
const oneDayMs = 24 * 60 * 60 * 1000;
- const deadlineMs = eventDateTime.getTime() - oneDayMs;
- const msUntilDeadline = deadlineMs - Date.now();
-
- if (msUntilDeadline <= 0) {
- return { daysLeft: 0, isClosed: true };
- }
-
- const daysLeft = Math.ceil(msUntilDeadline / oneDayMs);
- return { daysLeft, isClosed: false };
+ const msUntilDeadline = (eventDateTime.getTime() - oneDayMs) - Date.now();
+ if (msUntilDeadline <= 0) return { daysLeft: 0, isClosed: true };
+ return { daysLeft: Math.ceil(msUntilDeadline / oneDayMs), isClosed: false };
}
- // Adresse ist nur im 24h-Fenster VOR Eventstart sichtbar.
function isAddressVisibleWindow(event) {
const eventDateTime = parseEventDateTime(event);
- if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
- return false;
- }
-
+ if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) return false;
const msUntilStart = eventDateTime.getTime() - Date.now();
- const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
-
- return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs;
+ return msUntilStart >= 0 && msUntilStart <= 24 * 60 * 60 * 1000;
}
- function countRegistrationsForEvent(registrationMap, eventId) {
- return Object.values(registrationMap).reduce((count, ids) => {
- const hasEvent = Array.isArray(ids)
- && ids.map(id => Number(id)).includes(Number(eventId));
-
- return hasEvent ? count + 1 : count;
- }, 0);
- }
-
- // Ermittelt, ob das Event vom aktuell eingeloggten Benutzer erstellt wurde.
function isEventOwnedByCurrentUser(event, user) {
- if (!event || !user) {
- return false;
- }
-
+ 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 für ältere Datensätze ohne hostEmail.
+ if (userEmail && hostEmail) return userEmail === hostEmail;
const userFirstName = String(user.vorname || '').trim().toLowerCase();
const hostName = String(event.host?.name || '').trim().toLowerCase();
return Boolean(userFirstName && hostName && userFirstName === hostName);
}
- // Prüft, ob der aktuelle Benutzer bereits in der Teilnehmerliste des Events steht.
function isUserListedInEventParticipants(event, user) {
- if (!event || !user || !Array.isArray(event.participants)) {
- return false;
- }
-
+ if (!event || !user || !Array.isArray(event.participants)) return false;
const participantSet = new Set(
- event.participants
- .map(name => String(name || '').trim().toLowerCase())
- .filter(Boolean)
+ event.participants.map(name => String(name || '').trim().toLowerCase()).filter(Boolean)
);
-
const userFirstName = String(user.vorname || '').trim().toLowerCase();
- const userFullName = `${String(user.vorname || '').trim()} ${String(user.nachname || '').trim()}`
- .trim()
- .toLowerCase();
-
+ const userFullName = `${String(user.vorname || '').trim()} ${String(user.nachname || '').trim()}`.trim().toLowerCase();
return Boolean(
(userFirstName && participantSet.has(userFirstName))
|| (userFullName && participantSet.has(userFullName))
);
}
+ function formatEventDate(dateString) {
+ if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
+ const [year, month, day] = dateString.split('-');
+ return `${Number(day)}. ${['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'][Number(month)-1]} ${year}`;
+ }
+ 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 monthLabel = labels[match[2]];
+ return monthLabel ? `${Number(match[1])}. ${monthLabel} ${match[3]}` : dateString;
+ }
+
+ function formatEventTime(timeString) {
+ return timeString.replace('UHR', 'Uhr').trim();
+ }
+
+ function getDietLabel(diet) {
+ const labels = { FLEISCH:'Fleisch', FISCH:'Fisch', VEGGIE:'Vegetarisch', VEGAN:'Vegan' };
+ return labels[diet] || diet;
+ }
+
// Fetch data source and resolve the matching event record.
try {
const response = await fetch('data/events.json');
@@ -289,62 +214,11 @@
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 = {
- FLEISCH: 'Fleisch',
- FISCH: 'Fisch',
- VEGGIE: 'Vegetarisch',
- VEGAN: 'Vegan'
- };
-
- 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.'];
@@ -352,28 +226,23 @@
? event.menu
: ['Menü wird in Kürze bekannt gegeben.'];
const specifications = Array.isArray(event.specifications) && event.specifications.length > 0
- ? event.specifications
- : [];
+ ? event.specifications : [];
const registrationMap = getRegistrationMap();
const participants = getResolvedParticipants(event, registrationMap);
const isOwnEvent = isEventOwnedByCurrentUser(event, currentUser);
const participantNamesForView = participants
.map(name => getParticipantNameForViewer(name, isOwnEvent))
.filter(Boolean);
- const galleryImages = Array.isArray(event.gallery)
- ? event.gallery.filter(Boolean)
- : [];
+ const galleryImages = Array.isArray(event.gallery) ? event.gallery.filter(Boolean) : [];
const galleryMarkup = galleryImages.length > 0
- ? `
-
- ${galleryImages.slice(0, 9).map((img, index) => `
-
-
-
- `).join('')}
-
- `
- : '';
+ ? `
+ ${galleryImages.slice(0, 9).map((img, index) => `
+
+
+
+ `).join('')}
+
` : '';
+
const visibleParticipants = participantNamesForView.slice(0, 6);
const remainingParticipants = Math.max(0, participantNamesForView.length - visibleParticipants.length);
const totalGuests = Number.isFinite(event.spots) ? event.spots : 0;
@@ -383,245 +252,207 @@
const isRegistrationClosed = isRegistrationClosedForEvent(event);
const deregInfo = getDeregistrationInfo(event);
const userRegistrations = currentUser?.email && Array.isArray(registrationMap[currentUser.email])
- ? registrationMap[currentUser.email].map(id => Number(id))
- : [];
+ ? registrationMap[currentUser.email].map(id => Number(id)) : [];
const isRegistered = userRegistrations.includes(Number(event.id));
const isListedParticipant = isUserListedInEventParticipants(event, currentUser);
const hasAddressAccess = isRegistered || isListedParticipant;
- const actionButtonLabel = isOwnEvent
- ? 'Dein Event!'
- : !currentUser
- ? 'Einloggen'
- : isRegistered
- ? (deregInfo.isClosed ? 'Abmeldung geschlossen' : 'Abmelden')
- : isRegistrationClosed
- ? 'Anmeldung geschlossen'
- : 'Anmelden';
+
+ const actionButtonLabel = isOwnEvent ? 'Dein Event!'
+ : !currentUser ? 'Einloggen'
+ : isRegistered ? (deregInfo.isClosed ? 'Abmeldung geschlossen' : 'Abmelden')
+ : isRegistrationClosed ? 'Anmeldung geschlossen'
+ : 'Anmelden';
const actionButtonDisabled = isOwnEvent
|| (!isRegistered && (isFull || isRegistrationClosed))
|| (isRegistered && deregInfo.isClosed);
- const actionButtonVariantClass = isOwnEvent
- ? ' button-primary-eigener-event'
- : isRegistered
- ? ' button-primary-abmelden '
- : isRegistrationClosed
- ? ' button-primary '
- : ' button-primary ';
+ const actionButtonVariantClass = isOwnEvent ? ' button-primary-eigener-event'
+ : isRegistered ? ' button-primary-abmelden '
+ : ' button-primary ';
+
const shouldRevealAddress = Boolean(event.address) && isAddressVisibleWindow(event) && hasAddressAccess;
const addressPanelMarkup = shouldRevealAddress
- ? `
-
- Adresse
- ${event.address}
-
- `
- : `
-
- Adresse
- Vielen Dank für die Anmeldung! Die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.
-
- `;
+ ? `
Adresse ${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())} `),
...specifications.map(item => `
${item} `)
].join('');
- // Render complete detail page layout including:
- // hero metadata, host card, menu, participants, gallery and sticky action bar.
detailcontainer.innerHTML = `
-
-
-
-
- ${event.location}
-
-
-
- ${displayDate} | ${displayTime}
-
-
-
- ${confirmedGuests}/${totalGuests}
-
-
- ${event.title}
-
- ${detailChips}
-
-
-
-
-
-
-
- ${hostMessage.map(paragraph => `${paragraph}
`).join('')}
-
-
-
- Menu
-
-
-
-
-
-
Teilnehmer
- Alle ansehen
-
-
- ${visibleParticipants.map(name => `${name.charAt(0).toUpperCase()} `).join('')}
- ${remainingParticipants > 0 ? `+${remainingParticipants} ` : ''}
-
-
- ${participantNamesForView.map(name => `
-
- ${name}
-
- `).join('')}
-
-
-
- ${addressPanelMarkup}
-
-
- ${galleryMarkup}
-
-
-
-
-
-
-
- ${event.location}
-
-
-
- ${displayDate} | ${displayTime}
-
-
-
-
- ${confirmedGuests}/${totalGuests}
-
-
-
-
${event.title}
-
-
-
- ${isFull ? `
-
- Ausgebucht
-
- ` : `
-
- ${actionButtonLabel}
-
- `}
-
- ${isRegistered && deregInfo.daysLeft !== null ? `
-
- ${deregInfo.isClosed
- ? 'Abmeldefrist abgelaufen'
- : deregInfo.daysLeft === 1
- ? 'Noch 1 Tag zur Abmeldung'
- : `Noch ${deregInfo.daysLeft} Tage zur Abmeldung`}
-
- ` : ''}
-
-
-
-
-
-
- ×
-
-
+
+
+
${event.location}
+
${displayDate} | ${displayTime}
+
${confirmedGuests}/${totalGuests}
+ ${event.title}
+ ${detailChips}
+
+
+
+
+
+
+ ${hostMessage.map(paragraph => `${paragraph}
`).join('')}
+
+
+
+ Menu
+
+
+
+
+
+
Teilnehmer
+ Alle ansehen
+
+
+ ${visibleParticipants.map(name => `${name.charAt(0).toUpperCase()} `).join('')}
+ ${remainingParticipants > 0 ? `+${remainingParticipants} ` : ''}
+
+
+ ${participantNamesForView.map(name => `
+
+ ${name}
+
+ `).join('')}
+
+
+
+ ${addressPanelMarkup}
+
+ ${galleryMarkup}
+
+
+
+
+
+ ${event.location}
+ ${displayDate} | ${displayTime}
+ ${confirmedGuests}/${totalGuests}
+
+
${event.title}
+
+
+ ${isFull ? `
+ Ausgebucht
+ ` : `
+
+ ${actionButtonLabel}
+
+ `}
+ ${isRegistered && deregInfo.daysLeft !== null ? `
+
+ ${deregInfo.isClosed ? 'Abmeldefrist abgelaufen'
+ : deregInfo.daysLeft === 1 ? 'Noch 1 Tag zur Abmeldung'
+ : `Noch ${deregInfo.daysLeft} Tage zur Abmeldung`}
+
+ ` : ''}
+
+
+
+
+
+
+ ×
+
+
`;
- // ---------------------------------------------------------
- // Lightbox behavior for gallery images:
- // open on image click, close via backdrop, close button or ESC.
- // ---------------------------------------------------------
+ // DOM references after render
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]');
- // Harte Absicherung: Eigene Events sind auf der Detailseite immer deaktiviert.
+ // Eigene Events immer deaktiviert
if (registerButton && isOwnEvent) {
registerButton.disabled = true;
registerButton.textContent = 'Dein Event!';
registerButton.setAttribute('aria-disabled', 'true');
}
- // Anmeldung toggeln und im lokalen Registrierungs-Store persistieren.
+ // Anmeldung / Abmeldung mit Bestätigungs-Modal
if (registerButton) {
registerButton.addEventListener('click', () => {
- if (isOwnEvent) {
- return;
- }
+ 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);
+ const alreadyRegistered = (() => {
+ const map = getRegistrationMap();
+ const ids = Array.isArray(map[currentUser.email])
+ ? map[currentUser.email].map(id => Number(id)) : [];
+ return ids.includes(Number(event.id));
+ })();
- if (registrationSet.has(Number(event.id))) {
- registrationSet.delete(Number(event.id));
+ if (alreadyRegistered) {
+ const modal = document.getElementById('unregister-confirm-modal');
+ if (modal) modal.classList.add('show');
+
+ document.getElementById('confirm-unregister-btn').onclick = () => {
+ modal.classList.remove('show');
+ const map = getRegistrationMap();
+ const ids = new Set((map[currentUser.email] || []).map(id => Number(id)));
+ ids.delete(Number(event.id));
+ map[currentUser.email] = Array.from(ids);
+ setRegistrationMap(map);
+ const snackbar = document.getElementById('snackbar');
+ if (snackbar) {
+ snackbar.textContent = 'Du wurdest erfolgreich abgemeldet.';
+ snackbar.classList.add('snackbar--danger', 'snackbar--visible');
+ setTimeout(() => {
+ snackbar.classList.remove('snackbar--visible');
+ setTimeout(() => snackbar.classList.remove('snackbar--danger'), 400);
+ }, 3000);
+ }
+ renderDetailPage(event);
+ };
+
+ document.getElementById('unregister-modal-close').onclick = () => modal.classList.remove('show');
+ document.getElementById('unregister-modal-cancel').onclick = () => modal.classList.remove('show');
+ modal.addEventListener('click', e => { if (e.target === modal) modal.classList.remove('show'); });
- // Snackbar: Feedback bei Abmeldung.
- const snackbar = document.getElementById('snackbar');
- if (snackbar) {
- snackbar.textContent = 'Du wurdest erfolgreich abgemeldet.';
- snackbar.classList.add('snackbar--danger', 'snackbar--visible');
- setTimeout(() => {
- snackbar.classList.remove('snackbar--visible');
- setTimeout(() => snackbar.classList.remove('snackbar--danger'), 400);
- }, 3000);
- }
} else if (!isFull && !isRegistrationClosed) {
- registrationSet.add(Number(event.id));
+ const modal = document.getElementById('register-confirm-modal');
+ if (modal) modal.classList.add('show');
- // Snackbar: Feedback bei Anmeldung.
- const snackbar = document.getElementById('snackbar');
- if (snackbar) {
- snackbar.textContent = 'Du wurdest erfolgreich angemeldet.';
- snackbar.classList.add('snackbar--visible');
- setTimeout(() => snackbar.classList.remove('snackbar--visible'), 3000);
- }
+ document.getElementById('confirm-register-btn').onclick = () => {
+ modal.classList.remove('show');
+ const map = getRegistrationMap();
+ const ids = new Set((map[currentUser.email] || []).map(id => Number(id)));
+ ids.add(Number(event.id));
+ map[currentUser.email] = Array.from(ids);
+ setRegistrationMap(map);
+ const snackbar = document.getElementById('snackbar');
+ if (snackbar) {
+ snackbar.textContent = 'Du wurdest erfolgreich angemeldet.';
+ snackbar.classList.add('snackbar--visible');
+ setTimeout(() => snackbar.classList.remove('snackbar--visible'), 3000);
+ }
+ renderDetailPage(event);
+ };
+
+ document.getElementById('register-modal-close').onclick = () => modal.classList.remove('show');
+ document.getElementById('register-modal-cancel').onclick = () => modal.classList.remove('show');
+ modal.addEventListener('click', e => { if (e.target === modal) modal.classList.remove('show'); });
}
-
- nextRegistrationMap[currentUser.email] = Array.from(registrationSet);
- setRegistrationMap(nextRegistrationMap);
-
- // Re-Render aktualisiert Buttonzustand und CTA ohne Seitenreload.
- renderDetailPage(event);
});
}
- // "Alle ansehen": Teilnehmerliste aufklappen / zuklappen.
+ // "Alle ansehen": Teilnehmerliste aufklappen / zuklappen
const showAllBtn = detailcontainer.querySelector('[data-show-all-participants]');
const avatarRow = detailcontainer.querySelector('[data-participants-row]');
const fullList = detailcontainer.querySelector('[data-participants-full]');
@@ -635,32 +466,24 @@
});
}
- // Central close helper to keep all close paths consistent.
+ // Lightbox
function closeLightbox() {
- if (!lightbox) {
- return;
- }
-
+ 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;
- }
-
+ 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')) {
@@ -668,22 +491,11 @@
}
});
- // Close via dedicated icon/button.
lightboxClose?.addEventListener('click', closeLightbox);
- // Close with keyboard for accessibility.
document.addEventListener('keydown', event => {
- if (event.key === 'Escape') {
- closeLightbox();
- }
- });
- }
-
- // Back button navigation: returns to event overview page.
- if (backButton) {
- backButton.addEventListener('click', () => {
- window.location.href = 'event_overview.html';
+ if (event.key === 'Escape') closeLightbox();
});
}
}
-});
+});
\ No newline at end of file
diff --git a/js/event_overview.js b/js/event_overview.js
index 258ff11..be91f5d 100644
--- a/js/event_overview.js
+++ b/js/event_overview.js
@@ -536,29 +536,55 @@
: [];
const idSet = new Set(currentIds);
- // Abmeldung: Benutzer vom Event entfernen und Snackbar anzeigen.
- if (action === 'unregister') {
- idSet.delete(Number(event.id));
- const snackbar = document.getElementById('snackbar');
- if (snackbar) {
- snackbar.textContent = 'Du wurdest erfolgreich abgemeldet.';
- snackbar.classList.add('snackbar--danger', 'snackbar--visible');
- setTimeout(() => {
- snackbar.classList.remove('snackbar--visible');
- setTimeout(() => snackbar.classList.remove('snackbar--danger'), 400);
- }, 3000);
+ // Anmelde-Modal öffnen
+ if (action === 'register' && !isFull && !isRegistrationClosed) {
+ const modal = document.getElementById('register-confirm-modal');
+ if (modal) {
+ modal.classList.add('show');
+ document.getElementById('confirm-register-btn').onclick = () => {
+ modal.classList.remove('show');
+ const map = getRegistrationMap();
+ const ids = new Set((map[currentUser.email] || []).map(id => Number(id)));
+ ids.add(Number(event.id));
+ map[currentUser.email] = Array.from(ids);
+ setRegistrationMap(map);
+ const snackbar = document.getElementById('snackbar');
+ if (snackbar) {
+ snackbar.textContent = 'Du wurdest erfolgreich angemeldet.';
+ snackbar.classList.add('snackbar--visible');
+ setTimeout(() => snackbar.classList.remove('snackbar--visible'), 3000);
+ }
+ applyFilters();
+ };
}
+ return;
}
- // Anmeldung: Benutzer zum Event hinzufügen und Snackbar anzeigen.
- if (action === 'register' && !isFull && !isRegistrationClosed) {
- idSet.add(Number(event.id));
- const snackbar = document.getElementById('snackbar');
- if (snackbar) {
- snackbar.textContent = 'Du wurdest erfolgreich angemeldet.';
- snackbar.classList.add('snackbar--visible');
- setTimeout(() => snackbar.classList.remove('snackbar--visible'), 3000);
+ // Abmelde-Modal öffnen
+ if (action === 'unregister') {
+ const modal = document.getElementById('unregister-confirm-modal');
+ if (modal) {
+ modal.classList.add('show');
+ document.getElementById('confirm-unregister-btn').onclick = () => {
+ modal.classList.remove('show');
+ const map = getRegistrationMap();
+ const ids = new Set((map[currentUser.email] || []).map(id => Number(id)));
+ ids.delete(Number(event.id));
+ map[currentUser.email] = Array.from(ids);
+ setRegistrationMap(map);
+ const snackbar = document.getElementById('snackbar');
+ if (snackbar) {
+ snackbar.textContent = 'Du wurdest erfolgreich abgemeldet.';
+ snackbar.classList.add('snackbar--danger', 'snackbar--visible');
+ setTimeout(() => {
+ snackbar.classList.remove('snackbar--visible');
+ setTimeout(() => snackbar.classList.remove('snackbar--danger'), 400);
+ }, 3000);
+ }
+ applyFilters();
+ };
}
+ return;
}
nextRegistrationMap[currentUser.email] = Array.from(idSet);