feat: Web Push notifications
- VAPID-based push via web-push package - push_subscriptions table: endpoint + keys per user (upsert on conflict) - GET /api/push/vapid-key — public key for subscribe flow - POST/DELETE /api/push/subscribe — store/remove subscription - POST /api/push/test — manual test notification - Hourly scheduler: notifies users day before homework due + countdown expires - SW: push event handler shows notification; notificationclick opens /app - Settings: Push section with enable/disable/test buttons, auto-detects browser support and VAPID availability
This commit is contained in:
@@ -28,6 +28,32 @@ self.addEventListener('activate', e => {
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('push', e => {
|
||||
let data = { title: 'Klassenportal', body: '' };
|
||||
try { data = e.data ? e.data.json() : data; } catch {}
|
||||
e.waitUntil(
|
||||
self.registration.showNotification(data.title, {
|
||||
body: data.body,
|
||||
icon: '/icons/icon-192.png',
|
||||
badge: '/icons/icon-192.png',
|
||||
tag: data.tag || 'kp',
|
||||
renotify: true,
|
||||
data: { url: data.url || '/app' },
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', e => {
|
||||
e.notification.close();
|
||||
const url = e.notification.data?.url || '/app';
|
||||
e.waitUntil(
|
||||
clients.matchAll({ type: 'window', includeUncontrolled: true }).then(list => {
|
||||
const found = list.find(c => c.url.includes(self.location.origin));
|
||||
return found ? found.focus() : clients.openWindow(url);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', e => {
|
||||
const url = new URL(e.request.url);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user