From 222954b397202b5acfb00c095d2fc520aaf1bbde Mon Sep 17 00:00:00 2001
From: DS Boyce <260543580+ds-boyce@users.noreply.github.com>
Date: Wed, 25 Mar 2026 15:13:23 -0700
Subject: [PATCH] Pass correct log context to suggested user metrics (#10074)
(cherry picked from commit d44060a34e5078a22eb290613de09ad1a35cd09b)
---
src/analytics/metrics/types.ts | 29 +++---
src/components/FeedInterstitials.tsx | 48 ++++-----
src/components/ProgressGuide/FollowDialog.tsx | 97 ++++++++++++-------
3 files changed, 98 insertions(+), 76 deletions(-)
diff --git a/src/analytics/metrics/types.ts b/src/analytics/metrics/types.ts
index 113bef9137..1f6b25278b 100644
--- a/src/analytics/metrics/types.ts
+++ b/src/analytics/metrics/types.ts
@@ -480,10 +480,12 @@ export type Events = {
'suggestedUser:follow': {
logContext:
| 'Explore'
- | 'InterstitialDiscover'
- | 'InterstitialProfile'
- | 'Profile'
+ | 'DiscoverInterstitial'
+ | 'ProfileInterstitial'
+ | 'ProfileHeader'
| 'Onboarding'
+ | 'SeeMoreSuggestedUsers'
+ | 'ProgressGuide'
location: 'Card' | 'Profile' | 'FollowAll'
recId?: number | string
position: number
@@ -493,9 +495,11 @@ export type Events = {
'suggestedUser:press': {
logContext:
| 'Explore'
- | 'InterstitialDiscover'
- | 'InterstitialProfile'
+ | 'DiscoverInterstitial'
+ | 'ProfileInterstitial'
+ | 'ProfileHeader'
| 'Onboarding'
+ | 'SeeMoreSuggestedUsers'
recId?: number | string
position: number
suggestedDid: string
@@ -504,10 +508,11 @@ export type Events = {
'suggestedUser:seen': {
logContext:
| 'Explore'
- | 'InterstitialDiscover'
- | 'InterstitialProfile'
- | 'Profile'
+ | 'DiscoverInterstitial'
+ | 'ProfileInterstitial'
+ | 'ProfileHeader'
| 'Onboarding'
+ | 'SeeMoreSuggestedUsers'
| 'ProgressGuide'
recId?: number | string
position: number
@@ -517,14 +522,14 @@ export type Events = {
'suggestedUser:seeMore': {
logContext:
| 'Explore'
- | 'InterstitialDiscover'
- | 'InterstitialProfile'
- | 'Profile'
+ | 'DiscoverInterstitial'
+ | 'ProfileInterstitial'
+ | 'ProfileHeader'
| 'Onboarding'
recId?: number | string
}
'suggestedUser:dismiss': {
- logContext: 'InterstitialDiscover' | 'InterstitialProfile'
+ logContext: 'DiscoverInterstitial' | 'ProfileInterstitial' | 'ProfileHeader'
recId?: number | string
position: number
suggestedDid: string
diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx
index af73d904b7..645b90a4f6 100644
--- a/src/components/FeedInterstitials.tsx
+++ b/src/components/FeedInterstitials.tsx
@@ -8,9 +8,7 @@ import Animated, {
LinearTransition,
} from 'react-native-reanimated'
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
-import {msg} from '@lingui/core/macro'
-import {useLingui} from '@lingui/react'
-import {Trans} from '@lingui/react/macro'
+import {Trans, useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native'
import {type NavigationProp} from '#/lib/routes/types'
@@ -295,7 +293,7 @@ export function ProfileGrid({
}) {
const t = useTheme()
const ax = useAnalytics()
- const {_} = useLingui()
+ const {t: l} = useLingui()
const moderationOpts = useModerationOpts()
const {gtMobile} = useBreakpoints()
const followDialogControl = useDialogControl()
@@ -312,10 +310,10 @@ export function ProfileGrid({
const containerRef = useRef(null)
const hasTrackedRef = useRef(false)
const logContext: Metrics['suggestedUser:seen']['logContext'] = isFeedContext
- ? 'InterstitialDiscover'
+ ? 'DiscoverInterstitial'
: isProfileHeaderContext
- ? 'Profile'
- : 'InterstitialProfile'
+ ? 'ProfileHeader'
+ : 'ProfileInterstitial'
// Callback to fire seen events
const fireSeen = useCallback(() => {
@@ -336,7 +334,7 @@ export function ProfileGrid({
})
}
})
- }, [ax, isLoading, error, profiles, maxLength, logContext])
+ }, [isLoading, error, profiles, maxLength, ax, logContext])
// For profile header, fire when isVisible becomes true
useEffect(() => {
@@ -424,9 +422,7 @@ export function ProfileGrid({
profile={profile.actor}
onPress={() => {
ax.metric('suggestedUser:press', {
- logContext: isFeedContext
- ? 'InterstitialDiscover'
- : 'InterstitialProfile',
+ logContext,
recId: profile.recId,
position: index,
suggestedDid: profile.actor.did,
@@ -442,14 +438,12 @@ export function ProfileGrid({
{onDismiss && (
-
-
{gtMobile ? (
@@ -620,7 +610,7 @@ export function ProfileGrid({
onPress={() => {
followDialogControl.open()
ax.metric('suggestedUser:seeMore', {
- logContext: 'Explore',
+ logContext,
})
}}
/>
@@ -634,11 +624,11 @@ export function ProfileGrid({
}
function SeeMoreSuggestedProfilesCard({onPress}: {onPress: () => void}) {
- const {_} = useLingui()
+ const {t: l} = useLingui()
return (
Browse more suggestions
@@ -768,7 +758,7 @@ export function SuggestedFeeds() {
{content}
{
navigation.navigate('SearchTab')
}}
diff --git a/src/components/ProgressGuide/FollowDialog.tsx b/src/components/ProgressGuide/FollowDialog.tsx
index 643a1d018f..27b759ba7d 100644
--- a/src/components/ProgressGuide/FollowDialog.tsx
+++ b/src/components/ProgressGuide/FollowDialog.tsx
@@ -1,9 +1,7 @@
import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {TextInput, View, type ViewToken} from 'react-native'
import {type ModerationOpts} from '@atproto/api'
-import {msg} from '@lingui/core/macro'
-import {useLingui} from '@lingui/react'
-import {Trans} from '@lingui/react/macro'
+import {Trans, useLingui} from '@lingui/react/macro'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
@@ -64,14 +62,14 @@ export function FollowDialog({
showArrow?: boolean
}) {
const ax = useAnalytics()
- const {_} = useLingui()
+ const {t: l} = useLingui()
const control = Dialog.useDialogControl()
const {gtPhone} = useBreakpoints()
return (
<>
{
control.open()
ax.metric('progressGuide:followDialog:open', {})
@@ -112,7 +110,7 @@ let lastSelectedInterest = ''
let lastSearchText = ''
function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
- const {_} = useLingui()
+ const {t: l} = useLingui()
const ax = useAnalytics()
const interestsDisplayNames = useInterestsDisplayNames()
const {data: preferences} = usePreferencesQuery()
@@ -182,7 +180,7 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
_items.push({
type: 'empty',
key: 'empty',
- message: _(msg`We're having network issues, try again`),
+ message: l`We're having network issues, try again`,
})
} else {
const seen = new Set()
@@ -208,12 +206,12 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
!_items.length &&
!isSearchResultsError
) {
- _items.push({type: 'empty', key: 'empty', message: _(msg`No results`)})
+ _items.push({type: 'empty', key: 'empty', message: l`No results`})
}
return _items
}, [
- _,
+ l,
suggestions,
suggestionsError,
isFetchingSuggestions,
@@ -226,6 +224,9 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
isSearchResultsError,
])
+ const isGuide = Boolean(guide)
+ const recIdForLogging = hasSearchText ? undefined : suggestions?.recId
+
const renderItems = useCallback(
({item, index}: {item: Item; index: number}) => {
switch (item.type) {
@@ -235,6 +236,9 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
profile={item.profile}
moderationOpts={moderationOpts!}
noBorder={index === 0}
+ position={index}
+ recId={recIdForLogging}
+ isGuide={isGuide}
/>
)
}
@@ -248,7 +252,7 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
return null
}
},
- [moderationOpts],
+ [moderationOpts, recIdForLogging, isGuide],
)
// Track seen profiles
@@ -269,8 +273,8 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
i => i.type === 'profile' && i.profile.did === item.profile.did,
)
ax.metric('suggestedUser:seen', {
- logContext: 'ProgressGuide',
- recId: hasSearchText ? undefined : suggestions?.recId,
+ logContext: isGuide ? 'ProgressGuide' : 'SeeMoreSuggestedUsers',
+ recId: recIdForLogging,
position: position !== -1 ? position : 0,
suggestedDid: item.profile.did,
category: selectedInterestRef.current,
@@ -404,7 +408,7 @@ let Header = ({
Header = memo(Header)
function HeaderTop({guide}: {guide?: Follow10ProgressGuide}) {
- const {_} = useLingui()
+ const {t: l} = useLingui()
const t = useTheme()
const control = Dialog.useDialogContext()
return (
@@ -438,7 +442,7 @@ function HeaderTop({guide}: {guide?: Follow10ProgressGuide}) {
)}
{IS_WEB ? (
void
}): React.ReactNode => {
const t = useTheme()
- const {_} = useLingui()
+ const {t: l} = useLingui()
const label = active
- ? _(
- msg({
- message: `Search for "${interestsDisplayName}" (active)`,
- comment:
- 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is currently selected.',
- }),
- )
- : _(
- msg({
- message: `Search for "${interestsDisplayName}"`,
- comment:
- 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is not currently active and can be selected.',
- }),
- )
+ ? l({
+ message: `Search for "${interestsDisplayName}" (active)`,
+ comment:
+ 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is currently selected.',
+ })
+ : l({
+ message: `Search for "${interestsDisplayName}"`,
+ comment:
+ 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is not currently active and can be selected.',
+ })
return (
{
return (
)
}
@@ -552,14 +561,21 @@ function FollowProfileCardInner({
moderationOpts,
onFollow,
noBorder,
+ position,
+ recId,
+ isGuide,
}: {
profile: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts
onFollow?: () => void
noBorder?: boolean
+ position: number
+ recId?: string
+ isGuide: boolean
}) {
const control = Dialog.useDialogContext()
const t = useTheme()
+ const ax = useAnalytics()
return (
{
+ ax.metric('suggestedUser:follow', {
+ logContext: isGuide
+ ? 'ProgressGuide'
+ : 'SeeMoreSuggestedUsers',
+ location: 'Card',
+ recId,
+ position,
+ suggestedDid: profile.did,
+ category: null,
+ })
+ onFollow?.()
+ }}
colorInverted
/>
@@ -632,7 +660,7 @@ function SearchInput({
defaultValue: string
}) {
const t = useTheme()
- const {_} = useLingui()
+ const {t: l} = useLingui()
const {
state: hovered,
onIn: onMouseEnter,
@@ -652,10 +680,9 @@ function SearchInput({
size="md"
fill={interacted ? t.palette.primary_500 : t.palette.contrast_300}
/>
-
)