progresspulse-pwa
Version:
A modern PWA for tracking progress and achieving goals with iPhone-style design
140 lines (126 loc) • 3.5 kB
JavaScript
const CACHE_NAME = 'progresspulse-v1';
const urlsToCache = [
'/',
'/static/js/bundle.js',
'/static/css/main.css',
'/manifest.json'
];
// FCM Push Notification Handler
self.addEventListener('push', (event) => {
console.log('Push received:', event);
let notificationData = {
title: 'ProgressPulse',
body: 'You have a new notification',
icon: '/pwa-192x192.png',
badge: '/pwa-64x64.png',
tag: 'default',
requireInteraction: true,
data: {}
};
if (event.data) {
try {
const data = event.data.json();
notificationData = {
...notificationData,
title: data.title || notificationData.title,
body: data.body || data.message || notificationData.body,
icon: data.icon || notificationData.icon,
tag: data.tag || notificationData.tag,
data: data.data || data
};
} catch (e) {
notificationData.body = event.data.text() || notificationData.body;
}
}
event.waitUntil(
self.registration.showNotification(notificationData.title, {
body: notificationData.body,
icon: notificationData.icon,
badge: notificationData.badge,
tag: notificationData.tag,
requireInteraction: notificationData.requireInteraction,
data: notificationData.data,
actions: [
{
action: 'open',
title: 'Open App'
},
{
action: 'close',
title: 'Dismiss'
}
]
})
);
});
// Notification Click Handler
self.addEventListener('notificationclick', (event) => {
console.log('Notification clicked:', event);
event.notification.close();
if (event.action === 'close') {
return;
}
// Open app or focus existing window
event.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true })
.then((clientList) => {
// If app is already open, focus it
for (const client of clientList) {
if (client.url.includes(self.location.origin) && 'focus' in client) {
return client.focus();
}
}
// Otherwise open new window
if (clients.openWindow) {
const targetUrl = event.notification.data?.url || '/';
return clients.openWindow(targetUrl);
}
})
);
});
// Background Sync for offline notifications
self.addEventListener('sync', (event) => {
if (event.tag === 'background-sync') {
event.waitUntil(doBackgroundSync());
}
});
async function doBackgroundSync() {
// Handle offline notification queue
try {
const cache = await caches.open('notifications-cache');
const requests = await cache.keys();
for (const request of requests) {
try {
await fetch(request);
await cache.delete(request);
} catch (error) {
console.log('Background sync failed for:', request.url);
}
}
} catch (error) {
console.error('Background sync error:', error);
}
}
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});