223 lines
8.1 KiB
JavaScript
223 lines
8.1 KiB
JavaScript
// =============================================
|
|
// Dynamische Navigation
|
|
// Je nach Login-Status wird die Kopfzeile für
|
|
// alle Seiten mit passendem Markup aufgebaut.
|
|
// =============================================
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
|
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
|
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
|
const navcontainers = document.querySelectorAll('.nav-tab-links');
|
|
const currentPage = (window.location.pathname.split('/').pop() || 'index.html').toLowerCase();
|
|
|
|
// Beendet früh, falls auf einer Seite keine Hauptnavigation vorhanden ist.
|
|
if (!navcontainers.length) {
|
|
return;
|
|
}
|
|
|
|
// Liest den aktiven Benutzer robust aus localStorage.
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Logout-Funktion
|
|
window.logout = function() {
|
|
localStorage.removeItem(CURRENT_USER_KEY);
|
|
window.location.href = 'index.html';
|
|
};
|
|
|
|
// Hilfsfunktionen für Datumsberechnungen
|
|
function parseEventDateTime(event) {
|
|
if (!event?.date) return null;
|
|
const dateValue = String(event.date).trim();
|
|
const isoDateMatch = dateValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
let year, month, day;
|
|
|
|
if (isoDateMatch) {
|
|
year = Number(isoDateMatch[1]);
|
|
month = Number(isoDateMatch[2]);
|
|
day = Number(isoDateMatch[3]);
|
|
} else {
|
|
const monthMap = {
|
|
jan: 1, januar: 1,
|
|
feb: 2, februar: 2,
|
|
'mär': 3, mrz: 3, mar: 3, maerz: 3, märz: 3,
|
|
apr: 4, april: 4,
|
|
mai: 5,
|
|
jun: 6, juni: 6,
|
|
jul: 7, juli: 7,
|
|
aug: 8, august: 8,
|
|
sep: 9, sept: 9, september: 9,
|
|
okt: 10, oktober: 10,
|
|
nov: 11, november: 11,
|
|
dez: 12, dezember: 12
|
|
};
|
|
const localizedMatch = dateValue.match(/^(\d{1,2})\.\s*([A-Za-zÄÖÜäöü]{3,9})\.?\s*(\d{4})$/);
|
|
if (!localizedMatch) return null;
|
|
day = Number(localizedMatch[1]);
|
|
month = monthMap[String(localizedMatch[2]).toLowerCase()];
|
|
year = Number(localizedMatch[3]);
|
|
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 isAddressVisibleWindow(event) {
|
|
if (event.status === 'canceled') return false;
|
|
const eventDateTime = parseEventDateTime(event);
|
|
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) return false;
|
|
const now = Date.now();
|
|
const start = eventDateTime.getTime();
|
|
const revealStart = start - (24 * 60 * 60 * 1000);
|
|
const revealEnd = start + (1 * 60 * 60 * 1000);
|
|
return now >= revealStart && now <= revealEnd;
|
|
}
|
|
|
|
async function hasUnreadNotifications(user) {
|
|
if (!user || !user.email) return false;
|
|
|
|
let events = [];
|
|
try {
|
|
const rawStored = localStorage.getItem(EVENTS_STORAGE_KEY);
|
|
const storedEvents = rawStored ? JSON.parse(rawStored) : [];
|
|
|
|
const response = await fetch('data/events.json');
|
|
const apiEvents = await response.json();
|
|
events = [...storedEvents, ...apiEvents];
|
|
} catch (err) {
|
|
console.error('Fehler beim Laden der Events für Benachrichtigungen', err);
|
|
return false;
|
|
}
|
|
|
|
let map = {};
|
|
try {
|
|
const rawReg = localStorage.getItem(REGISTRATION_STORAGE_KEY);
|
|
map = rawReg ? JSON.parse(rawReg) : {};
|
|
} catch (err) {}
|
|
|
|
let seenAddresses = [];
|
|
try {
|
|
const rawSeen = localStorage.getItem('socialCookingSeenAddresses');
|
|
seenAddresses = rawSeen ? JSON.parse(rawSeen) : [];
|
|
} catch (err) {}
|
|
|
|
const registeredIds = Array.isArray(map[user.email]) ? map[user.email] : [];
|
|
const idSet = new Set(registeredIds.map(id => Number(id)));
|
|
|
|
const myRegisteredEvents = events.filter(e => idSet.has(Number(e.id)));
|
|
|
|
// Unread = address visible AND NOT marked as seen
|
|
return myRegisteredEvents.some(e => isAddressVisibleWindow(e) && !seenAddresses.includes(Number(e.id)));
|
|
}
|
|
|
|
// Baut die Navigation für ausgeloggte Besucher.
|
|
function buildLoggedOutNavigation() {
|
|
const loginIsActive = currentPage === 'login.html';
|
|
const signupIsActive = currentPage === 'signup.html';
|
|
const isIndex = currentPage === 'index.html' || currentPage === '';
|
|
|
|
// Auf der Startseite, Login und Signup nur Login anzeigen.
|
|
if (isIndex || loginIsActive || signupIsActive) {
|
|
return `
|
|
<a
|
|
class="button-small"
|
|
href="login.html"
|
|
aria-label="Login"
|
|
>
|
|
Login
|
|
</a>
|
|
`;
|
|
}
|
|
|
|
return `
|
|
<a
|
|
class="button-small auth-nav-button ${loginIsActive ? 'auth-nav-button--active' : 'auth-nav-button--default'}"
|
|
href="login.html"
|
|
aria-label="Login"
|
|
${loginIsActive ? 'aria-current="page"' : ''}
|
|
>
|
|
Login
|
|
</a>
|
|
<a
|
|
class="button-small auth-nav-button ${signupIsActive ? 'auth-nav-button--active' : 'auth-nav-button--default'}"
|
|
href="signup.html"
|
|
aria-label="Signup"
|
|
${signupIsActive ? 'aria-current="page"' : ''}
|
|
>
|
|
Signup
|
|
</a>
|
|
`;
|
|
}
|
|
|
|
// Baut die Navigation für eingeloggte Benutzer.
|
|
function buildLoggedInNavigation(user, hasNotifications) {
|
|
const initial = (user.vorname || 'U').charAt(0).toUpperCase();
|
|
const isEventOverview = currentPage === 'event_overview.html';
|
|
const isEventCreate = currentPage === 'event_create.html';
|
|
const notificationMarkup = hasNotifications ? '<span class="notification-dot"></span>' : '';
|
|
|
|
return `
|
|
<a
|
|
class="nav-tab${isEventCreate ? ' nav-tab--active' : ''}"
|
|
href="event_create.html"
|
|
${isEventCreate ? 'aria-current="page"' : ''}
|
|
>
|
|
Event erstellen
|
|
</a>
|
|
<a
|
|
class="nav-tab${isEventOverview ? ' nav-tab--active' : ''}"
|
|
href="event_overview.html"
|
|
${isEventOverview ? 'aria-current="page"' : ''}
|
|
>
|
|
Event finden
|
|
</a>
|
|
<button
|
|
class="button-small logout-button"
|
|
onclick="logout()"
|
|
aria-label="Logout"
|
|
>
|
|
Logout
|
|
</button>
|
|
<a
|
|
class="profile-pill"
|
|
href="my_profil.html"
|
|
aria-label="Mein Profil"
|
|
title="${user.vorname || 'Profil'}"
|
|
>
|
|
${initial}
|
|
${notificationMarkup}
|
|
</a>
|
|
`;
|
|
}
|
|
|
|
async function initNavigation() {
|
|
const currentUser = getCurrentUser();
|
|
let nextMarkup;
|
|
|
|
if (currentUser) {
|
|
const hasNotifications = await hasUnreadNotifications(currentUser);
|
|
nextMarkup = buildLoggedInNavigation(currentUser, hasNotifications);
|
|
} else {
|
|
nextMarkup = buildLoggedOutNavigation();
|
|
}
|
|
|
|
// Wendet das passende Markup auf alle vorhandenen Kopf-Navigationen an.
|
|
navcontainers.forEach(container => {
|
|
container.innerHTML = nextMarkup;
|
|
});
|
|
}
|
|
|
|
initNavigation();
|
|
});
|