Fall back to searching for users for non-english speakers

This commit is contained in:
Eric Bailey
2025-04-08 14:24:04 -05:00
parent f3d979b316
commit 052ffcf1d9
5 changed files with 116 additions and 21 deletions
+42 -11
View File
@@ -18,6 +18,7 @@ import {logger} from '#/logger'
import {type MetricEvents} from '#/logger/metrics'
import {useLanguagePrefs} from '#/state/preferences/languages'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {RQKEY_ROOT_PAGINATED as useActorSearchPaginatedQueryKeyRoot} from '#/state/queries/actor-search'
import {
type FeedPreviewItem,
useFeedPreviews,
@@ -29,10 +30,7 @@ import {
createGetSuggestedFeedsQueryKey,
useGetSuggestedFeedsQuery,
} from '#/state/queries/trending/useGetSuggestedFeedsQuery'
import {
getSuggestedUsersQueryKeyRoot,
useGetSuggestedUsersQuery,
} from '#/state/queries/trending/useGetSuggestedUsersQuery'
import {getSuggestedUsersQueryKeyRoot} from '#/state/queries/trending/useGetSuggestedUsersQuery'
import {createGetTrendsQueryKey} from '#/state/queries/trending/useGetTrendsQuery'
import {
createSuggestedStarterPacksQueryKey,
@@ -45,6 +43,10 @@ import {ViewFullThread} from '#/view/com/posts/ViewFullThread'
import {List} from '#/view/com/util/List'
import {FeedFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn'
import {
popularInterests,
useInterestsDisplayNames,
} from '#/screens/Onboarding/state'
import {
StarterPackCard,
StarterPackCardSkeleton,
@@ -53,6 +55,7 @@ import {ExploreInterestsCard} from '#/screens/Search/modules/ExploreInterestsCar
import {ExploreRecommendations} from '#/screens/Search/modules/ExploreRecommendations'
import {ExploreTrendingTopics} from '#/screens/Search/modules/ExploreTrendingTopics'
import {ExploreTrendingVideos} from '#/screens/Search/modules/ExploreTrendingVideos'
import {useSuggestedUsers} from '#/screens/Search/util/useSuggestedUsers'
import {atoms as a, native, platform, useTheme} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {Button} from '#/components/Button'
@@ -67,6 +70,7 @@ import {Trending2_Stroke2_Corner2_Rounded as Graph} from '#/components/icons/Tre
import {UserCircle_Stroke2_Corner0_Rounded as Person} from '#/components/icons/UserCircle'
import {Loader} from '#/components/Loader'
import * as ProfileCard from '#/components/ProfileCard'
import {boostInterests} from '#/components/ProgressGuide/FollowDialog'
import {SubtleHover} from '#/components/SubtleHover'
import {Text} from '#/components/Typography'
import * as ModuleHeader from './components/ModuleHeader'
@@ -138,6 +142,7 @@ type ExploreScreenItems =
metricsTag: MetricEvents['explore:module:searchButtonPress']['module']
tab: 'user' | 'profile' | 'feed'
}
hideDefaultTab?: boolean
}
| {
type: 'trendingTopics'
@@ -216,18 +221,30 @@ export function Explore({
const gate = useGate()
const guide = useProgressGuide('follow-10')
const [selectedInterest, setSelectedInterest] = useState<string | null>(null)
/*
* Begin special language handling
*/
const {contentLanguages} = useLanguagePrefs()
const userRequestsEnglish = useMemo(() => {
const useFullExperience = useMemo(() => {
return bcp47Match.basicFilter('en', contentLanguages).length > 0
}, [contentLanguages])
const personalizedInterests = preferences?.interests?.tags
const interestsDisplayNames = useInterestsDisplayNames()
const interests = Object.keys(interestsDisplayNames)
.sort(boostInterests(popularInterests))
.sort(boostInterests(personalizedInterests))
const {
data: suggestedUsers,
isLoading: suggestedUsersIsLoading,
error: suggestedUsersError,
isRefetching: suggestedUsersIsRefetching,
} = useGetSuggestedUsersQuery({
category: selectedInterest,
} = useSuggestedUsers({
category: selectedInterest || (useFullExperience ? null : interests[0]),
search: !useFullExperience,
})
/* End special language handling */
const {
data: feeds,
hasNextPage: hasNextFeedsPage,
@@ -294,6 +311,9 @@ export function Explore({
await qc.resetQueries({
queryKey: [getSuggestedUsersQueryKeyRoot],
}),
await qc.resetQueries({
queryKey: [useActorSearchPaginatedQueryKeyRoot],
}),
await qc.resetQueries({
queryKey: createGetSuggestedFeedsQueryKey(),
}),
@@ -342,6 +362,7 @@ export function Explore({
metricsTag: 'suggestedAccounts',
tab: 'user',
},
hideDefaultTab: !useFullExperience,
})
if (suggestedUsersIsLoading || suggestedUsersIsRefetching) {
@@ -361,6 +382,7 @@ export function Explore({
let seen = new Set()
const profileItems: ExploreScreenItems[] = []
for (const actor of suggestedUsers.actors) {
// checking for following still necessary if search data is used
if (!seen.has(actor.did) && !actor.viewer?.following) {
seen.add(actor.did)
profileItems.push({
@@ -377,7 +399,7 @@ export function Explore({
key: 'profileEmpty',
})
} else {
if (selectedInterest === null) {
if (selectedInterest === null && useFullExperience) {
// First "For You" tab, only show 5 to keep screen short
i.push(...profileItems.slice(0, 5))
} else {
@@ -403,6 +425,7 @@ export function Explore({
suggestedUsersIsRefetching,
suggestedUsersError,
selectedInterest,
useFullExperience,
])
const suggestedFeedsModule = useMemo(() => {
const i: ExploreScreenItems[] = []
@@ -574,7 +597,7 @@ export function Explore({
i.push(topBorder)
i.push(...interestsNuxModule)
if (userRequestsEnglish) {
if (useFullExperience) {
if (isNewUser) {
i.push(...suggestedFollowsModule)
i.push(...suggestedStarterPacksModule)
@@ -611,7 +634,7 @@ export function Explore({
feedPreviewsModule,
interestsNuxModule,
gate,
userRequestsEnglish,
useFullExperience,
])
const renderItem = useCallback(
@@ -655,6 +678,7 @@ export function Explore({
<SuggestedAccountsTabBar
selectedInterest={selectedInterest}
onSelectInterest={setSelectedInterest}
hideDefaultTab={item.hideDefaultTab}
/>
</View>
)
@@ -686,7 +710,13 @@ export function Explore({
return (
<View style={[a.px_lg, a.pb_lg]}>
<Admonition>
<Trans>No results for "{selectedInterest}".</Trans>
{selectedInterest ? (
<Trans>
No results for "{interestsDisplayNames[selectedInterest]}".
</Trans>
) : (
<Trans>No results.</Trans>
)}
</Admonition>
</View>
)
@@ -890,6 +920,7 @@ export function Explore({
focusSearchInput,
moderationOpts,
selectedInterest,
interestsDisplayNames,
_,
fetchNextPageFeedPreviews,
],
@@ -58,9 +58,11 @@ export function useLoadEnoughProfiles({
export function SuggestedAccountsTabBar({
selectedInterest,
onSelectInterest,
hideDefaultTab,
}: {
selectedInterest: string | null
onSelectInterest: (interest: string | null) => void
hideDefaultTab?: boolean
}) {
const {_} = useLingui()
const interestsDisplayNames = useInterestsDisplayNames()
@@ -72,8 +74,10 @@ export function SuggestedAccountsTabBar({
return (
<BlockDrawerGesture>
<Tabs
interests={['all', ...interests]}
selectedInterest={selectedInterest || 'all'}
interests={hideDefaultTab ? interests : ['all', ...interests]}
selectedInterest={
selectedInterest || (hideDefaultTab ? interests[0] : 'all')
}
onSelectTab={tab => {
logger.metric(
'explore:suggestedAccounts:tabPressed',
@@ -83,10 +87,14 @@ export function SuggestedAccountsTabBar({
onSelectInterest(tab === 'all' ? null : tab)
}}
hasSearchText={false}
interestsDisplayNames={{
all: _(msg`For You`),
...interestsDisplayNames,
}}
interestsDisplayNames={
hideDefaultTab
? interestsDisplayNames
: {
all: _(msg`For You`),
...interestsDisplayNames,
}
}
TabComponent={Tab}
contentContainerStyle={[
{
@@ -0,0 +1,56 @@
import {useMemo} from 'react'
import {useActorSearchPaginated} from '#/state/queries/actor-search'
import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
import {useInterestsDisplayNames} from '#/screens/Onboarding/state'
/**
* Conditional hook, used in case a user is a non-english speaker, in which
* case we fall back to searching for users instead of our more curated set.
*/
export function useSuggestedUsers({
category = null,
search = false,
}: {
category?: string | null
/**
* If true, we'll search for users using the translated value of `category`,
* based on the user's "app language setting
*/
search?: boolean
}) {
const interestsDisplayNames = useInterestsDisplayNames()
const curated = useGetSuggestedUsersQuery({
enabled: !search,
category,
})
const searched = useActorSearchPaginated({
enabled: !!search,
// use user's app language translation for this value
query: category ? interestsDisplayNames[category] : '',
limit: 10,
})
return useMemo(() => {
if (search) {
return {
// we're not paginating right now
data: searched?.data
? {
actors: searched.data.pages.flatMap(p => p.actors) ?? [],
}
: undefined,
isLoading: searched.isLoading,
error: searched.error,
isRefetching: searched.isRefetching,
}
} else {
return {
data: curated.data,
isLoading: curated.isLoading,
error: curated.error,
isRefetching: curated.isRefetching,
}
}
}, [curated, searched, search])
}
+1 -1
View File
@@ -17,7 +17,7 @@ import {useAgent} from '#/state/session'
const RQKEY_ROOT = 'actor-search'
export const RQKEY = (query: string) => [RQKEY_ROOT, query]
const RQKEY_ROOT_PAGINATED = `${RQKEY_ROOT}_paginated`
export const RQKEY_ROOT_PAGINATED = `${RQKEY_ROOT}_paginated`
export const RQKEY_PAGINATED = (query: string, limit?: number) => [
RQKEY_ROOT_PAGINATED,
query,
@@ -13,12 +13,12 @@ import {STALE} from '#/state/queries'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {useAgent} from '#/state/session'
export type QueryProps = {category?: string | null}
export type QueryProps = {category?: string | null; enabled?: boolean}
export const getSuggestedUsersQueryKeyRoot = 'unspecced-suggested-users'
export const createGetSuggestedUsersQueryKey = (props: QueryProps) => [
getSuggestedUsersQueryKeyRoot,
...Object.values(props),
props.category,
]
export function useGetSuggestedUsersQuery(props: QueryProps) {
@@ -26,7 +26,7 @@ export function useGetSuggestedUsersQuery(props: QueryProps) {
const {data: preferences} = usePreferencesQuery()
return useQuery({
enabled: !!preferences,
enabled: !!preferences && props.enabled,
staleTime: STALE.MINUTES.THREE,
queryKey: createGetSuggestedUsersQueryKey(props),
queryFn: async () => {