Fall back to searching for users for non-english speakers
This commit is contained in:
@@ -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])
|
||||
}
|
||||
@@ -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 () => {
|
||||
|
||||
Reference in New Issue
Block a user