// Main JavaScript for Simcoe Connect Hub // API Configuration const API_CONFIG = { baseURL: '/api', endpoints: { weather: '/weather', alerts: '/alerts', events: '/events', businesses: '/businesses', chat: '/functions/chatbot-rag' } }; // Utility Functions class Utils { static formatDate(date) { return new Intl.DateTimeFormat('en-CA', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }).format(date); } static debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } static showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 transform transition-transform duration-300 ${ type === 'error' ? 'bg-red-500 text-white' : type === 'success' ? 'bg-green-500 text-white' : 'bg-blue-500 text-white' }`; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.style.transform = 'translateX(100%)'; setTimeout(() => notification.remove(), 300); }, 3000); } } // Live Data Management class LiveDataManager { static async fetchWeatherData() { try { const response = await fetch(`${API_CONFIG.baseURL}${API_CONFIG.endpoints.weather}`); if (!response.ok) throw new Error('Weather data unavailable'); return await response.json(); } catch (error) { console.error('Failed to fetch weather data:', error); return null; } } static async fetchWeatherAlerts() { try { const response = await fetch(`${API_CONFIG.baseURL}${API_CONFIG.endpoints.alerts}`); if (!response.ok) throw new Error('Alert data unavailable'); return await response.json(); } catch (error) { console.error('Failed to fetch weather alerts:', error); return null; } } static async fetchFeaturedEvents() { try { const response = await fetch(`${API_CONFIG.baseURL}${API_CONFIG.endpoints.events}?featured=true&limit=3`); if (!response.ok) throw new Error('Events data unavailable'); return await response.json(); } catch (error) { console.error('Failed to fetch events:', error); return []; } } static async fetchFeaturedBusinesses() { try { const response = await fetch(`${API_CONFIG.baseURL}${API_CONFIG.endpoints.businesses}?featured=true&limit=3`); if (!response.ok) throw new Error('Businesses data unavailable'); return await response.json(); } catch (error) { console.error('Failed to fetch businesses:', error); return []; } } } // UI Controller class UIController { static updateWeatherDisplay(weatherData) { const weatherContainer = document.getElementById('weatherData'); if (!weatherData) { weatherContainer.innerHTML = `

Weather data temporarily unavailable

`; return; } weatherContainer.innerHTML = `
Temperature ${weatherData.temperature}°C
Conditions ${weatherData.conditions}
Updated ${Utils.formatDate(new Date(weatherData.updatedAt))}
`; feather.replace(); } static updateEventsDisplay(events) { const eventsContainer = document.getElementById('eventsList'); if (!events || events.length === 0) { eventsContainer.innerHTML = `

No upcoming events

`; return; } eventsContainer.innerHTML = events.map(event => `

${event.title}

${Utils.formatDate(new Date(event.date))}

`).join(''); } static updateBusinessesDisplay(businesses) { const businessesContainer = document.getElementById('businessesList'); if (!businesses || businesses.length === 0) { businessesContainer.innerHTML = `

No featured businesses

`; return; } businessesContainer.innerHTML = businesses.map(business => `

${business.name}

${business.category}

`).join(''); feather.replace(); } static showWeatherAlert(alert) { if (!alert || !alert.message) return; const alertBanner = document.getElementById('weatherAlert'); const alertText = document.getElementById('alertText'); alertText.textContent = alert.message; alertBanner.classList.remove('hidden'); // Add appropriate styling based on alert severity if (alert.severity === 'high') { alertBanner.className = alertBanner.className.replace('from-primary-500 to-primary-600', 'from-red-500 to-red-600'); } } } // Event Handlers function closeAlert() { const alertBanner = document.getElementById('weatherAlert'); alertBanner.classList.add('hidden'); } // Search functionality const searchHandler = Utils.debounce((query) => { if (query.length > 2) { window.location.href = `/search?q=${encodeURIComponent(query)}`; } }, 500); document.getElementById('mainSearch')?.addEventListener('input', (e) => { searchHandler(e.target.value); }); // Live Data Loading Functions async function loadWeatherData() { const weatherData = await LiveDataManager.fetchWeatherData(); UIController.updateWeatherDisplay(weatherData); } async function checkWeatherAlerts() { const alerts = await LiveDataManager.fetchWeatherAlerts(); if (alerts && alerts.length > 0) { alerts.forEach(alert => UIController.showWeatherAlert(alert)); } } async function loadFeaturedEvents() { const events = await LiveDataManager.fetchFeaturedEvents(); UIController.updateEventsDisplay(events); } async function loadFeaturedBusinesses() { const businesses = await LiveDataManager.fetchFeaturedBusinesses(); UIController.updateBusinessesDisplay(businesses); } // Auto-refresh live data every 30 seconds setInterval(() => { loadWeatherData(); loadFeaturedEvents(); loadFeaturedBusinesses(); checkWeatherAlerts(); }, 30000); // Initialize service worker for offline functionality if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('SW registered: ', registration); }) .catch(registrationError => { console.log('SW registration failed: ', registrationError); }); }); } // Error handling window.addEventListener('error', (event) => { console.error('Global error:', event.error); Utils.showNotification('Something went wrong. Please try again.', 'error'); });