about summary refs log tree commit diff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/analytics/analytics.tsx158
-rw-r--r--src/lib/analytics/analytics.web.tsx80
-rw-r--r--src/lib/analytics/types.ts181
-rw-r--r--src/lib/hooks/useAccountSwitcher.ts5
-rw-r--r--src/lib/hooks/useNotificationHandler.ts24
5 files changed, 12 insertions, 436 deletions
diff --git a/src/lib/analytics/analytics.tsx b/src/lib/analytics/analytics.tsx
deleted file mode 100644
index 5f93d982f..000000000
--- a/src/lib/analytics/analytics.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import React from 'react'
-import {AppState, AppStateStatus} from 'react-native'
-import AsyncStorage from '@react-native-async-storage/async-storage'
-import {createClient, SegmentClient} from '@segment/analytics-react-native'
-import * as Sentry from '@sentry/react-native'
-import {sha256} from 'js-sha256'
-
-import {logger} from '#/logger'
-import {SessionAccount, useSession} from '#/state/session'
-import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
-
-type AppInfo = {
-  build?: string | undefined
-  name?: string | undefined
-  namespace?: string | undefined
-  version?: string | undefined
-}
-
-// Delay creating until first actual use.
-let segmentClient: SegmentClient | null = null
-function getClient(): SegmentClient {
-  if (!segmentClient) {
-    segmentClient = createClient({
-      writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
-      trackAppLifecycleEvents: false,
-      proxy: 'https://api.events.bsky.app/v1',
-    })
-  }
-  return segmentClient
-}
-
-export const track = async <E extends keyof TrackPropertiesMap>(
-  event: E,
-  properties?: TrackPropertiesMap[E],
-) => {
-  await getClient().track(event, properties)
-}
-
-export function useAnalytics() {
-  const {hasSession} = useSession()
-
-  return React.useMemo(() => {
-    if (hasSession) {
-      return {
-        async screen<E extends keyof ScreenPropertiesMap>(
-          event: E,
-          properties?: ScreenPropertiesMap[E],
-        ) {
-          await getClient().screen(event, properties)
-        },
-        async track<E extends keyof TrackPropertiesMap>(
-          event: E,
-          properties?: TrackPropertiesMap[E],
-        ) {
-          await getClient().track(event, properties)
-        },
-      }
-    }
-    // dont send analytics pings for anonymous users
-    return {
-      screen: async () => {},
-      track: async () => {},
-    }
-  }, [hasSession])
-}
-
-export function init(account: SessionAccount | undefined) {
-  setupListenersOnce()
-
-  if (account) {
-    const client = getClient()
-    if (account.did) {
-      const did_hashed = sha256(account.did)
-      client.identify(did_hashed, {did_hashed})
-      Sentry.setUser({id: did_hashed})
-      logger.debug('Ping w/hash')
-    } else {
-      logger.debug('Ping w/o hash')
-      client.identify()
-    }
-  }
-}
-
-let didSetupListeners = false
-function setupListenersOnce() {
-  if (didSetupListeners) {
-    return
-  }
-  didSetupListeners = true
-  // NOTE
-  // this is a copy of segment's own lifecycle event tracking
-  // we handle it manually to ensure that it never fires while the app is backgrounded
-  // -prf
-  const client = getClient()
-  client.isReady.onChange(async () => {
-    if (AppState.currentState !== 'active') {
-      logger.debug('Prevented a metrics ping while the app was backgrounded')
-      return
-    }
-    const context = client.context.get()
-    if (typeof context?.app === 'undefined') {
-      logger.debug('Aborted metrics ping due to unavailable context')
-      return
-    }
-
-    const oldAppInfo = await readAppInfo()
-    const newAppInfo = context.app as AppInfo
-    writeAppInfo(newAppInfo)
-    logger.debug('Recording app info', {new: newAppInfo, old: oldAppInfo})
-
-    if (typeof oldAppInfo === 'undefined') {
-      client.track('Application Installed', {
-        version: newAppInfo.version,
-        build: newAppInfo.build,
-      })
-    } else if (newAppInfo.version !== oldAppInfo.version) {
-      client.track('Application Updated', {
-        version: newAppInfo.version,
-        build: newAppInfo.build,
-        previous_version: oldAppInfo.version,
-        previous_build: oldAppInfo.build,
-      })
-    }
-    client.track('Application Opened', {
-      from_background: false,
-      version: newAppInfo.version,
-      build: newAppInfo.build,
-    })
-  })
-
-  let lastState: AppStateStatus = AppState.currentState
-  AppState.addEventListener('change', (state: AppStateStatus) => {
-    if (state === 'active' && lastState !== 'active') {
-      const context = client.context.get()
-      client.track('Application Opened', {
-        from_background: true,
-        version: context?.app?.version,
-        build: context?.app?.build,
-      })
-    } else if (state !== 'active' && lastState === 'active') {
-      client.track('Application Backgrounded')
-    }
-    lastState = state
-  })
-}
-
-async function writeAppInfo(value: AppInfo) {
-  await AsyncStorage.setItem('BSKY_APP_INFO', JSON.stringify(value))
-}
-
-async function readAppInfo(): Promise<AppInfo | undefined> {
-  const rawData = await AsyncStorage.getItem('BSKY_APP_INFO')
-  const obj = rawData ? JSON.parse(rawData) : undefined
-  if (!obj || typeof obj !== 'object') {
-    return undefined
-  }
-  return obj
-}
diff --git a/src/lib/analytics/analytics.web.tsx b/src/lib/analytics/analytics.web.tsx
deleted file mode 100644
index c7f0ed3b1..000000000
--- a/src/lib/analytics/analytics.web.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React from 'react'
-import {createClient} from '@segment/analytics-react'
-import * as Sentry from '@sentry/react-native'
-import {sha256} from 'js-sha256'
-
-import {logger} from '#/logger'
-import {SessionAccount, useSession} from '#/state/session'
-import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
-
-type SegmentClient = ReturnType<typeof createClient>
-
-// Delay creating until first actual use.
-let segmentClient: SegmentClient | null = null
-function getClient(): SegmentClient {
-  if (!segmentClient) {
-    segmentClient = createClient(
-      {
-        writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
-      },
-      {
-        integrations: {
-          'Segment.io': {
-            apiHost: 'api.events.bsky.app/v1',
-          },
-        },
-      },
-    )
-  }
-  return segmentClient
-}
-
-export const track = async <E extends keyof TrackPropertiesMap>(
-  event: E,
-  properties?: TrackPropertiesMap[E],
-) => {
-  await getClient().track(event, properties)
-}
-
-export function useAnalytics() {
-  const {hasSession} = useSession()
-
-  return React.useMemo(() => {
-    if (hasSession) {
-      return {
-        async screen<E extends keyof ScreenPropertiesMap>(
-          event: E,
-          properties?: ScreenPropertiesMap[E],
-        ) {
-          await getClient().screen(event, properties)
-        },
-        async track<E extends keyof TrackPropertiesMap>(
-          event: E,
-          properties?: TrackPropertiesMap[E],
-        ) {
-          await getClient().track(event, properties)
-        },
-      }
-    }
-    // dont send analytics pings for anonymous users
-    return {
-      screen: async () => {},
-      track: async () => {},
-    }
-  }, [hasSession])
-}
-
-export function init(account: SessionAccount | undefined) {
-  if (account) {
-    const client = getClient()
-    if (account.did) {
-      const did_hashed = sha256(account.did)
-      client.identify(did_hashed, {did_hashed})
-      Sentry.setUser({id: did_hashed})
-      logger.debug('Ping w/hash')
-    } else {
-      logger.debug('Ping w/o hash')
-      client.identify()
-    }
-  }
-}
diff --git a/src/lib/analytics/types.ts b/src/lib/analytics/types.ts
deleted file mode 100644
index 720495ea1..000000000
--- a/src/lib/analytics/types.ts
+++ /dev/null
@@ -1,181 +0,0 @@
-export type TrackPropertiesMap = {
-  // LOGIN / SIGN UP events
-  'Sign In': {resumedSession: boolean} // CAN BE SERVER
-  'Create Account': {} // CAN BE SERVER
-  'Try Create Account': {}
-  'Signin:PressedForgotPassword': {}
-  'Signin:PressedSelectService': {}
-  // COMPOSER / CREATE POST events
-  'Create Post': {imageCount: string | number} // CAN BE SERVER
-  'Composer:PastedPhotos': {}
-  'Composer:CameraOpened': {}
-  'Composer:GalleryOpened': {}
-  'Composer:ThreadgateOpened': {}
-  'HomeScreen:PressCompose': {}
-  'ProfileScreen:PressCompose': {}
-  // EDIT PROFILE events
-  'EditHandle:ViewCustomForm': {}
-  'EditHandle:ViewProvidedForm': {}
-  'EditHandle:SetNewHandle': {}
-  'EditProfile:AvatarSelected': {}
-  'EditProfile:BannerSelected': {}
-  'EditProfile:Save': {} // CAN BE SERVER
-  // FEED events
-  'Feed:onRefresh': {}
-  'Feed:onEndReached': {}
-  // POST events
-  'Post:Like': {} // CAN BE SERVER
-  'Post:Unlike': {} // CAN BE SERVER
-  'Post:Repost': {} // CAN BE SERVER
-  'Post:Unrepost': {} // CAN BE SERVER
-  'Post:Delete': {} // CAN BE SERVER
-  'Post:ThreadMute': {} // CAN BE SERVER
-  'Post:ThreadUnmute': {} // CAN BE SERVER
-  'Post:Reply': {} // CAN BE SERVER
-  'Post:EditThreadgateOpened': {}
-  'Post:ThreadgateEdited': {}
-  // PROFILE events
-  'Profile:Follow': {
-    username: string
-  }
-  'Profile:Unfollow': {
-    username: string
-  }
-  // PROFILE HEADER events
-  'ProfileHeader:EditProfileButtonClicked': {}
-  'ProfileHeader:FollowersButtonClicked': {
-    handle: string
-  }
-  'ProfileHeader:FollowsButtonClicked': {
-    handle: string
-  }
-  'ProfileHeader:ShareButtonClicked': {}
-  'ProfileHeader:MuteAccountButtonClicked': {}
-  'ProfileHeader:UnmuteAccountButtonClicked': {}
-  'ProfileHeader:ReportAccountButtonClicked': {}
-  'ProfileHeader:AddToListsButtonClicked': {}
-  'ProfileHeader:BlockAccountButtonClicked': {}
-  'ProfileHeader:UnblockAccountButtonClicked': {}
-  'ProfileHeader:FollowButtonClicked': {}
-  'ProfileHeader:UnfollowButtonClicked': {}
-  'ProfileHeader:SuggestedFollowsOpened': {}
-  'ProfileHeader:SuggestedFollowFollowed': {}
-  'ViewHeader:MenuButtonClicked': {}
-  // SETTINGS events
-  'Settings:SwitchAccountButtonClicked': {}
-  'Settings:AddAccountButtonClicked': {}
-  'Settings:ChangeHandleButtonClicked': {}
-  'Settings:InvitecodesButtonClicked': {}
-  'Settings:SignOutButtonClicked': {}
-  'Settings:ContentlanguagesButtonClicked': {}
-  // MENU events
-  'Menu:ItemClicked': {url: string}
-  'Menu:FeedbackClicked': {}
-  'Menu:HelpClicked': {}
-  // MOBILE SHELL events
-  'MobileShell:MyProfileButtonPressed': {}
-  'MobileShell:HomeButtonPressed': {}
-  'MobileShell:SearchButtonPressed': {}
-  'MobileShell:NotificationsButtonPressed': {}
-  'MobileShell:FeedsButtonPressed': {}
-  'MobileShell:MessagesButtonPressed': {}
-  // NOTIFICATIONS events
-  'Notificatons:OpenApp': {}
-  // LISTS events
-  'Lists:onRefresh': {}
-  'Lists:onEndReached': {}
-  'CreateList:AvatarSelected': {}
-  'CreateList:SaveCurateList': {} // CAN BE SERVER
-  'CreateList:SaveModList': {} // CAN BE SERVER
-  'Lists:Mute': {} // CAN BE SERVER
-  'Lists:Unmute': {} // CAN BE SERVER
-  'Lists:Block': {} // CAN BE SERVER
-  'Lists:Unblock': {} // CAN BE SERVER
-  'Lists:Delete': {} // CAN BE SERVER
-  'Lists:Share': {} // CAN BE SERVER
-  // CUSTOM FEED events
-  'CustomFeed:Save': {}
-  'CustomFeed:Unsave': {}
-  'CustomFeed:Like': {}
-  'CustomFeed:Unlike': {}
-  'CustomFeed:Share': {}
-  'CustomFeed:Pin': {
-    uri: string
-    name?: string
-  }
-  'CustomFeed:Unpin': {
-    uri: string
-    name?: string
-  }
-  'CustomFeed:Reorder': {
-    uri: string
-    name?: string
-    index: number
-  }
-  'CustomFeed:LoadMore': {}
-  'MultiFeed:onEndReached': {}
-  'MultiFeed:onRefresh': {}
-  // MODERATION events
-  'Moderation:ContentfilteringButtonClicked': {}
-  // ONBOARDING events
-  'Onboarding:Begin': {}
-  'Onboarding:Complete': {}
-  'Onboarding:Skipped': {}
-  'Onboarding:Reset': {}
-  'Onboarding:SuggestedFollowFollowed': {}
-  'Onboarding:CustomFeedAdded': {}
-  // Onboarding v2
-  'OnboardingV2:Begin': {}
-  'OnboardingV2:StepInterests:Start': {}
-  'OnboardingV2:StepInterests:End': {
-    selectedInterests: string[]
-    selectedInterestsLength: number
-  }
-  'OnboardingV2:StepInterests:Error': {}
-  'OnboardingV2:StepSuggestedAccounts:Start': {}
-  'OnboardingV2:StepSuggestedAccounts:End': {
-    selectedAccountsLength: number
-  }
-  'OnboardingV2:StepFollowingFeed:Start': {}
-  'OnboardingV2:StepFollowingFeed:End': {}
-  'OnboardingV2:StepAlgoFeeds:Start': {}
-  'OnboardingV2:StepAlgoFeeds:End': {
-    selectedPrimaryFeeds: string[]
-    selectedPrimaryFeedsLength: number
-    selectedSecondaryFeeds: string[]
-    selectedSecondaryFeedsLength: number
-  }
-  'OnboardingV2:StepTopicalFeeds:Start': {}
-  'OnboardingV2:StepTopicalFeeds:End': {
-    selectedFeeds: string[]
-    selectedFeedsLength: number
-  }
-  'OnboardingV2:StepModeration:Start': {}
-  'OnboardingV2:StepModeration:End': {}
-  'OnboardingV2:StepProfile:Start': {}
-  'OnboardingV2:StepProfile:End': {}
-  'OnboardingV2:StepFinished:Start': {}
-  'OnboardingV2:StepFinished:End': {}
-  'OnboardingV2:Complete': {}
-  'OnboardingV2:Skip': {}
-}
-
-export type ScreenPropertiesMap = {
-  Login: {}
-  CreateAccount: {}
-  'Choose Account': {}
-  'Signin:ForgotPassword': {}
-  'Signin:SetNewPasswordForm': {}
-  'Signin:PasswordUpdatedForm': {}
-  Feed: {}
-  Notifications: {}
-  Profile: {}
-  'Profile:Preview': {}
-  Settings: {}
-  AppPasswords: {}
-  Moderation: {}
-  PreferencesExternalEmbeds: {}
-  BlockedAccounts: {}
-  MutedAccounts: {}
-  SavedFeeds: {}
-}
diff --git a/src/lib/hooks/useAccountSwitcher.ts b/src/lib/hooks/useAccountSwitcher.ts
index 09ff30277..22eb348f2 100644
--- a/src/lib/hooks/useAccountSwitcher.ts
+++ b/src/lib/hooks/useAccountSwitcher.ts
@@ -2,7 +2,6 @@ import {useCallback, useState} from 'react'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
-import {useAnalytics} from '#/lib/analytics/analytics'
 import {logger} from '#/logger'
 import {isWeb} from '#/platform/detection'
 import {SessionAccount, useSessionApi} from '#/state/session'
@@ -14,7 +13,6 @@ import {LogEvents} from '../statsig/statsig'
 export function useAccountSwitcher() {
   const [pendingDid, setPendingDid] = useState<string | null>(null)
   const {_} = useLingui()
-  const {track} = useAnalytics()
   const {resumeSession} = useSessionApi()
   const {requestSwitchToAccount} = useLoggedOutViewControls()
 
@@ -23,7 +21,6 @@ export function useAccountSwitcher() {
       account: SessionAccount,
       logContext: LogEvents['account:loggedIn']['logContext'],
     ) => {
-      track('Settings:SwitchAccountButtonClicked')
       if (pendingDid) {
         // The session API isn't resilient to race conditions so let's just ignore this.
         return
@@ -62,7 +59,7 @@ export function useAccountSwitcher() {
         setPendingDid(null)
       }
     },
-    [_, track, resumeSession, requestSwitchToAccount, pendingDid],
+    [_, resumeSession, requestSwitchToAccount, pendingDid],
   )
 
   return {onPressSwitchAccount, pendingDid}
diff --git a/src/lib/hooks/useNotificationHandler.ts b/src/lib/hooks/useNotificationHandler.ts
index e4e7e1474..625ec9e6a 100644
--- a/src/lib/hooks/useNotificationHandler.ts
+++ b/src/lib/hooks/useNotificationHandler.ts
@@ -3,19 +3,18 @@ import * as Notifications from 'expo-notifications'
 import {CommonActions, useNavigation} from '@react-navigation/native'
 import {useQueryClient} from '@tanstack/react-query'
 
+import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
+import {NavigationProp} from '#/lib/routes/types'
+import {logEvent} from '#/lib/statsig/statsig'
 import {logger} from '#/logger'
-import {track} from 'lib/analytics/analytics'
-import {useAccountSwitcher} from 'lib/hooks/useAccountSwitcher'
-import {NavigationProp} from 'lib/routes/types'
-import {logEvent} from 'lib/statsig/statsig'
-import {isAndroid} from 'platform/detection'
-import {useCurrentConvoId} from 'state/messages/current-convo-id'
-import {RQKEY as RQKEY_NOTIFS} from 'state/queries/notifications/feed'
-import {invalidateCachedUnreadPage} from 'state/queries/notifications/unread'
-import {truncateAndInvalidate} from 'state/queries/util'
-import {useSession} from 'state/session'
-import {useLoggedOutViewControls} from 'state/shell/logged-out'
-import {useCloseAllActiveElements} from 'state/util'
+import {isAndroid} from '#/platform/detection'
+import {useCurrentConvoId} from '#/state/messages/current-convo-id'
+import {RQKEY as RQKEY_NOTIFS} from '#/state/queries/notifications/feed'
+import {invalidateCachedUnreadPage} from '#/state/queries/notifications/unread'
+import {truncateAndInvalidate} from '#/state/queries/util'
+import {useSession} from '#/state/session'
+import {useLoggedOutViewControls} from '#/state/shell/logged-out'
+import {useCloseAllActiveElements} from '#/state/util'
 import {resetToTab} from '#/Navigation'
 
 type NotificationReason =
@@ -228,7 +227,6 @@ export function useNotificationsHandler() {
             {},
             logger.DebugContext.notifications,
           )
-          track('Notificatons:OpenApp')
           logEvent('notifications:openApp', {})
           invalidateCachedUnreadPage()
           truncateAndInvalidate(queryClient, RQKEY_NOTIFS())