const CACHE_NAME = 'bakery-ai-v2.0.0'; const urlsToCache = [ '/', '/index.html', '/manifest.json', '/manifest.webmanifest', '/favicon.ico', ]; // Install event - cache assets self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); self.skipWaiting(); }); // Activate event - clean up old caches self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames .filter((cacheName) => cacheName !== CACHE_NAME) .map((cacheName) => caches.delete(cacheName)) ); }) ); self.clients.claim(); }); // Fetch event - serve from cache, fallback to network self.addEventListener('fetch', (event) => { // Skip cross-origin requests if (!event.request.url.startsWith(self.location.origin)) { return; } // API calls - network first, cache fallback if (event.request.url.includes('/api/')) { event.respondWith( fetch(event.request) .then((response) => { // Clone the response before caching const responseToCache = response.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(event.request, responseToCache); }); return response; }) .catch(() => { return caches.match(event.request); }) ); return; } // Static assets - network first, cache fallback (for versioned assets) if (event.request.destination === 'script' || event.request.destination === 'style' || event.request.destination === 'image') { event.respondWith( fetch(event.request).then((response) => { // Clone the response before caching const responseToCache = response.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(event.request, responseToCache); }); return response; }).catch(() => { return caches.match(event.request); }) ); } else { // Other requests - cache first, network fallback event.respondWith( caches.match(event.request).then((response) => { return response || fetch(event.request); }) ); } }); // Background sync for offline actions self.addEventListener('sync', (event) => { if (event.tag === 'sync-inventory') { event.waitUntil(syncInventoryData()); } }); // Push notifications self.addEventListener('push', (event) => { const options = { body: event.data ? event.data.text() : 'Nueva notificación de Bakery AI', icon: '/icons/icon-192.png', badge: '/icons/badge-72.png', vibrate: [100, 50, 100], data: { dateOfArrival: Date.now(), primaryKey: 1, }, }; event.waitUntil( self.registration.showNotification('Bakery AI', options) ); }); // Notification click handler self.addEventListener('notificationclick', (event) => { event.notification.close(); event.waitUntil( clients.openWindow('/') ); }); // Helper function for background sync async function syncInventoryData() { try { const cache = await caches.open(CACHE_NAME); const requests = await cache.keys(); const pendingRequests = requests.filter( req => req.url.includes('/api/') && req.method === 'POST' ); for (const request of pendingRequests) { try { await fetch(request); await cache.delete(request); } catch (error) { console.error('Failed to sync:', error); } } } catch (error) { console.error('Sync failed:', error); } }