226 lines
7.5 KiB
JavaScript
226 lines
7.5 KiB
JavaScript
/**
|
||
* 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;
|