[Explore] Reduced experience (#8160)
* Only show suggested users for non-english users * Fall back to searching for users for non-english speakers * Disable other queries if full experience is disabled * Bump package * If no content langs, use full exp
This commit is contained in:
+1
-1
@@ -58,7 +58,7 @@
|
|||||||
"icons:optimize": "svgo -f ./assets/icons"
|
"icons:optimize": "svgo -f ./assets/icons"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atproto/api": "^0.14.20",
|
"@atproto/api": "^0.14.21",
|
||||||
"@bitdrift/react-native": "^0.6.8",
|
"@bitdrift/react-native": "^0.6.8",
|
||||||
"@braintree/sanitize-url": "^6.0.2",
|
"@braintree/sanitize-url": "^6.0.2",
|
||||||
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
||||||
|
|||||||
@@ -8,13 +8,16 @@ import {
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
import * as bcp47Match from 'bcp-47-match'
|
||||||
|
|
||||||
import {useGate} from '#/lib/statsig/statsig'
|
import {useGate} from '#/lib/statsig/statsig'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {type MetricEvents} from '#/logger/metrics'
|
import {type MetricEvents} from '#/logger/metrics'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences/languages'
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
|
import {RQKEY_ROOT_PAGINATED as useActorSearchPaginatedQueryKeyRoot} from '#/state/queries/actor-search'
|
||||||
import {
|
import {
|
||||||
type FeedPreviewItem,
|
type FeedPreviewItem,
|
||||||
useFeedPreviews,
|
useFeedPreviews,
|
||||||
@@ -26,10 +29,7 @@ import {
|
|||||||
createGetSuggestedFeedsQueryKey,
|
createGetSuggestedFeedsQueryKey,
|
||||||
useGetSuggestedFeedsQuery,
|
useGetSuggestedFeedsQuery,
|
||||||
} from '#/state/queries/trending/useGetSuggestedFeedsQuery'
|
} from '#/state/queries/trending/useGetSuggestedFeedsQuery'
|
||||||
import {
|
import {getSuggestedUsersQueryKeyRoot} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
||||||
getSuggestedUsersQueryKeyRoot,
|
|
||||||
useGetSuggestedUsersQuery,
|
|
||||||
} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
|
||||||
import {createGetTrendsQueryKey} from '#/state/queries/trending/useGetTrendsQuery'
|
import {createGetTrendsQueryKey} from '#/state/queries/trending/useGetTrendsQuery'
|
||||||
import {
|
import {
|
||||||
createSuggestedStarterPacksQueryKey,
|
createSuggestedStarterPacksQueryKey,
|
||||||
@@ -42,6 +42,10 @@ import {ViewFullThread} from '#/view/com/posts/ViewFullThread'
|
|||||||
import {List} from '#/view/com/util/List'
|
import {List} from '#/view/com/util/List'
|
||||||
import {FeedFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
import {FeedFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
||||||
import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn'
|
import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn'
|
||||||
|
import {
|
||||||
|
popularInterests,
|
||||||
|
useInterestsDisplayNames,
|
||||||
|
} from '#/screens/Onboarding/state'
|
||||||
import {
|
import {
|
||||||
StarterPackCard,
|
StarterPackCard,
|
||||||
StarterPackCardSkeleton,
|
StarterPackCardSkeleton,
|
||||||
@@ -50,6 +54,7 @@ import {ExploreInterestsCard} from '#/screens/Search/modules/ExploreInterestsCar
|
|||||||
import {ExploreRecommendations} from '#/screens/Search/modules/ExploreRecommendations'
|
import {ExploreRecommendations} from '#/screens/Search/modules/ExploreRecommendations'
|
||||||
import {ExploreTrendingTopics} from '#/screens/Search/modules/ExploreTrendingTopics'
|
import {ExploreTrendingTopics} from '#/screens/Search/modules/ExploreTrendingTopics'
|
||||||
import {ExploreTrendingVideos} from '#/screens/Search/modules/ExploreTrendingVideos'
|
import {ExploreTrendingVideos} from '#/screens/Search/modules/ExploreTrendingVideos'
|
||||||
|
import {useSuggestedUsers} from '#/screens/Search/util/useSuggestedUsers'
|
||||||
import {atoms as a, native, platform, useTheme} from '#/alf'
|
import {atoms as a, native, platform, useTheme} from '#/alf'
|
||||||
import {Admonition} from '#/components/Admonition'
|
import {Admonition} from '#/components/Admonition'
|
||||||
import {Button} from '#/components/Button'
|
import {Button} from '#/components/Button'
|
||||||
@@ -64,6 +69,7 @@ import {Trending2_Stroke2_Corner2_Rounded as Graph} from '#/components/icons/Tre
|
|||||||
import {UserCircle_Stroke2_Corner0_Rounded as Person} from '#/components/icons/UserCircle'
|
import {UserCircle_Stroke2_Corner0_Rounded as Person} from '#/components/icons/UserCircle'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as ProfileCard from '#/components/ProfileCard'
|
import * as ProfileCard from '#/components/ProfileCard'
|
||||||
|
import {boostInterests} from '#/components/ProgressGuide/FollowDialog'
|
||||||
import {SubtleHover} from '#/components/SubtleHover'
|
import {SubtleHover} from '#/components/SubtleHover'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import * as ModuleHeader from './components/ModuleHeader'
|
import * as ModuleHeader from './components/ModuleHeader'
|
||||||
@@ -135,6 +141,7 @@ type ExploreScreenItems =
|
|||||||
metricsTag: MetricEvents['explore:module:searchButtonPress']['module']
|
metricsTag: MetricEvents['explore:module:searchButtonPress']['module']
|
||||||
tab: 'user' | 'profile' | 'feed'
|
tab: 'user' | 'profile' | 'feed'
|
||||||
}
|
}
|
||||||
|
hideDefaultTab?: boolean
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'trendingTopics'
|
type: 'trendingTopics'
|
||||||
@@ -151,7 +158,7 @@ type ExploreScreenItems =
|
|||||||
| {
|
| {
|
||||||
type: 'profile'
|
type: 'profile'
|
||||||
key: string
|
key: string
|
||||||
profile: AppBskyActorDefs.ProfileViewBasic
|
profile: AppBskyActorDefs.ProfileView
|
||||||
recId?: number
|
recId?: number
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
@@ -212,14 +219,31 @@ export function Explore({
|
|||||||
const gate = useGate()
|
const gate = useGate()
|
||||||
const guide = useProgressGuide('follow-10')
|
const guide = useProgressGuide('follow-10')
|
||||||
const [selectedInterest, setSelectedInterest] = useState<string | null>(null)
|
const [selectedInterest, setSelectedInterest] = useState<string | null>(null)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Begin special language handling
|
||||||
|
*/
|
||||||
|
const {contentLanguages} = useLanguagePrefs()
|
||||||
|
const useFullExperience = useMemo(() => {
|
||||||
|
if (contentLanguages.length === 0) return true
|
||||||
|
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 {
|
const {
|
||||||
data: suggestedUsers,
|
data: suggestedUsers,
|
||||||
isLoading: suggestedUsersIsLoading,
|
isLoading: suggestedUsersIsLoading,
|
||||||
error: suggestedUsersError,
|
error: suggestedUsersError,
|
||||||
isRefetching: suggestedUsersIsRefetching,
|
isRefetching: suggestedUsersIsRefetching,
|
||||||
} = useGetSuggestedUsersQuery({
|
} = useSuggestedUsers({
|
||||||
category: selectedInterest,
|
category: selectedInterest || (useFullExperience ? null : interests[0]),
|
||||||
|
search: !useFullExperience,
|
||||||
})
|
})
|
||||||
|
/* End special language handling */
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: feeds,
|
data: feeds,
|
||||||
hasNextPage: hasNextFeedsPage,
|
hasNextPage: hasNextFeedsPage,
|
||||||
@@ -227,7 +251,7 @@ export function Explore({
|
|||||||
isFetchingNextPage: isFetchingNextFeedsPage,
|
isFetchingNextPage: isFetchingNextFeedsPage,
|
||||||
error: feedsError,
|
error: feedsError,
|
||||||
fetchNextPage: fetchNextFeedsPage,
|
fetchNextPage: fetchNextFeedsPage,
|
||||||
} = useGetPopularFeedsQuery({limit: 10})
|
} = useGetPopularFeedsQuery({limit: 10, enabled: useFullExperience})
|
||||||
const interestsNux = useNux(Nux.ExploreInterestsCard)
|
const interestsNux = useNux(Nux.ExploreInterestsCard)
|
||||||
const showInterestsNux =
|
const showInterestsNux =
|
||||||
interestsNux.status === 'ready' && !interestsNux.nux?.completed
|
interestsNux.status === 'ready' && !interestsNux.nux?.completed
|
||||||
@@ -237,7 +261,7 @@ export function Explore({
|
|||||||
isLoading: isLoadingSuggestedSPs,
|
isLoading: isLoadingSuggestedSPs,
|
||||||
error: suggestedSPsError,
|
error: suggestedSPsError,
|
||||||
isRefetching: isRefetchingSuggestedSPs,
|
isRefetching: isRefetchingSuggestedSPs,
|
||||||
} = useSuggestedStarterPacksQuery()
|
} = useSuggestedStarterPacksQuery({enabled: useFullExperience})
|
||||||
|
|
||||||
const isLoadingMoreFeeds = isFetchingNextFeedsPage && !isLoadingFeeds
|
const isLoadingMoreFeeds = isFetchingNextFeedsPage && !isLoadingFeeds
|
||||||
const [hasPressedLoadMoreFeeds, setHasPressedLoadMoreFeeds] = useState(false)
|
const [hasPressedLoadMoreFeeds, setHasPressedLoadMoreFeeds] = useState(false)
|
||||||
@@ -260,7 +284,9 @@ export function Explore({
|
|||||||
hasPressedLoadMoreFeeds,
|
hasPressedLoadMoreFeeds,
|
||||||
])
|
])
|
||||||
|
|
||||||
const {data: suggestedFeeds} = useGetSuggestedFeedsQuery()
|
const {data: suggestedFeeds} = useGetSuggestedFeedsQuery({
|
||||||
|
enabled: useFullExperience,
|
||||||
|
})
|
||||||
const {
|
const {
|
||||||
data: feedPreviewSlices,
|
data: feedPreviewSlices,
|
||||||
query: {
|
query: {
|
||||||
@@ -270,7 +296,7 @@ export function Explore({
|
|||||||
hasNextPage: hasNextPageFeedPreviews,
|
hasNextPage: hasNextPageFeedPreviews,
|
||||||
error: feedPreviewSlicesError,
|
error: feedPreviewSlicesError,
|
||||||
},
|
},
|
||||||
} = useFeedPreviews(suggestedFeeds?.feeds ?? [])
|
} = useFeedPreviews(suggestedFeeds?.feeds ?? [], useFullExperience)
|
||||||
|
|
||||||
const qc = useQueryClient()
|
const qc = useQueryClient()
|
||||||
const [isPTR, setIsPTR] = useState(false)
|
const [isPTR, setIsPTR] = useState(false)
|
||||||
@@ -286,6 +312,9 @@ export function Explore({
|
|||||||
await qc.resetQueries({
|
await qc.resetQueries({
|
||||||
queryKey: [getSuggestedUsersQueryKeyRoot],
|
queryKey: [getSuggestedUsersQueryKeyRoot],
|
||||||
}),
|
}),
|
||||||
|
await qc.resetQueries({
|
||||||
|
queryKey: [useActorSearchPaginatedQueryKeyRoot],
|
||||||
|
}),
|
||||||
await qc.resetQueries({
|
await qc.resetQueries({
|
||||||
queryKey: createGetSuggestedFeedsQueryKey(),
|
queryKey: createGetSuggestedFeedsQueryKey(),
|
||||||
}),
|
}),
|
||||||
@@ -334,6 +363,7 @@ export function Explore({
|
|||||||
metricsTag: 'suggestedAccounts',
|
metricsTag: 'suggestedAccounts',
|
||||||
tab: 'user',
|
tab: 'user',
|
||||||
},
|
},
|
||||||
|
hideDefaultTab: !useFullExperience,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (suggestedUsersIsLoading || suggestedUsersIsRefetching) {
|
if (suggestedUsersIsLoading || suggestedUsersIsRefetching) {
|
||||||
@@ -353,6 +383,7 @@ export function Explore({
|
|||||||
let seen = new Set()
|
let seen = new Set()
|
||||||
const profileItems: ExploreScreenItems[] = []
|
const profileItems: ExploreScreenItems[] = []
|
||||||
for (const actor of suggestedUsers.actors) {
|
for (const actor of suggestedUsers.actors) {
|
||||||
|
// checking for following still necessary if search data is used
|
||||||
if (!seen.has(actor.did) && !actor.viewer?.following) {
|
if (!seen.has(actor.did) && !actor.viewer?.following) {
|
||||||
seen.add(actor.did)
|
seen.add(actor.did)
|
||||||
profileItems.push({
|
profileItems.push({
|
||||||
@@ -369,7 +400,7 @@ export function Explore({
|
|||||||
key: 'profileEmpty',
|
key: 'profileEmpty',
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (selectedInterest === null) {
|
if (selectedInterest === null && useFullExperience) {
|
||||||
// First "For You" tab, only show 5 to keep screen short
|
// First "For You" tab, only show 5 to keep screen short
|
||||||
i.push(...profileItems.slice(0, 5))
|
i.push(...profileItems.slice(0, 5))
|
||||||
} else {
|
} else {
|
||||||
@@ -395,6 +426,7 @@ export function Explore({
|
|||||||
suggestedUsersIsRefetching,
|
suggestedUsersIsRefetching,
|
||||||
suggestedUsersError,
|
suggestedUsersError,
|
||||||
selectedInterest,
|
selectedInterest,
|
||||||
|
useFullExperience,
|
||||||
])
|
])
|
||||||
const suggestedFeedsModule = useMemo(() => {
|
const suggestedFeedsModule = useMemo(() => {
|
||||||
const i: ExploreScreenItems[] = []
|
const i: ExploreScreenItems[] = []
|
||||||
@@ -565,26 +597,31 @@ export function Explore({
|
|||||||
|
|
||||||
i.push(topBorder)
|
i.push(topBorder)
|
||||||
i.push(...interestsNuxModule)
|
i.push(...interestsNuxModule)
|
||||||
if (isNewUser) {
|
|
||||||
i.push(...suggestedFollowsModule)
|
if (useFullExperience) {
|
||||||
i.push(...suggestedStarterPacksModule)
|
if (isNewUser) {
|
||||||
i.push({
|
i.push(...suggestedFollowsModule)
|
||||||
type: 'header',
|
i.push(...suggestedStarterPacksModule)
|
||||||
key: 'trending-topics-header',
|
i.push({
|
||||||
title: _(msg`Trending topics`),
|
type: 'header',
|
||||||
icon: Graph,
|
key: 'trending-topics-header',
|
||||||
bottomBorder: true,
|
title: _(msg`Trending topics`),
|
||||||
})
|
icon: Graph,
|
||||||
i.push(trendingTopicsModule)
|
bottomBorder: true,
|
||||||
|
})
|
||||||
|
i.push(trendingTopicsModule)
|
||||||
|
} else {
|
||||||
|
i.push(trendingTopicsModule)
|
||||||
|
i.push(...suggestedFollowsModule)
|
||||||
|
i.push(...suggestedStarterPacksModule)
|
||||||
|
}
|
||||||
|
if (gate('explore_show_suggested_feeds')) {
|
||||||
|
i.push(...suggestedFeedsModule)
|
||||||
|
}
|
||||||
|
i.push(...feedPreviewsModule)
|
||||||
} else {
|
} else {
|
||||||
i.push(trendingTopicsModule)
|
|
||||||
i.push(...suggestedFollowsModule)
|
i.push(...suggestedFollowsModule)
|
||||||
i.push(...suggestedStarterPacksModule)
|
|
||||||
}
|
}
|
||||||
if (gate('explore_show_suggested_feeds')) {
|
|
||||||
i.push(...suggestedFeedsModule)
|
|
||||||
}
|
|
||||||
i.push(...feedPreviewsModule)
|
|
||||||
|
|
||||||
return i
|
return i
|
||||||
}, [
|
}, [
|
||||||
@@ -598,6 +635,7 @@ export function Explore({
|
|||||||
feedPreviewsModule,
|
feedPreviewsModule,
|
||||||
interestsNuxModule,
|
interestsNuxModule,
|
||||||
gate,
|
gate,
|
||||||
|
useFullExperience,
|
||||||
])
|
])
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
@@ -641,6 +679,7 @@ export function Explore({
|
|||||||
<SuggestedAccountsTabBar
|
<SuggestedAccountsTabBar
|
||||||
selectedInterest={selectedInterest}
|
selectedInterest={selectedInterest}
|
||||||
onSelectInterest={setSelectedInterest}
|
onSelectInterest={setSelectedInterest}
|
||||||
|
hideDefaultTab={item.hideDefaultTab}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -672,7 +711,13 @@ export function Explore({
|
|||||||
return (
|
return (
|
||||||
<View style={[a.px_lg, a.pb_lg]}>
|
<View style={[a.px_lg, a.pb_lg]}>
|
||||||
<Admonition>
|
<Admonition>
|
||||||
<Trans>No results for "{selectedInterest}".</Trans>
|
{selectedInterest ? (
|
||||||
|
<Trans>
|
||||||
|
No results for "{interestsDisplayNames[selectedInterest]}".
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>No results.</Trans>
|
||||||
|
)}
|
||||||
</Admonition>
|
</Admonition>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -876,6 +921,7 @@ export function Explore({
|
|||||||
focusSearchInput,
|
focusSearchInput,
|
||||||
moderationOpts,
|
moderationOpts,
|
||||||
selectedInterest,
|
selectedInterest,
|
||||||
|
interestsDisplayNames,
|
||||||
_,
|
_,
|
||||||
fetchNextPageFeedPreviews,
|
fetchNextPageFeedPreviews,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -58,9 +58,11 @@ export function useLoadEnoughProfiles({
|
|||||||
export function SuggestedAccountsTabBar({
|
export function SuggestedAccountsTabBar({
|
||||||
selectedInterest,
|
selectedInterest,
|
||||||
onSelectInterest,
|
onSelectInterest,
|
||||||
|
hideDefaultTab,
|
||||||
}: {
|
}: {
|
||||||
selectedInterest: string | null
|
selectedInterest: string | null
|
||||||
onSelectInterest: (interest: string | null) => void
|
onSelectInterest: (interest: string | null) => void
|
||||||
|
hideDefaultTab?: boolean
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const interestsDisplayNames = useInterestsDisplayNames()
|
const interestsDisplayNames = useInterestsDisplayNames()
|
||||||
@@ -72,8 +74,10 @@ export function SuggestedAccountsTabBar({
|
|||||||
return (
|
return (
|
||||||
<BlockDrawerGesture>
|
<BlockDrawerGesture>
|
||||||
<Tabs
|
<Tabs
|
||||||
interests={['all', ...interests]}
|
interests={hideDefaultTab ? interests : ['all', ...interests]}
|
||||||
selectedInterest={selectedInterest || 'all'}
|
selectedInterest={
|
||||||
|
selectedInterest || (hideDefaultTab ? interests[0] : 'all')
|
||||||
|
}
|
||||||
onSelectTab={tab => {
|
onSelectTab={tab => {
|
||||||
logger.metric(
|
logger.metric(
|
||||||
'explore:suggestedAccounts:tabPressed',
|
'explore:suggestedAccounts:tabPressed',
|
||||||
@@ -83,10 +87,14 @@ export function SuggestedAccountsTabBar({
|
|||||||
onSelectInterest(tab === 'all' ? null : tab)
|
onSelectInterest(tab === 'all' ? null : tab)
|
||||||
}}
|
}}
|
||||||
hasSearchText={false}
|
hasSearchText={false}
|
||||||
interestsDisplayNames={{
|
interestsDisplayNames={
|
||||||
all: _(msg`For You`),
|
hideDefaultTab
|
||||||
...interestsDisplayNames,
|
? interestsDisplayNames
|
||||||
}}
|
: {
|
||||||
|
all: _(msg`For You`),
|
||||||
|
...interestsDisplayNames,
|
||||||
|
}
|
||||||
|
}
|
||||||
TabComponent={Tab}
|
TabComponent={Tab}
|
||||||
contentContainerStyle={[
|
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'
|
const RQKEY_ROOT = 'actor-search'
|
||||||
export const RQKEY = (query: string) => [RQKEY_ROOT, query]
|
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) => [
|
export const RQKEY_PAGINATED = (query: string, limit?: number) => [
|
||||||
RQKEY_ROOT_PAGINATED,
|
RQKEY_ROOT_PAGINATED,
|
||||||
query,
|
query,
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ export type FeedPreviewItem =
|
|||||||
|
|
||||||
export function useFeedPreviews(
|
export function useFeedPreviews(
|
||||||
feedsMaybeWithDuplicates: AppBskyFeedDefs.GeneratorView[],
|
feedsMaybeWithDuplicates: AppBskyFeedDefs.GeneratorView[],
|
||||||
|
isEnabled: boolean = true,
|
||||||
) {
|
) {
|
||||||
const feeds = useMemo(
|
const feeds = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -135,7 +136,7 @@ export function useFeedPreviews(
|
|||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
const userInterests = aggregateUserInterests(preferences)
|
const userInterests = aggregateUserInterests(preferences)
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
const enabled = feeds.length > 0
|
const enabled = feeds.length > 0 && isEnabled
|
||||||
|
|
||||||
const query = useInfiniteQuery({
|
const query = useInfiniteQuery({
|
||||||
enabled,
|
enabled,
|
||||||
|
|||||||
+11
-11
@@ -1,18 +1,18 @@
|
|||||||
import {useCallback, useEffect, useMemo, useRef} from 'react'
|
import {useCallback, useEffect, useMemo, useRef} from 'react'
|
||||||
import {
|
import {
|
||||||
AppBskyActorDefs,
|
type AppBskyActorDefs,
|
||||||
AppBskyFeedDefs,
|
type AppBskyFeedDefs,
|
||||||
AppBskyGraphDefs,
|
type AppBskyGraphDefs,
|
||||||
AppBskyUnspeccedGetPopularFeedGenerators,
|
type AppBskyUnspeccedGetPopularFeedGenerators,
|
||||||
AtUri,
|
AtUri,
|
||||||
moderateFeedGenerator,
|
moderateFeedGenerator,
|
||||||
RichText,
|
RichText,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {
|
import {
|
||||||
InfiniteData,
|
type InfiniteData,
|
||||||
keepPreviousData,
|
keepPreviousData,
|
||||||
QueryClient,
|
type QueryClient,
|
||||||
QueryKey,
|
type QueryKey,
|
||||||
useInfiniteQuery,
|
useInfiniteQuery,
|
||||||
useMutation,
|
useMutation,
|
||||||
useQuery,
|
useQuery,
|
||||||
@@ -28,7 +28,7 @@ import {usePreferencesQuery} from '#/state/queries/preferences'
|
|||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
import {router} from '#/routes'
|
import {router} from '#/routes'
|
||||||
import {useModerationOpts} from '../preferences/moderation-opts'
|
import {useModerationOpts} from '../preferences/moderation-opts'
|
||||||
import {FeedDescriptor} from './post-feed'
|
import {type FeedDescriptor} from './post-feed'
|
||||||
import {precacheResolvedUri} from './resolve-uri'
|
import {precacheResolvedUri} from './resolve-uri'
|
||||||
|
|
||||||
export type FeedSourceFeedInfo = {
|
export type FeedSourceFeedInfo = {
|
||||||
@@ -203,12 +203,12 @@ export const KNOWN_AUTHED_ONLY_FEEDS = [
|
|||||||
'at://did:plc:vpkhqolt662uhesyj6nxm7ys/app.bsky.feed.generator/followpics', // the gram, by why
|
'at://did:plc:vpkhqolt662uhesyj6nxm7ys/app.bsky.feed.generator/followpics', // the gram, by why
|
||||||
]
|
]
|
||||||
|
|
||||||
type GetPopularFeedsOptions = {limit?: number}
|
type GetPopularFeedsOptions = {limit?: number; enabled?: boolean}
|
||||||
|
|
||||||
export function createGetPopularFeedsQueryKey(
|
export function createGetPopularFeedsQueryKey(
|
||||||
options?: GetPopularFeedsOptions,
|
options?: GetPopularFeedsOptions,
|
||||||
) {
|
) {
|
||||||
return ['getPopularFeeds', options]
|
return ['getPopularFeeds', options?.limit]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useGetPopularFeedsQuery(options?: GetPopularFeedsOptions) {
|
export function useGetPopularFeedsQuery(options?: GetPopularFeedsOptions) {
|
||||||
@@ -237,7 +237,7 @@ export function useGetPopularFeedsQuery(options?: GetPopularFeedsOptions) {
|
|||||||
QueryKey,
|
QueryKey,
|
||||||
string | undefined
|
string | undefined
|
||||||
>({
|
>({
|
||||||
enabled: Boolean(moderationOpts),
|
enabled: Boolean(moderationOpts) && options?.enabled !== false,
|
||||||
queryKey: createGetPopularFeedsQueryKey(options),
|
queryKey: createGetPopularFeedsQueryKey(options),
|
||||||
queryFn: async ({pageParam}) => {
|
queryFn: async ({pageParam}) => {
|
||||||
const res = await agent.app.bsky.unspecced.getPopularFeedGenerators({
|
const res = await agent.app.bsky.unspecced.getPopularFeedGenerators({
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ export const DEFAULT_LIMIT = 5
|
|||||||
|
|
||||||
export const createGetSuggestedFeedsQueryKey = () => ['suggested-feeds']
|
export const createGetSuggestedFeedsQueryKey = () => ['suggested-feeds']
|
||||||
|
|
||||||
export function useGetSuggestedFeedsQuery() {
|
export function useGetSuggestedFeedsQuery({enabled}: {enabled?: boolean}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
const savedFeeds = preferences?.savedFeeds
|
const savedFeeds = preferences?.savedFeeds
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: !!preferences,
|
enabled: !!preferences && enabled !== false,
|
||||||
staleTime: STALE.MINUTES.THREE,
|
staleTime: STALE.MINUTES.THREE,
|
||||||
queryKey: createGetSuggestedFeedsQueryKey(),
|
queryKey: createGetSuggestedFeedsQueryKey(),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import {STALE} from '#/state/queries'
|
|||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {useAgent} from '#/state/session'
|
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 getSuggestedUsersQueryKeyRoot = 'unspecced-suggested-users'
|
||||||
export const createGetSuggestedUsersQueryKey = (props: QueryProps) => [
|
export const createGetSuggestedUsersQueryKey = (props: QueryProps) => [
|
||||||
getSuggestedUsersQueryKeyRoot,
|
getSuggestedUsersQueryKeyRoot,
|
||||||
...Object.values(props),
|
props.category,
|
||||||
]
|
]
|
||||||
|
|
||||||
export function useGetSuggestedUsersQuery(props: QueryProps) {
|
export function useGetSuggestedUsersQuery(props: QueryProps) {
|
||||||
@@ -26,7 +26,7 @@ export function useGetSuggestedUsersQuery(props: QueryProps) {
|
|||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: !!preferences,
|
enabled: !!preferences && props.enabled,
|
||||||
staleTime: STALE.MINUTES.THREE,
|
staleTime: STALE.MINUTES.THREE,
|
||||||
queryKey: createGetSuggestedUsersQueryKey(props),
|
queryKey: createGetSuggestedUsersQueryKey(props),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@@ -52,7 +52,7 @@ export function useGetSuggestedUsersQuery(props: QueryProps) {
|
|||||||
export function* findAllProfilesInQueryData(
|
export function* findAllProfilesInQueryData(
|
||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
did: string,
|
did: string,
|
||||||
): Generator<AppBskyActorDefs.ProfileViewBasic, void> {
|
): Generator<AppBskyActorDefs.ProfileView, void> {
|
||||||
const responses =
|
const responses =
|
||||||
queryClient.getQueriesData<AppBskyUnspeccedGetSuggestedUsers.OutputSchema>({
|
queryClient.getQueriesData<AppBskyUnspeccedGetSuggestedUsers.OutputSchema>({
|
||||||
queryKey: [getSuggestedUsersQueryKeyRoot],
|
queryKey: [getSuggestedUsersQueryKeyRoot],
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ export const createSuggestedStarterPacksQueryKey = () => [
|
|||||||
'suggested-starter-packs',
|
'suggested-starter-packs',
|
||||||
]
|
]
|
||||||
|
|
||||||
export function useSuggestedStarterPacksQuery() {
|
export function useSuggestedStarterPacksQuery({enabled}: {enabled?: boolean}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
const contentLangs = getContentLanguages().join(',')
|
const contentLangs = getContentLanguages().join(',')
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: !!preferences,
|
enabled: !!preferences && enabled !== false,
|
||||||
staleTime: STALE.MINUTES.THREE,
|
staleTime: STALE.MINUTES.THREE,
|
||||||
queryKey: createSuggestedStarterPacksQueryKey(),
|
queryKey: createSuggestedStarterPacksQueryKey(),
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
|
|||||||
@@ -80,10 +80,10 @@
|
|||||||
tlds "^1.234.0"
|
tlds "^1.234.0"
|
||||||
zod "^3.23.8"
|
zod "^3.23.8"
|
||||||
|
|
||||||
"@atproto/api@^0.14.20":
|
"@atproto/api@^0.14.21":
|
||||||
version "0.14.20"
|
version "0.14.21"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.20.tgz#904c85a91748f3203fd929415cb8fb3bc78d35d3"
|
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.21.tgz#29c189b7dba316945cf7317b9ded49b1b60d3ad9"
|
||||||
integrity sha512-Daip22+u9N+EVPk9PsEEVrTfjIqGczXnAT7o2EHGd0JsOzMbp3a6wmW1beKqYDzPf+Dc36/39JeUYYqhB3fKjg==
|
integrity sha512-hCIcjks/snscH3ZtZFoicQN2hRM5MpWQUvvzyIa265XQ2vSv5BP+gsQVIHWtYKt+gzwq1E7jY4us6c4N7fsLlQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@atproto/common-web" "^0.4.1"
|
"@atproto/common-web" "^0.4.1"
|
||||||
"@atproto/lexicon" "^0.4.10"
|
"@atproto/lexicon" "^0.4.10"
|
||||||
|
|||||||
Reference in New Issue
Block a user