elk/service-worker/web-push-notifications.ts
2022-12-26 10:13:59 +01:00

86 lines
2.3 KiB
TypeScript

/// <reference lib="WebWorker" />
/// <reference types="vite/client" />
import type { PushPayload } from '~/service-worker/types'
declare const self: ServiceWorkerGlobalScope
export const onPush = (event: PushEvent) => {
const promise = isClientFocused().then((isFocused) => {
if (isFocused)
return Promise.resolve()
const options: PushPayload = event.data!.json()
const {
access_token,
body,
icon,
notification_id,
notification_type,
preferred_locale,
} = options
let url = 'home'
if (notification_type) {
switch (notification_type) {
case 'follow':
url = 'notifications'
break
case 'mention':
url = 'notifications/mention'
break
}
}
const notificationOptions: NotificationOptions = {
badge: '/pwa-192x192.png',
body,
data: {
access_token,
preferred_locale,
url: `/${url}`,
},
dir: 'auto',
icon,
lang: preferred_locale,
tag: notification_id,
timestamp: new Date().getTime(),
}
return self.registration.showNotification(options.title, notificationOptions)
})
event.waitUntil(promise)
}
export const onNotificationClick = (event: NotificationEvent) => {
const reactToNotificationClick = new Promise((resolve) => {
event.notification.close()
resolve(openUrl(event.notification.data.url))
})
event.waitUntil(reactToNotificationClick)
}
function findBestClient(clients: WindowClient[]) {
const focusedClient = clients.find(client => client.focused)
const visibleClient = clients.find(client => client.visibilityState === 'visible')
return focusedClient || visibleClient || clients[0]
}
async function openUrl(url: string) {
const clients = await self.clients.matchAll({ type: 'window' })
// Chrome 42-48 does not support navigate
if (clients.length !== 0 && 'navigate' in clients[0]) {
const client = findBestClient(clients as WindowClient[])
await client.navigate(url).then(client => client?.focus())
}
await self.clients.openWindow(url)
}
function isClientFocused() {
return self.clients
.matchAll({ type: 'window', includeUncontrolled: true })
.then(windowClients => Promise.resolve(windowClients.some(windowClient => windowClient.focused)))
}