// Calendar Alarms Service Worker // Handles background alarm checking when the main app is not active const SW_VERSION = 'v1.0.0'; const CACHE_NAME = `calendar-alarms-${SW_VERSION}`; const STORAGE_KEY = 'calendar_alarms'; // Install event self.addEventListener('install', event => { console.log(`Service Worker ${SW_VERSION} installing...`); self.skipWaiting(); // Activate immediately }); // Activate event self.addEventListener('activate', event => { console.log(`Service Worker ${SW_VERSION} activated`); event.waitUntil(self.clients.claim()); // Take control immediately }); // Message handler for communication with main app self.addEventListener('message', event => { const { type, data } = event.data; switch (type) { case 'CHECK_ALARMS': handleCheckAlarms(event, data); break; case 'SCHEDULE_ALARM': handleScheduleAlarm(data, event); break; case 'REMOVE_ALARM': handleRemoveAlarm(data, event); break; case 'PING': event.ports[0].postMessage({ type: 'PONG', version: SW_VERSION }); break; default: console.warn('Unknown message type:', type); } }); // Handle alarm checking request function handleCheckAlarms(event, data) { try { // Main app sends alarms data to check const allAlarms = data?.alarms || []; const dueAlarms = checkProvidedAlarms(allAlarms); // Send results back to main app event.ports[0].postMessage({ type: 'ALARMS_DUE', data: dueAlarms }); console.log(`Checked ${allAlarms.length} alarms, found ${dueAlarms.length} due`); } catch (error) { console.error('Error checking alarms:', error); event.ports[0].postMessage({ type: 'ALARM_CHECK_ERROR', error: error.message }); } } // Process alarms sent from main app function checkProvidedAlarms(alarms) { const now = new Date(); const nowStr = formatDateTimeForComparison(now); // Filter alarms that should trigger and are pending const dueAlarms = alarms.filter(alarm => { return alarm.status === 'Pending' && alarm.trigger_time <= nowStr; }); return dueAlarms; } // Handle schedule alarm request (not needed with localStorage approach) function handleScheduleAlarm(alarmData, event) { // Service worker doesn't handle storage with localStorage approach // Main app handles all storage operations event.ports[0].postMessage({ type: 'ALARM_SCHEDULED', data: { success: true, alarmId: alarmData.id } }); } // Handle remove alarm request (not needed with localStorage approach) function handleRemoveAlarm(alarmData, event) { // Service worker doesn't handle storage with localStorage approach // Main app handles all storage operations event.ports[0].postMessage({ type: 'ALARM_REMOVED', data: { success: true, eventUid: alarmData.eventUid } }); } // Format date time for comparison (YYYY-MM-DDTHH:MM:SS) function formatDateTimeForComparison(date) { return date.getFullYear() + '-' + String(date.getMonth() + 1).padStart(2, '0') + '-' + String(date.getDate()).padStart(2, '0') + 'T' + String(date.getHours()).padStart(2, '0') + ':' + String(date.getMinutes()).padStart(2, '0') + ':' + String(date.getSeconds()).padStart(2, '0'); } // Background alarm checking (runs periodically) // Note: Service worker can't access localStorage, so this just pings the main app setInterval(async () => { try { // Notify all clients to check their alarms const clients = await self.clients.matchAll(); clients.forEach(client => { client.postMessage({ type: 'BACKGROUND_ALARM_CHECK_REQUEST' }); }); console.log('Requested alarm check from main app'); } catch (error) { console.error('Background alarm check failed:', error); } }, 60000); // Check every minute // Handle push notifications (for future enhancement) self.addEventListener('push', event => { console.log('Push notification received:', event); // Future: Handle server-sent alarm notifications }); // Handle notification clicks self.addEventListener('notificationclick', event => { console.log('Notification clicked:', event); event.notification.close(); // Focus or open the calendar app event.waitUntil( self.clients.matchAll().then(clients => { // Try to focus existing client for (const client of clients) { if (client.url.includes('localhost') || client.url.includes(self.location.origin)) { return client.focus(); } } // Open new window if no client exists return self.clients.openWindow('/'); }) ); }); console.log(`Calendar Alarms Service Worker ${SW_VERSION} loaded`);