store/resources/js/sw.ts

91 lines
3.6 KiB
TypeScript

const sw = self as unknown as ServiceWorkerGlobalScope;
interface ExtendableEvent extends Event {
waitUntil(fn: Promise<unknown>): void;
}
interface PushEvent extends ExtendableEvent {
data: PushMessageData | null;
}
interface PushMessageData {
json(): unknown;
text(): string;
}
interface NotificationEvent extends ExtendableEvent {
notification: Notification;
}
// ──────────────────────────────────────────────────────────────────────────────
// Service Worker: Install & Activate
// ──────────────────────────────────────────────────────────────────────────────
sw.addEventListener('install', () => {
sw.skipWaiting();
});
sw.addEventListener('activate', (event: Event) => {
(event as ExtendableEvent).waitUntil(sw.clients.claim());
});
// ──────────────────────────────────────────────────────────────────────────────
// Push Notification Handler
// ──────────────────────────────────────────────────────────────────────────────
sw.addEventListener('push', (event: Event) => {
const pushEvent = event as PushEvent;
if (!pushEvent.data) {
return;
}
let data: { title?: string; body?: string; icon?: string; url?: string } =
{};
try {
data = pushEvent.data.json() as typeof data;
} catch {
data = { title: 'DST Collection', body: pushEvent.data.text() };
}
const title = data.title ?? 'DST Collection';
const options: NotificationOptions = {
body: data.body ?? '',
icon: data.icon ?? '/assets/pwa-192x192.png',
badge: '/assets/pwa-64x64.png',
data: { url: data.url ?? '/admin/master/categories' },
tag: 'dst-notification',
renotify: true,
};
pushEvent.waitUntil(sw.registration.showNotification(title, options));
});
// ──────────────────────────────────────────────────────────────────────────────
// Notification Click Handler
// ──────────────────────────────────────────────────────────────────────────────
sw.addEventListener('notificationclick', (event: Event) => {
const notifEvent = event as NotificationEvent;
notifEvent.notification.close();
const targetUrl: string =
(notifEvent.notification.data?.url as string) ?? '/admin/dashboard';
notifEvent.waitUntil(
sw.clients
.matchAll({ type: 'window', includeUncontrolled: true })
.then((clientList) => {
for (const client of clientList) {
if ('focus' in client) {
return (client as WindowClient)
.navigate(targetUrl)
.then((c) => c?.focus());
}
}
return sw.clients.openWindow(targetUrl);
}),
);
});