Move analytics out of init (#2115)

* Remove listenSessionLoaded from analytics

* Move analytics init call to navigation ready

* Remove zod dependency from analytics

* Mirror changes on the web

* Delete listenSessionLoaded

* Only set up listeners once
zio/stable
dan 2023-12-06 20:04:05 +00:00 committed by GitHub
parent 748212e000
commit 6335be14e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 35 additions and 48 deletions

View File

@ -16,7 +16,7 @@ import {ThemeProvider} from 'lib/ThemeContext'
import {s} from 'lib/styles'
import {Shell} from 'view/shell'
import * as notifications from 'lib/notifications/notifications'
import * as analytics from 'lib/analytics/analytics'
import {Provider as AnalyticsProvider} from 'lib/analytics/analytics'
import * as Toast from 'view/com/util/Toast'
import {queryClient} from 'lib/react-query'
import {TestCtrls} from 'view/com/testing/TestCtrls'
@ -45,7 +45,6 @@ function InnerApp() {
// init
useEffect(() => {
analytics.init()
notifications.init(queryClient)
listenSessionDropped(() => {
Toast.show('Sorry! Your session expired. Please log in again.')
@ -72,7 +71,7 @@ function InnerApp() {
<LoggedOutViewProvider>
<UnreadNotifsProvider>
<ThemeProvider theme={colorMode}>
<analytics.Provider>
<AnalyticsProvider>
{/* All components should be within this provider */}
<RootSiblingParent>
<GestureHandlerRootView style={s.h100pct}>
@ -80,7 +79,7 @@ function InnerApp() {
<Shell />
</GestureHandlerRootView>
</RootSiblingParent>
</analytics.Provider>
</AnalyticsProvider>
</ThemeProvider>
</UnreadNotifsProvider>
</LoggedOutViewProvider>

View File

@ -9,7 +9,7 @@ import 'view/icons'
import {init as initPersistedState} from '#/state/persisted'
import {useColorMode} from 'state/shell'
import * as analytics from 'lib/analytics/analytics'
import {Provider as AnalyticsProvider} from 'lib/analytics/analytics'
import {Shell} from 'view/shell/index'
import {ToastContainer} from 'view/com/util/Toast.web'
import {ThemeProvider} from 'lib/ThemeContext'
@ -37,7 +37,6 @@ function InnerApp() {
// init
useEffect(() => {
analytics.init()
const account = persisted.get('session').currentAccount
resumeSession(account)
}, [resumeSession])
@ -59,7 +58,7 @@ function InnerApp() {
<LoggedOutViewProvider>
<UnreadNotifsProvider>
<ThemeProvider theme={colorMode}>
<analytics.Provider>
<AnalyticsProvider>
{/* All components should be within this provider */}
<RootSiblingParent>
<SafeAreaProvider>
@ -67,7 +66,7 @@ function InnerApp() {
</SafeAreaProvider>
</RootSiblingParent>
<ToastContainer />
</analytics.Provider>
</AnalyticsProvider>
</ThemeProvider>
</UnreadNotifsProvider>
</LoggedOutViewProvider>

View File

@ -41,6 +41,7 @@ import {
shouldRequestEmailConfirmation,
setEmailConfirmationRequested,
} from './state/shell/reminders'
import {init as initAnalytics} from './lib/analytics/analytics'
import {HomeScreen} from './view/screens/Home'
import {SearchScreen} from './view/screens/Search'
@ -474,6 +475,8 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
const {openModal} = useModalControls()
function onReady() {
initAnalytics(currentAccount)
if (currentAccount && shouldRequestEmailConfirmation(currentAccount)) {
openModal({name: 'verify-email', showReminder: true})
setEmailConfirmationRequested()

View File

@ -7,20 +7,17 @@ import {
useAnalytics as useAnalyticsOrig,
ClientMethods,
} from '@segment/analytics-react-native'
import {z} from 'zod'
import {useSession} from '#/state/session'
import {useSession, SessionAccount} from '#/state/session'
import {sha256} from 'js-sha256'
import {ScreenEvent, TrackEvent} from './types'
import {logger} from '#/logger'
import {listenSessionLoaded} from '#/state/events'
export const appInfo = z.object({
build: z.string().optional(),
name: z.string().optional(),
namespace: z.string().optional(),
version: z.string().optional(),
})
export type AppInfo = z.infer<typeof appInfo>
type AppInfo = {
build?: string | undefined
name?: string | undefined
namespace?: string | undefined
version?: string | undefined
}
const segmentClient = createClient({
writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
@ -58,8 +55,10 @@ export function useAnalytics() {
}, [hasSession, methods])
}
export function init() {
listenSessionLoaded(account => {
export function init(account: SessionAccount | undefined) {
setupListenersOnce()
if (account) {
if (account.did) {
const did_hashed = sha256(account.did)
segmentClient.identify(did_hashed, {did_hashed})
@ -68,8 +67,15 @@ export function init() {
logger.debug('Ping w/o hash')
segmentClient.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

View File

@ -6,9 +6,8 @@ import {
} from '@segment/analytics-react'
import {sha256} from 'js-sha256'
import {useSession} from '#/state/session'
import {useSession, SessionAccount} from '#/state/session'
import {logger} from '#/logger'
import {listenSessionLoaded} from '#/state/events'
const segmentClient = createClient(
{
@ -44,8 +43,8 @@ export function useAnalytics() {
}, [hasSession, methods])
}
export function init() {
listenSessionLoaded(account => {
export function init(account: SessionAccount | undefined) {
if (account) {
if (account.did) {
if (account.did) {
const did_hashed = sha256(account.did)
@ -56,7 +55,7 @@ export function init() {
segmentClient.identify()
}
}
})
}
}
export function Provider({children}: React.PropsWithChildren<{}>) {

View File

@ -1,6 +1,4 @@
import EventEmitter from 'eventemitter3'
import {BskyAgent} from '@atproto/api'
import {SessionAccount} from './session'
type UnlistenFn = () => void
@ -16,19 +14,6 @@ export function listenSoftReset(fn: () => void): UnlistenFn {
return () => emitter.off('soft-reset', fn)
}
export function emitSessionLoaded(
sessionAccount: SessionAccount,
agent: BskyAgent,
) {
emitter.emit('session-loaded', sessionAccount, agent)
}
export function listenSessionLoaded(
fn: (sessionAccount: SessionAccount, agent: BskyAgent) => void,
): UnlistenFn {
emitter.on('session-loaded', fn)
return () => emitter.off('session-loaded', fn)
}
export function emitSessionDropped() {
emitter.emit('session-dropped')
}

View File

@ -8,7 +8,7 @@ import {logger} from '#/logger'
import * as persisted from '#/state/persisted'
import {PUBLIC_BSKY_AGENT} from '#/state/queries'
import {IS_PROD} from '#/lib/constants'
import {emitSessionLoaded, emitSessionDropped} from '../events'
import {emitSessionDropped} from '../events'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useCloseAllActiveElements} from '#/state/util'
import {track} from '#/lib/analytics/analytics'
@ -210,7 +210,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
__globalAgent = agent
queryClient.clear()
upsertAccount(account)
emitSessionLoaded(account, agent)
logger.debug(
`session: created account`,
@ -262,7 +261,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
__globalAgent = agent
queryClient.clear()
upsertAccount(account)
emitSessionLoaded(account, agent)
logger.debug(
`session: logged in`,
@ -355,12 +353,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
__globalAgent = agent
queryClient.clear()
upsertAccount(account)
emitSessionLoaded(account, agent)
// Intentionally not awaited to unblock the UI:
resumeSessionWithFreshAccount().then(async freshAccount => {
resumeSessionWithFreshAccount().then(freshAccount => {
if (JSON.stringify(account) !== JSON.stringify(freshAccount)) {
upsertAccount(freshAccount)
emitSessionLoaded(freshAccount, agent)
}
})
} else {
@ -368,7 +365,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
__globalAgent = agent
queryClient.clear()
upsertAccount(freshAccount)
emitSessionLoaded(freshAccount, agent)
}
async function resumeSessionWithFreshAccount(): Promise<SessionAccount> {