mirror of
https://github.com/xtr-dev/payload-notifications.git
synced 2025-12-10 19:03:23 +00:00
197 lines
5.5 KiB
JavaScript
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') |