// 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 = `
`;
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 = `
`;
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');
});