freealberta/map/app/public/js/listmonk-status.js
2025-08-15 11:14:38 -06:00

226 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 = `
<span class="status-icon">⏳</span>
<span class="status-text">Email Sync</span>
`;
// 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 = `
<div class="notification-header">
<strong>⚠️ Email Sync Error</strong>
<button class="close-btn" onclick="this.parentElement.parentElement.remove()">×</button>
</div>
<div class="notification-body">
<p>The email list synchronization is not working:</p>
<code>${this.escapeHtml(error || 'Connection failed')}</code>
<p>New contacts will be saved locally but won't sync to email lists until this is resolved.</p>
<p>Please contact your administrator if this persists.</p>
</div>
`;
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 = `
<div class="notification-header">
<strong>✅ Email Sync Restored</strong>
<button class="close-btn" onclick="this.parentElement.parentElement.remove()">×</button>
</div>
<div class="notification-body">
<p>Email list synchronization is working again. New contacts will now sync automatically.</p>
</div>
`;
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;