// Service Worker for Great Lakes Ice Report PWA const CACHE_NAME = 'ice-report-v4'; const OFFLINE_URL = '/offline.html'; // Files to cache for offline functionality const CACHE_FILES = [ '/', '/index.html', '/admin.html', '/privacy.html', '/style.css', '/app.js', '/admin.js', '/utils.js', '/version-footer.js', '/manifest.json', OFFLINE_URL ]; // Install event - cache essential files self.addEventListener('install', (event) => { console.log('Service Worker: Installing...'); event.waitUntil( caches.open(CACHE_NAME) .then((cache) => { console.log('Service Worker: Caching files'); return cache.addAll(CACHE_FILES); }) .then(() => { console.log('Service Worker: Files cached successfully'); return self.skipWaiting(); }) .catch((error) => { console.error('Service Worker: Cache failed:', error); }) ); }); // Activate event - clean up old caches self.addEventListener('activate', (event) => { console.log('Service Worker: Activating...'); event.waitUntil( caches.keys() .then((cacheNames) => { return Promise.all( cacheNames .filter((cacheName) => cacheName !== CACHE_NAME) .map((cacheName) => { console.log('Service Worker: Deleting old cache:', cacheName); return caches.delete(cacheName); }) ); }) .then(() => { console.log('Service Worker: Activated'); return self.clients.claim(); }) ); }); // Fetch event - serve cached content when offline self.addEventListener('fetch', (event) => { // Only handle GET requests if (event.request.method !== 'GET') { return; } // Skip cross-origin requests if (!event.request.url.startsWith(self.location.origin)) { return; } event.respondWith( caches.match(event.request) .then((response) => { // Return cached version if available if (response) { return response; } // Try to fetch from network return fetch(event.request) .then((response) => { // Don't cache non-successful responses if (!response || response.status !== 200 || response.type !== 'basic') { return response; } // Clone the response for caching const responseToCache = response.clone(); // Cache successful responses for static assets if (event.request.url.match(/\.(js|css|html|png|jpg|jpeg|gif|svg|ico|woff|woff2)$/)) { caches.open(CACHE_NAME) .then((cache) => { cache.put(event.request, responseToCache); }); } return response; }) .catch(() => { // If network fails and we're requesting an HTML page, show offline page if (event.request.headers.get('accept').includes('text/html')) { return caches.match(OFFLINE_URL); } // For other requests, just fail throw new Error('Network failed and no cache available'); }); }) ); }); // Background sync for when connection is restored self.addEventListener('sync', (event) => { if (event.tag === 'background-sync') { console.log('Service Worker: Background sync triggered'); // Could implement queued location submissions here } }); // Push notifications (for future use) self.addEventListener('push', (event) => { if (event.data) { const data = event.data.json(); console.log('Service Worker: Push message received:', data); // Could show notifications about severe weather warnings const options = { body: data.body, icon: '/icons/icon-192.png', badge: '/icons/icon-72.png', tag: 'ice-report', renotify: true }; event.waitUntil( self.registration.showNotification(data.title, options) ); } });