Some comments and cleanup

This commit is contained in:
Eric Bailey
2026-01-21 11:00:48 -06:00
parent bdfbbef9ce
commit 71c6771e87
8 changed files with 69 additions and 16 deletions
+32
View File
@@ -0,0 +1,32 @@
import {useEffect, useRef} from 'react'
import {getCurrentState, onAppStateChange} from '#/lib/appState'
import {useAnalytics} from '#/analytics'
/**
* Tracks passive analytics like app foreground/background time.
*/
export function PassiveAnalytics() {
const ax = useAnalytics()
const lastActive = useRef(
getCurrentState() === 'active' ? performance.now() : null,
)
useEffect(() => {
const sub = onAppStateChange(state => {
if (state === 'active') {
lastActive.current = performance.now()
ax.metric('state:foreground', {})
} else if (lastActive.current !== null) {
ax.metric('state:background', {
secondsActive: Math.round(
(performance.now() - lastActive.current) / 1e3,
),
})
}
})
return () => sub.remove()
}, [ax])
return null
}
+22
View File
@@ -61,8 +61,17 @@ const Context = createContext<AnalyticsBaseContextType>({
},
})
/**
* Ensures that deviceId is set and migrated from legacy storage. Handled on
* startup in `App.<platform>.tsx`. This must be awaited prior to the app
* booting up.
*/
export const setupDeviceId = getAndMigrateDeviceId()
/**
* Analytics context provider. Decorates the parent analytics context with
* additional metadata. Nesting should be done carefully and sparingly.
*/
export function AnalyticsContext({
children,
metadata,
@@ -102,6 +111,11 @@ export function AnalyticsContext({
return <Context.Provider value={childContext}>{children}</Context.Provider>
}
/**
* Feature gates provider. Decorates the parent analytics context with
* feature gate capabilities. Should be mounted within `AnalyticsContext`,
* and below the `<Fragment key={did} />` breaker in `App.<platform>.tsx`.
*/
export function AnalyticsFeaturesContext({
children,
}: {
@@ -133,10 +147,18 @@ export function AnalyticsFeaturesContext({
return <Context.Provider value={childContext}>{children}</Context.Provider>
}
/**
* Basic analytics context without feature gates. Should really only be used
* above the `AnalyticsFeaturesContext` provider.
*/
export function useAnalyticsBase() {
return useContext(Context)
}
/**
* The main analytics context, including feature gates. Use this everywhere you
* need metrics, features, or logging within the React tree.
*/
export function useAnalytics() {
const ctx = useContext(Context)
if (!('feature' in ctx) || !('Features' in ctx)) {
+1 -1
View File
@@ -3,7 +3,7 @@ import {isNetworkError} from '#/lib/strings/errors'
import {Sentry} from '#/logger/sentry/lib'
import * as env from '#/env'
// TODO just fucken use logger in here
// TODO debug logging
type Event<M extends Record<string, any>> = {
time: number
-15
View File
@@ -3,18 +3,3 @@ import {type Events} from '#/analytics/metrics/types'
export type {Events as Metrics} from '#/analytics/metrics/types'
export const metrics = new MetricsClient<Events>()
/*
* TODO
let lastActive = getCurrentState() === 'active' ? performance.now() : null
onAppStateChange(state => {
if (state === 'active') {
lastActive = performance.now()
metrics.track('state:foreground', {})
} else if (lastActive !== null) {
metrics.track('state:background', {
secondsActive: Math.round((performance.now() - lastActive) / 1e3),
})
}
})
*/
+4
View File
@@ -1,3 +1,7 @@
/*
* Do not import runtime code into this file
*/
import {type NotificationReason} from '#/lib/hooks/useNotificationHandler'
import {type FeedDescriptor} from '#/state/queries/post-feed'
import {type LiveEventFeedMetricContext} from '#/features/liveEvents/types'
+4
View File
@@ -4,6 +4,10 @@ import {BSKY_SERVICE} from '#/lib/constants'
import {type SessionAccount} from '#/state/session'
import {type MergeableMetadata, type SessionMetadata} from '#/analytics/types'
/**
* Thin `useMemo` wrapper that marks the metadata as memoized and provides a
* type guard.
*/
export function useMeta(metadata: MergeableMetadata) {
const m = useMemo(() => metadata, [metadata])
// @ts-ignore
+3
View File
@@ -42,6 +42,7 @@ import {Outlet as PortalOutlet} from '#/components/Portal'
import {useAgeAssurance} from '#/ageAssurance'
import {NoAccessScreen} from '#/ageAssurance/components/NoAccessScreen'
import {RedirectOverlay} from '#/ageAssurance/components/RedirectOverlay'
import {PassiveAnalytics} from '#/analytics/PassiveAnalytics'
import {IS_ANDROID, IS_IOS} from '#/env'
import {RoutesContainer, TabsNavigator} from '#/Navigation'
import {BottomSheetOutlet} from '../../../modules/bottom-sheet'
@@ -245,6 +246,8 @@ export function Shell() {
<RedirectOverlay />
</>
)}
<PassiveAnalytics />
</View>
)
}
+3
View File
@@ -34,6 +34,7 @@ import {WelcomeModal} from '#/components/WelcomeModal'
import {useAgeAssurance} from '#/ageAssurance'
import {NoAccessScreen} from '#/ageAssurance/components/NoAccessScreen'
import {RedirectOverlay} from '#/ageAssurance/components/RedirectOverlay'
import {PassiveAnalytics} from '#/analytics/PassiveAnalytics'
import {FlatNavigator, RoutesContainer} from '#/Navigation'
import {Composer} from './Composer.web'
import {DrawerContent} from './Drawer'
@@ -181,6 +182,8 @@ export function Shell() {
<RedirectOverlay />
</>
)}
<PassiveAnalytics />
</View>
)
}