diff --git a/components/settings/__tests__/notification-settings.test.tsx b/components/settings/__tests__/notification-settings.test.tsx index a9db650ba..b6047870d 100644 --- a/components/settings/__tests__/notification-settings.test.tsx +++ b/components/settings/__tests__/notification-settings.test.tsx @@ -103,6 +103,20 @@ describe('NotificationSettings - pushNotifyInboxOnly', () => { ); }); + it('checks push again when the user comes back to the tab', async () => { + Object.defineProperty(document, 'visibilityState', { value: 'visible', configurable: true }); + const { findByText } = render(); + await findByText('email.inbox_only'); + const check = webPush.isWebPushEnabled as ReturnType; + await waitFor(() => expect(check).toHaveBeenCalled()); + const before = check.mock.calls.length; + + // Push may have been turned off elsewhere (site settings, another tab) meanwhile. + await act(async () => { window.dispatchEvent(new Event('focus')); }); + + await waitFor(() => expect(check.mock.calls.length).toBeGreaterThan(before)); + }); + it('does not re-sync when push is disabled on this device', async () => { (webPush.isWebPushEnabled as ReturnType).mockResolvedValueOnce(false); render(); diff --git a/components/settings/notification-settings.tsx b/components/settings/notification-settings.tsx index a7a63ab82..2ab9c809b 100644 --- a/components/settings/notification-settings.tsx +++ b/components/settings/notification-settings.tsx @@ -80,16 +80,37 @@ export function NotificationSettings() { const activeRelayLabel = relayOptions.find((option) => option.url === activeRelayUrl)?.label ?? activeRelayUrl; + const busy = pushStatus.kind === 'busy'; + useEffect(() => { if (!supported) return; if (!client) return; const accountId = client.getAccountId(); if (!accountId) return; - void (async () => { - const enabled = await isWebPushEnabled(accountId); - setPushStatus(enabled ? { kind: 'enabled' } : { kind: 'idle' }); - })(); - }, [supported, client]); + let cancelled = false; + const refreshStatus = async () => { + try { + const enabled = await isWebPushEnabled(accountId); + if (!cancelled) { + setPushStatus(enabled ? { kind: 'enabled' } : { kind: 'idle' }); + } + } catch { + if (!cancelled) setPushStatus({ kind: 'idle' }); + } + }; + const onVisible = () => { + if (document.visibilityState === 'visible') void refreshStatus(); + }; + if (pushStatus.kind === 'busy' || pushStatus.kind === 'error') return; + void refreshStatus(); + window.addEventListener('focus', onVisible); + document.addEventListener('visibilitychange', onVisible); + return () => { + cancelled = true; + window.removeEventListener('focus', onVisible); + document.removeEventListener('visibilitychange', onVisible); + }; + }, [supported, client, pushStatus.kind]); // The device list is worth loading even when push is off on this browser - // revoking a stale registration left on another device is exactly what you @@ -108,7 +129,6 @@ export function NotificationSettings() { void refreshDevices(); }, [refreshDevices]); - const busy = pushStatus.kind === 'busy'; const pushEnabled = pushStatus.kind === 'enabled'; // In the static Lite build push is off by design (no service worker, see // components/service-worker-registration.tsx), not a browser limitation.