Files

197 lines
5.5 KiB
JavaScript

/**
* Service Worker for Web Push Notifications
* Payload Notifications Plugin Demo
*/
console.log('[SW] Service worker loaded')
// Service worker lifecycle events
self.addEventListener('install', (event) => {
console.log('[SW] Installing service worker')
self.skipWaiting()
})
self.addEventListener('activate', (event) => {
console.log('[SW] Activating service worker')
event.waitUntil(self.clients.claim())
})
// Handle push events
self.addEventListener('push', (event) => {
console.log('[SW] Push event received')
if (!event.data) {
console.log('[SW] Push event has no data')
return
}
try {
const payload = event.data.json()
console.log('[SW] Push payload:', payload)
const { title, body, icon, badge, image, data, actions, tag, requireInteraction } = payload
const notificationOptions = {
body,
icon: icon || '/icons/notification-icon.png',
badge: badge || '/icons/notification-badge.png',
image,
data,
actions: actions || [
{ action: 'view', title: 'View', icon: '/icons/view.png' },
{ action: 'dismiss', title: 'Dismiss', icon: '/icons/dismiss.png' }
],
tag: tag || 'notification',
requireInteraction: requireInteraction || false,
timestamp: Date.now(),
vibrate: [200, 100, 200],
renotify: true,
}
event.waitUntil(
self.registration.showNotification(title || 'New Notification', notificationOptions)
)
} catch (error) {
console.error('[SW] Error processing push notification:', error)
// Fallback notification
event.waitUntil(
self.registration.showNotification('New Notification', {
body: 'You have a new notification',
icon: '/icons/notification-icon.png',
badge: '/icons/notification-badge.png',
tag: 'fallback',
})
)
}
})
// Handle notification clicks
self.addEventListener('notificationclick', (event) => {
console.log('[SW] Notification click received')
console.log('[SW] Action:', event.action)
console.log('[SW] Notification data:', event.notification.data)
event.notification.close()
const data = event.notification.data || {}
// Handle action button clicks
if (event.action) {
switch (event.action) {
case 'view':
if (data.url) {
event.waitUntil(
clients.openWindow(data.url)
)
} else {
event.waitUntil(
clients.openWindow('/admin/collections/notifications')
)
}
break
case 'dismiss':
// Just close the notification (already done above)
break
default:
console.log('[SW] Unknown action:', event.action)
}
} else {
// Default click behavior - open the admin panel or specific URL
const urlToOpen = data.url || '/admin/collections/notifications'
event.waitUntil(
clients.matchAll({ type: 'window' }).then((windowClients) => {
// Check if there is already an open window
for (const client of windowClients) {
if (client.url.includes('/admin') && 'focus' in client) {
return client.focus()
}
}
// If no admin window is open, open a new one
return clients.openWindow(urlToOpen)
})
)
}
// Track notification click
if (data.notificationId) {
fetch('/api/push-notifications/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'click',
notificationId: data.notificationId,
timestamp: Date.now(),
}),
}).catch((error) => {
console.error('[SW] Failed to track notification click:', error)
})
}
})
// Handle notification close events
self.addEventListener('notificationclose', (event) => {
console.log('[SW] Notification closed:', event.notification.tag)
const data = event.notification.data || {}
// Track notification close
if (data.notificationId) {
fetch('/api/push-notifications/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'close',
notificationId: data.notificationId,
timestamp: Date.now(),
}),
}).catch((error) => {
console.error('[SW] Failed to track notification close:', error)
})
}
})
// Handle background sync (optional)
self.addEventListener('sync', (event) => {
console.log('[SW] Background sync:', event.tag)
if (event.tag === 'push-notification-sync') {
event.waitUntil(
// Handle offline notification sync
Promise.resolve()
)
}
})
// Handle message events from the main thread
self.addEventListener('message', (event) => {
console.log('[SW] Message received:', event.data)
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting()
}
// Handle test notifications sent from the demo page
if (event.data && event.data.type === 'TEST_NOTIFICATION') {
const payload = event.data.payload
self.registration.showNotification(payload.title, {
body: payload.body,
icon: payload.icon,
badge: payload.badge,
data: payload.data,
actions: [
{ action: 'view', title: 'View', icon: '/icons/view.png' },
{ action: 'dismiss', title: 'Dismiss', icon: '/icons/dismiss.png' }
],
tag: 'test-notification',
requireInteraction: false,
timestamp: Date.now(),
vibrate: [200, 100, 200],
})
}
})
console.log('[SW] Service worker setup complete')