From ea308b28a9e8e2f4befde84db4e5b4e7a3319c58 Mon Sep 17 00:00:00 2001 From: Ryan Kegel Date: Wed, 22 Apr 2026 22:01:31 -0400 Subject: [PATCH] feat: refactor notification click handling to improve navigation and action execution --- frontend/vue-app/public/sw.js | 75 ++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/frontend/vue-app/public/sw.js b/frontend/vue-app/public/sw.js index 8794b5f..d74ba1e 100644 --- a/frontend/vue-app/public/sw.js +++ b/frontend/vue-app/public/sw.js @@ -48,13 +48,67 @@ self.addEventListener('notificationclick', function (event) { const entityId = payload.entity_id const entityType = payload.entity_type + function navigateOrOpen(url) { + return clients + .matchAll({ type: 'window', includeUncontrolled: true }) + .then(function (clientList) { + const sameOriginClients = clientList.filter(function (c) { + return new URL(c.url).origin === self.location.origin + }) + if (sameOriginClients.length > 0) { + const client = sameOriginClients[0] + return client.focus().then(function () { + return client.navigate(url) + }) + } + return clients.openWindow(url) + }) + } + + function executeDigestAction(token) { + return fetch('/api/digest-action/' + token, { + method: 'POST', + credentials: 'include', + }) + .then(function (res) { + if (res.ok) { + // Action executed — navigate to parent view to show the result + var successUrl = + childId && entityId && entityType + ? '/parent/' + childId + '?scrollTo=' + entityId + '&entityType=' + entityType + : '/parent' + return navigateOrOpen(successUrl) + } + if (res.status === 401) { + // Not authenticated — navigate with digestToken so the PIN flow executes the action + var authUrl = + childId && entityId && entityType + ? '/parent/' + + childId + + '?digestToken=' + + token + + '&scrollTo=' + + entityId + + '&entityType=' + + entityType + : '/parent' + return navigateOrOpen(authUrl) + } + // Token invalid/used/expired — navigate to parent + return navigateOrOpen(childId ? '/parent/' + childId : '/parent') + }) + .catch(function () { + return navigateOrOpen('/parent') + }) + } + if (event.action === 'approve' && approveToken) { - event.waitUntil(fetch('/api/digest-action/' + approveToken)) + event.waitUntil(executeDigestAction(approveToken)) return } if (event.action === 'deny' && denyToken) { - event.waitUntil(fetch('/api/digest-action/' + denyToken)) + event.waitUntil(executeDigestAction(denyToken)) return } @@ -64,20 +118,5 @@ self.addEventListener('notificationclick', function (event) { ? '/parent/' + childId + '?scrollTo=' + entityId + '&entityType=' + entityType : '/parent' - event.waitUntil( - clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function (clientList) { - const sameOriginClients = clientList.filter(function (c) { - return new URL(c.url).origin === self.location.origin - }) - - if (sameOriginClients.length > 0) { - const client = sameOriginClients[0] - return client.focus().then(function () { - return client.navigate(deepLinkUrl) - }) - } - - return clients.openWindow(deepLinkUrl) - }), - ) + event.waitUntil(navigateOrOpen(deepLinkUrl)) })