fix: proper umlauts across all files, simplify gallery upload, fix Menu spelling, show local events in overview
This commit is contained in:
parent
e805abbf12
commit
e91cd8572e
@ -562,6 +562,70 @@ textarea:focus {
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
/* Gallery Upload */
|
||||
.gallery-upload {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.gallery-preview {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.gallery-thumb {
|
||||
position: relative;
|
||||
width: 5.5rem;
|
||||
height: 5.5rem;
|
||||
border-radius: var(--radius-sm, 0.5rem);
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.gallery-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.gallery-thumb-remove {
|
||||
position: absolute;
|
||||
top: 0.2rem;
|
||||
right: 0.2rem;
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.gallery-add-btn {
|
||||
width: 5.5rem;
|
||||
height: 5.5rem;
|
||||
border: 2px dashed var(--color-border-strong);
|
||||
border-radius: var(--radius-sm, 0.5rem);
|
||||
background: transparent;
|
||||
font-size: 2rem;
|
||||
color: var(--color-muted);
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: border-color 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
.gallery-add-btn:hover {
|
||||
border-color: var(--olive);
|
||||
color: var(--olive);
|
||||
}
|
||||
|
||||
.site-footer {
|
||||
width: min(100% - 2rem, var(--max-width));
|
||||
margin: 0 auto;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.profile-page {
|
||||
.profile-page {
|
||||
/* Reserve a large safe zone below sticky nav so title/actions are never covered. */
|
||||
margin-top: 0;
|
||||
padding-top: 6.5rem;
|
||||
@ -76,7 +76,7 @@
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
/* Konsistentes Karten-Layout fuer alle Profilsektionen. */
|
||||
/* Konsistentes Karten-Layout für alle Profilsektionen. */
|
||||
.profile-panel {
|
||||
background: rgba(255, 255, 255, 0.88);
|
||||
border-radius: var(--radius-lg);
|
||||
@ -113,7 +113,7 @@
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
/* Einzelne Eventkarte fuer "Meine Events" und "Meine Anmeldungen". */
|
||||
/* Einzelne Eventkarte für "Meine Events" und "Meine Anmeldungen". */
|
||||
.profile-event-card {
|
||||
border: 1px solid rgba(107, 107, 5, 0.25);
|
||||
border-radius: var(--radius-md);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Italienische Tavolata",
|
||||
@ -15,7 +15,7 @@
|
||||
},
|
||||
"hostMessage": [
|
||||
"Ciao zusammen! Ich liebe die italienische Küche, nicht nur wegen des Essens, sondern wegen des Gefühls: Alle sitzen an einem langen Tisch, teilen sich grosse Platten und geniessen die Zeit.",
|
||||
"Genau das möchte ich mit euch teilen. Ich bereite dafuer eine klassische Tavolata vor, bei der verschiedene Gerichte in die Mitte des Tisches kommen und sich jeder bedient."
|
||||
"Genau das möchte ich mit euch teilen. Ich bereite dafür eine klassische Tavolata vor, bei der verschiedene Gerichte in die Mitte des Tisches kommen und sich jeder bedient."
|
||||
],
|
||||
"menu": [
|
||||
"Bruschetta-Variationen und Antipasti",
|
||||
|
||||
@ -285,6 +285,15 @@
|
||||
<label for="eventDescription">Beschreibung des Events</label>
|
||||
<textarea id="eventDescription" name="eventDescription" rows="6" required></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label>Fotos hinzufügen <span class="field-hint-inline">(optional)</span></label>
|
||||
<div class="gallery-upload">
|
||||
<div class="gallery-preview" id="galleryPreview"></div>
|
||||
<button type="button" class="gallery-add-btn" id="galleryAddBtn" aria-label="Foto hinzufügen">+</button>
|
||||
<input type="file" id="galleryFileInput" accept="image/*" multiple hidden />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// =============================
|
||||
// =============================
|
||||
// SETUP: Wichtige HTML-Elemente holen
|
||||
// Diese Konstanten verbinden unser JavaScript mit dem HTML.
|
||||
// So können wir später Buttons, Formularfelder und Bereiche steuern.
|
||||
@ -428,9 +428,9 @@ function buildStoredEvent() {
|
||||
? []
|
||||
: getCheckboxValues("allergies").split(", ").filter(Boolean),
|
||||
allergiesNote: form.elements.allergiesOther.value.trim(),
|
||||
// Host wird separat gefuehrt und nicht als angemeldeter Gast gezaehlt.
|
||||
// Host wird separat geführt und nicht als angemeldeter Gast gezählt.
|
||||
participants: [],
|
||||
gallery: [],
|
||||
gallery: [...galleryImages],
|
||||
createdAt: new Date().toISOString(),
|
||||
source: "local"
|
||||
};
|
||||
@ -737,6 +737,64 @@ function focusFieldByName(fieldName) {
|
||||
}
|
||||
|
||||
|
||||
// =============================
|
||||
// STEP 8b: Galerie-Upload (Fotos hinzufügen)
|
||||
// =============================
|
||||
const galleryImages = [];
|
||||
|
||||
function registerGalleryHandlers() {
|
||||
const addBtn = document.getElementById("galleryAddBtn");
|
||||
const fileInput = document.getElementById("galleryFileInput");
|
||||
const preview = document.getElementById("galleryPreview");
|
||||
|
||||
if (!addBtn) return;
|
||||
|
||||
// Klick auf + öffnet direkt den Datei-Dialog
|
||||
addBtn.addEventListener("click", () => {
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
// Datei(en) hochladen
|
||||
fileInput.addEventListener("change", () => {
|
||||
Array.from(fileInput.files).forEach(file => {
|
||||
if (!file.type.startsWith("image/")) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
addGalleryImage(e.target.result);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
fileInput.value = "";
|
||||
});
|
||||
|
||||
function addGalleryImage(src) {
|
||||
galleryImages.push(src);
|
||||
renderGalleryPreview();
|
||||
}
|
||||
|
||||
function removeGalleryImage(index) {
|
||||
galleryImages.splice(index, 1);
|
||||
renderGalleryPreview();
|
||||
}
|
||||
|
||||
function renderGalleryPreview() {
|
||||
preview.innerHTML = "";
|
||||
galleryImages.forEach((src, i) => {
|
||||
const thumb = document.createElement("div");
|
||||
thumb.className = "gallery-thumb";
|
||||
thumb.innerHTML = `
|
||||
<img src="${src}" alt="Foto ${i + 1}">
|
||||
<button type="button" class="gallery-thumb-remove" aria-label="Foto entfernen">×</button>
|
||||
`;
|
||||
thumb.querySelector(".gallery-thumb-remove").addEventListener("click", () => {
|
||||
removeGalleryImage(i);
|
||||
});
|
||||
preview.appendChild(thumb);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =============================
|
||||
// STEP 9: Alles starten
|
||||
// Hier werden alle Event Listener registriert
|
||||
@ -765,6 +823,7 @@ function initEventCreationFlow() {
|
||||
registerMenuBulletHandler();
|
||||
registerValidationFeedbackHandlers();
|
||||
registerReviewEditHandlers();
|
||||
registerGalleryHandlers();
|
||||
|
||||
// Browser-Zurück-Taste: vorherigen Schritt wiederherstellen
|
||||
window.addEventListener("popstate", (e) => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||
@ -152,13 +152,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
return userEmail === hostEmail;
|
||||
}
|
||||
|
||||
// Fallback fuer aeltere Datensaetze ohne hostEmail.
|
||||
// Fallback für ältere Datensätze ohne hostEmail.
|
||||
const userFirstName = String(user.vorname || '').trim().toLowerCase();
|
||||
const hostName = String(event.host?.name || '').trim().toLowerCase();
|
||||
return Boolean(userFirstName && hostName && userFirstName === hostName);
|
||||
}
|
||||
|
||||
// Prueft, ob der aktuelle Benutzer bereits in der Teilnehmerliste des Events steht.
|
||||
// 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;
|
||||
@ -258,7 +258,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
: ['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.'];
|
||||
: ['Menü wird in Kürze bekannt gegeben.'];
|
||||
const specifications = Array.isArray(event.specifications) && event.specifications.length > 0
|
||||
? event.specifications
|
||||
: [];
|
||||
@ -329,7 +329,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
<img src="${locationIconPath}" alt="">
|
||||
${event.location}
|
||||
</span>
|
||||
<p class="event-date-time">${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gaeste</p>
|
||||
<p class="event-date-time">${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gäste</p>
|
||||
</div>
|
||||
<h1 class="detail-title">${event.title}</h1>
|
||||
<div class="event-meta-row detail-chip-row">
|
||||
@ -349,7 +349,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
</article>
|
||||
|
||||
<article class="detail-panel detail-panel-compact">
|
||||
<h2 class="detail-section-title">Menue</h2>
|
||||
<h2 class="detail-section-title">Menu</h2>
|
||||
<ul class="detail-menu-list">
|
||||
${menuItems.map(item => `<li>${item}</li>`).join('')}
|
||||
</ul>
|
||||
@ -393,7 +393,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
<img src="${locationIconPath}" alt="">
|
||||
${event.location}
|
||||
</span>
|
||||
<span class="detail-action-meta-text">| ${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gaeste</span>
|
||||
<span class="detail-action-meta-text">| ${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gäste</span>
|
||||
</small>
|
||||
<strong>${event.title}</strong>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||
@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Prueft, ob ein Event dem aktuellen Benutzer gehoert.
|
||||
// Prüft, ob ein Event dem aktuellen Benutzer gehört.
|
||||
function isEventOwnedByCurrentUser(event, user) {
|
||||
if (!event || !user) {
|
||||
return false;
|
||||
@ -198,7 +198,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
: `${timeString} Uhr`;
|
||||
}
|
||||
|
||||
// Baut aus Eventdatum/-zeit ein Date-Objekt fuer Fristlogik und Vergleiche.
|
||||
// Baut aus Eventdatum/-zeit ein Date-Objekt für Fristlogik und Vergleiche.
|
||||
function parseEventDateTime(event) {
|
||||
if (!event?.date) {
|
||||
return null;
|
||||
@ -252,7 +252,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return new Date(year, month - 1, day, hours, minutes, 0, 0);
|
||||
}
|
||||
|
||||
// Zaehlt eindeutige Registrierungen eines Events ueber alle Benutzer.
|
||||
// Zählt eindeutige Registrierungen eines Events über alle Benutzer.
|
||||
function countRegistrationsForEvent(registrationMap, eventId) {
|
||||
return Object.values(registrationMap).reduce((count, ids) => {
|
||||
const hasEvent = Array.isArray(ids)
|
||||
@ -385,7 +385,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
<img src="${locationIconPath}" alt="">
|
||||
${event.location}
|
||||
</span>
|
||||
<p class="event-date-time">${displayDate} | ${displayTime} | ${bookedSeats}/${totalCapacity} Gaeste</p>
|
||||
<p class="event-date-time">${displayDate} | ${displayTime} | ${bookedSeats}/${totalCapacity} Gäste</p>
|
||||
</div>
|
||||
<h2 class="event-title">${event.title}</h2>
|
||||
<div class="event-meta-row">
|
||||
@ -444,7 +444,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Anmeldung: Benutzer zum Event hinzufuegen und Snackbar anzeigen.
|
||||
// Anmeldung: Benutzer zum Event hinzufügen und Snackbar anzeigen.
|
||||
if (action === 'register' && !isFull && !isRegistrationClosed) {
|
||||
idSet.add(Number(event.id));
|
||||
const snackbar = document.getElementById('snackbar');
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// =============================================
|
||||
// =============================================
|
||||
// Galerie-Karussell (Startseite)
|
||||
// Diese Datei steuert die Foto-Galerie mit Pfeilen.
|
||||
// =============================================
|
||||
@ -9,7 +9,7 @@ const prevArrow = document.querySelector('.gallery__arrow--prev');
|
||||
const nextArrow = document.querySelector('.gallery__arrow--next');
|
||||
const dotsContainer = document.querySelector('.gallery__dots');
|
||||
|
||||
// Nur ausfuehren, wenn die Galerie auf der Seite vorhanden ist.
|
||||
// Nur ausführen, wenn die Galerie auf der Seite vorhanden ist.
|
||||
if (carouselTrack) {
|
||||
// Alle einzelnen Karten/Bilder im Track sammeln.
|
||||
const items = Array.from(carouselTrack.querySelectorAll('.gallery__item'));
|
||||
@ -62,7 +62,7 @@ if (carouselTrack) {
|
||||
updateTrack();
|
||||
}
|
||||
|
||||
// Geht zur naechsten Seite (mit Wrap-around am Ende).
|
||||
// Geht zur nächsten Seite (mit Wrap-around am Ende).
|
||||
function showNext() {
|
||||
activePage = (activePage + 1) % pageCount;
|
||||
updateTrack();
|
||||
@ -80,13 +80,13 @@ if (carouselTrack) {
|
||||
if (nextArrow) nextArrow.addEventListener('click', showNext);
|
||||
if (prevArrow) prevArrow.addEventListener('click', showPrev);
|
||||
|
||||
// Tastatur-Support fuer Barrierefreiheit.
|
||||
// Tastatur-Support für Barrierefreiheit.
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'ArrowRight') showNext();
|
||||
if (event.key === 'ArrowLeft') showPrev();
|
||||
});
|
||||
|
||||
// Reagiert auf Bildschirmgroessen-Aenderungen.
|
||||
// Reagiert auf Bildschirmgrössen-Änderungen.
|
||||
window.addEventListener('resize', function() {
|
||||
var newPerPage = getItemsPerPage();
|
||||
if (newPerPage !== itemsPerPage) {
|
||||
@ -99,7 +99,7 @@ if (carouselTrack) {
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// Lightbox: Bild vergroessern bei Klick
|
||||
// Lightbox: Bild vergrössern bei Klick
|
||||
// =============================================
|
||||
const lightbox = document.getElementById('gallery-lightbox');
|
||||
const lightboxImage = lightbox ? lightbox.querySelector('.lightbox__image') : null;
|
||||
@ -119,7 +119,7 @@ if (carouselTrack) {
|
||||
lightboxImage.src = '';
|
||||
}
|
||||
|
||||
// Klick auf Galerie-Bild oeffnet die Lightbox.
|
||||
// Klick auf Galerie-Bild öffnet die Lightbox.
|
||||
items.forEach(function(item) {
|
||||
var img = item.querySelector('img');
|
||||
if (img) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// =============================================
|
||||
// =============================================
|
||||
// Mini-Galerie auf der Landingpage
|
||||
// Diese Datei hebt immer ein Bild hervor und
|
||||
// erlaubt Navigation mit Pfeilen/Tastatur.
|
||||
@ -38,7 +38,7 @@ function showPrev() {
|
||||
if (nextBtn) nextBtn.addEventListener('click', showNext);
|
||||
if (prevBtn) prevBtn.addEventListener('click', showPrev);
|
||||
|
||||
// Tastatursteuerung fuer bessere Bedienbarkeit.
|
||||
// Tastatursteuerung für bessere Bedienbarkeit.
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'ArrowRight') {
|
||||
showNext();
|
||||
|
||||
10
js/login.js
10
js/login.js
@ -1,4 +1,4 @@
|
||||
// =============================================
|
||||
// =============================================
|
||||
// Login-Logik
|
||||
// Diese Datei validiert die Eingaben, sucht den
|
||||
// Benutzer im localStorage und legt die Session an.
|
||||
@ -25,12 +25,12 @@ function getStoredUsers() {
|
||||
}
|
||||
}
|
||||
|
||||
// Speichert den aktiven Benutzer fuer nachfolgende Seiten.
|
||||
// Speichert den aktiven Benutzer für nachfolgende Seiten.
|
||||
function setCurrentUser(user) {
|
||||
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(user));
|
||||
}
|
||||
|
||||
// Erstellt einen Demo-Benutzer, falls fuer die E-Mail noch kein Account existiert.
|
||||
// Erstellt einen Demo-Benutzer, falls für die E-Mail noch kein Account existiert.
|
||||
function createFallbackUser(email, passwort) {
|
||||
const localPart = email.split('@')[0] || 'Gast';
|
||||
const normalized = localPart.replace(/[._-]/g, ' ').trim();
|
||||
@ -86,7 +86,7 @@ function validateForm(event) {
|
||||
passwortGroup.classList.remove('has-error');
|
||||
}
|
||||
|
||||
// Wenn alle Validierungen bestanden, pruefen wir:
|
||||
// Wenn alle Validierungen bestanden, prüfen wir:
|
||||
// 1) gibt es den Benutzer schon?
|
||||
// 2) ist das Passwort korrekt?
|
||||
// Danach speichern wir die aktive Session.
|
||||
@ -103,7 +103,7 @@ function validateForm(event) {
|
||||
const userToLogin = matchedUser || createFallbackUser(emailValue, passwortValue);
|
||||
setCurrentUser(userToLogin);
|
||||
|
||||
// Snackbar anzeigen und dann zur Event-Uebersicht weiterleiten.
|
||||
// Snackbar anzeigen und dann zur Event-Übersicht weiterleiten.
|
||||
var snackbar = document.getElementById('snackbar');
|
||||
if (snackbar) {
|
||||
snackbar.classList.add('snackbar--visible');
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||
const USERS_STORAGE_KEY = 'socialCookingUsers';
|
||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||
|
||||
// Zentrale DOM-Referenzen fuer klare, testbare Funktionen.
|
||||
// Zentrale DOM-Referenzen für klare, testbare Funktionen.
|
||||
const loggedOutState = document.getElementById('logged-out-state');
|
||||
const loggedInContent = document.getElementById('logged-in-content');
|
||||
const profileHeadline = document.getElementById('profile-headline');
|
||||
@ -109,7 +109,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
profileSubline.textContent = 'Bitte logge dich ein, um deinen Bereich zu sehen.';
|
||||
}
|
||||
|
||||
// Fuellt Ueberschriften und Formular mit den aktuellen Benutzerdaten.
|
||||
// Füllt Überschriften und Formular mit den aktuellen Benutzerdaten.
|
||||
function renderLoggedInState(user) {
|
||||
loggedOutState.classList.add('hidden');
|
||||
loggedInContent.classList.remove('hidden');
|
||||
@ -154,7 +154,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
// Globale Funktionen fuer das Logout-Modal.
|
||||
// Globale Funktionen für das Logout-Modal.
|
||||
window.closeLogoutModal = function() {
|
||||
const logoutModal = document.getElementById('logoutModal');
|
||||
logoutModal.classList.remove('show');
|
||||
@ -305,7 +305,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
setStoredEvents(nextStoredEvents);
|
||||
|
||||
// Event-ID fuer alle Benutzer aus den Anmeldungen entfernen.
|
||||
// Event-ID für alle Benutzer aus den Anmeldungen entfernen.
|
||||
const registrationMap = getRegistrationMap();
|
||||
Object.keys(registrationMap).forEach(email => {
|
||||
const ids = Array.isArray(registrationMap[email])
|
||||
@ -366,12 +366,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// Speichert Profilaenderungen lokal und synchronisiert auch den Benutzerkatalog.
|
||||
// Speichert Profiländerungen lokal und synchronisiert auch den Benutzerkatalog.
|
||||
function handleProfileSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!validateProfileForm()) {
|
||||
profileFeedback.textContent = 'Bitte pruefe die markierten Felder.';
|
||||
profileFeedback.textContent = 'Bitte prüfe die markierten Felder.';
|
||||
return;
|
||||
}
|
||||
|
||||
@ -389,7 +389,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(nextUser));
|
||||
syncUserInUserStore(previousEmail, nextUser);
|
||||
|
||||
// Falls sich die E-Mail geaendert hat, verschieben wir bestehende Anmeldungen auf die neue E-Mail.
|
||||
// Falls sich die E-Mail geändert hat, verschieben wir bestehende Anmeldungen auf die neue E-Mail.
|
||||
migrateRegistrationEmail(previousEmail, nextUser.email);
|
||||
|
||||
passwortInput.value = '';
|
||||
@ -450,7 +450,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
// Ermittelt angemeldete Events ueber die Registration-Map.
|
||||
// Ermittelt angemeldete Events über die Registration-Map.
|
||||
function getMyRegisteredEvents(events, user) {
|
||||
const registrationMap = getRegistrationMap();
|
||||
const registeredIds = Array.isArray(registrationMap[user.email]) ? registrationMap[user.email] : [];
|
||||
@ -459,7 +459,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return events.filter(event => idSet.has(Number(event.id)));
|
||||
}
|
||||
|
||||
// Rendert gehostete Events inkl. Zaehler.
|
||||
// Rendert gehostete Events inkl. Zähler.
|
||||
function renderMyEvents(events, user) {
|
||||
const hostedEvents = getMyHostedEvents(events, user);
|
||||
myEventsCount.textContent = String(hostedEvents.length);
|
||||
@ -471,7 +471,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}, 'hosting');
|
||||
}
|
||||
|
||||
// Rendert angemeldete Events inkl. Zaehler.
|
||||
// Rendert angemeldete Events inkl. Zähler.
|
||||
function renderMyRegistrations(events, user) {
|
||||
const registeredEvents = getMyRegisteredEvents(events, user);
|
||||
myRegistrationsCount.textContent = String(registeredEvents.length);
|
||||
@ -483,7 +483,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}, 'registrations');
|
||||
}
|
||||
|
||||
// Baut die Eventkarten fuer beide Listen in einheitlichem Markup.
|
||||
// Baut die Eventkarten für beide Listen in einheitlichem Markup.
|
||||
function renderEventCards(container, events, emptyStateConfig, mode) {
|
||||
container.innerHTML = '';
|
||||
|
||||
@ -538,7 +538,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
// Gibt true zurueck, wenn ein Event innerhalb der naechsten 12 Stunden startet.
|
||||
// Gibt true zurück, wenn ein Event innerhalb der nächsten 12 Stunden startet.
|
||||
function isAddressVisibleWindow(event) {
|
||||
const eventDateTime = parseEventDateTime(event);
|
||||
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
|
||||
@ -551,7 +551,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return msUntilStart >= 0 && msUntilStart <= twelveHoursInMs;
|
||||
}
|
||||
|
||||
// Parse fuer ISO- und lokalisierte Datumsformate aus den Eventdaten.
|
||||
// Parse für ISO- und lokalisierte Datumsformate aus den Eventdaten.
|
||||
function parseEventDateTime(event) {
|
||||
if (!event?.date) {
|
||||
return null;
|
||||
@ -605,7 +605,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return new Date(year, month - 1, day, hours, minutes, 0, 0);
|
||||
}
|
||||
|
||||
// Formatiert ein Eventdatum konsistent fuer die Profilkarten.
|
||||
// Formatiert ein Eventdatum konsistent für die Profilkarten.
|
||||
function formatEventDate(dateString) {
|
||||
if (!dateString) {
|
||||
return 'Kein Datum';
|
||||
@ -620,7 +620,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return dateString;
|
||||
}
|
||||
|
||||
// Vereinheitlicht die Zeitanzeige fuer die Profilseite.
|
||||
// Vereinheitlicht die Zeitanzeige für die Profilseite.
|
||||
function formatEventTime(timeString) {
|
||||
if (!timeString) {
|
||||
return 'Keine Uhrzeit';
|
||||
@ -629,7 +629,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return timeString.includes('UHR') ? timeString.replace('UHR', 'Uhr').trim() : timeString;
|
||||
}
|
||||
|
||||
// Normalisiert Vergleichswerte fuer robuste String-Matches.
|
||||
// Normalisiert Vergleichswerte für robuste String-Matches.
|
||||
function normalizeText(value) {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// =============================================
|
||||
// =============================================
|
||||
// Dynamische Navigation
|
||||
// Je nach Login-Status wird die Kopfzeile fuer
|
||||
// Je nach Login-Status wird die Kopfzeile für
|
||||
// alle Seiten mit passendem Markup aufgebaut.
|
||||
// =============================================
|
||||
|
||||
@ -9,7 +9,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const navContainers = document.querySelectorAll('.nav-tab-links');
|
||||
const currentPage = (window.location.pathname.split('/').pop() || 'index.html').toLowerCase();
|
||||
|
||||
// Beendet frueh, falls auf einer Seite keine Hauptnavigation vorhanden ist.
|
||||
// Beendet früh, falls auf einer Seite keine Hauptnavigation vorhanden ist.
|
||||
if (!navContainers.length) {
|
||||
return;
|
||||
}
|
||||
@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Baut die Navigation fuer ausgeloggte Besucher.
|
||||
// Baut die Navigation für ausgeloggte Besucher.
|
||||
function buildLoggedOutNavigation() {
|
||||
const loginIsActive = currentPage === 'login.html';
|
||||
const signupIsActive = currentPage === 'signup.html';
|
||||
@ -64,7 +64,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
`;
|
||||
}
|
||||
|
||||
// Baut die Navigation fuer eingeloggte Benutzer.
|
||||
// Baut die Navigation für eingeloggte Benutzer.
|
||||
function buildLoggedInNavigation(user) {
|
||||
const initial = (user.vorname || 'U').charAt(0).toUpperCase();
|
||||
const isEventOverview = currentPage === 'event_overview.html';
|
||||
|
||||
10
js/signup.js
10
js/signup.js
@ -1,4 +1,4 @@
|
||||
// =============================================
|
||||
// =============================================
|
||||
// Signup-Logik
|
||||
// Diese Datei validiert das Formular, speichert
|
||||
// neue Benutzer lokal und startet direkt die Session.
|
||||
@ -31,7 +31,7 @@ function setStoredUsers(users) {
|
||||
localStorage.setItem(USERS_STORAGE_KEY, JSON.stringify(users));
|
||||
}
|
||||
|
||||
// Speichert den aktiven Benutzer fuer nachfolgende Seiten.
|
||||
// Speichert den aktiven Benutzer für nachfolgende Seiten.
|
||||
function setCurrentUser(user) {
|
||||
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(user));
|
||||
}
|
||||
@ -49,7 +49,7 @@ function closeWelcomeModal() {
|
||||
window.location.href = 'event_overview.html';
|
||||
}
|
||||
|
||||
// Hauptfunktion fuer Formularvalidierung und Speicherung.
|
||||
// Hauptfunktion für Formularvalidierung und Speicherung.
|
||||
function validateForm(event) {
|
||||
event.preventDefault();
|
||||
|
||||
@ -110,8 +110,8 @@ function validateForm(event) {
|
||||
passwortGroup.classList.remove('has-error');
|
||||
}
|
||||
|
||||
// Wenn alles gueltig ist:
|
||||
// 1) auf doppelte E-Mail pruefen
|
||||
// Wenn alles gültig ist:
|
||||
// 1) auf doppelte E-Mail prüfen
|
||||
// 2) neuen Benutzer speichern
|
||||
// 3) als aktuellen Benutzer einloggen
|
||||
if (isValid) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user