/** * Benachrichtigungssystem für die MYP 3D-Druck Platform * Verwaltet die Anzeige und Interaktion mit Benachrichtigungen */ class NotificationManager { constructor() { this.notificationToggle = document.getElementById('notificationToggle'); this.notificationDropdown = document.getElementById('notificationDropdown'); this.notificationBadge = document.getElementById('notificationBadge'); this.notificationList = document.getElementById('notificationList'); this.markAllReadBtn = document.getElementById('markAllRead'); this.isOpen = false; this.notifications = []; // CSRF-Token aus Meta-Tag holen this.csrfToken = this.getCSRFToken(); this.init(); } /** * Holt das CSRF-Token aus dem Meta-Tag * @returns {string} Das CSRF-Token */ getCSRFToken() { const metaTag = document.querySelector('meta[name="csrf-token"]'); return metaTag ? metaTag.getAttribute('content') : ''; } /** * Erstellt die Standard-Headers für API-Anfragen mit CSRF-Token * @returns {Object} Headers-Objekt */ getAPIHeaders() { const headers = { 'Content-Type': 'application/json', }; if (this.csrfToken) { headers['X-CSRFToken'] = this.csrfToken; } return headers; } init() { if (!this.notificationToggle) return; // Event Listeners this.notificationToggle.addEventListener('click', (e) => { e.stopPropagation(); this.toggleDropdown(); }); if (this.markAllReadBtn) { this.markAllReadBtn.addEventListener('click', () => { this.markAllAsRead(); }); } // Dropdown schließen bei Klick außerhalb document.addEventListener('click', (e) => { if (!this.notificationDropdown.contains(e.target) && !this.notificationToggle.contains(e.target)) { this.closeDropdown(); } }); // Benachrichtigungen laden this.loadNotifications(); // Regelmäßige Updates setInterval(() => { this.loadNotifications(); }, 30000); // Alle 30 Sekunden } toggleDropdown() { if (this.isOpen) { this.closeDropdown(); } else { this.openDropdown(); } } openDropdown() { this.notificationDropdown.classList.remove('hidden'); this.notificationToggle.setAttribute('aria-expanded', 'true'); this.isOpen = true; // Animation this.notificationDropdown.style.opacity = '0'; this.notificationDropdown.style.transform = 'translateY(-10px)'; requestAnimationFrame(() => { this.notificationDropdown.style.transition = 'opacity 0.2s ease, transform 0.2s ease'; this.notificationDropdown.style.opacity = '1'; this.notificationDropdown.style.transform = 'translateY(0)'; }); } closeDropdown() { this.notificationDropdown.style.transition = 'opacity 0.2s ease, transform 0.2s ease'; this.notificationDropdown.style.opacity = '0'; this.notificationDropdown.style.transform = 'translateY(-10px)'; setTimeout(() => { this.notificationDropdown.classList.add('hidden'); this.notificationToggle.setAttribute('aria-expanded', 'false'); this.isOpen = false; }, 200); } async loadNotifications() { try { const response = await fetch('/api/notifications'); if (response.ok) { const data = await response.json(); this.notifications = data.notifications || []; this.updateUI(); } } catch (error) { console.error('Fehler beim Laden der Benachrichtigungen:', error); } } updateUI() { this.updateBadge(); this.updateNotificationList(); } updateBadge() { const unreadCount = this.notifications.filter(n => !n.read).length; if (unreadCount > 0) { this.notificationBadge.textContent = unreadCount > 99 ? '99+' : unreadCount.toString(); this.notificationBadge.classList.remove('hidden'); } else { this.notificationBadge.classList.add('hidden'); } } updateNotificationList() { if (this.notifications.length === 0) { this.notificationList.innerHTML = `
${this.getNotificationTitle(notification.type)}
${isUnread ? '' : ''}${this.getNotificationMessage(notification)}
${timeAgo}