fix(pwa): N105 — notification clicks work after the tab is closed
OS notifications were shown via page-level `new Notification()` whose onclick only works while the originating tab is alive — clicking a notification after closing the tab did nothing. - New `showOsNotification()` (utils/dom) prefers `registration.showNotification()` so the notification is service-worker-owned and persists; falls back to `new Notification()` (with the previous onclick) when no SW is available, so worst case is unchanged behaviour. - sw.ts gains a `notificationclick` handler: focuses an existing app window and forwards the target path, or opens the app if none is open. - ClientNonUIFeatures forwards the SW `notificationClick` message to react-router `navigate()` (works for both hash and browser router configs), and uses a per-room `tag` to coalesce notifications (replacing the old notifRef.close() dedup a SW notification can't hold). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -254,6 +254,42 @@ export const notificationPermission = (permission: NotificationPermission) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show an OS notification.
|
||||
*
|
||||
* Prefers a service-worker-owned notification (`registration.showNotification`)
|
||||
* so the notification persists and its click is handled by the SW
|
||||
* `notificationclick` listener even after the originating tab is closed — the
|
||||
* data.path is forwarded to the SW. Falls back to a page-level `Notification`
|
||||
* (with the provided `onClick`) when no service worker is available, preserving
|
||||
* the previous behaviour.
|
||||
*/
|
||||
export const showOsNotification = async (
|
||||
title: string,
|
||||
options: NotificationOptions & { data?: { path?: string } },
|
||||
onClick?: () => void,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
if ('serviceWorker' in navigator) {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
if (registration && typeof registration.showNotification === 'function') {
|
||||
await registration.showNotification(title, options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// fall through to the page-level Notification below
|
||||
}
|
||||
|
||||
const noti = new Notification(title, options);
|
||||
if (onClick) {
|
||||
noti.onclick = () => {
|
||||
onClick();
|
||||
noti.close();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const getMouseEventCords = (event: MouseEvent) => ({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
|
||||
Reference in New Issue
Block a user