diff --git a/app/javascript/controllers/notifications_controller.js b/app/javascript/controllers/notifications_controller.js index 02fce86d7e..5a2c20a6bb 100644 --- a/app/javascript/controllers/notifications_controller.js +++ b/app/javascript/controllers/notifications_controller.js @@ -9,6 +9,8 @@ export default class extends Controller { async connect() { if (!this.#allowed) return + this.#listenForSubscriptionChanges() + switch(Notification.permission) { case "default": this.subscribeButtonTarget.hidden = false @@ -20,11 +22,20 @@ export default class extends Controller { if (registration && subscription) { this.element.classList.add(this.enabledClass) + } else if (registration) { + this.subscribeButtonTarget.hidden = false + this.element.classList.remove(this.enabledClass) } break } } + disconnect() { + if (this.messageHandler) { + navigator.serviceWorker?.removeEventListener("message", this.messageHandler) + } + } + async attemptToSubscribe() { if (this.#allowed) { const registration = await this.#getServiceWorkerRegistration() || await this.#registerServiceWorker() @@ -50,6 +61,24 @@ export default class extends Controller { return navigator.serviceWorker && window.Notification } + #listenForSubscriptionChanges() { + this.messageHandler = (event) => { + if (event.data?.type === "pushsubscriptionchange") { + this.#syncRenewedSubscription(event.data.subscription) + } + } + navigator.serviceWorker.addEventListener("message", this.messageHandler) + } + + async #syncRenewedSubscription({ endpoint, p256dh_key, auth_key }) { + const body = JSON.stringify({ push_subscription: { endpoint, p256dh_key, auth_key } }) + const response = await post(this.subscriptionsUrlValue, { body, responseKind: "turbo-stream" }) + if (response.ok) { + this.element.classList.add(this.enabledClass) + this.subscribeButtonTarget.hidden = true + } + } + async #getServiceWorkerRegistration() { return navigator.serviceWorker.getRegistration("/service-worker.js", { scope: "/" }) } diff --git a/app/views/pwa/service_worker.js b/app/views/pwa/service_worker.js index df284d5780..a3a1b2c3d2 100644 --- a/app/views/pwa/service_worker.js +++ b/app/views/pwa/service_worker.js @@ -39,3 +39,34 @@ async function openURL(url) { await self.clients.openWindow(url) } } + +self.addEventListener("pushsubscriptionchange", (event) => { + event.waitUntil(resubscribe(event)) +}) + +async function resubscribe(event) { + const oldSubscription = event.oldSubscription + const applicationServerKey = oldSubscription?.options?.applicationServerKey + + if (!applicationServerKey) return + + const newSubscription = await self.registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: applicationServerKey + }) + + await syncSubscriptionWithServer(newSubscription) +} + +async function syncSubscriptionWithServer(subscription) { + const { endpoint, keys: { p256dh, auth } } = subscription.toJSON() + const clients = await self.clients.matchAll({ type: "window" }) + const client = clients[0] + + if (client) { + client.postMessage({ + type: "pushsubscriptionchange", + subscription: { endpoint, p256dh_key: p256dh, auth_key: auth } + }) + } +}