diff --git a/pos/static/pwa/sw.js b/pos/static/pwa/sw.js index 9fff508..94fd3ab 100644 --- a/pos/static/pwa/sw.js +++ b/pos/static/pwa/sw.js @@ -1,8 +1,8 @@ // /home/Autopartes/pos/static/pwa/sw.js -// Nexus POS — Service Worker v3 +// Nexus POS — Service Worker v5 // Self-contained vanilla JS. No external imports. -const CACHE_NAME = 'nexus-pos-v4'; +const CACHE_NAME = 'nexus-pos-v5'; const APP_SHELL = [ '/pos/login', @@ -31,6 +31,7 @@ const APP_SHELL = [ '/pos/static/js/reports.js', '/pos/static/js/offline-banner.js', '/pos/static/js/sync-engine.js', + '/pos/static/js/brand-catalog.js', '/pos/static/pwa/manifest.json', '/pos/static/pwa/icon-192.png', '/pos/static/pwa/icon-512.png' @@ -126,12 +127,12 @@ self.addEventListener('fetch', function (event) { return; } - // Never cache auth endpoints — tokens must always come from the server + // Never cache auth endpoints if (url.pathname.indexOf('/pos/api/auth/') !== -1) { return; } - // Don't cache login page — always fetch fresh to avoid stale redirects + // Don't cache login page if (url.pathname === '/pos/login' || url.pathname === '/pos/login/') { event.respondWith(networkFirst(req)); return; @@ -143,7 +144,6 @@ self.addEventListener('fetch', function (event) { fetch(req.clone()).then(function (response) { return response; }).catch(function () { - // Clone request body to store it for later retry return req.clone().text().then(function (bodyText) { var entry = { url: req.url, @@ -156,19 +156,13 @@ self.addEventListener('fetch', function (event) { }).then(function () { return new Response( JSON.stringify({ queued: true, message: 'Added to offline queue' }), - { - status: 200, - headers: { 'Content-Type': 'application/json' } - } + { status: 200, headers: { 'Content-Type': 'application/json' } } ); }).catch(function (err) { console.error('[SW] Failed to queue offline cart request:', err); return new Response( JSON.stringify({ queued: false, message: 'Failed to queue request' }), - { - status: 503, - headers: { 'Content-Type': 'application/json' } - } + { status: 503, headers: { 'Content-Type': 'application/json' } } ); }) }) @@ -176,31 +170,31 @@ self.addEventListener('fetch', function (event) { return; } - // API calls → network-first (except WhatsApp which must be real-time) + // WhatsApp endpoints need fresh data if (url.pathname.indexOf('/pos/api/whatsapp/') !== -1) { - // WhatsApp endpoints need fresh server data; skip SW caching return; } + + // API calls -> network-first if (url.pathname.indexOf('/pos/api/') !== -1) { event.respondWith(networkFirst(req)); return; } - // Everything else → cache-first + // Everything else -> cache-first event.respondWith(cacheFirst(req)); }); function cacheFirst(request) { return caches.match(request).then(function (cached) { if (cached) { - // Update cache in background fetch(request).then(function (response) { if (response && response.status === 200) { caches.open(CACHE_NAME).then(function (cache) { cache.put(request, response); }); } - }).catch(function () { /* offline, ignore */ }); + }).catch(function () {}); return cached; } return fetch(request).then(function (response) { @@ -230,7 +224,6 @@ function networkFirst(request) { } // ─── Background Sync ───────────────────────────────────────────── -// Existing sync handler + new cart-specific sync self.addEventListener('sync', function (event) { if (event.tag === 'nexus-pos-sync') { event.waitUntil( @@ -250,8 +243,6 @@ self.addEventListener('sync', function (event) { return; } console.log('[SW] Syncing', entries.length, 'pending cart action(s)...'); - - // Replay each pending request to the server var syncPromises = entries.map(function (entry) { return fetch(entry.url, { method: entry.method, @@ -268,7 +259,6 @@ self.addEventListener('sync', function (event) { return { ok: false, id: entry.id }; }); }); - return Promise.all(syncPromises).then(function (results) { var allOk = results.every(function (r) { return r.ok; }); if (allOk) { @@ -276,7 +266,6 @@ self.addEventListener('sync', function (event) { console.log('[SW] All cart actions synced. Pending queue cleared.'); }); } else { - // Remove only successfully synced entries; failed ones will retry next time var failedIds = results.filter(function (r) { return !r.ok; }).map(function (r) { return r.id; }); console.warn('[SW] Some cart actions failed. Keeping', failedIds.length, 'entries for retry.'); } @@ -298,7 +287,6 @@ self.addEventListener('push', function (event) { data = { title: event.data.text() }; } } - var title = data.title || 'Nexus POS'; var options = { body: data.body || 'Tienes una nueva notificación del POS.', @@ -308,7 +296,6 @@ self.addEventListener('push', function (event) { data: data.data || { url: '/pos/sale' }, requireInteraction: false }; - event.waitUntil( self.registration.showNotification(title, options) ); @@ -317,14 +304,11 @@ self.addEventListener('push', function (event) { // ─── Notification Click ────────────────────────────────────────── self.addEventListener('notificationclick', function (event) { event.notification.close(); - var targetUrl = event.notification.data && event.notification.data.url ? event.notification.data.url : '/pos/sale'; - event.waitUntil( self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function (clientList) { - // Focus existing tab if it matches the target scope for (var i = 0; i < clientList.length; i++) { var client = clientList[i]; if (client.url.indexOf('/pos/') !== -1 && 'focus' in client) { @@ -335,7 +319,6 @@ self.addEventListener('notificationclick', function (event) { }); } } - // Otherwise open a new window if (self.clients.openWindow) { return self.clients.openWindow(targetUrl); } @@ -343,28 +326,11 @@ self.addEventListener('notificationclick', function (event) { ); }); -// ─── Periodic Background Sync (stub for future use) ────────────── -// This can be used to warm the cache daily or refresh catalog data -// in the background. Requires user permission and browser support. -// self.addEventListener('periodicsync', function (event) { -// if (event.tag === 'nexus-daily-sync') { -// event.waitUntil( -// // e.g. cache warming, catalog refresh, etc. -// caches.open(CACHE_NAME).then(function (cache) { -// return cache.add('/pos/api/catalog/refresh'); -// }).catch(function (err) { -// console.error('[SW] periodicsync failed:', err); -// }) -// ); -// } -// }); - // ─── Message handler ───────────────────────────────────────────── self.addEventListener('message', function (event) { if (event.data && event.data.type === 'SKIP_WAITING') { self.skipWaiting(); } - if (event.data && event.data.type === 'CLEAR_CACHES') { event.waitUntil( caches.keys().then(function (names) {