// Main Application Module class MainApp { constructor() { this.init(); } init() { // Initialize message display system window.messageDisplay = new MessageDisplay(); // Check API health on startup this.checkAPIHealth(); // Add global error handling window.addEventListener('error', (e) => { // Only log and show message for actual errors, not null/undefined if (e.error) { console.error('Global error:', e.error); console.error('Error details:', { message: e.message, filename: e.filename, lineno: e.lineno, colno: e.colno, error: e.error }); window.messageDisplay?.show('An unexpected error occurred. Please refresh the page and try again.', 'error'); } else { // Just log these non-critical errors without showing popup console.log('Non-critical error event:', { message: e.message, filename: e.filename, lineno: e.lineno, colno: e.colno, type: e.type }); } }); // Add unhandled promise rejection handling window.addEventListener('unhandledrejection', (e) => { if (e.reason) { console.error('Unhandled promise rejection:', e.reason); window.messageDisplay?.show('An unexpected error occurred. Please try again.', 'error'); e.preventDefault(); } else { console.log('Non-critical promise rejection:', e); } }); } async checkAPIHealth() { try { await window.apiClient.checkHealth(); console.log('API health check passed'); } catch (error) { console.error('API health check failed:', error); window.messageDisplay.show('Connection to server failed. Please check your internet connection and try again.', 'error'); } } } // Message Display System class MessageDisplay { constructor() { this.container = document.getElementById('message-display'); this.timeouts = new Map(); } show(message, type = 'info', duration = 5000) { // Clear existing timeout for this container if (this.timeouts.has(this.container)) { clearTimeout(this.timeouts.get(this.container)); } // Set message content and type this.container.innerHTML = message; this.container.className = `message-display ${type}`; this.container.style.display = 'block'; // Auto-hide after duration const timeout = setTimeout(() => { this.hide(); }, duration); this.timeouts.set(this.container, timeout); // Add click to dismiss this.container.style.cursor = 'pointer'; this.container.onclick = () => this.hide(); } hide() { this.container.style.display = 'none'; this.container.onclick = null; // Clear timeout if (this.timeouts.has(this.container)) { clearTimeout(this.timeouts.get(this.container)); this.timeouts.delete(this.container); } } } // Utility functions const Utils = { // Format postal code consistently formatPostalCode(postalCode) { const cleaned = postalCode.replace(/\s/g, '').toUpperCase(); if (cleaned.length === 6) { return `${cleaned.slice(0, 3)} ${cleaned.slice(3)}`; } return cleaned; }, // Sanitize text input sanitizeText(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }, // Debounce function for input handling debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }, // Check if we're on mobile isMobile() { return window.innerWidth <= 768; }, // Format date for display formatDate(dateString) { const date = new Date(dateString); return date.toLocaleDateString('en-CA', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } }; // Make utils globally available window.Utils = Utils; // Initialize app when DOM is loaded document.addEventListener('DOMContentLoaded', () => { window.mainApp = new MainApp(); // Add some basic accessibility improvements document.addEventListener('keydown', (e) => { // Allow Escape to close modals (handled in individual modules) // Add tab navigation improvements if needed }); // Add responsive behavior window.addEventListener('resize', Utils.debounce(() => { // Handle responsive layout changes if needed const isMobile = Utils.isMobile(); document.body.classList.toggle('mobile', isMobile); }, 250)); // Initial mobile class document.body.classList.toggle('mobile', Utils.isMobile()); });