Overfetch trending topics before filtering (#11477)
This commit is contained in:
@@ -1,154 +0,0 @@
|
|||||||
import {useCallback} from 'react'
|
|
||||||
import {ScrollView, View} from 'react-native'
|
|
||||||
import {useLingui} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
useTrendingSettings,
|
|
||||||
useTrendingSettingsApi,
|
|
||||||
} from '#/state/preferences/trending'
|
|
||||||
import {useGetTrendsQuery} from '#/state/queries/trending/useGetTrendsQuery'
|
|
||||||
import {useTrendingConfig} from '#/state/service-config'
|
|
||||||
import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
|
||||||
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
|
|
||||||
import {atoms as a, useGutters, useTheme} from '#/alf'
|
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
|
||||||
import {Trending2_Stroke2_Corner2_Rounded as Graph} from '#/components/icons/Trending'
|
|
||||||
import * as Prompt from '#/components/Prompt'
|
|
||||||
import {TrendingTopicLink} from '#/components/TrendingTopics'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
import {useAnalytics} from '#/analytics'
|
|
||||||
|
|
||||||
const TRENDING_LIMIT = 14
|
|
||||||
|
|
||||||
export function TrendingInterstitial() {
|
|
||||||
const {enabled} = useTrendingConfig()
|
|
||||||
const {trendingDisabled} = useTrendingSettings()
|
|
||||||
return enabled && !trendingDisabled ? <Inner /> : null
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Inner() {
|
|
||||||
const t = useTheme()
|
|
||||||
const {t: l} = useLingui()
|
|
||||||
const ax = useAnalytics()
|
|
||||||
const gutters = useGutters([0, 'base', 0, 'base'])
|
|
||||||
const trendingPrompt = Prompt.usePromptControl()
|
|
||||||
const {setTrendingDisabled} = useTrendingSettingsApi()
|
|
||||||
const {
|
|
||||||
data: trending,
|
|
||||||
error,
|
|
||||||
isLoading,
|
|
||||||
} = useGetTrendsQuery({
|
|
||||||
limit: TRENDING_LIMIT,
|
|
||||||
refetchOnWindowFocus: true,
|
|
||||||
})
|
|
||||||
const noTopics = !isLoading && !error && !trending?.trends?.length
|
|
||||||
|
|
||||||
const onConfirmHide = useCallback(() => {
|
|
||||||
ax.metric('trendingTopics:hide', {context: 'interstitial'})
|
|
||||||
setTrendingDisabled(true)
|
|
||||||
}, [ax, setTrendingDisabled])
|
|
||||||
|
|
||||||
return error || noTopics ? null : (
|
|
||||||
<View style={[t.atoms.border_contrast_low, a.border_t, a.border_b]}>
|
|
||||||
<BlockDrawerGesture>
|
|
||||||
<ScrollView
|
|
||||||
horizontal
|
|
||||||
showsHorizontalScrollIndicator={false}
|
|
||||||
decelerationRate="fast">
|
|
||||||
<View style={[gutters, a.flex_row, a.align_center, a.gap_lg]}>
|
|
||||||
<View style={{paddingLeft: 4, paddingRight: 2}}>
|
|
||||||
<Graph size="sm" />
|
|
||||||
</View>
|
|
||||||
{isLoading ? (
|
|
||||||
<View style={[a.py_lg, a.flex_row, a.gap_lg, a.align_center]}>
|
|
||||||
<LoadingPlaceholder
|
|
||||||
width={80}
|
|
||||||
height={undefined}
|
|
||||||
style={{alignSelf: 'stretch'}}
|
|
||||||
/>
|
|
||||||
<LoadingPlaceholder
|
|
||||||
width={50}
|
|
||||||
height={undefined}
|
|
||||||
style={{alignSelf: 'stretch'}}
|
|
||||||
/>
|
|
||||||
<LoadingPlaceholder
|
|
||||||
width={120}
|
|
||||||
height={undefined}
|
|
||||||
style={{alignSelf: 'stretch'}}
|
|
||||||
/>
|
|
||||||
<LoadingPlaceholder
|
|
||||||
width={30}
|
|
||||||
height={undefined}
|
|
||||||
style={{alignSelf: 'stretch'}}
|
|
||||||
/>
|
|
||||||
<LoadingPlaceholder
|
|
||||||
width={180}
|
|
||||||
height={undefined}
|
|
||||||
style={{alignSelf: 'stretch'}}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
a.text_sm,
|
|
||||||
a.font_semi_bold,
|
|
||||||
]}>
|
|
||||||
{' '}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
) : !trending?.trends ? null : (
|
|
||||||
<>
|
|
||||||
{trending.trends.map((topic, index) => {
|
|
||||||
const rank = index + 1
|
|
||||||
return (
|
|
||||||
<TrendingTopicLink
|
|
||||||
key={topic.link}
|
|
||||||
topic={topic}
|
|
||||||
metricContext="interstitial"
|
|
||||||
rank={rank}
|
|
||||||
recId={trending.recId}
|
|
||||||
onPress={() => {
|
|
||||||
ax.metric('trendingTopic:click', {
|
|
||||||
context: 'interstitial',
|
|
||||||
rank,
|
|
||||||
recId: trending.recId,
|
|
||||||
})
|
|
||||||
}}>
|
|
||||||
<View style={[a.py_lg]}>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
a.text_sm,
|
|
||||||
a.font_semi_bold,
|
|
||||||
]}>
|
|
||||||
{topic.topic}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</TrendingTopicLink>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
<Button
|
|
||||||
label={l`Hide trending topics`}
|
|
||||||
size="tiny"
|
|
||||||
variant="ghost"
|
|
||||||
color="secondary"
|
|
||||||
shape="round"
|
|
||||||
onPress={() => trendingPrompt.open()}>
|
|
||||||
<ButtonIcon icon={X} />
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</BlockDrawerGesture>
|
|
||||||
|
|
||||||
<Prompt.Basic
|
|
||||||
control={trendingPrompt}
|
|
||||||
title={l`Hide trending topics?`}
|
|
||||||
description={l`You can update this later from your settings.`}
|
|
||||||
confirmButtonCta={l`Hide`}
|
|
||||||
onConfirm={onConfirmHide}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
useTrendingSettingsApi,
|
useTrendingSettingsApi,
|
||||||
} from '#/state/preferences/trending'
|
} from '#/state/preferences/trending'
|
||||||
import {
|
import {
|
||||||
|
DEFAULT_FETCH_LIMIT,
|
||||||
DEFAULT_LIMIT,
|
DEFAULT_LIMIT,
|
||||||
useGetTrendsQuery,
|
useGetTrendsQuery,
|
||||||
} from '#/state/queries/trending/useGetTrendsQuery'
|
} from '#/state/queries/trending/useGetTrendsQuery'
|
||||||
@@ -57,7 +58,10 @@ function Inner() {
|
|||||||
error,
|
error,
|
||||||
isLoading,
|
isLoading,
|
||||||
isRefetching,
|
isRefetching,
|
||||||
} = useGetTrendsQuery({limit: topicCount})
|
} = useGetTrendsQuery({
|
||||||
|
fetchLimit: Math.min(topicCount * 2, DEFAULT_FETCH_LIMIT),
|
||||||
|
limit: topicCount,
|
||||||
|
})
|
||||||
const noTopics = !isLoading && !error && !trending?.trends?.length
|
const noTopics = !isLoading && !error && !trending?.trends?.length
|
||||||
const showLoading = isLoading || isRefetching
|
const showLoading = isLoading || isRefetching
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ import {useAppviewClient} from '#/state/session'
|
|||||||
import {app} from '#/lexicons'
|
import {app} from '#/lexicons'
|
||||||
|
|
||||||
export const DEFAULT_LIMIT = 5
|
export const DEFAULT_LIMIT = 5
|
||||||
|
export const DEFAULT_FETCH_LIMIT = 20
|
||||||
|
|
||||||
type QueryProps = {
|
type QueryProps = {
|
||||||
|
fetchLimit?: number
|
||||||
limit?: number
|
limit?: number
|
||||||
refetchOnWindowFocus?: boolean
|
refetchOnWindowFocus?: boolean
|
||||||
}
|
}
|
||||||
@@ -29,12 +31,13 @@ function dedupe<T extends {link: string}>(trends: T[]): T[] {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createGetTrendsQueryKey = (limit?: number) =>
|
export const createGetTrendsQueryKey = (fetchLimit?: number) =>
|
||||||
limit === undefined ? ['trends'] : ['trends', {limit}]
|
fetchLimit === undefined ? ['trends'] : ['trends', {limit: fetchLimit}]
|
||||||
|
|
||||||
export function useGetTrendsQuery(props: QueryProps = {}) {
|
export function useGetTrendsQuery(props: QueryProps = {}) {
|
||||||
const client = useAppviewClient()
|
const client = useAppviewClient()
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
|
const fetchLimit = props.fetchLimit ?? DEFAULT_FETCH_LIMIT
|
||||||
const limit = props.limit ?? DEFAULT_LIMIT
|
const limit = props.limit ?? DEFAULT_LIMIT
|
||||||
const mutedWords = useMemo(() => {
|
const mutedWords = useMemo(() => {
|
||||||
return preferences?.moderationPrefs?.mutedWords || []
|
return preferences?.moderationPrefs?.mutedWords || []
|
||||||
@@ -44,13 +47,13 @@ export function useGetTrendsQuery(props: QueryProps = {}) {
|
|||||||
enabled: !!preferences,
|
enabled: !!preferences,
|
||||||
refetchOnWindowFocus: props.refetchOnWindowFocus,
|
refetchOnWindowFocus: props.refetchOnWindowFocus,
|
||||||
staleTime: STALE.MINUTES.THREE,
|
staleTime: STALE.MINUTES.THREE,
|
||||||
queryKey: createGetTrendsQueryKey(limit),
|
queryKey: createGetTrendsQueryKey(fetchLimit),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const contentLangs = getContentLanguages().join(',')
|
const contentLangs = getContentLanguages().join(',')
|
||||||
const data = await client.call(
|
const data = await client.call(
|
||||||
app.bsky.unspecced.getTrends,
|
app.bsky.unspecced.getTrends,
|
||||||
{
|
{
|
||||||
limit,
|
limit: fetchLimit,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -75,10 +78,10 @@ export function useGetTrendsQuery(props: QueryProps = {}) {
|
|||||||
text: `${t.topic} ${t.displayName} ${t.category}`,
|
text: `${t.topic} ${t.displayName} ${t.category}`,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
),
|
).slice(0, limit),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[mutedWords],
|
[limit, mutedWords],
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ import {
|
|||||||
PostFeedVideoGridRowPlaceholder,
|
PostFeedVideoGridRowPlaceholder,
|
||||||
} from '#/components/feeds/PostFeedVideoGridRow'
|
} from '#/components/feeds/PostFeedVideoGridRow'
|
||||||
import {FeedTrendingTopicsInterstitial} from '#/components/interstitials/FeedTrendingTopics'
|
import {FeedTrendingTopicsInterstitial} from '#/components/interstitials/FeedTrendingTopics'
|
||||||
import {TrendingInterstitial} from '#/components/interstitials/Trending'
|
|
||||||
import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interstitials/TrendingVideos'
|
import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interstitials/TrendingVideos'
|
||||||
import {isStandardSiteEmbed} from '#/components/Post/Embed/StandardSiteEmbed/utils'
|
import {isStandardSiteEmbed} from '#/components/Post/Embed/StandardSiteEmbed/utils'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
@@ -146,10 +145,6 @@ type FeedRow =
|
|||||||
type: 'interstitialProgressGuide'
|
type: 'interstitialProgressGuide'
|
||||||
key: string
|
key: string
|
||||||
}
|
}
|
||||||
| {
|
|
||||||
type: 'interstitialTrending'
|
|
||||||
key: string
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
type: 'interstitialFeedTrendingTopics'
|
type: 'interstitialFeedTrendingTopics'
|
||||||
key: string
|
key: string
|
||||||
@@ -853,8 +848,6 @@ let PostFeed = ({
|
|||||||
return <ProgressGuide />
|
return <ProgressGuide />
|
||||||
} else if (row.type === 'ageAssuranceBanner') {
|
} else if (row.type === 'ageAssuranceBanner') {
|
||||||
return <AgeAssuranceDismissibleFeedBanner />
|
return <AgeAssuranceDismissibleFeedBanner />
|
||||||
} else if (row.type === 'interstitialTrending') {
|
|
||||||
return <TrendingInterstitial />
|
|
||||||
} else if (row.type === 'interstitialFeedTrendingTopics') {
|
} else if (row.type === 'interstitialFeedTrendingTopics') {
|
||||||
return (
|
return (
|
||||||
<FeedTrendingTopicsInterstitial feedSliceIndex={row.feedSliceIndex} />
|
<FeedTrendingTopicsInterstitial feedSliceIndex={row.feedSliceIndex} />
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ function Inner() {
|
|||||||
error,
|
error,
|
||||||
isLoading,
|
isLoading,
|
||||||
} = useGetTrendsQuery({
|
} = useGetTrendsQuery({
|
||||||
limit: DEFAULT_LIMIT,
|
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
})
|
})
|
||||||
const noTopics = !isLoading && !error && !trending?.trends?.length
|
const noTopics = !isLoading && !error && !trending?.trends?.length
|
||||||
|
|||||||
Reference in New Issue
Block a user