Use new endpoints for suggested users (#10185)
This commit is contained in:
@@ -7,7 +7,7 @@ import Animated, {
|
||||
LayoutAnimationConfig,
|
||||
LinearTransition,
|
||||
} from 'react-native-reanimated'
|
||||
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
@@ -15,11 +15,9 @@ import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useGetPopularFeedsQuery} from '#/state/queries/feed'
|
||||
import {type FeedDescriptor} from '#/state/queries/post-feed'
|
||||
import {useProfilesQuery} from '#/state/queries/profile'
|
||||
import {useSuggestedFollowsByActorWithDismiss} from '#/state/queries/suggested-follows'
|
||||
import {useGetSuggestedUsersForDiscoverQuery} from '#/state/queries/trending/useGetSuggestedUsersForDiscoverQuery'
|
||||
import {useSession} from '#/state/session'
|
||||
import * as userActionHistory from '#/state/userActionHistory'
|
||||
import {type SeenPost} from '#/state/userActionHistory'
|
||||
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
|
||||
import {
|
||||
atoms as a,
|
||||
@@ -37,12 +35,12 @@ import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Has
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {ProgressGuideList} from '#/components/ProgressGuide/List'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type Metrics, useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {FollowDialogWithoutGuide} from './ProgressGuide/FollowDialog'
|
||||
import {ProgressGuideList} from './ProgressGuide/List'
|
||||
|
||||
const DISMISS_ANIMATION_DURATION = 200
|
||||
|
||||
@@ -109,95 +107,6 @@ export function SuggestedFeedsCardPlaceholder() {
|
||||
)
|
||||
}
|
||||
|
||||
function getRank(seenPost: SeenPost): string {
|
||||
let tier: string
|
||||
if (seenPost.feedContext === 'popfriends') {
|
||||
tier = 'a'
|
||||
} else if (seenPost.feedContext?.startsWith('cluster')) {
|
||||
tier = 'b'
|
||||
} else if (seenPost.feedContext === 'popcluster') {
|
||||
tier = 'c'
|
||||
} else if (seenPost.feedContext?.startsWith('ntpc')) {
|
||||
tier = 'd'
|
||||
} else if (seenPost.feedContext?.startsWith('t-')) {
|
||||
tier = 'e'
|
||||
} else if (seenPost.feedContext === 'nettop') {
|
||||
tier = 'f'
|
||||
} else {
|
||||
tier = 'g'
|
||||
}
|
||||
let score = Math.round(
|
||||
Math.log(
|
||||
1 + seenPost.likeCount + seenPost.repostCount + seenPost.replyCount,
|
||||
),
|
||||
)
|
||||
if (seenPost.isFollowedBy || Math.random() > 0.9) {
|
||||
score *= 2
|
||||
}
|
||||
const rank = 100 - score
|
||||
return `${tier}-${rank}`
|
||||
}
|
||||
|
||||
function sortSeenPosts(postA: SeenPost, postB: SeenPost): 0 | 1 | -1 {
|
||||
const rankA = getRank(postA)
|
||||
const rankB = getRank(postB)
|
||||
// Yes, we're comparing strings here.
|
||||
// The "larger" string means a worse rank.
|
||||
if (rankA > rankB) {
|
||||
return 1
|
||||
} else if (rankA < rankB) {
|
||||
return -1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
function useExperimentalSuggestedUsersQuery() {
|
||||
const {currentAccount} = useSession()
|
||||
const userActionSnapshot = userActionHistory.useActionHistorySnapshot()
|
||||
const dids = useMemo(() => {
|
||||
const {likes, follows, followSuggestions, seen} = userActionSnapshot
|
||||
const likeDids = likes
|
||||
.map(l => new AtUri(l))
|
||||
.map(uri => uri.host)
|
||||
.filter(did => !follows.includes(did))
|
||||
let suggestedDids: string[] = []
|
||||
if (followSuggestions.length > 0) {
|
||||
suggestedDids = [
|
||||
// It's ok if these will pick the same item (weighed by its frequency)
|
||||
/* eslint-disable react-hooks/purity */
|
||||
followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
|
||||
followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
|
||||
followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
|
||||
followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
|
||||
/* eslint-enable react-hooks/purity */
|
||||
]
|
||||
}
|
||||
const seenDids = seen
|
||||
.sort(sortSeenPosts)
|
||||
.map(l => new AtUri(l.uri))
|
||||
.map(uri => uri.host)
|
||||
return [...new Set([...suggestedDids, ...likeDids, ...seenDids])].filter(
|
||||
did => did !== currentAccount?.did,
|
||||
)
|
||||
}, [userActionSnapshot, currentAccount])
|
||||
const {data, isLoading, error} = useProfilesQuery({
|
||||
handles: dids.slice(0, 16),
|
||||
})
|
||||
|
||||
const profiles = data
|
||||
? data.profiles.filter(profile => {
|
||||
return !profile.viewer?.following
|
||||
})
|
||||
: []
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
profiles: profiles.slice(0, 6),
|
||||
}
|
||||
}
|
||||
|
||||
export function SuggestedFollows({feed}: {feed: FeedDescriptor}) {
|
||||
const {currentAccount} = useSession()
|
||||
const [feedType, feedUriOrDid] = feed.split('|')
|
||||
@@ -229,11 +138,9 @@ export function SuggestedFollowsProfile({did}: {did: string}) {
|
||||
}
|
||||
|
||||
export function SuggestedFollowsHome() {
|
||||
const {
|
||||
isLoading: isSuggestionsLoading,
|
||||
profiles: experimentalProfiles,
|
||||
error: experimentalError,
|
||||
} = useExperimentalSuggestedUsersQuery()
|
||||
const {isLoading, data, error} = useGetSuggestedUsersForDiscoverQuery()
|
||||
|
||||
const profiles = data?.actors
|
||||
|
||||
const [dismissedDids, setDismissedDids] = useState<Set<string>>(new Set())
|
||||
|
||||
@@ -247,12 +154,12 @@ export function SuggestedFollowsHome() {
|
||||
recId?: string
|
||||
}> = []
|
||||
|
||||
for (const profile of experimentalProfiles) {
|
||||
result.push({actor: profile, recId: undefined})
|
||||
for (const profile of profiles ?? []) {
|
||||
result.push({actor: profile, recId: data?.recId})
|
||||
}
|
||||
|
||||
return result
|
||||
}, [experimentalProfiles])
|
||||
}, [data?.recId, profiles])
|
||||
|
||||
const filteredProfiles = useMemo(() => {
|
||||
return allProfiles.filter(p => !dismissedDids.has(p.actor.did))
|
||||
@@ -260,10 +167,10 @@ export function SuggestedFollowsHome() {
|
||||
|
||||
return (
|
||||
<ProfileGrid
|
||||
isSuggestionsLoading={isSuggestionsLoading}
|
||||
isSuggestionsLoading={isLoading}
|
||||
profiles={filteredProfiles}
|
||||
totalProfileCount={allProfiles.length}
|
||||
error={experimentalError}
|
||||
error={error}
|
||||
viewContext="feed"
|
||||
onDismiss={onDismiss}
|
||||
/>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useActorSearch} from '#/state/queries/actor-search'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
||||
import {useGetSuggestedUsersForSeeMoreQuery} from '#/state/queries/trending/useGetSuggestedUsersForSeeMoreQuery'
|
||||
import {useSession} from '#/state/session'
|
||||
import {type Follow10ProgressGuide} from '#/state/shell/progress-guide'
|
||||
import {type ListMethods} from '#/view/com/util/List'
|
||||
@@ -141,7 +141,7 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
|
||||
data: suggestions,
|
||||
isFetching: isFetchingSuggestions,
|
||||
error: suggestionsError,
|
||||
} = useGetSuggestedUsersQuery({
|
||||
} = useGetSuggestedUsersForSeeMoreQuery({
|
||||
category: selectedInterest,
|
||||
limit: 50,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user