// Service Worker for Push Notifications // Template SaaS v2.0 const CACHE_NAME = 'template-saas-v1'; // Install event self.addEventListener('install', (event) => { console.log('[SW] Installing service worker...'); self.skipWaiting(); }); // Activate event self.addEventListener('activate', (event) => { console.log('[SW] Service worker activated'); event.waitUntil(self.clients.claim()); }); // Push notification received self.addEventListener('push', (event) => { console.log('[SW] Push notification received'); let data = { title: 'Nueva notificacion', body: 'Tienes una nueva notificacion', icon: '/icon-192.png', badge: '/badge-72.png', url: '/', data: {}, }; if (event.data) { try { data = { ...data, ...event.data.json() }; } catch (e) { console.error('[SW] Error parsing push data:', e); } } const options = { body: data.body, icon: data.icon || '/icon-192.png', badge: data.badge || '/badge-72.png', vibrate: [100, 50, 100], tag: data.notificationId || 'default', renotify: true, requireInteraction: data.requireInteraction || false, data: { url: data.url || '/', notificationId: data.notificationId, ...data.data, }, actions: data.actions || [ { action: 'view', title: 'Ver' }, { action: 'dismiss', title: 'Descartar' }, ], }; event.waitUntil( self.registration.showNotification(data.title, options) ); }); // Notification click handler self.addEventListener('notificationclick', (event) => { console.log('[SW] Notification clicked:', event.action); event.notification.close(); if (event.action === 'dismiss') { return; } const url = event.notification.data?.url || '/'; event.waitUntil( self.clients .matchAll({ type: 'window', includeUncontrolled: true }) .then((clientList) => { // Try to find an existing window and navigate for (const client of clientList) { if (client.url.includes(self.location.origin) && 'focus' in client) { return client.focus().then((focusedClient) => { if (focusedClient && 'navigate' in focusedClient) { return focusedClient.navigate(url); } }); } } // If no window found, open a new one if (self.clients.openWindow) { return self.clients.openWindow(url); } }) ); }); // Notification close handler self.addEventListener('notificationclose', (event) => { console.log('[SW] Notification closed'); // Optionally track notification dismissals const notificationId = event.notification.data?.notificationId; if (notificationId) { // Could send analytics here } }); // Push subscription change handler self.addEventListener('pushsubscriptionchange', (event) => { console.log('[SW] Push subscription changed'); event.waitUntil( self.registration.pushManager .subscribe({ userVisibleOnly: true, applicationServerKey: event.oldSubscription?.options?.applicationServerKey, }) .then((subscription) => { // Notify the app about the new subscription return self.clients.matchAll().then((clients) => { clients.forEach((client) => { client.postMessage({ type: 'PUSH_SUBSCRIPTION_CHANGED', subscription: JSON.stringify(subscription), }); }); }); }) ); }); // Message handler (for app communication) self.addEventListener('message', (event) => { console.log('[SW] Message received:', event.data); if (event.data?.type === 'SKIP_WAITING') { self.skipWaiting(); } }); // Background sync (for offline notifications) self.addEventListener('sync', (event) => { console.log('[SW] Background sync:', event.tag); if (event.tag === 'sync-notifications') { event.waitUntil(syncNotifications()); } }); async function syncNotifications() { // This would sync any pending notification actions console.log('[SW] Syncing notifications...'); } console.log('[SW] Service worker loaded');