diff --git a/components/serviceworker.js b/components/serviceworker.js index 5266e3fb5..58d6745f4 100644 --- a/components/serviceworker.js +++ b/components/serviceworker.js @@ -158,9 +158,10 @@ export const ServiceWorkerProvider = ({ children }) => { // since (a lot of) browsers don't support the pushsubscriptionchange event, // we sync with server manually by checking on every page reload if the push subscription changed. // see https://medium.com/@madridserginho/how-to-handle-webpush-api-pushsubscriptionchange-event-in-modern-browsers-6e47840d756f + navigator?.serviceWorker?.controller?.postMessage?.({ action: STORE_OS, os: detectOS() }) + logger.info('sent STORE_OS to service worker: ', detectOS()) navigator?.serviceWorker?.controller?.postMessage?.({ action: SYNC_SUBSCRIPTION }) logger.info('sent SYNC_SUBSCRIPTION to service worker') - navigator?.serviceWorker?.controller?.postMessage?.({ action: STORE_OS, os: detectOS() }) }, [registration, permission.notification]) const contextValue = useMemo(() => ({ diff --git a/sw/eventListener.js b/sw/eventListener.js index 1efdee342..ed34eb744 100644 --- a/sw/eventListener.js +++ b/sw/eventListener.js @@ -11,11 +11,20 @@ const storage = new ServiceWorkerStorage('sw:storage', 1) let messageChannelPort let actionChannelPort -// TODO 756.2 Fix iOS check, initialValue isn't updated if iOS is true +// DONE 756.2 Fix iOS check, initialValue isn't updated if iOS is true +// FIX: store os in ServiceWorkerStorage and update it on every STORE_OS message + // operating system. the value will be received via a STORE_OS message from app since service workers don't have access to window.navigator let os = '' const iOS = () => os === 'iOS' +async function getOS () { + if (!os) { + os = await storage.getItem('os') || '' + } + return os +} + // current push notification count for badge purposes let activeCount = 0 @@ -32,7 +41,7 @@ export function onPush (sw) { // generate random ID for every incoming push for better tracing in logs const nid = crypto.randomUUID() log(`[sw:push] ${nid} - received notification with tag ${tag}`) - + const currentOS = await getOS() // due to missing proper tag support in Safari on iOS, we can't rely on the tag built-in filter. // we therefore fetch all notifications with the same tag and manually filter them, too. // see https://bugs.webkit.org/show_bug.cgi?id=258922 @@ -57,7 +66,7 @@ export function onPush (sw) { // close them and then we display the notification. const notifications = await sw.registration.getNotifications({ tag }) // we only close notifications manually on iOS because we don't want to degrade android UX just because iOS is behind in their support. - if (iOS()) { + if (currentOS === 'iOS') { log(`[sw:push] ${nid} - closing existing notifications`) notifications.filter(({ tag: nTag }) => nTag === tag).forEach(n => n.close()) } @@ -85,7 +94,7 @@ export function onPush (sw) { // return null } - return await mergeAndShowNotification(sw, payload, notifications, tag, nid) + return await mergeAndShowNotification(sw, payload, notifications, tag, nid, currentOS) })()) } } @@ -95,7 +104,7 @@ export function onPush (sw) { const immediatelyShowNotification = (tag) => !tag || ['TIP', 'FORWARDEDTIP', 'EARN', 'STREAK', 'TERRITORY_TRANSFER'].includes(tag.split('-')[0]) -const mergeAndShowNotification = async (sw, payload, currentNotifications, tag, nid) => { +const mergeAndShowNotification = async (sw, payload, currentNotifications, tag, nid, currentOS) => { // sanity check const otherTagNotifications = currentNotifications.filter(({ tag: nTag }) => nTag !== tag) if (otherTagNotifications.length > 0) { @@ -120,7 +129,7 @@ const mergeAndShowNotification = async (sw, payload, currentNotifications, tag, const SUM_SATS_TAGS = ['DEPOSIT', 'WITHDRAWAL'] // this should reflect the amount of notifications that were already merged before let initialAmount = currentNotifications[0]?.data?.amount || 1 - if (iOS()) initialAmount = 1 + if (currentOS === 'iOS') initialAmount = 1 log(`[sw:push] ${nid} - initial amount: ${initialAmount}`) const mergedPayload = currentNotifications.reduce((acc, { data }) => { let newAmount, newSats @@ -132,7 +141,7 @@ const mergeAndShowNotification = async (sw, payload, currentNotifications, tag, } const newPayload = { ...data, amount: newAmount, sats: newSats } return newPayload - }, { ...incomingData, amount: 1 }) // 1 is hard coded to test iOS scenario, should be initialValue + }, { ...incomingData, amount: initialAmount }) log(`[sw:push] ${nid} - merged payload: ${JSON.stringify(mergedPayload)}`) @@ -177,7 +186,6 @@ const mergeAndShowNotification = async (sw, payload, currentNotifications, tag, } // TODO 756.3 sometimes you get sent to very old threads, this is because the notification is not updated -// PROPOSAL close all notifications with the same tag export function onNotificationClick (sw) { return (event) => { @@ -253,19 +261,21 @@ export function onPushSubscriptionChange (sw) { } export function onMessage (sw) { - return (event) => { + return async (event) => { if (event.data.action === ACTION_PORT) { actionChannelPort = event.ports[0] return } if (event.data.action === STORE_OS) { - os = event.data.os + event.waitUntil(storage.setItem('os', event.data.os)) return } if (event.data.action === MESSAGE_PORT) { messageChannelPort = event.ports[0] } log('[sw:message] received message', 'info', { action: event.data.action }) + const currentOS = await getOS() + log('[sw:message] stored os: ' + currentOS, 'info', { action: event.data.action }) if (event.data.action === STORE_SUBSCRIPTION) { log('[sw:message] storing subscription in IndexedDB', 'info', { endpoint: event.data.subscription.endpoint }) return event.waitUntil(storage.setItem('subscription', { ...event.data.subscription, swVersion: 2 }))