import { Controller } from '@hotwired/stimulus'; export default class extends Controller { static targets = ['badge', 'list']; static values = { userId: Number, mercureUrl: String }; connect() { this.loadNotifications(); this.connectToMercure(); this.toastContainer = this.createToastContainer(); } disconnect() { if (this.eventSource) { this.eventSource.close(); } } async loadNotifications() { try { const response = await fetch('/notifications/unread'); const data = await response.json(); this.updateBadge(data.unreadCount); this.renderNotifications(data.notifications); } catch (error) { console.error('Failed to load notifications:', error); } } async connectToMercure() { try { // Fetch the JWT token and topic from the server const response = await fetch('/mercure-token'); const data = await response.json(); // Use server-provided topic if available, otherwise fallback to default per-user topic const topic = data.topic || `http://portail.solutions-easy.moi/notifications/user/${this.userIdValue}`; const url = new URL(this.mercureUrlValue); url.searchParams.append('topic', topic); // Add authorization token as URL param if provided (Mercure can accept it this way) if (data.token) { url.searchParams.append('authorization', data.token); } try { this.eventSource = new EventSource(url.toString()); } catch (e) { console.error('❌ Failed to create EventSource:', e); return; } this.eventSource.onopen = () => { }; this.eventSource.onmessage = (event) => { try { const notification = JSON.parse(event.data); this.handleNewNotification(notification); } catch (parseError) { console.error('Failed to parse Mercure message data:', parseError, 'raw data:', event.data); } }; this.eventSource.onerror = (error) => { try { console.error('EventSource readyState:', this.eventSource.readyState); } catch (e) { console.error('Could not read EventSource.readyState:', e); } // EventSource will automatically try to reconnect. // If closed, log it for debugging. try { if (this.eventSource.readyState === EventSource.CLOSED) { console.log(); } else if (this.eventSource.readyState === EventSource.CONNECTING) { console.log(); } else if (this.eventSource.readyState === EventSource.OPEN) { console.log(); } } catch (e) { console.error('Error while checking EventSource state:', e); } }; } catch (error) { console.error('Failed to connect to Mercure:', error); } } handleNewNotification(notification) { this.showToast(notification); this.loadNotifications(); } updateBadge(count) { const badge = this.badgeTarget; if (count > 0) { badge.textContent = count > 99 ? '99+' : count; badge.style.display = 'block'; } else { badge.style.display = 'none'; } } renderNotifications(notifications) { const list = this.listTarget; if (notifications.length === 0) { list.innerHTML = `
Aucune notification
${this.escapeHtml(notification.message)}
${timeAgo}