Log rank and parent index with trending topic events (#11331)

This commit is contained in:
DS Boyce
2026-07-29 16:14:44 -07:00
committed by GitHub
parent 15c6c7955d
commit 91517af01c
7 changed files with 143 additions and 98 deletions
+4
View File
@@ -756,10 +756,14 @@ export type Events = {
'trendingTopic:seen': { 'trendingTopic:seen': {
context: 'sidebar' | 'interstitial' | 'explore' context: 'sidebar' | 'interstitial' | 'explore'
recId?: string recId?: string
rank: number
feedSliceIndex?: number
} }
'trendingTopic:click': { 'trendingTopic:click': {
context: 'sidebar' | 'interstitial' | 'explore' context: 'sidebar' | 'interstitial' | 'explore'
recId?: string recId?: string
rank: number
feedSliceIndex?: number
} }
'trendingVideos:show': { 'trendingVideos:show': {
context: 'settings' context: 'settings'
+11 -2
View File
@@ -13,16 +13,18 @@ import {type Metrics, useAnalytics} from '#/analytics'
export function TrendingTopicLink({ export function TrendingTopicLink({
topic: raw, topic: raw,
metricContext, metricContext,
rank,
recId, recId,
children, children,
...rest ...rest
}: { }: {
topic: AppBskyUnspeccedDefs.TrendView topic: AppBskyUnspeccedDefs.TrendView
metricContext: Metrics['trendingTopic:seen']['context'] metricContext: Metrics['trendingTopic:seen']['context']
rank: number
recId?: string recId?: string
} & Omit<LinkProps, 'to' | 'label'>) { } & Omit<LinkProps, 'to' | 'label'>) {
const topic = useTopic(raw) const topic = useTopic(raw)
useTrendingTopicSeen(metricContext, recId) useTrendingTopicSeen(metricContext, rank, recId)
return ( return (
<InternalLink <InternalLink
@@ -37,11 +39,18 @@ export function TrendingTopicLink({
export function useTrendingTopicSeen( export function useTrendingTopicSeen(
context: Metrics['trendingTopic:seen']['context'], context: Metrics['trendingTopic:seen']['context'],
rank: number,
recId?: string, recId?: string,
feedSliceIndex?: number,
) { ) {
const ax = useAnalytics() const ax = useAnalytics()
const trackSeen = useCallOnce(() => { const trackSeen = useCallOnce(() => {
ax.metric('trendingTopic:seen', {context, recId}) ax.metric('trendingTopic:seen', {
context,
rank,
feedSliceIndex,
recId,
})
}) })
useEffect(() => { useEffect(() => {
@@ -32,15 +32,21 @@ import {useAnalytics} from '#/analytics'
const TOPIC_COUNT = 3 const TOPIC_COUNT = 3
export function FeedTrendingTopicsInterstitial() { export function FeedTrendingTopicsInterstitial({
feedSliceIndex,
}: {
feedSliceIndex: number
}) {
const {enabled} = useTrendingConfig() const {enabled} = useTrendingConfig()
const {trendingDisabled} = useTrendingSettings() const {trendingDisabled} = useTrendingSettings()
const {rightNavVisible} = useLayoutBreakpoints() const {rightNavVisible} = useLayoutBreakpoints()
return enabled && !trendingDisabled && !rightNavVisible ? <Inner /> : null return enabled && !trendingDisabled && !rightNavVisible ? (
<Inner feedSliceIndex={feedSliceIndex} />
) : null
} }
function Inner() { function Inner({feedSliceIndex}: {feedSliceIndex: number}) {
const t = useTheme() const t = useTheme()
const {t: l} = useLingui() const {t: l} = useLingui()
const gutters = useGutters([0, 'base']) const gutters = useGutters([0, 'base'])
@@ -132,20 +138,26 @@ function Inner() {
? Array.from({length: TOPIC_COUNT}).map((_, i) => ( ? Array.from({length: TOPIC_COUNT}).map((_, i) => (
<TrendingTopicRowSkeleton key={i} rank={i + 1} /> <TrendingTopicRowSkeleton key={i} rank={i + 1} />
)) ))
: trending?.trends?.map((trend, index) => ( : trending?.trends?.map((trend, index) => {
<TrendRow const rank = index + 1
key={trend.link} return (
trend={trend} <TrendRow
rank={index + 1} key={trend.link}
recId={trending.recId} trend={trend}
onPress={() => { rank={rank}
ax.metric('trendingTopic:click', { feedSliceIndex={feedSliceIndex}
context: 'interstitial', recId={trending.recId}
recId: trending.recId, onPress={() => {
}) ax.metric('trendingTopic:click', {
}} context: 'interstitial',
/> rank,
))} feedSliceIndex,
recId: trending.recId,
})
}}
/>
)
})}
</View> </View>
</View> </View>
</View> </View>
@@ -166,11 +178,13 @@ function Inner() {
function TrendRow({ function TrendRow({
trend, trend,
rank, rank,
feedSliceIndex,
recId, recId,
onPress, onPress,
}: ViewStyleProp & { }: ViewStyleProp & {
trend: AppBskyUnspeccedDefs.TrendView trend: AppBskyUnspeccedDefs.TrendView
rank: number rank: number
feedSliceIndex: number
recId?: string recId?: string
children?: React.ReactNode children?: React.ReactNode
onPress?: () => void onPress?: () => void
@@ -180,7 +194,7 @@ function TrendRow({
const actors = useModerateTrendingActors(trend.actors) const actors = useModerateTrendingActors(trend.actors)
const formattedPostCount = formatCount(i18n, trend.postCount) const formattedPostCount = formatCount(i18n, trend.postCount)
useTrendingTopicSeen('interstitial', recId) useTrendingTopicSeen('interstitial', rank, recId, feedSliceIndex)
return ( return (
<Link <Link
+29 -24
View File
@@ -98,30 +98,35 @@ export function Inner() {
</View> </View>
) : !trending?.trends ? null : ( ) : !trending?.trends ? null : (
<> <>
{trending.trends.map(topic => ( {trending.trends.map((topic, index) => {
<TrendingTopicLink const rank = index + 1
key={topic.link} return (
topic={topic} <TrendingTopicLink
metricContext="interstitial" key={topic.link}
recId={trending.recId} topic={topic}
onPress={() => { metricContext="interstitial"
ax.metric('trendingTopic:click', { rank={rank}
context: 'interstitial', recId={trending.recId}
recId: trending.recId, onPress={() => {
}) ax.metric('trendingTopic:click', {
}}> context: 'interstitial',
<View style={[a.py_lg]}> rank,
<Text recId: trending.recId,
style={[ })
t.atoms.text_contrast_medium, }}>
a.text_sm, <View style={[a.py_lg]}>
a.font_semi_bold, <Text
]}> style={[
{topic.topic} t.atoms.text_contrast_medium,
</Text> a.text_sm,
</View> a.font_semi_bold,
</TrendingTopicLink> ]}>
))} {topic.topic}
</Text>
</View>
</TrendingTopicLink>
)
})}
<Button <Button
label={l`Hide trending topics`} label={l`Hide trending topics`}
size="tiny" size="tiny"
@@ -79,20 +79,24 @@ function Inner() {
? Array.from({length: topicCount}).map((__, i) => ( ? Array.from({length: topicCount}).map((__, i) => (
<TrendingTopicRowSkeleton key={i} /> <TrendingTopicRowSkeleton key={i} />
)) ))
: trending?.trends.map((trend, index) => ( : trending?.trends.map((trend, index) => {
<TrendRow const rank = index + 1
key={trend.link} return (
trend={trend} <TrendRow
rank={index + 1} key={trend.link}
recId={trending.recId} trend={trend}
onPress={() => { rank={rank}
ax.metric('trendingTopic:click', { recId={trending.recId}
context: 'explore', onPress={() => {
recId: trending.recId, ax.metric('trendingTopic:click', {
}) context: 'explore',
}} rank,
/> recId: trending.recId,
))} })
}}
/>
)
})}
</View> </View>
<Prompt.Basic <Prompt.Basic
@@ -128,7 +132,7 @@ export function TrendRow({
const actors = useModerateTrendingActors(trend.actors) const actors = useModerateTrendingActors(trend.actors)
const formattedPostCount = formatCount(i18n, trend.postCount) const formattedPostCount = formatCount(i18n, trend.postCount)
useTrendingTopicSeen('explore', recId) useTrendingTopicSeen('explore', rank, recId)
const description = useMemo(() => { const description = useMemo(() => {
if (!trend.description) return if (!trend.description) return
+5 -1
View File
@@ -159,6 +159,7 @@ type FeedRow =
| { | {
type: 'interstitialFeedTrendingTopics' type: 'interstitialFeedTrendingTopics'
key: string key: string
feedSliceIndex: number
} }
| { | {
type: 'interstitialTrendingVideos' type: 'interstitialTrendingVideos'
@@ -583,6 +584,7 @@ let PostFeed = ({
arr.push({ arr.push({
type: 'interstitialFeedTrendingTopics', type: 'interstitialFeedTrendingTopics',
key: 'interstitialFeedTrendingTopics-' + sliceIndex, key: 'interstitialFeedTrendingTopics-' + sliceIndex,
feedSliceIndex: sliceIndex,
}) })
} else if (sliceIndex === trendingIndices.videos) { } else if (sliceIndex === trendingIndices.videos) {
if (areVideoFeedsEnabled && !trendingVideoDisabled) { if (areVideoFeedsEnabled && !trendingVideoDisabled) {
@@ -858,7 +860,9 @@ let PostFeed = ({
} else if (row.type === 'interstitialTrending') { } else if (row.type === 'interstitialTrending') {
return <TrendingInterstitial /> return <TrendingInterstitial />
} else if (row.type === 'interstitialFeedTrendingTopics') { } else if (row.type === 'interstitialFeedTrendingTopics') {
return <FeedTrendingTopicsInterstitial /> return (
<FeedTrendingTopicsInterstitial feedSliceIndex={row.feedSliceIndex} />
)
} else if (row.type === 'liveEventFeedsAndTrendingBanner') { } else if (row.type === 'liveEventFeedsAndTrendingBanner') {
return <DiscoverFeedLiveEventFeedsAndTrendingBanner /> return <DiscoverFeedLiveEventFeedsAndTrendingBanner />
} else if (row.type === 'composerPrompt') { } else if (row.type === 'composerPrompt') {
@@ -119,44 +119,49 @@ function Inner() {
)) ))
) : !trending?.trends ? null : ( ) : !trending?.trends ? null : (
<> <>
{trending.trends.slice(0, DEFAULT_LIMIT).map((topic, i) => ( {trending.trends.slice(0, DEFAULT_LIMIT).map((topic, i) => {
<TrendingTopicLink const rank = i + 1
key={topic.link} return (
topic={topic} <TrendingTopicLink
metricContext="sidebar" key={topic.link}
recId={trending.recId} topic={topic}
onPress={() => { metricContext="sidebar"
ax.metric('trendingTopic:click', { rank={rank}
context: 'sidebar', recId={trending.recId}
recId: trending.recId, onPress={() => {
}) ax.metric('trendingTopic:click', {
}}> context: 'sidebar',
{({hovered}) => ( rank,
<View style={[a.flex_1, a.flex_row, a.gap_xs]}> recId: trending.recId,
<Text })
style={[ }}>
a.text_sm, {({hovered}) => (
a.leading_snug, <View style={[a.flex_1, a.flex_row, a.gap_xs]}>
t.atoms.text_contrast_low, <Text
{minWidth: 16}, style={[
]}> a.text_sm,
{i + 1}. a.leading_snug,
</Text> t.atoms.text_contrast_low,
<Text {minWidth: 16},
style={[ ]}>
a.flex_1, {rank}.
a.text_sm, </Text>
a.leading_snug, <Text
hovered style={[
? [t.atoms.text, a.underline] a.flex_1,
: t.atoms.text_contrast_medium, a.text_sm,
]}> a.leading_snug,
{topic.displayName ?? topic.topic} hovered
</Text> ? [t.atoms.text, a.underline]
</View> : t.atoms.text_contrast_medium,
)} ]}>
</TrendingTopicLink> {topic.displayName ?? topic.topic}
))} </Text>
</View>
)}
</TrendingTopicLink>
)
})}
</> </>
)} )}
</View> </View>