const CACHE_NAME = 'greenhome-1766074058129'; const STATIC_CACHE_NAME = 'greenhome-static-1766074058129'; // Static assets to cache on install const STATIC_FILES_TO_CACHE = [ '/', '/manifest.json', '/icon-192.png', '/icon-512.png', ]; // Check if request is for static assets function isStaticAsset(url) { return ( url.includes('/_next/static/') || url.includes('/_next/image') || url.match(/\.(js|css|woff|woff2|ttf|eot|svg|png|jpg|jpeg|gif|webp|ico)$/i) ); } // Check if request is for external API (skip caching) function isExternalApiRequest(url) { return url.startsWith('http') && !url.startsWith(self.location.origin); } self.addEventListener('install', (event) => { event.waitUntil( (async () => { const cache = await caches.open(STATIC_CACHE_NAME); try { await cache.addAll(STATIC_FILES_TO_CACHE); } catch (error) { console.log('Some static files failed to cache:', error); } // Don't skip waiting automatically - let user decide when to update // await self.skipWaiting(); })() ); }); self.addEventListener('activate', (event) => { event.waitUntil( (async () => { await self.clients.claim(); // Remove old caches const keys = await caches.keys(); await Promise.all( keys .filter((key) => key !== CACHE_NAME && key !== STATIC_CACHE_NAME) .map((key) => caches.delete(key)) ); })() ); }); // Listen for messages from clients (e.g., when user clicks update button) self.addEventListener('message', (event) => { if (event.data && event.data.type === 'SKIP_WAITING') { self.skipWaiting().then(() => { // Notify all clients about update return self.clients.matchAll(); }).then((clients) => { clients.forEach((client) => { client.postMessage({ type: 'SW_UPDATED' }); }); }); } }); self.addEventListener('fetch', (event) => { const { request } = event; const url = new URL(request.url); // Skip non-GET requests and external API requests if (request.method !== 'GET' || isExternalApiRequest(url.href)) { return; } // Handle navigation requests (pages) if (request.mode === 'navigate') { event.respondWith( (async () => { try { // Try network first const preloadResponse = await event.preloadResponse; if (preloadResponse) { const cache = await caches.open(CACHE_NAME); cache.put(request, preloadResponse.clone()); return preloadResponse; } const networkResponse = await fetch(request); // Cache successful responses if (networkResponse.ok) { const cache = await caches.open(CACHE_NAME); cache.put(request, networkResponse.clone()); } return networkResponse; } catch (error) { // Network failed, try cache const cache = await caches.open(CACHE_NAME); const cachedResponse = await cache.match(request); if (cachedResponse) { return cachedResponse; } // Fallback to home page if available const homePage = await cache.match('/'); if (homePage) { return homePage; } // Last resort: return offline page return new Response('Offline - No internet connection', { status: 503, statusText: 'Service Unavailable', headers: { 'Content-Type': 'text/html' }, }); } })() ); return; } // Handle static assets (Cache First strategy) if (isStaticAsset(url.href)) { event.respondWith( (async () => { const cache = await caches.open(STATIC_CACHE_NAME); const cachedResponse = await cache.match(request); if (cachedResponse) { return cachedResponse; } try { const networkResponse = await fetch(request); // Cache successful responses if (networkResponse.ok) { cache.put(request, networkResponse.clone()); } return networkResponse; } catch (error) { // If network fails and no cache, return error return new Response('Resource not available offline', { status: 503, statusText: 'Service Unavailable', }); } })() ); return; } // Handle other requests (Network First strategy) event.respondWith( (async () => { const cache = await caches.open(CACHE_NAME); try { // Try network first const networkResponse = await fetch(request); // Cache successful responses if (networkResponse.ok) { cache.put(request, networkResponse.clone()); } return networkResponse; } catch (error) { // Network failed, try cache const cachedResponse = await cache.match(request); if (cachedResponse) { return cachedResponse; } // Return error if no cache available return new Response('Resource not available offline', { status: 503, statusText: 'Service Unavailable', }); } })() ); });