63 lines
2.1 KiB
JavaScript

// Shows the server's web push notifications and opens the conversation they belong to.
// No fetch handler: the app always loads from the network.
self.addEventListener("install", () => {
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(self.clients.claim());
});
function appPath(value) {
return typeof value === "string" && value.startsWith("/") && !value.startsWith("//")
? value
: "/app";
}
self.addEventListener("push", (event) => {
event.waitUntil(
(async () => {
let data = {};
try {
data = event.data ? event.data.json() : {};
} catch {
data = {};
}
const windows = await self.clients.matchAll({ type: "window", includeUncontrolled: true });
// The app in front of the user already shows what happened.
if (windows.some((client) => client.focused && client.visibilityState === "visible")) return;
await self.registration.showNotification(
typeof data.title === "string" && data.title ? data.title : "evOo",
{
body: typeof data.body === "string" ? data.body : "",
// Same tag as the in-app notification, so one replaces the other.
tag: typeof data.tag === "string" && data.tag ? data.tag : undefined,
icon: "/icon-192.png",
badge: "/icon-192.png",
data: { url: appPath(data.url) },
},
);
})(),
);
});
self.addEventListener("notificationclick", (event) => {
event.notification.close();
event.waitUntil(
(async () => {
const target = new URL(appPath(event.notification.data?.url), self.location.origin).href;
const windows = await self.clients.matchAll({ type: "window", includeUncontrolled: true });
const open =
windows.find((client) => client.url === target) ??
windows.find((client) => new URL(client.url).origin === self.location.origin);
if (!open) {
await self.clients.openWindow(target);
return;
}
const focused = await open.focus();
if (focused.url !== target) await focused.navigate(target).catch(() => undefined);
})(),
);
});