diff --git a/eslint.config.mjs b/eslint.config.mjs
index c3c36b4c4f..951d3442c5 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -119,7 +119,6 @@ export default defineConfig(
},
],
'bsky-internal/use-exact-imports': 'error',
- 'bsky-internal/use-typed-gates': 'error',
'bsky-internal/use-prefixed-imports': 'error',
/**
diff --git a/eslint/index.js b/eslint/index.js
index 3cd7e61344..4d59c8c1d0 100644
--- a/eslint/index.js
+++ b/eslint/index.js
@@ -8,7 +8,6 @@ const plugin = {
rules: {
'avoid-unwrapped-text': require('./avoid-unwrapped-text'),
'use-exact-imports': require('./use-exact-imports'),
- 'use-typed-gates': require('./use-typed-gates'),
'use-prefixed-imports': require('./use-prefixed-imports'),
},
}
diff --git a/eslint/use-typed-gates.js b/eslint/use-typed-gates.js
deleted file mode 100644
index 37969951e7..0000000000
--- a/eslint/use-typed-gates.js
+++ /dev/null
@@ -1,41 +0,0 @@
-'use strict'
-
-module.exports = {
- meta: {
- type: 'suggestion',
- docs: {
- description:
- 'Enforce using internal statsig wrapper instead of npm package',
- },
- schema: [],
- },
- create(context) {
- return {
- ImportSpecifier(node) {
- if (
- !node.local ||
- node.local.type !== 'Identifier' ||
- node.local.name !== 'useGate'
- ) {
- return
- }
- if (
- node.parent.type !== 'ImportDeclaration' ||
- !node.parent.source ||
- node.parent.source.type !== 'Literal'
- ) {
- return
- }
- const source = node.parent.source.value
- if (source.startsWith('statsig') || source.startsWith('@statsig')) {
- context.report({
- node,
- message:
- "Use useGate() from '#/lib/statsig/statsig' instead of the one on npm.",
- })
- }
- // TODO: Verify gate() call results aren't stored in variables.
- },
- }
- },
-}
diff --git a/jest/jestSetup.js b/jest/jestSetup.js
index ec5d4a9361..2b9ddf5348 100644
--- a/jest/jestSetup.js
+++ b/jest/jestSetup.js
@@ -99,19 +99,9 @@ jest.mock('expo-modules-core', () => ({
requireNativeViewManager: jest.fn().mockImplementation(_ => {
return () => null
}),
+ createPermissionHook: () => () => [true],
}))
jest.mock('expo-localization', () => ({
getLocales: () => [],
}))
-
-jest.mock('statsig-react-native-expo', () => ({
- Statsig: {
- initialize() {},
- initializeCalled() {
- return false
- },
- },
-}))
-
-jest.mock('../src/lib/statsig/statsig', () => ({}))
diff --git a/package.json b/package.json
index fc9d5ed714..2be25b505b 100644
--- a/package.json
+++ b/package.json
@@ -220,7 +220,6 @@
"react-textarea-autosize": "^8.5.3",
"sonner": "^2.0.7",
"sonner-native": "^0.21.0",
- "statsig-react-native-expo": "^4.6.1",
"tippy.js": "^6.3.7",
"tlds": "^1.234.0",
"tldts": "^6.1.46",
diff --git a/src/App.native.tsx b/src/App.native.tsx
index fe57ba86d3..1568f7b8ae 100644
--- a/src/App.native.tsx
+++ b/src/App.native.tsx
@@ -17,7 +17,6 @@ import * as Sentry from '@sentry/react-native'
import {KeyboardControllerProvider} from '#/lib/hooks/useEnableKeyboardController'
import {Provider as HideBottomBarBorderProvider} from '#/lib/hooks/useHideBottomBarBorder'
import {QueryProvider} from '#/lib/react-query'
-import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
import {s} from '#/lib/styles'
import {ThemeProvider} from '#/lib/ThemeContext'
import I18nProvider from '#/locale/i18nProvider'
@@ -153,53 +152,51 @@ function InnerApp() {
-
-
-
-
-
- {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/App.web.tsx b/src/App.web.tsx
index 0a632ccdbf..a0eff936f5 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -9,7 +9,6 @@ import {useLingui} from '@lingui/react'
import * as Sentry from '@sentry/react-native'
import {QueryProvider} from '#/lib/react-query'
-import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
import {ThemeProvider} from '#/lib/ThemeContext'
import I18nProvider from '#/locale/i18nProvider'
import {logger} from '#/logger'
@@ -132,49 +131,47 @@ function InnerApp() {
-
-
-
-
-
- {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ageAssurance/components/NoAccessScreen.tsx b/src/ageAssurance/components/NoAccessScreen.tsx
index ca5716a37a..9515b820e3 100644
--- a/src/ageAssurance/components/NoAccessScreen.tsx
+++ b/src/ageAssurance/components/NoAccessScreen.tsx
@@ -9,7 +9,6 @@ import {
useCreateSupportLink,
} from '#/lib/hooks/useCreateSupportLink'
import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
-import {logger} from '#/logger'
import {useIsBirthdateUpdateAllowed} from '#/state/birthdate'
import {useSessionApi} from '#/state/session'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
@@ -36,8 +35,8 @@ import {
isLegacyBirthdateBug,
useAgeAssuranceRegionConfig,
} from '#/ageAssurance/util'
-import {IS_WEB} from '#/env'
-import {IS_NATIVE} from '#/env'
+import {useAnalytics} from '#/analytics'
+import {IS_NATIVE, IS_WEB} from '#/env'
import {useDeviceGeolocationApi} from '#/geolocation'
const textStyles = [a.text_md, a.leading_snug]
@@ -45,6 +44,7 @@ const textStyles = [a.text_md, a.leading_snug]
export function NoAccessScreen() {
const t = useTheme()
const {_} = useLingui()
+ const ax = useAnalytics()
const {gtPhone} = useBreakpoints()
const insets = useSafeAreaInsets()
const birthdateControl = useDialogControl()
@@ -63,8 +63,8 @@ export function NoAccessScreen() {
useEffect(() => {
// just counting overall hits here
- logger.metric(`blockedGeoOverlay:shown`, {})
- logger.metric(`ageAssurance:noAccessScreen:shown`, {
+ ax.metric(`blockedGeoOverlay:shown`, {})
+ ax.metric(`ageAssurance:noAccessScreen:shown`, {
accountCreatedAt: data?.accountCreatedAt || 'unknown',
isAARegion,
hasDeclaredAge,
@@ -103,10 +103,7 @@ export function NoAccessScreen() {
label={_(msg`Click here to update your birthdate`)}
style={[textStyles]}
{...createStaticClick(() => {
- logger.metric(
- 'ageAssurance:noAccessScreen:openBirthdateDialog',
- {},
- )
+ ax.metric('ageAssurance:noAccessScreen:openBirthdateDialog', {})
birthdateControl.open()
})}>
clicking here
@@ -272,6 +269,7 @@ export function NoAccessScreen() {
function AccessSection() {
const t = useTheme()
const {_, i18n} = useLingui()
+ const ax = useAnalytics()
const control = useDialogControl()
const appealControl = Dialog.useDialogControl()
const locationControl = Dialog.useDialogControl()
@@ -305,7 +303,7 @@ function AccessSection() {
label={_(msg`Contact our moderation team`)}
{...createStaticClick(() => {
appealControl.open()
- logger.metric('ageAssurance:appealDialogOpen', {})
+ ax.metric('ageAssurance:appealDialogOpen', {})
})}>
contact our moderation team
{' '}
@@ -321,7 +319,7 @@ function AccessSection() {
color={hasInitiated ? 'secondary' : 'primary'}
onPress={() => {
control.open()
- logger.metric('ageAssurance:initDialogOpen', {
+ ax.metric('ageAssurance:initDialogOpen', {
hasInitiatedPreviously: hasInitiated,
})
}}>
diff --git a/src/ageAssurance/components/RedirectOverlay.tsx b/src/ageAssurance/components/RedirectOverlay.tsx
index b7bc51df3c..dbd498447a 100644
--- a/src/ageAssurance/components/RedirectOverlay.tsx
+++ b/src/ageAssurance/components/RedirectOverlay.tsx
@@ -25,9 +25,8 @@ import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icon
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
-import {logger} from '#/ageAssurance'
-import {IS_WEB} from '#/env'
-import {IS_IOS} from '#/env'
+import {useAnalytics} from '#/analytics'
+import {IS_IOS, IS_WEB} from '#/env'
export type RedirectOverlayState = {
result: 'success' | 'unknown'
@@ -174,6 +173,7 @@ export function RedirectOverlay() {
function Inner() {
const t = useTheme()
+ const ax = useAnalytics()
const {_} = useLingui()
const agent = useAgent()
const polling = useRef(false)
@@ -187,7 +187,7 @@ function Inner() {
polling.current = true
- logger.metric('ageAssurance:redirectDialogOpen', {})
+ ax.metric('ageAssurance:redirectDialogOpen', {})
wait(
3e3,
@@ -218,18 +218,18 @@ function Inner() {
setSuccess(true)
- logger.metric('ageAssurance:redirectDialogSuccess', {})
+ ax.metric('ageAssurance:redirectDialogSuccess', {})
})
.catch(() => {
if (unmounted.current) return
setError(true)
- logger.metric('ageAssurance:redirectDialogFail', {})
+ ax.metric('ageAssurance:redirectDialogFail', {})
})
return () => {
unmounted.current = true
}
- }, [agent])
+ }, [ax, agent])
if (success) {
return (
diff --git a/src/ageAssurance/useBeginAgeAssurance.ts b/src/ageAssurance/useBeginAgeAssurance.ts
index 897b03bbdb..28a4591747 100644
--- a/src/ageAssurance/useBeginAgeAssurance.ts
+++ b/src/ageAssurance/useBeginAgeAssurance.ts
@@ -12,6 +12,7 @@ import {isNetworkError} from '#/lib/hooks/useCleanError'
import {useAgent} from '#/state/session'
import {usePatchAgeAssuranceServerState} from '#/ageAssurance'
import {logger} from '#/ageAssurance/logger'
+import {useAnalytics} from '#/analytics'
import {BLUESKY_PROXY_DID} from '#/env'
import {useGeolocation} from '#/geolocation'
@@ -19,6 +20,7 @@ const IS_DEV_ENV = BLUESKY_PROXY_DID !== PUBLIC_APPVIEW_DID
const APPVIEW = IS_DEV_ENV ? DEV_ENV_APPVIEW : PUBLIC_APPVIEW
export function useBeginAgeAssurance() {
+ const ax = useAnalytics()
const agent = useAgent()
const geolocation = useGeolocation()
const patchAgeAssuranceStateResponse = usePatchAgeAssuranceServerState()
@@ -48,15 +50,11 @@ export function useBeginAgeAssurance() {
appView.sessionManager.session.accessJwt = token
appView.sessionManager.session.refreshJwt = ''
- logger.metric(
- 'ageAssurance:api:begin',
- {
- platform: Platform.OS,
- countryCode,
- regionCode,
- },
- {statsig: false},
- )
+ ax.metric('ageAssurance:api:begin', {
+ platform: Platform.OS,
+ countryCode,
+ regionCode,
+ })
/*
* 2s wait is good actually. Email sending takes a hot sec and this helps
diff --git a/src/analytics/index.tsx b/src/analytics/index.tsx
index 3753e335c1..ea538d1ca7 100644
--- a/src/analytics/index.tsx
+++ b/src/analytics/index.tsx
@@ -11,7 +11,7 @@ import {
} from '#/analytics/features'
import {
getAndMigrateDeviceId,
- getDeviceIdOrThrow,
+ getDeviceId,
getInitialSessionId,
useSessionId,
} from '#/analytics/identifiers'
@@ -24,6 +24,7 @@ import {device} from '#/storage'
export * as utils from '#/analytics/utils'
export const features = {init, refresh}
+export {Features} from '#/analytics/features'
export {type Metrics} from '#/analytics/metrics'
type LoggerType = {
@@ -38,7 +39,7 @@ type LoggerType = {
useContext: (context: Exclude) => LoggerType
Context: typeof Logger.Context
}
-type AnalyticsContextType = {
+export type AnalyticsContextType = {
metadata: Metadata
logger: LoggerType
metric: (
@@ -49,7 +50,7 @@ type AnalyticsContextType = {
feature: (feature: Features) => boolean
Features: typeof Features
}
-type AnalyticsBaseContextType = Omit<
+export type AnalyticsBaseContextType = Omit<
AnalyticsContextType,
'feature' | 'Features'
>
@@ -75,11 +76,14 @@ function createLogger(
const Context = createContext({
logger: createLogger(Logger.Context.Default, {}),
metric: (event, payload, metadata) => {
+ if (metadata && '__meta' in metadata) {
+ delete metadata.__meta
+ }
metrics.track(event, payload, metadata)
},
metadata: {
base: {
- deviceId: getDeviceIdOrThrow() ?? 'unknown',
+ deviceId: getDeviceId() ?? 'unknown',
sessionId: getInitialSessionId(),
platform: Platform.OS,
appVersion: env.APP_VERSION,
@@ -114,8 +118,7 @@ export function AnalyticsContext({
metadata?: MergeableMetadata
}) {
if (metadata) {
- // @ts-ignore
- if (metadata.__meta !== true) {
+ if (!('__meta' in metadata)) {
throw new Error(
'Use the useMeta() helper when passing metadata to AnalyticsContext',
)
diff --git a/src/analytics/metrics/client.ts b/src/analytics/metrics/client.ts
index 42f50c38de..b47d3154d5 100644
--- a/src/analytics/metrics/client.ts
+++ b/src/analytics/metrics/client.ts
@@ -74,7 +74,7 @@ export class MetricsClient> {
})
try {
- const body = JSON.stringify(events)
+ const body = JSON.stringify({events})
if (env.IS_WEB && 'navigator' in globalThis && navigator.sendBeacon) {
navigator.sendBeacon(
TRACKING_ENDPOINT,
diff --git a/src/analytics/metrics/types.ts b/src/analytics/metrics/types.ts
index 0d2119da92..0fa5279edf 100644
--- a/src/analytics/metrics/types.ts
+++ b/src/analytics/metrics/types.ts
@@ -148,6 +148,7 @@ export type Events = {
feedUrl: string
feedType: string
index: number
+ reason?: string
}
'feed:endReached': {
feedUrl: string
diff --git a/src/components/PostControls/BookmarkButton.tsx b/src/components/PostControls/BookmarkButton.tsx
index ac391a1ae9..3b8e8db3d9 100644
--- a/src/components/PostControls/BookmarkButton.tsx
+++ b/src/components/PostControls/BookmarkButton.tsx
@@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react'
import type React from 'react'
import {useCleanError} from '#/lib/hooks/useCleanError'
-import {logger} from '#/logger'
import {type Shadow} from '#/state/cache/post-shadow'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
@@ -15,6 +14,7 @@ import {useTheme} from '#/alf'
import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
import * as toast from '#/components/Toast'
+import {useAnalytics} from '#/analytics'
import {PostControlButton, PostControlButtonIcon} from './PostControlButton'
export const BookmarkButton = memo(function BookmarkButton({
@@ -29,6 +29,7 @@ export const BookmarkButton = memo(function BookmarkButton({
hitSlop?: Insets
}): React.ReactNode {
const t = useTheme()
+ const ax = useAnalytics()
const {_} = useLingui()
const {mutateAsync: bookmark} = useBookmarkMutation()
const cleanError = useCleanError()
@@ -52,7 +53,7 @@ export const BookmarkButton = memo(function BookmarkButton({
post,
})
- logger.metric('post:bookmark', {
+ ax.metric('post:bookmark', {
uri: post.uri,
authorDid: post.author.did,
logContext,
@@ -92,7 +93,7 @@ export const BookmarkButton = memo(function BookmarkButton({
uri: post.uri,
})
- logger.metric('post:unbookmark', {
+ ax.metric('post:unbookmark', {
uri: post.uri,
authorDid: post.author.did,
logContext,
diff --git a/src/components/PostControls/DiscoverDebug.tsx b/src/components/PostControls/DiscoverDebug.tsx
index 93d6126d99..5c18322c5e 100644
--- a/src/components/PostControls/DiscoverDebug.tsx
+++ b/src/components/PostControls/DiscoverDebug.tsx
@@ -3,11 +3,11 @@ import * as Clipboard from 'expo-clipboard'
import {t} from '@lingui/macro'
import {DISCOVER_DEBUG_DIDS} from '#/lib/constants'
-import {useGate} from '#/lib/statsig/statsig'
import {useSession} from '#/state/session'
import {atoms as a, useTheme} from '#/alf'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {IS_INTERNAL} from '#/env'
export function DiscoverDebug({
@@ -15,12 +15,12 @@ export function DiscoverDebug({
}: {
feedContext: string | undefined
}) {
+ const ax = useAnalytics()
const {currentAccount} = useSession()
- const gate = useGate()
const isDiscoverDebugUser =
IS_INTERNAL ||
DISCOVER_DEBUG_DIDS[currentAccount?.did || ''] ||
- gate('debug_show_feedcontext')
+ ax.feature(ax.Features.DebugFeedContext)
const theme = useTheme()
return (
diff --git a/src/components/PostControls/PostMenu/PostMenuItems.tsx b/src/components/PostControls/PostMenu/PostMenuItems.tsx
index ce93e81ab1..1413678d2e 100644
--- a/src/components/PostControls/PostMenu/PostMenuItems.tsx
+++ b/src/components/PostControls/PostMenu/PostMenuItems.tsx
@@ -26,15 +26,17 @@ import {
type CommonNavigatorParams,
type NavigationProp,
} from '#/lib/routes/types'
-import {logEvent, useGate} from '#/lib/statsig/statsig'
import {richTextToString} from '#/lib/strings/rich-text-helpers'
import {toShareUrl} from '#/lib/strings/url-helpers'
import {logger} from '#/logger'
import {type Shadow} from '#/state/cache/post-shadow'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
-import {useLanguagePrefs} from '#/state/preferences'
-import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences'
+import {
+ useHiddenPosts,
+ useHiddenPostsApi,
+ useLanguagePrefs,
+} from '#/state/preferences'
import {usePinnedPostMutation} from '#/state/queries/pinned-post'
import {
usePostDeleteMutation,
@@ -71,13 +73,17 @@ import {
import {Eye_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/Eye'
import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash'
import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter'
-import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
-import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute'
+import {
+ Mute_Stroke2_Corner0_Rounded as Mute,
+ Mute_Stroke2_Corner0_Rounded as MuteIcon,
+} from '#/components/icons/Mute'
import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/Person'
import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2'
-import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
-import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker'
+import {
+ SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute,
+ SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon,
+} from '#/components/icons/Speaker'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
import {Loader} from '#/components/Loader'
@@ -87,6 +93,7 @@ import {
useReportDialogControl,
} from '#/components/moderation/ReportDialog'
import * as Prompt from '#/components/Prompt'
+import {useAnalytics} from '#/analytics'
import {IS_INTERNAL} from '#/env'
import * as bsky from '#/types/bsky'
@@ -116,6 +123,7 @@ let PostMenuItems = ({
}): React.ReactNode => {
const {hasSession, currentAccount} = useSession()
const {_} = useLingui()
+ const ax = useAnalytics()
const langPrefs = useLanguagePrefs()
const {mutateAsync: deletePostMutate} = usePostDeleteMutation()
const {mutateAsync: pinPostMutate, isPending: isPinPending} =
@@ -212,7 +220,7 @@ let PostMenuItems = ({
try {
if (isThreadMuted) {
unmuteThread()
- logger.metric('post:unmute', {
+ ax.metric('post:unmute', {
uri: postUri,
authorDid: postAuthor.did,
logContext,
@@ -221,7 +229,7 @@ let PostMenuItems = ({
Toast.show(_(msg`You will now receive notifications for this thread`))
} else {
muteThread()
- logger.metric('post:mute', {
+ ax.metric('post:mute', {
uri: postUri,
authorDid: postAuthor.did,
logContext,
@@ -258,21 +266,17 @@ let PostMenuItems = ({
AppBskyFeedPost.isRecord,
)
) {
- logger.metric(
- 'translate',
- {
- sourceLanguages: post.record.langs ?? [],
- targetLanguage: langPrefs.primaryLanguage,
- textLength: post.record.text.length,
- },
- {statsig: false},
- )
+ ax.metric('translate', {
+ sourceLanguages: post.record.langs ?? [],
+ targetLanguage: langPrefs.primaryLanguage,
+ textLength: post.record.text.length,
+ })
}
}
const onHidePost = () => {
hidePost({uri: postUri})
- logEvent('thread:click:hideReplyForMe', {})
+ ax.metric('thread:click:hideReplyForMe', {})
}
const hideInPWI = !!postAuthor.labels?.find(
@@ -286,7 +290,7 @@ let PostMenuItems = ({
feedContext: postFeedContext,
reqId: postReqId,
})
- logger.metric('post:showMore', {
+ ax.metric('post:showMore', {
uri: postUri,
authorDid: postAuthor.did,
logContext,
@@ -304,7 +308,7 @@ let PostMenuItems = ({
feedContext: postFeedContext,
reqId: postReqId,
})
- logger.metric('post:showLess', {
+ ax.metric('post:showLess', {
uri: postUri,
authorDid: postAuthor.did,
logContext,
@@ -368,7 +372,7 @@ let PostMenuItems = ({
// Log metric only when hiding (not when showing)
if (isHide) {
- logEvent('thread:click:hideReplyForEveryone', {})
+ ax.metric('thread:click:hideReplyForEveryone', {})
}
Toast.show(
@@ -405,7 +409,7 @@ let PostMenuItems = ({
}
const onPressPin = () => {
- logEvent(isPinned ? 'post:unpin' : 'post:pin', {})
+ ax.metric(isPinned ? 'post:unpin' : 'post:pin', {})
pinPostMutate({
postUri,
postCid,
@@ -458,11 +462,10 @@ let PostMenuItems = ({
const onSignIn = () => requireSignIn(() => {})
- const gate = useGate()
const isDiscoverDebugUser =
IS_INTERNAL ||
DISCOVER_DEBUG_DIDS[currentAccount?.did || ''] ||
- gate('debug_show_feedcontext')
+ ax.feature(ax.Features.DebugFeedContext)
return (
<>
diff --git a/src/components/PostControls/ShareMenu/RecentChats.tsx b/src/components/PostControls/ShareMenu/RecentChats.tsx
index e17a6adb2a..2648b485e1 100644
--- a/src/components/PostControls/ShareMenu/RecentChats.tsx
+++ b/src/components/PostControls/ShareMenu/RecentChats.tsx
@@ -8,7 +8,6 @@ import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
import {type NavigationProp} from '#/lib/routes/types'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
-import {logger} from '#/logger'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useListConvosQuery} from '#/state/queries/messages/list-conversations'
@@ -20,9 +19,11 @@ import {useDialogContext} from '#/components/Dialog'
import {Text} from '#/components/Typography'
import {useSimpleVerificationState} from '#/components/verification'
import {VerificationCheck} from '#/components/verification/VerificationCheck'
+import {useAnalytics} from '#/analytics'
import type * as bsky from '#/types/bsky'
export function RecentChats({postUri}: {postUri: string}) {
+ const ax = useAnalytics()
const control = useDialogContext()
const {currentAccount} = useSession()
const {data} = useListConvosQuery({status: 'accepted'})
@@ -32,7 +33,7 @@ export function RecentChats({postUri}: {postUri: string}) {
const onSelectChat = (convoId: string) => {
control.close(() => {
- logger.metric('share:press:recentDm', {}, {statsig: true})
+ ax.metric('share:press:recentDm', {})
navigation.navigate('MessagesConversation', {
conversation: convoId,
embed: postUri,
diff --git a/src/components/PostControls/ShareMenu/ShareMenuItems.tsx b/src/components/PostControls/ShareMenu/ShareMenuItems.tsx
index 8ba9ea3e25..fe2f0a9c77 100644
--- a/src/components/PostControls/ShareMenu/ShareMenuItems.tsx
+++ b/src/components/PostControls/ShareMenu/ShareMenuItems.tsx
@@ -9,7 +9,6 @@ import {makeProfileLink} from '#/lib/routes/links'
import {type NavigationProp} from '#/lib/routes/types'
import {shareText, shareUrl} from '#/lib/sharing'
import {toShareUrl} from '#/lib/strings/url-helpers'
-import {logger} from '#/logger'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useSession} from '#/state/session'
import * as Toast from '#/view/com/util/Toast'
@@ -23,6 +22,7 @@ import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/i
import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlaneIcon} from '#/components/icons/PaperPlane'
import * as Menu from '#/components/Menu'
import {useAgeAssurance} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
import {IS_IOS} from '#/env'
import {useDevMode} from '#/storage/hooks/dev-mode'
import {RecentChats} from './RecentChats'
@@ -32,6 +32,7 @@ let ShareMenuItems = ({
post,
onShare: onShareProp,
}: ShareMenuItemsProps): React.ReactNode => {
+ const ax = useAnalytics()
const {hasSession} = useSession()
const {_} = useLingui()
const navigation = useNavigation()
@@ -54,14 +55,14 @@ let ShareMenuItems = ({
}, [postAuthor])
const onSharePost = () => {
- logger.metric('share:press:nativeShare', {}, {statsig: true})
+ ax.metric('share:press:nativeShare', {})
const url = toShareUrl(href)
shareUrl(url)
onShareProp()
}
const onCopyLink = async () => {
- logger.metric('share:press:copyLink', {}, {statsig: true})
+ ax.metric('share:press:copyLink', {})
const url = toShareUrl(href)
if (IS_IOS) {
// iOS only
@@ -100,7 +101,7 @@ let ShareMenuItems = ({
testID="postDropdownSendViaDMBtn"
label={_(msg`Send via direct message`)}
onPress={() => {
- logger.metric('share:press:openDmSearch', {}, {statsig: true})
+ ax.metric('share:press:openDmSearch', {})
sendViaChatControl.open()
}}>
diff --git a/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx b/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
index 408035db90..c1da73ca82 100644
--- a/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
+++ b/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
@@ -8,7 +8,6 @@ import {makeProfileLink} from '#/lib/routes/links'
import {type NavigationProp} from '#/lib/routes/types'
import {shareText, shareUrl} from '#/lib/sharing'
import {toShareUrl} from '#/lib/strings/url-helpers'
-import {logger} from '#/logger'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useSession} from '#/state/session'
import {useBreakpoints} from '#/alf'
@@ -21,6 +20,7 @@ import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/compon
import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane'
import * as Menu from '#/components/Menu'
import {useAgeAssurance} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
import {useDevMode} from '#/storage/hooks/dev-mode'
import {type ShareMenuItemsProps} from './ShareMenuItems.types'
@@ -31,6 +31,7 @@ let ShareMenuItems = ({
timestamp,
onShare: onShareProp,
}: ShareMenuItemsProps): React.ReactNode => {
+ const ax = useAnalytics()
const {hasSession} = useSession()
const {gtMobile} = useBreakpoints()
const {_} = useLingui()
@@ -56,14 +57,14 @@ let ShareMenuItems = ({
}, [postAuthor])
const onCopyLink = () => {
- logger.metric('share:press:copyLink', {}, {statsig: true})
+ ax.metric('share:press:copyLink', {})
const url = toShareUrl(href)
shareUrl(url)
onShareProp()
}
const onSelectChatToShareTo = (conversation: string) => {
- logger.metric('share:press:dmSelected', {}, {statsig: true})
+ ax.metric('share:press:dmSelected', {})
navigation.navigate('MessagesConversation', {
conversation,
embed: postUri,
@@ -102,7 +103,7 @@ let ShareMenuItems = ({
testID="postDropdownSendViaDMBtn"
label={_(msg`Send via direct message`)}
onPress={() => {
- logger.metric('share:press:openDmSearch', {}, {statsig: true})
+ ax.metric('share:press:openDmSearch', {})
sendViaChatControl.open()
}}>
@@ -117,7 +118,7 @@ let ShareMenuItems = ({
testID="postDropdownEmbedBtn"
label={_(msg`Embed post`)}
onPress={() => {
- logger.metric('share:press:embed', {}, {statsig: true})
+ ax.metric('share:press:embed', {})
embedPostControl.open()
}}>
{_(msg`Embed post`)}
diff --git a/src/components/PostControls/ShareMenu/index.tsx b/src/components/PostControls/ShareMenu/index.tsx
index 0748f1a371..b53bd63c01 100644
--- a/src/components/PostControls/ShareMenu/index.tsx
+++ b/src/components/PostControls/ShareMenu/index.tsx
@@ -13,7 +13,6 @@ import {useLingui} from '@lingui/react'
import {makeProfileLink} from '#/lib/routes/links'
import {shareUrl} from '#/lib/sharing'
import {toShareUrl} from '#/lib/strings/url-helpers'
-import {logger} from '#/logger'
import {type Shadow} from '#/state/cache/post-shadow'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
import {EventStopper} from '#/view/com/util/EventStopper'
@@ -21,6 +20,7 @@ import {native} from '#/alf'
import {ArrowShareRight_Stroke2_Corner2_Rounded as ArrowShareRightIcon} from '#/components/icons/ArrowShareRight'
import {useMenuControl} from '#/components/Menu'
import * as Menu from '#/components/Menu'
+import {useAnalytics} from '#/analytics'
import {PostControlButton, PostControlButtonIcon} from '../PostControlButton'
import {ShareMenuItems} from './ShareMenuItems'
@@ -47,6 +47,7 @@ let ShareMenuButton = ({
hitSlop?: Insets
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
}): React.ReactNode => {
+ const ax = useAnalytics()
const {_} = useLingui()
const {feedDescriptor} = useFeedFeedbackContext()
@@ -61,20 +62,17 @@ let ShareMenuButton = ({
// menuControl.open() fires but RN doesn't expose flushSync.
setTimeout(menuControl.open)
- logger.metric(
- 'post:share',
- {
- uri: post.uri,
- authorDid: post.author.did,
- logContext,
- feedDescriptor,
- postContext: big ? 'thread' : 'feed',
- },
- {statsig: true},
- )
+ ax.metric('post:share', {
+ uri: post.uri,
+ authorDid: post.author.did,
+ logContext,
+ feedDescriptor,
+ postContext: big ? 'thread' : 'feed',
+ })
},
}),
[
+ ax,
menuControl,
setHasBeenOpen,
big,
@@ -86,7 +84,7 @@ let ShareMenuButton = ({
)
const onNativeLongPress = () => {
- logger.metric('share:press:nativeShare', {}, {statsig: true})
+ ax.metric('share:press:nativeShare', {})
const urip = new AtUri(post.uri)
const href = makeProfileLink(post.author, 'post', urip.rkey)
const url = toShareUrl(href)
diff --git a/src/components/PostControls/index.tsx b/src/components/PostControls/index.tsx
index 45688c2617..4eb67879ab 100644
--- a/src/components/PostControls/index.tsx
+++ b/src/components/PostControls/index.tsx
@@ -13,7 +13,6 @@ import {CountWheel} from '#/lib/custom-animations/CountWheel'
import {AnimatedLikeIcon} from '#/lib/custom-animations/LikeIcon'
import {useHaptics} from '#/lib/haptics'
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
-import {logger} from '#/logger'
import {type Shadow} from '#/state/cache/types'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
import {
@@ -30,6 +29,7 @@ import {atoms as a, useBreakpoints} from '#/alf'
import {Reply as Bubble} from '#/components/icons/Reply'
import {useFormatPostStatCount} from '#/components/PostControls/util'
import * as Skele from '#/components/Skeleton'
+import {useAnalytics} from '#/analytics'
import {BookmarkButton} from './BookmarkButton'
import {
PostControlButton,
@@ -71,6 +71,7 @@ let PostControls = ({
viaRepost?: {uri: string; cid: string}
variant?: 'compact' | 'normal' | 'large'
}): React.ReactNode => {
+ const ax = useAnalytics()
const {_} = useLingui()
const {openComposer} = useOpenComposer()
const {feedDescriptor} = useFeedFeedbackContext()
@@ -175,7 +176,7 @@ let PostControls = ({
feedContext,
reqId,
})
- logger.metric('post:clickQuotePost', {
+ ax.metric('post:clickQuotePost', {
uri: post.uri,
authorDid: post.author.did,
logContext,
@@ -226,7 +227,7 @@ let PostControls = ({
!replyDisabled
? () =>
requireAuth(() => {
- logger.metric('post:clickReply', {
+ ax.metric('post:clickReply', {
uri: post.uri,
authorDid: post.author.did,
logContext,
diff --git a/src/components/ProgressGuide/FollowDialog.tsx b/src/components/ProgressGuide/FollowDialog.tsx
index fe4e29d98a..78ac868b28 100644
--- a/src/components/ProgressGuide/FollowDialog.tsx
+++ b/src/components/ProgressGuide/FollowDialog.tsx
@@ -10,8 +10,6 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
-import {logEvent} from '#/lib/statsig/statsig'
-import {logger} from '#/logger'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useActorSearch} from '#/state/queries/actor-search'
import {usePreferencesQuery} from '#/state/queries/preferences'
@@ -36,6 +34,7 @@ import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {boostInterests, InterestTabs} from '#/components/InterestTabs'
import * as ProfileCard from '#/components/ProfileCard'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
import type * as bsky from '#/types/bsky'
import {ProgressGuideTask} from './Task'
@@ -67,6 +66,7 @@ export function FollowDialog({
guide: Follow10ProgressGuide
showArrow?: boolean
}) {
+ const ax = useAnalytics()
const {_} = useLingui()
const control = Dialog.useDialogControl()
const {gtPhone} = useBreakpoints()
@@ -78,7 +78,7 @@ export function FollowDialog({
label={_(msg`Find people to follow`)}
onPress={() => {
control.open()
- logEvent('progressGuide:followDialog:open', {})
+ ax.metric('progressGuide:followDialog:open', {})
}}
size={gtPhone ? 'small' : 'large'}
color="primary">
@@ -118,6 +118,7 @@ let lastSearchText = ''
function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
const {_} = useLingui()
+ const ax = useAnalytics()
const interestsDisplayNames = useInterestsDisplayNames()
const {data: preferences} = usePreferencesQuery()
const personalizedInterests = preferences?.interests?.tags
@@ -271,17 +272,13 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
const position = itemsRef.current.findIndex(
i => i.type === 'profile' && i.profile.did === item.profile.did,
)
- logger.metric(
- 'suggestedUser:seen',
- {
- logContext: 'ProgressGuide',
- recId: undefined,
- position: position !== -1 ? position : 0,
- suggestedDid: item.profile.did,
- category: selectedInterestRef.current,
- },
- {statsig: true},
- )
+ ax.metric('suggestedUser:seen', {
+ logContext: 'ProgressGuide',
+ recId: undefined,
+ position: position !== -1 ? position : 0,
+ suggestedDid: item.profile.did,
+ category: selectedInterestRef.current,
+ })
}
}
}
diff --git a/src/components/StarterPack/QrCodeDialog.tsx b/src/components/StarterPack/QrCodeDialog.tsx
index 4c9bcc510d..e0c894a769 100644
--- a/src/components/StarterPack/QrCodeDialog.tsx
+++ b/src/components/StarterPack/QrCodeDialog.tsx
@@ -19,6 +19,7 @@ import {FloppyDisk_Stroke2_Corner0_Rounded as FloppyDiskIcon} from '#/components
import {Loader} from '#/components/Loader'
import {QrCode} from '#/components/StarterPack/QrCode'
import * as Toast from '#/components/Toast'
+import {useAnalytics} from '#/analytics'
import {IS_NATIVE, IS_WEB} from '#/env'
import * as bsky from '#/types/bsky'
@@ -32,6 +33,7 @@ export function QrCodeDialog({
control: DialogControlProps
}) {
const {_} = useLingui()
+ const ax = useAnalytics()
const {gtMobile} = useBreakpoints()
const [isSaveProcessing, setIsSaveProcessing] = useState(false)
const [isCopyProcessing, setIsCopyProcessing] = useState(false)
@@ -104,7 +106,7 @@ export function QrCodeDialog({
link.click()
}
- logger.metric('starterPack:share', {
+ ax.metric('starterPack:share', {
starterPack: starterPack.uri,
shareType: 'qrcode',
qrShareType: 'save',
@@ -129,7 +131,7 @@ export function QrCodeDialog({
navigator.clipboard.write([item])
})
- logger.metric('starterPack:share', {
+ ax.metric('starterPack:share', {
starterPack: starterPack.uri,
shareType: 'qrcode',
qrShareType: 'copy',
@@ -145,7 +147,7 @@ export function QrCodeDialog({
control.close(() => {
Sharing.shareAsync(uri, {mimeType: 'image/png', UTI: 'image/png'}).then(
() => {
- logger.metric('starterPack:share', {
+ ax.metric('starterPack:share', {
starterPack: starterPack.uri,
shareType: 'qrcode',
qrShareType: 'share',
diff --git a/src/components/StarterPack/ShareDialog.tsx b/src/components/StarterPack/ShareDialog.tsx
index 1dbbb07eef..eb9e98b3b1 100644
--- a/src/components/StarterPack/ShareDialog.tsx
+++ b/src/components/StarterPack/ShareDialog.tsx
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
import {useSaveImageToMediaLibrary} from '#/lib/media/save-image'
import {shareUrl} from '#/lib/sharing'
import {getStarterPackOgCard} from '#/lib/strings/starter-pack'
-import {logger} from '#/logger'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {type DialogControlProps} from '#/components/Dialog'
@@ -17,6 +16,7 @@ import {Download_Stroke2_Corner0_Rounded as DownloadIcon} from '#/components/ico
import {QrCode_Stroke2_Corner0_Rounded as QrCodeIcon} from '#/components/icons/QrCode'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {IS_NATIVE, IS_WEB} from '#/env'
interface Props {
@@ -46,6 +46,7 @@ function ShareDialogInner({
control,
}: Props) {
const {_} = useLingui()
+ const ax = useAnalytics()
const t = useTheme()
const {gtMobile} = useBreakpoints()
@@ -54,7 +55,7 @@ function ShareDialogInner({
const onShareLink = async () => {
if (!link) return
shareUrl(link)
- logger.metric('starterPack:share', {
+ ax.metric('starterPack:share', {
starterPack: starterPack.uri,
shareType: 'link',
})
diff --git a/src/components/StarterPack/Wizard/WizardListCard.tsx b/src/components/StarterPack/Wizard/WizardListCard.tsx
index 089092636d..b5cd15a112 100644
--- a/src/components/StarterPack/Wizard/WizardListCard.tsx
+++ b/src/components/StarterPack/Wizard/WizardListCard.tsx
@@ -13,7 +13,6 @@ import {useLingui} from '@lingui/react'
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
-import {logger} from '#/logger'
import {useSession} from '#/state/session'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {
@@ -25,6 +24,7 @@ import {Button, ButtonText} from '#/components/Button'
import * as Toggle from '#/components/forms/Toggle'
import {Checkbox} from '#/components/forms/Toggle'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import type * as bsky from '#/types/bsky'
function WizardListCard({
@@ -130,6 +130,7 @@ export function WizardProfileCard({
profile: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts
}) {
+ const ax = useAnalytics()
const {currentAccount} = useSession()
// Determine the "main" profile for this starter pack - either targetDid or current account
@@ -151,10 +152,10 @@ export function WizardProfileCard({
if (profile.did === targetProfileDid) return
if (!included) {
- logger.metric('starterPack:addUser', {})
+ ax.metric('starterPack:addUser', {})
dispatch({type: 'AddProfile', profile})
} else {
- logger.metric('starterPack:removeUser', {})
+ ax.metric('starterPack:removeUser', {})
dispatch({type: 'RemoveProfile', profileDid: profile.did})
}
}
diff --git a/src/components/WelcomeModal.tsx b/src/components/WelcomeModal.tsx
index 1271a5f3ac..9b4ab08ebb 100644
--- a/src/components/WelcomeModal.tsx
+++ b/src/components/WelcomeModal.tsx
@@ -5,13 +5,13 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {FocusGuards, FocusScope} from 'radix-ui/internal'
-import {logger} from '#/logger'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {Logo} from '#/view/icons/Logo'
import {atoms as a, flatten, useBreakpoints, web} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
const welcomeModalBg = require('../../assets/images/welcome-modal-bg.jpg')
@@ -25,6 +25,7 @@ interface WelcomeModalProps {
export function WelcomeModal({control}: WelcomeModalProps) {
const {_} = useLingui()
+ const ax = useAnalytics()
const {requestSwitchToAccount} = useLoggedOutViewControls()
const {gtMobile} = useBreakpoints()
const [isExiting, setIsExiting] = useState(false)
@@ -40,23 +41,24 @@ export function WelcomeModal({control}: WelcomeModalProps) {
useEffect(() => {
if (control.isOpen) {
- logger.metric('welcomeModal:presented', {})
+ ax.metric('welcomeModal:presented', {})
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [control.isOpen])
const onPressCreateAccount = () => {
- logger.metric('welcomeModal:signupClicked', {})
+ ax.metric('welcomeModal:signupClicked', {})
control.close()
requestSwitchToAccount({requestedAccount: 'new'})
}
const onPressExplore = () => {
- logger.metric('welcomeModal:exploreClicked', {})
+ ax.metric('welcomeModal:exploreClicked', {})
fadeOutAndClose()
}
const onPressSignIn = () => {
- logger.metric('welcomeModal:signinClicked', {})
+ ax.metric('welcomeModal:signinClicked', {})
control.close()
requestSwitchToAccount({requestedAccount: 'existing'})
}
@@ -222,7 +224,7 @@ export function WelcomeModal({control}: WelcomeModalProps) {
]}
hoverStyle={[a.bg_transparent]}
onPress={() => {
- logger.metric('welcomeModal:dismissed', {})
+ ax.metric('welcomeModal:dismissed', {})
fadeOutAndClose()
}}
color="secondary"
diff --git a/src/components/WhoCanReply.tsx b/src/components/WhoCanReply.tsx
index 292d041b70..8e93ee4fcc 100644
--- a/src/components/WhoCanReply.tsx
+++ b/src/components/WhoCanReply.tsx
@@ -17,7 +17,6 @@ import {useLingui} from '@lingui/react'
import {HITSLOP_10} from '#/lib/constants'
import {makeListLink, makeProfileLink} from '#/lib/routes/links'
-import {logger} from '#/logger'
import {
type ThreadgateAllowUISetting,
threadgateViewToAllowUISetting,
@@ -36,6 +35,7 @@ import {Earth_Stroke2_Corner0_Rounded as EarthIcon} from '#/components/icons/Glo
import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group'
import {InlineLinkText} from '#/components/Link'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {IS_NATIVE} from '#/env'
import * as bsky from '#/types/bsky'
@@ -46,8 +46,9 @@ interface WhoCanReplyProps {
}
export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
- const {_} = useLingui()
const t = useTheme()
+ const ax = useAnalytics()
+ const {_} = useLingui()
const infoDialogControl = useDialogControl()
const editDialogControl = useDialogControl()
@@ -90,7 +91,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
Keyboard.dismiss()
}
if (isThreadAuthor) {
- logger.metric('thread:click:editOwnThreadgate', {})
+ ax.metric('thread:click:editOwnThreadgate', {})
// wait on prefetch if it manages to resolve in under 200ms
// otherwise, proceed immediately and show the spinner -sfn
@@ -101,7 +102,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
editDialogControl.open()
})
} else {
- logger.metric('thread:click:viewSomeoneElsesThreadgate', {})
+ ax.metric('thread:click:viewSomeoneElsesThreadgate', {})
infoDialogControl.open()
}
diff --git a/src/components/activity-notifications/SubscribeProfileDialog.tsx b/src/components/activity-notifications/SubscribeProfileDialog.tsx
index a8a5df39f2..cb0cae9fcc 100644
--- a/src/components/activity-notifications/SubscribeProfileDialog.tsx
+++ b/src/components/activity-notifications/SubscribeProfileDialog.tsx
@@ -17,13 +17,11 @@ import {
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles'
-import {logger} from '#/logger'
import {updateProfileShadow} from '#/state/cache/profile-shadow'
import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions'
import {useAgent} from '#/state/session'
import * as Toast from '#/view/com/util/Toast'
-import {platform, useTheme, web} from '#/alf'
-import {atoms as a} from '#/alf'
+import {atoms as a, platform, useTheme, web} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {
Button,
@@ -36,6 +34,7 @@ import * as Toggle from '#/components/forms/Toggle'
import {Loader} from '#/components/Loader'
import * as ProfileCard from '#/components/ProfileCard'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
import type * as bsky from '#/types/bsky'
@@ -71,6 +70,7 @@ function DialogInner({
moderationOpts: ModerationOpts
includeProfile?: boolean
}) {
+ const ax = useAnalytics()
const {_} = useLingui()
const t = useTheme()
const agent = useAgent()
@@ -133,7 +133,7 @@ function DialogInner({
})
if (!activitySubscription.post && !activitySubscription.reply) {
- logger.metric('activitySubscription:disable', {})
+ ax.metric('activitySubscription:disable', {})
Toast.show(
_(
msg`You will no longer receive notifications for ${sanitizeHandle(profile.handle, '@')}`,
@@ -160,7 +160,7 @@ function DialogInner({
},
)
} else {
- logger.metric('activitySubscription:enable', {
+ ax.metric('activitySubscription:enable', {
setting: activitySubscription.reply ? 'posts_and_replies' : 'posts',
})
if (!initialState.post && !initialState.reply) {
@@ -177,7 +177,7 @@ function DialogInner({
})
},
onError: err => {
- logger.error('Could not save activity subscription', {message: err})
+ ax.logger.error('Could not save activity subscription', {message: err})
},
})
diff --git a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx
index 41659d3edb..7d7b5ade06 100644
--- a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx
+++ b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx
@@ -20,8 +20,9 @@ import {Divider} from '#/components/Divider'
import {createStaticClick, InlineLinkText} from '#/components/Link'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
-import {logger, useAgeAssurance} from '#/ageAssurance'
+import {useAgeAssurance} from '#/ageAssurance'
import {useComputeAgeAssuranceRegionAccess} from '#/ageAssurance/useComputeAgeAssuranceRegionAccess'
+import {useAnalytics} from '#/analytics'
import {IS_NATIVE} from '#/env'
import {useDeviceGeolocationApi} from '#/geolocation'
@@ -41,6 +42,7 @@ export function AgeAssuranceAccountCard({style}: ViewStyleProp & {}) {
function Inner({style}: ViewStyleProp & {}) {
const t = useTheme()
const {_, i18n} = useLingui()
+ const ax = useAnalytics()
const control = useDialogControl()
const appealControl = Dialog.useDialogControl()
const locationControl = Dialog.useDialogControl()
@@ -138,7 +140,7 @@ function Inner({style}: ViewStyleProp & {}) {
label={_(msg`Contact our moderation team`)}
{...createStaticClick(() => {
appealControl.open()
- logger.metric('ageAssurance:appealDialogOpen', {})
+ ax.metric('ageAssurance:appealDialogOpen', {})
})}>
contact our moderation team
{' '}
@@ -167,7 +169,7 @@ function Inner({style}: ViewStyleProp & {}) {
color={hasInitiated ? 'secondary' : 'primary'}
onPress={() => {
control.open()
- logger.metric('ageAssurance:initDialogOpen', {
+ ax.metric('ageAssurance:initDialogOpen', {
hasInitiatedPreviously: hasInitiated,
})
}}>
diff --git a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx
index 1ef29dfbbb..426924b637 100644
--- a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx
+++ b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx
@@ -10,7 +10,7 @@ import {ShieldCheck_Stroke2_Corner0_Rounded as Shield} from '#/components/icons/
import {InlineLinkText} from '#/components/Link'
import {Text} from '#/components/Typography'
import {useAgeAssurance} from '#/ageAssurance'
-import {logger} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
export function AgeAssuranceAdmonition({
children,
@@ -40,6 +40,7 @@ function Inner({
}) {
const t = useTheme()
const {_} = useLingui()
+ const ax = useAnalytics()
return (
<>
@@ -92,7 +93,7 @@ function Inner({
to={'/settings/account'}
style={[a.text_sm, a.leading_snug, a.font_semi_bold]}
onPress={() => {
- logger.metric('ageAssurance:navigateToSettings', {})
+ ax.metric('ageAssurance:navigateToSettings', {})
}}>
account settings.
diff --git a/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx b/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx
index d8330a94c3..c7f4c170e1 100644
--- a/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx
+++ b/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx
@@ -15,6 +15,7 @@ import * as Dialog from '#/components/Dialog'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
import {logger} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
export function AgeAssuranceAppealDialog({
control,
@@ -37,6 +38,7 @@ export function AgeAssuranceAppealDialog({
function Inner({control}: {control: Dialog.DialogControlProps}) {
const {_} = useLingui()
+ const ax = useAnalytics()
const {currentAccount} = useSession()
const {gtPhone} = useBreakpoints()
const agent = useAgent()
@@ -46,7 +48,7 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
const {mutate, isPending} = useMutation({
mutationFn: async () => {
- logger.metric('ageAssurance:appealDialogSubmit', {})
+ ax.metric('ageAssurance:appealDialogSubmit', {})
await agent.createModerationReport(
{
diff --git a/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx b/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx
index aa1d527f62..b32a2457b3 100644
--- a/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx
+++ b/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx
@@ -12,7 +12,7 @@ import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {Link} from '#/components/Link'
import {Text} from '#/components/Typography'
import {useAgeAssurance} from '#/ageAssurance'
-import {logger} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
export function useInternalState() {
const aa = useAgeAssurance()
@@ -42,6 +42,7 @@ export function useInternalState() {
export function AgeAssuranceDismissibleFeedBanner() {
const t = useTheme()
+ const ax = useAnalytics()
const {_} = useLingui()
const {visible, close} = useInternalState()
const copy = useAgeAssuranceCopy()
@@ -66,7 +67,7 @@ export function AgeAssuranceDismissibleFeedBanner() {
to="/settings/account"
onPress={() => {
close()
- logger.metric('ageAssurance:navigateToSettings', {})
+ ax.metric('ageAssurance:navigateToSettings', {})
}}
style={[a.w_full, a.justify_between, a.align_center, a.gap_md]}>
{
close()
- logger.metric('ageAssurance:dismissFeedBanner', {})
+ ax.metric('ageAssurance:dismissFeedBanner', {})
}}
style={[
a.absolute,
diff --git a/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx b/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx
index 14c7ed300f..fcfdf18017 100644
--- a/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx
+++ b/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx
@@ -10,10 +10,11 @@ import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy
import {Button, ButtonIcon} from '#/components/Button'
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {useAgeAssurance} from '#/ageAssurance'
-import {logger} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
const {_} = useLingui()
+ const ax = useAnalytics()
const aa = useAgeAssurance()
const {nux} = useNux(Nux.AgeAssuranceDismissibleNotice)
const copy = useAgeAssuranceCopy()
@@ -45,7 +46,7 @@ export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
completed: true,
data: undefined,
})
- logger.metric('ageAssurance:dismissSettingsNotice', {})
+ ax.metric('ageAssurance:dismissSettingsNotice', {})
}}
style={[
a.absolute,
diff --git a/src/components/ageAssurance/AgeAssuranceInitDialog.tsx b/src/components/ageAssurance/AgeAssuranceInitDialog.tsx
index 32f6b0044a..8414b5fbd8 100644
--- a/src/components/ageAssurance/AgeAssuranceInitDialog.tsx
+++ b/src/components/ageAssurance/AgeAssuranceInitDialog.tsx
@@ -19,8 +19,7 @@ import {useSession} from '#/state/session'
import {atoms as a, web} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
-import {urls} from '#/components/ageAssurance/const'
-import {KWS_SUPPORTED_LANGS} from '#/components/ageAssurance/const'
+import {KWS_SUPPORTED_LANGS, urls} from '#/components/ageAssurance/const'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {Divider} from '#/components/Divider'
@@ -30,9 +29,9 @@ import {LanguageSelect} from '#/components/LanguageSelect'
import {SimpleInlineLinkText} from '#/components/Link'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
-import {logger} from '#/ageAssurance'
import {useAgeAssurance} from '#/ageAssurance'
import {useBeginAgeAssurance} from '#/ageAssurance/useBeginAgeAssurance'
+import {useAnalytics} from '#/analytics'
export {useDialogControl} from '#/components/Dialog/context'
@@ -64,6 +63,7 @@ export function AgeAssuranceInitDialog({
function Inner() {
const {_} = useLingui()
+ const ax = useAnalytics()
const {currentAccount} = useSession()
const langPrefs = useLanguagePrefs()
const cleanError = useCleanError()
@@ -116,7 +116,7 @@ function Inner() {
const onSubmit = async () => {
setLanguageError(false)
- logger.metric('ageAssurance:initDialogSubmit', {})
+ ax.metric('ageAssurance:initDialogSubmit', {})
try {
const {status} = runEmailValidation()
@@ -143,7 +143,7 @@ function Inner() {
error = _(
msg`Please enter a valid, non-temporary email address. You may need to access this email in the future.`,
)
- logger.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'})
+ ax.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'})
} else if (e.error === 'DidTooLong') {
error = (
<>
@@ -159,14 +159,14 @@ function Inner() {
>
)
- logger.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
+ ax.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
} else {
- logger.metric('ageAssurance:initDialogError', {code: 'other'})
+ ax.metric('ageAssurance:initDialogError', {code: 'other'})
}
} else {
const {clean, raw} = cleanError(e)
error = clean || raw || error
- logger.metric('ageAssurance:initDialogError', {code: 'other'})
+ ax.metric('ageAssurance:initDialogError', {code: 'other'})
}
setError(error)
diff --git a/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx b/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx
index 0cbf6bed04..fc8dfeef4a 100644
--- a/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx
+++ b/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx
@@ -16,7 +16,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icon
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
-import {logger} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
import {IS_NATIVE} from '#/env'
export type AgeAssuranceRedirectDialogState = {
@@ -81,6 +81,7 @@ export function AgeAssuranceRedirectDialog() {
export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
const t = useTheme()
+ const ax = useAnalytics()
const {_} = useLingui()
const agent = useAgent()
const polling = useRef(false)
@@ -94,7 +95,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
polling.current = true
- logger.metric('ageAssurance:redirectDialogOpen', {})
+ ax.metric('ageAssurance:redirectDialogOpen', {})
wait(
3e3,
@@ -125,18 +126,18 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
setSuccess(true)
- logger.metric('ageAssurance:redirectDialogSuccess', {})
+ ax.metric('ageAssurance:redirectDialogSuccess', {})
})
.catch(() => {
if (unmounted.current) return
setError(true)
- logger.metric('ageAssurance:redirectDialogFail', {})
+ ax.metric('ageAssurance:redirectDialogFail', {})
})
return () => {
unmounted.current = true
}
- }, [agent, control])
+ }, [ax, agent, control])
if (success) {
return (
diff --git a/src/components/ageAssurance/AgeRestrictedScreen.tsx b/src/components/ageAssurance/AgeRestrictedScreen.tsx
index 9f9c4c4d5b..8c77e8e43d 100644
--- a/src/components/ageAssurance/AgeRestrictedScreen.tsx
+++ b/src/components/ageAssurance/AgeRestrictedScreen.tsx
@@ -13,7 +13,7 @@ import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link'
import {Text} from '#/components/Typography'
import {useAgeAssurance} from '#/ageAssurance'
-import {logger} from '#/ageAssurance'
+import {useAnalytics} from '#/analytics'
export function AgeRestrictedScreen({
children,
@@ -27,6 +27,7 @@ export function AgeRestrictedScreen({
rightHeaderSlot?: React.ReactNode
}) {
const {_} = useLingui()
+ const ax = useAnalytics()
const copy = useAgeAssuranceCopy()
const aa = useAgeAssurance()
@@ -74,7 +75,7 @@ export function AgeRestrictedScreen({
variant="solid"
color="primary"
onPress={() => {
- logger.metric('ageAssurance:navigateToSettings', {})
+ ax.metric('ageAssurance:navigateToSettings', {})
}}>
Go to account settings
diff --git a/src/components/contacts/FindContactsBannerNUX.tsx b/src/components/contacts/FindContactsBannerNUX.tsx
index 768fee519b..577474a3a4 100644
--- a/src/components/contacts/FindContactsBannerNUX.tsx
+++ b/src/components/contacts/FindContactsBannerNUX.tsx
@@ -6,12 +6,12 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {HITSLOP_10} from '#/lib/constants'
-import {logger} from '#/logger'
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
import {atoms as a, useTheme} from '#/alf'
import {Button} from '#/components/Button'
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
import {Link} from '../Link'
import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allowlist'
@@ -19,6 +19,7 @@ import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allow
export function FindContactsBannerNUX() {
const t = useTheme()
const {_} = useLingui()
+ const ax = useAnalytics()
const {visible, close} = useInternalState()
if (!visible) return null
@@ -30,7 +31,7 @@ export function FindContactsBannerNUX() {
to={{screen: 'FindContactsFlow'}}
label={_(msg`Import contacts to find your friends`)}
onPress={() => {
- logger.metric('contacts:nux:bannerPressed', {})
+ ax.metric('contacts:nux:bannerPressed', {})
}}
style={[
a.w_full,
@@ -84,6 +85,7 @@ export function FindContactsBannerNUX() {
)
}
function useInternalState() {
+ const ax = useAnalytics()
const {nux} = useNux(Nux.FindContactsDismissibleBanner)
const {mutate: save, variables} = useSaveNux()
const hidden = !!variables
@@ -103,7 +105,7 @@ function useInternalState() {
completed: true,
data: undefined,
})
- logger.metric('contacts:nux:bannerDismissed', {})
+ ax.metric('contacts:nux:bannerDismissed', {})
}
return {visible, close}
diff --git a/src/components/contacts/screens/GetContacts.tsx b/src/components/contacts/screens/GetContacts.tsx
index 5df967a8a5..909be81abc 100644
--- a/src/components/contacts/screens/GetContacts.tsx
+++ b/src/components/contacts/screens/GetContacts.tsx
@@ -28,6 +28,7 @@ import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {
contactsWithPhoneNumbersOnly,
filterMatchedNumbers,
@@ -51,6 +52,7 @@ export function GetContacts({
context: 'Onboarding' | 'Standalone'
}) {
const {_} = useLingui()
+ const ax = useAnalytics()
const agent = useAgent()
const insets = useSafeAreaInsets()
const gutters = useGutters([0, 'wide'])
@@ -100,16 +102,16 @@ export function GetContacts({
},
onSuccess: (result, contacts) => {
if (context === 'Onboarding') {
- logger.metric('onboarding:contacts:contactsShared', {})
+ ax.metric('onboarding:contacts:contactsShared', {})
}
if (result.matches.length > 0) {
- logger.metric('contacts:import:success', {
+ ax.metric('contacts:import:success', {
contactCount: contacts.length,
matchCount: result.matches.length,
entryPoint: context,
})
} else {
- logger.metric('contacts:import:failure', {
+ ax.metric('contacts:import:failure', {
reason: 'noValidNumbers',
entryPoint: context,
})
@@ -134,7 +136,7 @@ export function GetContacts({
})
},
onError: err => {
- logger.metric('contacts:import:failure', {
+ ax.metric('contacts:import:failure', {
reason: isNetworkError(err) ? 'networkError' : 'unknown',
entryPoint: context,
})
@@ -180,7 +182,7 @@ export function GetContacts({
permissions = await Contacts.requestPermissionsAsync()
}
- logger.metric('contacts:permission:request', {
+ ax.metric('contacts:permission:request', {
status: permissions.granted ? 'granted' : 'denied',
accessLevelIOS: ios(permissions.accessPrivileges),
})
diff --git a/src/components/contacts/screens/PhoneInput.tsx b/src/components/contacts/screens/PhoneInput.tsx
index 25bffaf144..8eec5742e8 100644
--- a/src/components/contacts/screens/PhoneInput.tsx
+++ b/src/components/contacts/screens/PhoneInput.tsx
@@ -31,6 +31,7 @@ import * as Layout from '#/components/Layout'
import {InlineLinkText} from '#/components/Link'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {useGeolocation} from '#/geolocation'
import {isFindContactsFeatureEnabled} from '../country-allowlist'
import {
@@ -52,6 +53,7 @@ export function PhoneInput({
onSkip: () => void
}) {
const {_} = useLingui()
+ const ax = useAnalytics()
const t = useTheme()
const agent = useAgent()
const location = useGeolocation()
@@ -85,7 +87,7 @@ export function PhoneInput({
payload: {phoneCountryCode, phoneNumber},
})
- logger.metric('contacts:phone:phoneEntered', {entryPoint: context})
+ ax.metric('contacts:phone:phoneEntered', {entryPoint: context})
},
onMutate: () => {
Keyboard.dismiss()
diff --git a/src/components/contacts/screens/VerifyNumber.tsx b/src/components/contacts/screens/VerifyNumber.tsx
index ec676ad724..c316c66af7 100644
--- a/src/components/contacts/screens/VerifyNumber.tsx
+++ b/src/components/contacts/screens/VerifyNumber.tsx
@@ -23,6 +23,7 @@ import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {OTPInput} from '../components/OTPInput'
import {constructFullPhoneNumber, prettyPhoneNumber} from '../phone-number'
import {type Action, type State, useOnPressBackButton} from '../state'
@@ -40,6 +41,7 @@ export function VerifyNumber({
}) {
const t = useTheme()
const {_} = useLingui()
+ const ax = useAnalytics()
const agent = useAgent()
const gutters = useGutters([0, 'wide'])
@@ -83,7 +85,7 @@ export function VerifyNumber({
})
}, 1000)
- logger.metric('contacts:phone:phoneVerified', {entryPoint: context})
+ ax.metric('contacts:phone:phoneVerified', {entryPoint: context})
},
onMutate: () => setError(null),
onError: err => {
diff --git a/src/components/contacts/screens/ViewMatches.tsx b/src/components/contacts/screens/ViewMatches.tsx
index d92cb88b1e..b9aec3ed95 100644
--- a/src/components/contacts/screens/ViewMatches.tsx
+++ b/src/components/contacts/screens/ViewMatches.tsx
@@ -39,6 +39,7 @@ import {Loader} from '#/components/Loader'
import * as ProfileCard from '#/components/ProfileCard'
import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import type * as bsky from '#/types/bsky'
import {InviteInfo} from '../components/InviteInfo'
import {type Action, type Contact, type Match, type State} from '../state'
@@ -83,6 +84,7 @@ export function ViewMatches({
}) {
const t = useTheme()
const {_} = useLingui()
+ const ax = useAnalytics()
const gutter = useGutters([0, 'wide'])
const moderationOpts = useModerationOpts()
const queryClient = useQueryClient()
@@ -109,9 +111,9 @@ export function ViewMatches({
const cumulativeFollowCount = useRef(0)
const onFollow = useCallback(() => {
- logger.metric('contacts:matches:follow', {entryPoint: context})
+ ax.metric('contacts:matches:follow', {entryPoint: context})
cumulativeFollowCount.current += 1
- }, [context])
+ }, [ax, context])
const {mutate: followAll, isPending: isFollowingAll} = useMutation({
mutationFn: async () => {
@@ -132,7 +134,7 @@ export function ViewMatches({
return followableDids
},
onMutate: () =>
- logger.metric('contacts:matches:followAll', {
+ ax.metric('contacts:matches:followAll', {
followCount: followableDids.length,
entryPoint: context,
}),
@@ -218,7 +220,7 @@ export function ViewMatches({
await agent.app.bsky.contact.dismissMatch({subject: did})
},
onMutate: did => {
- logger.metric('contacts:matches:dismiss', {entryPoint: context})
+ ax.metric('contacts:matches:dismiss', {entryPoint: context})
dispatch({type: 'DISMISS_MATCH', payload: {did}})
},
onSuccess: (_res, did) => {
@@ -392,7 +394,7 @@ export function ViewMatches({
label={context === 'Onboarding' ? _(msg`Next`) : _(msg`Done`)}
onPress={() => {
if (context === 'Onboarding') {
- logger.metric('onboarding:contacts:nextPressed', {
+ ax.metric('onboarding:contacts:nextPressed', {
matchCount: allMatches.length,
followCount: cumulativeFollowCount.current,
dismissedMatchCount: state.dismissedMatches.length,
@@ -516,6 +518,7 @@ function ContactItem({
const gutter = useGutters([0, 'wide'])
const t = useTheme()
const {_} = useLingui()
+ const ax = useAnalytics()
const {currentAccount} = useSession()
const name = contact.name ?? contact.firstName ?? contact.lastName
@@ -564,7 +567,7 @@ function ContactItem({
color="secondary"
size="small"
onPress={async () => {
- logger.metric('contacts:matches:invite', {
+ ax.metric('contacts:matches:invite', {
entryPoint: context,
})
try {
diff --git a/src/components/dialogs/GifSelect.tsx b/src/components/dialogs/GifSelect.tsx
index 259395a8c9..23fd2f38e6 100644
--- a/src/components/dialogs/GifSelect.tsx
+++ b/src/components/dialogs/GifSelect.tsx
@@ -11,7 +11,6 @@ import {Image} from 'expo-image'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
-import {logEvent} from '#/lib/statsig/statsig'
import {cleanError} from '#/lib/strings/errors'
import {
type Gif,
@@ -30,6 +29,7 @@ import {useThrottledValue} from '#/components/hooks/useThrottledValue'
import {ArrowLeft_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow'
import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass'
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
+import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
export function GifSelectDialog({
@@ -280,14 +280,15 @@ export function GifPreview({
gif: Gif
onSelectGif: (gif: Gif) => void
}) {
+ const ax = useAnalytics()
const {gtTablet} = useBreakpoints()
const {_} = useLingui()
const t = useTheme()
const onPress = useCallback(() => {
- logEvent('composer:gif:select', {})
+ ax.metric('composer:gif:select', {})
onSelectGif(gif)
- }, [onSelectGif, gif])
+ }, [ax, onSelectGif, gif])
return (