- Service worker + Web Push API for browser/mobile notifications - PWA manifest with icons for home screen install (iOS 16.4+) - Push subscription management (subscribe/unsubscribe API routes) - Notification toggle in Settings > General - Push scheduler script (cron) checks cached events and sends notifications at reminder times, with dedup tracking - Test notification endpoint at /api/push/test - Persists reminders in calendar event cache for scheduler access - New DB models: PushSubscription, SentNotification - New user field: notificationsEnabled Setup: generate VAPID keys with `npx tsx scripts/generate-vapid-keys.ts` and add to .env, then run scheduler via cron every minute. v1.37.0
52 lines
1.3 KiB
JavaScript
52 lines
1.3 KiB
JavaScript
// Push notification service worker
|
|
self.addEventListener('push', function(event) {
|
|
if (!event.data) return;
|
|
|
|
let data;
|
|
try {
|
|
data = event.data.json();
|
|
} catch (e) {
|
|
data = { title: 'Calendar Reminder', body: event.data.text() };
|
|
}
|
|
|
|
const options = {
|
|
body: data.body || '',
|
|
icon: data.icon || '/icons/icon-192.png',
|
|
badge: '/icons/icon-192.png',
|
|
data: { url: data.url || '/tasks' },
|
|
vibrate: [200, 100, 200],
|
|
tag: data.eventId || 'calendar-reminder',
|
|
renotify: true,
|
|
};
|
|
|
|
event.waitUntil(
|
|
self.registration.showNotification(data.title || 'Calendar Reminder', options)
|
|
);
|
|
});
|
|
|
|
self.addEventListener('notificationclick', function(event) {
|
|
event.notification.close();
|
|
|
|
const url = event.notification.data?.url || '/tasks';
|
|
|
|
event.waitUntil(
|
|
clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function(clientList) {
|
|
// Focus existing window if available
|
|
for (var i = 0; i < clientList.length; i++) {
|
|
var client = clientList[i];
|
|
if (client.url.includes('/tasks') && 'focus' in client) {
|
|
return client.focus();
|
|
}
|
|
}
|
|
// Open new window
|
|
if (clients.openWindow) {
|
|
return clients.openWindow(url);
|
|
}
|
|
})
|
|
);
|
|
});
|
|
|
|
self.addEventListener('activate', function(event) {
|
|
event.waitUntil(clients.claim());
|
|
});
|