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 oncezio/stable
parent
748212e000
commit
6335be14e1
|
@ -16,7 +16,7 @@ import {ThemeProvider} from 'lib/ThemeContext'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
import {Shell} from 'view/shell'
|
import {Shell} from 'view/shell'
|
||||||
import * as notifications from 'lib/notifications/notifications'
|
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 * as Toast from 'view/com/util/Toast'
|
||||||
import {queryClient} from 'lib/react-query'
|
import {queryClient} from 'lib/react-query'
|
||||||
import {TestCtrls} from 'view/com/testing/TestCtrls'
|
import {TestCtrls} from 'view/com/testing/TestCtrls'
|
||||||
|
@ -45,7 +45,6 @@ function InnerApp() {
|
||||||
|
|
||||||
// init
|
// init
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
analytics.init()
|
|
||||||
notifications.init(queryClient)
|
notifications.init(queryClient)
|
||||||
listenSessionDropped(() => {
|
listenSessionDropped(() => {
|
||||||
Toast.show('Sorry! Your session expired. Please log in again.')
|
Toast.show('Sorry! Your session expired. Please log in again.')
|
||||||
|
@ -72,7 +71,7 @@ function InnerApp() {
|
||||||
<LoggedOutViewProvider>
|
<LoggedOutViewProvider>
|
||||||
<UnreadNotifsProvider>
|
<UnreadNotifsProvider>
|
||||||
<ThemeProvider theme={colorMode}>
|
<ThemeProvider theme={colorMode}>
|
||||||
<analytics.Provider>
|
<AnalyticsProvider>
|
||||||
{/* All components should be within this provider */}
|
{/* All components should be within this provider */}
|
||||||
<RootSiblingParent>
|
<RootSiblingParent>
|
||||||
<GestureHandlerRootView style={s.h100pct}>
|
<GestureHandlerRootView style={s.h100pct}>
|
||||||
|
@ -80,7 +79,7 @@ function InnerApp() {
|
||||||
<Shell />
|
<Shell />
|
||||||
</GestureHandlerRootView>
|
</GestureHandlerRootView>
|
||||||
</RootSiblingParent>
|
</RootSiblingParent>
|
||||||
</analytics.Provider>
|
</AnalyticsProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</UnreadNotifsProvider>
|
</UnreadNotifsProvider>
|
||||||
</LoggedOutViewProvider>
|
</LoggedOutViewProvider>
|
||||||
|
|
|
@ -9,7 +9,7 @@ import 'view/icons'
|
||||||
|
|
||||||
import {init as initPersistedState} from '#/state/persisted'
|
import {init as initPersistedState} from '#/state/persisted'
|
||||||
import {useColorMode} from 'state/shell'
|
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 {Shell} from 'view/shell/index'
|
||||||
import {ToastContainer} from 'view/com/util/Toast.web'
|
import {ToastContainer} from 'view/com/util/Toast.web'
|
||||||
import {ThemeProvider} from 'lib/ThemeContext'
|
import {ThemeProvider} from 'lib/ThemeContext'
|
||||||
|
@ -37,7 +37,6 @@ function InnerApp() {
|
||||||
|
|
||||||
// init
|
// init
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
analytics.init()
|
|
||||||
const account = persisted.get('session').currentAccount
|
const account = persisted.get('session').currentAccount
|
||||||
resumeSession(account)
|
resumeSession(account)
|
||||||
}, [resumeSession])
|
}, [resumeSession])
|
||||||
|
@ -59,7 +58,7 @@ function InnerApp() {
|
||||||
<LoggedOutViewProvider>
|
<LoggedOutViewProvider>
|
||||||
<UnreadNotifsProvider>
|
<UnreadNotifsProvider>
|
||||||
<ThemeProvider theme={colorMode}>
|
<ThemeProvider theme={colorMode}>
|
||||||
<analytics.Provider>
|
<AnalyticsProvider>
|
||||||
{/* All components should be within this provider */}
|
{/* All components should be within this provider */}
|
||||||
<RootSiblingParent>
|
<RootSiblingParent>
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
|
@ -67,7 +66,7 @@ function InnerApp() {
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
</RootSiblingParent>
|
</RootSiblingParent>
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
</analytics.Provider>
|
</AnalyticsProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</UnreadNotifsProvider>
|
</UnreadNotifsProvider>
|
||||||
</LoggedOutViewProvider>
|
</LoggedOutViewProvider>
|
||||||
|
|
|
@ -41,6 +41,7 @@ import {
|
||||||
shouldRequestEmailConfirmation,
|
shouldRequestEmailConfirmation,
|
||||||
setEmailConfirmationRequested,
|
setEmailConfirmationRequested,
|
||||||
} from './state/shell/reminders'
|
} from './state/shell/reminders'
|
||||||
|
import {init as initAnalytics} from './lib/analytics/analytics'
|
||||||
|
|
||||||
import {HomeScreen} from './view/screens/Home'
|
import {HomeScreen} from './view/screens/Home'
|
||||||
import {SearchScreen} from './view/screens/Search'
|
import {SearchScreen} from './view/screens/Search'
|
||||||
|
@ -474,6 +475,8 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||||
const {openModal} = useModalControls()
|
const {openModal} = useModalControls()
|
||||||
|
|
||||||
function onReady() {
|
function onReady() {
|
||||||
|
initAnalytics(currentAccount)
|
||||||
|
|
||||||
if (currentAccount && shouldRequestEmailConfirmation(currentAccount)) {
|
if (currentAccount && shouldRequestEmailConfirmation(currentAccount)) {
|
||||||
openModal({name: 'verify-email', showReminder: true})
|
openModal({name: 'verify-email', showReminder: true})
|
||||||
setEmailConfirmationRequested()
|
setEmailConfirmationRequested()
|
||||||
|
|
|
@ -7,20 +7,17 @@ import {
|
||||||
useAnalytics as useAnalyticsOrig,
|
useAnalytics as useAnalyticsOrig,
|
||||||
ClientMethods,
|
ClientMethods,
|
||||||
} from '@segment/analytics-react-native'
|
} from '@segment/analytics-react-native'
|
||||||
import {z} from 'zod'
|
import {useSession, SessionAccount} from '#/state/session'
|
||||||
import {useSession} from '#/state/session'
|
|
||||||
import {sha256} from 'js-sha256'
|
import {sha256} from 'js-sha256'
|
||||||
import {ScreenEvent, TrackEvent} from './types'
|
import {ScreenEvent, TrackEvent} from './types'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {listenSessionLoaded} from '#/state/events'
|
|
||||||
|
|
||||||
export const appInfo = z.object({
|
type AppInfo = {
|
||||||
build: z.string().optional(),
|
build?: string | undefined
|
||||||
name: z.string().optional(),
|
name?: string | undefined
|
||||||
namespace: z.string().optional(),
|
namespace?: string | undefined
|
||||||
version: z.string().optional(),
|
version?: string | undefined
|
||||||
})
|
}
|
||||||
export type AppInfo = z.infer<typeof appInfo>
|
|
||||||
|
|
||||||
const segmentClient = createClient({
|
const segmentClient = createClient({
|
||||||
writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
|
writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
|
||||||
|
@ -58,8 +55,10 @@ export function useAnalytics() {
|
||||||
}, [hasSession, methods])
|
}, [hasSession, methods])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function init() {
|
export function init(account: SessionAccount | undefined) {
|
||||||
listenSessionLoaded(account => {
|
setupListenersOnce()
|
||||||
|
|
||||||
|
if (account) {
|
||||||
if (account.did) {
|
if (account.did) {
|
||||||
const did_hashed = sha256(account.did)
|
const did_hashed = sha256(account.did)
|
||||||
segmentClient.identify(did_hashed, {did_hashed})
|
segmentClient.identify(did_hashed, {did_hashed})
|
||||||
|
@ -68,8 +67,15 @@ export function init() {
|
||||||
logger.debug('Ping w/o hash')
|
logger.debug('Ping w/o hash')
|
||||||
segmentClient.identify()
|
segmentClient.identify()
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let didSetupListeners = false
|
||||||
|
function setupListenersOnce() {
|
||||||
|
if (didSetupListeners) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
didSetupListeners = true
|
||||||
// NOTE
|
// NOTE
|
||||||
// this is a copy of segment's own lifecycle event tracking
|
// 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
|
// we handle it manually to ensure that it never fires while the app is backgrounded
|
||||||
|
|
|
@ -6,9 +6,8 @@ import {
|
||||||
} from '@segment/analytics-react'
|
} from '@segment/analytics-react'
|
||||||
import {sha256} from 'js-sha256'
|
import {sha256} from 'js-sha256'
|
||||||
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession, SessionAccount} from '#/state/session'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {listenSessionLoaded} from '#/state/events'
|
|
||||||
|
|
||||||
const segmentClient = createClient(
|
const segmentClient = createClient(
|
||||||
{
|
{
|
||||||
|
@ -44,8 +43,8 @@ export function useAnalytics() {
|
||||||
}, [hasSession, methods])
|
}, [hasSession, methods])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function init() {
|
export function init(account: SessionAccount | undefined) {
|
||||||
listenSessionLoaded(account => {
|
if (account) {
|
||||||
if (account.did) {
|
if (account.did) {
|
||||||
if (account.did) {
|
if (account.did) {
|
||||||
const did_hashed = sha256(account.did)
|
const did_hashed = sha256(account.did)
|
||||||
|
@ -56,7 +55,7 @@ export function init() {
|
||||||
segmentClient.identify()
|
segmentClient.identify()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import EventEmitter from 'eventemitter3'
|
import EventEmitter from 'eventemitter3'
|
||||||
import {BskyAgent} from '@atproto/api'
|
|
||||||
import {SessionAccount} from './session'
|
|
||||||
|
|
||||||
type UnlistenFn = () => void
|
type UnlistenFn = () => void
|
||||||
|
|
||||||
|
@ -16,19 +14,6 @@ export function listenSoftReset(fn: () => void): UnlistenFn {
|
||||||
return () => emitter.off('soft-reset', fn)
|
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() {
|
export function emitSessionDropped() {
|
||||||
emitter.emit('session-dropped')
|
emitter.emit('session-dropped')
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {logger} from '#/logger'
|
||||||
import * as persisted from '#/state/persisted'
|
import * as persisted from '#/state/persisted'
|
||||||
import {PUBLIC_BSKY_AGENT} from '#/state/queries'
|
import {PUBLIC_BSKY_AGENT} from '#/state/queries'
|
||||||
import {IS_PROD} from '#/lib/constants'
|
import {IS_PROD} from '#/lib/constants'
|
||||||
import {emitSessionLoaded, emitSessionDropped} from '../events'
|
import {emitSessionDropped} from '../events'
|
||||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
import {useCloseAllActiveElements} from '#/state/util'
|
import {useCloseAllActiveElements} from '#/state/util'
|
||||||
import {track} from '#/lib/analytics/analytics'
|
import {track} from '#/lib/analytics/analytics'
|
||||||
|
@ -210,7 +210,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
__globalAgent = agent
|
__globalAgent = agent
|
||||||
queryClient.clear()
|
queryClient.clear()
|
||||||
upsertAccount(account)
|
upsertAccount(account)
|
||||||
emitSessionLoaded(account, agent)
|
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`session: created account`,
|
`session: created account`,
|
||||||
|
@ -262,7 +261,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
__globalAgent = agent
|
__globalAgent = agent
|
||||||
queryClient.clear()
|
queryClient.clear()
|
||||||
upsertAccount(account)
|
upsertAccount(account)
|
||||||
emitSessionLoaded(account, agent)
|
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`session: logged in`,
|
`session: logged in`,
|
||||||
|
@ -355,12 +353,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
__globalAgent = agent
|
__globalAgent = agent
|
||||||
queryClient.clear()
|
queryClient.clear()
|
||||||
upsertAccount(account)
|
upsertAccount(account)
|
||||||
emitSessionLoaded(account, agent)
|
|
||||||
// Intentionally not awaited to unblock the UI:
|
// Intentionally not awaited to unblock the UI:
|
||||||
resumeSessionWithFreshAccount().then(async freshAccount => {
|
resumeSessionWithFreshAccount().then(freshAccount => {
|
||||||
if (JSON.stringify(account) !== JSON.stringify(freshAccount)) {
|
if (JSON.stringify(account) !== JSON.stringify(freshAccount)) {
|
||||||
upsertAccount(freshAccount)
|
upsertAccount(freshAccount)
|
||||||
emitSessionLoaded(freshAccount, agent)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -368,7 +365,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
__globalAgent = agent
|
__globalAgent = agent
|
||||||
queryClient.clear()
|
queryClient.clear()
|
||||||
upsertAccount(freshAccount)
|
upsertAccount(freshAccount)
|
||||||
emitSessionLoaded(freshAccount, agent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resumeSessionWithFreshAccount(): Promise<SessionAccount> {
|
async function resumeSessionWithFreshAccount(): Promise<SessionAccount> {
|
||||||
|
|
Loading…
Reference in New Issue