Files
bsky-social-app/src/state/queries/trending/useGetTrendsQuery.ts
T

88 lines
2.5 KiB
TypeScript

import {useCallback, useMemo} from 'react'
import {hasMutedWord} from '@bsky/sdk/moderation'
import {useQuery} from '@tanstack/react-query'
import {
aggregateUserInterests,
createBskyTopicsHeader,
} from '#/lib/api/feed/utils'
import {logger} from '#/logger'
import {getContentLanguages} from '#/state/preferences/languages'
import {STALE} from '#/state/queries'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {useAppviewClient} from '#/state/session'
import {app} from '#/lexicons'
export const DEFAULT_LIMIT = 5
export const DEFAULT_FETCH_LIMIT = 20
type QueryProps = {
fetchLimit?: number
limit?: number
refetchOnWindowFocus?: boolean
}
function dedupe<T extends {link: string}>(trends: T[]): T[] {
const seen = new Set<string>()
return trends.filter(trend => {
if (seen.has(trend.link)) return false
seen.add(trend.link)
return true
})
}
export const createGetTrendsQueryKey = (fetchLimit?: number) =>
fetchLimit === undefined ? ['trends'] : ['trends', {limit: fetchLimit}]
export function useGetTrendsQuery(props: QueryProps = {}) {
const client = useAppviewClient()
const {data: preferences} = usePreferencesQuery()
const fetchLimit = props.fetchLimit ?? DEFAULT_FETCH_LIMIT
const limit = props.limit ?? DEFAULT_LIMIT
const mutedWords = useMemo(() => {
return preferences?.moderationPrefs?.mutedWords || []
}, [preferences?.moderationPrefs])
return useQuery({
enabled: !!preferences,
refetchOnWindowFocus: props.refetchOnWindowFocus,
staleTime: STALE.MINUTES.THREE,
queryKey: createGetTrendsQueryKey(fetchLimit),
queryFn: async () => {
const contentLangs = getContentLanguages().join(',')
const data = await client.call(
app.bsky.unspecced.getTrends,
{
limit: fetchLimit,
},
{
headers: {
...createBskyTopicsHeader(aggregateUserInterests(preferences)),
'Accept-Language': contentLangs,
},
},
)
if (!data.recIdStr) {
logger.debug('useGetTrendsQuery response missing recIdStr')
}
return data
},
select: useCallback(
(data: app.bsky.unspecced.getTrends.$OutputBody) => {
return {
recId: data.recIdStr,
trends: dedupe(
(data.trends ?? []).filter(t => {
return !hasMutedWord({
mutedWords,
text: `${t.topic} ${t.displayName} ${t.category}`,
})
}),
).slice(0, limit),
}
},
[limit, mutedWords],
),
})
}