Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions app/javascript/controllers/notifications_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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: "/" })
}
Expand Down
31 changes: 31 additions & 0 deletions app/views/pwa/service_worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
})
}
}