about summary refs log tree commit diff
path: root/src/lib/notifications
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2023-12-06 18:05:59 +0000
committerGitHub <noreply@github.com>2023-12-06 10:05:59 -0800
commitde38595a7a04e3dfe67c5251472f1817152b8116 (patch)
treee5a227e614b26368d52e9a91f9c0cb007e251497 /src/lib/notifications
parent7d158f82fb1c82101c3a0cb637f911ac87e8006b (diff)
downloadvoidsky-de38595a7a04e3dfe67c5251472f1817152b8116.tar.zst
Split notification init, add cleanup (#2102)
* Inline never-imported export

* Remove pretense at handling cleanup

* Extract per-session listener to a function

* Split notifications.init() from notifications.onSessionLoaded()

* Tweak forked code to be more similar

* Remove unnecessary guards

* Split notifications.onSessionLoaded in two

* Always use getAgent()

* Remove dep on listenSessionLoaded, add cleanup
Diffstat (limited to 'src/lib/notifications')
-rw-r--r--src/lib/notifications/notifications.ts161
1 files changed, 77 insertions, 84 deletions
diff --git a/src/lib/notifications/notifications.ts b/src/lib/notifications/notifications.ts
index 6e79e6b91..d115dc98f 100644
--- a/src/lib/notifications/notifications.ts
+++ b/src/lib/notifications/notifications.ts
@@ -6,75 +6,80 @@ import {track} from 'lib/analytics/analytics'
 import {logger} from '#/logger'
 import {RQKEY as RQKEY_NOTIFS} from '#/state/queries/notifications/feed'
 import {truncateAndInvalidate} from '#/state/queries/util'
-import {listenSessionLoaded} from '#/state/events'
+import {SessionAccount, getAgent} from '#/state/session'
 
 const SERVICE_DID = (serviceUrl?: string) =>
   serviceUrl?.includes('staging')
     ? 'did:web:api.staging.bsky.dev'
     : 'did:web:api.bsky.app'
 
-export function init(queryClient: QueryClient) {
-  listenSessionLoaded(async (account, agent) => {
-    // request notifications permission once the user has logged in
-    const perms = await Notifications.getPermissionsAsync()
-    if (!perms.granted) {
-      await Notifications.requestPermissionsAsync()
-    }
+export async function requestPermissionsAndRegisterToken(
+  account: SessionAccount,
+) {
+  // request notifications permission once the user has logged in
+  const perms = await Notifications.getPermissionsAsync()
+  if (!perms.granted) {
+    await Notifications.requestPermissionsAsync()
+  }
 
-    // register the push token with the server
-    const token = await getPushToken()
-    if (token) {
-      try {
-        await agent.api.app.bsky.notification.registerPush({
-          serviceDid: SERVICE_DID(account.service),
-          platform: devicePlatform,
-          token: token.data,
-          appId: 'xyz.blueskyweb.app',
-        })
-        logger.debug(
-          'Notifications: Sent push token (init)',
-          {
-            tokenType: token.type,
-            token: token.data,
-          },
-          logger.DebugContext.notifications,
-        )
-      } catch (error) {
-        logger.error('Notifications: Failed to set push token', {error})
-      }
-    }
+  // register the push token with the server
+  const token = await Notifications.getDevicePushTokenAsync()
+  try {
+    await getAgent().api.app.bsky.notification.registerPush({
+      serviceDid: SERVICE_DID(account.service),
+      platform: devicePlatform,
+      token: token.data,
+      appId: 'xyz.blueskyweb.app',
+    })
+    logger.debug(
+      'Notifications: Sent push token (init)',
+      {
+        tokenType: token.type,
+        token: token.data,
+      },
+      logger.DebugContext.notifications,
+    )
+  } catch (error) {
+    logger.error('Notifications: Failed to set push token', {error})
+  }
+}
 
-    // listens for new changes to the push token
-    // In rare situations, a push token may be changed by the push notification service while the app is running. When a token is rolled, the old one becomes invalid and sending notifications to it will fail. A push token listener will let you handle this situation gracefully by registering the new token with your backend right away.
-    Notifications.addPushTokenListener(async ({data: t, type}) => {
+export function registerTokenChangeHandler(
+  account: SessionAccount,
+): () => void {
+  // listens for new changes to the push token
+  // In rare situations, a push token may be changed by the push notification service while the app is running. When a token is rolled, the old one becomes invalid and sending notifications to it will fail. A push token listener will let you handle this situation gracefully by registering the new token with your backend right away.
+  const sub = Notifications.addPushTokenListener(async newToken => {
+    logger.debug(
+      'Notifications: Push token changed',
+      {tokenType: newToken.data, token: newToken.type},
+      logger.DebugContext.notifications,
+    )
+    try {
+      await getAgent().api.app.bsky.notification.registerPush({
+        serviceDid: SERVICE_DID(account.service),
+        platform: devicePlatform,
+        token: newToken.data,
+        appId: 'xyz.blueskyweb.app',
+      })
       logger.debug(
-        'Notifications: Push token changed',
-        {t, tokenType: type},
+        'Notifications: Sent push token (event)',
+        {
+          tokenType: newToken.type,
+          token: newToken.data,
+        },
         logger.DebugContext.notifications,
       )
-      if (t) {
-        try {
-          await agent.api.app.bsky.notification.registerPush({
-            serviceDid: SERVICE_DID(account.service),
-            platform: devicePlatform,
-            token: t,
-            appId: 'xyz.blueskyweb.app',
-          })
-          logger.debug(
-            'Notifications: Sent push token (event)',
-            {
-              tokenType: type,
-              token: t,
-            },
-            logger.DebugContext.notifications,
-          )
-        } catch (error) {
-          logger.error('Notifications: Failed to set push token', {error})
-        }
-      }
-    })
+    } catch (error) {
+      logger.error('Notifications: Failed to set push token', {error})
+    }
   })
+  return () => {
+    sub.remove()
+  }
+}
 
+export function init(queryClient: QueryClient) {
   // handle notifications that are received, both in the foreground or background
   Notifications.addNotificationReceivedListener(event => {
     logger.debug(
@@ -104,35 +109,23 @@ export function init(queryClient: QueryClient) {
   })
 
   // handle notifications that are tapped on
-  const sub = Notifications.addNotificationResponseReceivedListener(
-    response => {
+  Notifications.addNotificationResponseReceivedListener(response => {
+    logger.debug(
+      'Notifications: response received',
+      {
+        actionIdentifier: response.actionIdentifier,
+      },
+      logger.DebugContext.notifications,
+    )
+    if (response.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER) {
       logger.debug(
-        'Notifications: response received',
-        {
-          actionIdentifier: response.actionIdentifier,
-        },
+        'User pressed a notification, opening notifications tab',
+        {},
         logger.DebugContext.notifications,
       )
-      if (
-        response.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER
-      ) {
-        logger.debug(
-          'User pressed a notification, opening notifications tab',
-          {},
-          logger.DebugContext.notifications,
-        )
-        track('Notificatons:OpenApp')
-        truncateAndInvalidate(queryClient, RQKEY_NOTIFS())
-        resetToTab('NotificationsTab') // open notifications tab
-      }
-    },
-  )
-
-  return () => {
-    sub.remove()
-  }
-}
-
-export function getPushToken() {
-  return Notifications.getDevicePushTokenAsync()
+      track('Notificatons:OpenApp')
+      truncateAndInvalidate(queryClient, RQKEY_NOTIFS())
+      resetToTab('NotificationsTab') // open notifications tab
+    }
+  })
 }