/** * Listmonk Status Manager * Handles real-time status monitoring and user notifications for email list sync */ class ListmonkStatus { constructor() { this.statusElement = null; this.checkInterval = null; this.lastErrorShown = null; this.currentStatus = { enabled: false, connected: false, lastError: null }; this.init(); } init() { // Only initialize if user is authenticated if (window.currentUser) { this.createStatusIndicator(); this.startStatusCheck(); } } createStatusIndicator() { // Create status indicator element const indicator = document.createElement('div'); indicator.id = 'listmonk-status'; indicator.className = 'listmonk-status-indicator checking'; indicator.innerHTML = ` Email Sync `; // Find a good place to put it - try header actions first let container = document.querySelector('.header-actions'); if (!container) { // Fallback to header nav container = document.querySelector('.header-nav'); } if (!container) { // Fallback to header itself container = document.querySelector('header'); } if (container) { container.appendChild(indicator); this.statusElement = indicator; } } async checkStatus() { try { const response = await fetch('/api/listmonk/status', { credentials: 'include' }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const status = await response.json(); this.updateIndicator(status); } catch (error) { console.error('Failed to check Listmonk status:', error); this.updateIndicator({ enabled: false, connected: false, lastError: error.message }); } } updateIndicator(status) { if (!this.statusElement) return; const icon = this.statusElement.querySelector('.status-icon'); const text = this.statusElement.querySelector('.status-text'); // Update current status const wasConnected = this.currentStatus.connected; this.currentStatus = status; if (!status.enabled) { this.statusElement.className = 'listmonk-status-indicator disabled'; icon.innerHTML = '⭕'; text.textContent = 'Sync Off'; this.statusElement.title = 'Email list synchronization is disabled'; } else if (status.connected) { this.statusElement.className = 'listmonk-status-indicator connected'; icon.innerHTML = '✅'; text.textContent = 'Sync On'; this.statusElement.title = 'Email lists are synchronizing automatically'; // If we just reconnected, show a brief success message if (!wasConnected && this.lastErrorShown) { this.showReconnectedNotification(); } } else { this.statusElement.className = 'listmonk-status-indicator error'; icon.innerHTML = '❌'; text.textContent = 'Sync Error'; this.statusElement.title = status.lastError || 'Email list sync failed - check configuration'; // Show popup warning if this is a new error or first time seeing this error const errorKey = status.lastError + (status.lastErrorTime || ''); if ((!this.lastErrorShown || this.lastErrorShown !== errorKey) && status.lastError) { this.showSyncError(status.lastError); this.lastErrorShown = errorKey; } } } showSyncError(error) { // Don't spam notifications if (document.querySelector('.sync-error-notification')) { return; } // Create and show error notification const notification = document.createElement('div'); notification.className = 'sync-error-notification'; notification.innerHTML = `
⚠️ Email Sync Error

The email list synchronization is not working:

${this.escapeHtml(error || 'Connection failed')}

New contacts will be saved locally but won't sync to email lists until this is resolved.

Please contact your administrator if this persists.

`; document.body.appendChild(notification); // Auto-remove after 15 seconds setTimeout(() => { if (notification && notification.parentNode) { notification.remove(); } }, 15000); } showReconnectedNotification() { // Don't show if there's already a notification if (document.querySelector('.sync-success-notification')) { return; } const notification = document.createElement('div'); notification.className = 'sync-success-notification'; notification.innerHTML = `
✅ Email Sync Restored

Email list synchronization is working again. New contacts will now sync automatically.

`; document.body.appendChild(notification); // Auto-remove after 5 seconds setTimeout(() => { if (notification && notification.parentNode) { notification.remove(); } }, 5000); } startStatusCheck() { // Check immediately this.checkStatus(); // Then check every 30 seconds this.checkInterval = setInterval(() => { this.checkStatus(); }, 30000); } stopStatusCheck() { if (this.checkInterval) { clearInterval(this.checkInterval); this.checkInterval = null; } } // Utility method for HTML escaping escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Manual refresh method for admin panel async refresh() { if (this.statusElement) { this.statusElement.className = 'listmonk-status-indicator checking'; this.statusElement.querySelector('.status-icon').innerHTML = '⏳'; } await this.checkStatus(); } // Get current status (for admin panel) getCurrentStatus() { return { ...this.currentStatus }; } } // Initialize when DOM is ready document.addEventListener('DOMContentLoaded', () => { // Only create if we don't already have one if (!window.listmonkStatus) { window.listmonkStatus = new ListmonkStatus(); } }); // Export for use in other modules window.ListmonkStatus = ListmonkStatus;