diff options
author | Hailey <me@haileyok.com> | 2024-09-27 14:01:57 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-27 14:01:57 -0700 |
commit | f68b15219fd02e23d965015201400138ed69d59d (patch) | |
tree | 1134642fff8db10b2cfca827a6c0d9cd2a4dbd5b /src/lib | |
parent | bcd096b85aee45c38de7cfbcf1115b0a544589ae (diff) | |
download | voidsky-f68b15219fd02e23d965015201400138ed69d59d.tar.zst |
Remove Segment (#5518)
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/analytics/analytics.tsx | 158 | ||||
-rw-r--r-- | src/lib/analytics/analytics.web.tsx | 80 | ||||
-rw-r--r-- | src/lib/analytics/types.ts | 181 | ||||
-rw-r--r-- | src/lib/hooks/useAccountSwitcher.ts | 5 | ||||
-rw-r--r-- | src/lib/hooks/useNotificationHandler.ts | 24 |
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()) |