···77 LayoutAnimationConfig,
88 LinearTransition,
99} from 'react-native-reanimated'
1010-import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
1010+import {type AppBskyFeedDefs} from '@atproto/api'
1111import {Trans, useLingui} from '@lingui/react/macro'
1212import {useNavigation} from '@react-navigation/native'
1313···1515import {useModerationOpts} from '#/state/preferences/moderation-opts'
1616import {useGetPopularFeedsQuery} from '#/state/queries/feed'
1717import {type FeedDescriptor} from '#/state/queries/post-feed'
1818-import {useProfilesQuery} from '#/state/queries/profile'
1918import {useSuggestedFollowsByActorWithDismiss} from '#/state/queries/suggested-follows'
1919+import {useGetSuggestedUsersForDiscoverQuery} from '#/state/queries/trending/useGetSuggestedUsersForDiscoverQuery'
2020import {useSession} from '#/state/session'
2121-import * as userActionHistory from '#/state/userActionHistory'
2222-import {type SeenPost} from '#/state/userActionHistory'
2321import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
2422import {
2523 atoms as a,
···3735import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
3836import {InlineLinkText} from '#/components/Link'
3937import * as ProfileCard from '#/components/ProfileCard'
3838+import {ProgressGuideList} from '#/components/ProgressGuide/List'
4039import {Text} from '#/components/Typography'
4140import {type Metrics, useAnalytics} from '#/analytics'
4241import {IS_IOS} from '#/env'
4342import type * as bsky from '#/types/bsky'
4443import {FollowDialogWithoutGuide} from './ProgressGuide/FollowDialog'
4545-import {ProgressGuideList} from './ProgressGuide/List'
46444745const DISMISS_ANIMATION_DURATION = 200
4846···109107 )
110108}
111109112112-function getRank(seenPost: SeenPost): string {
113113- let tier: string
114114- if (seenPost.feedContext === 'popfriends') {
115115- tier = 'a'
116116- } else if (seenPost.feedContext?.startsWith('cluster')) {
117117- tier = 'b'
118118- } else if (seenPost.feedContext === 'popcluster') {
119119- tier = 'c'
120120- } else if (seenPost.feedContext?.startsWith('ntpc')) {
121121- tier = 'd'
122122- } else if (seenPost.feedContext?.startsWith('t-')) {
123123- tier = 'e'
124124- } else if (seenPost.feedContext === 'nettop') {
125125- tier = 'f'
126126- } else {
127127- tier = 'g'
128128- }
129129- let score = Math.round(
130130- Math.log(
131131- 1 + seenPost.likeCount + seenPost.repostCount + seenPost.replyCount,
132132- ),
133133- )
134134- if (seenPost.isFollowedBy || Math.random() > 0.9) {
135135- score *= 2
136136- }
137137- const rank = 100 - score
138138- return `${tier}-${rank}`
139139-}
140140-141141-function sortSeenPosts(postA: SeenPost, postB: SeenPost): 0 | 1 | -1 {
142142- const rankA = getRank(postA)
143143- const rankB = getRank(postB)
144144- // Yes, we're comparing strings here.
145145- // The "larger" string means a worse rank.
146146- if (rankA > rankB) {
147147- return 1
148148- } else if (rankA < rankB) {
149149- return -1
150150- } else {
151151- return 0
152152- }
153153-}
154154-155155-function useExperimentalSuggestedUsersQuery() {
156156- const {currentAccount} = useSession()
157157- const userActionSnapshot = userActionHistory.useActionHistorySnapshot()
158158- const dids = useMemo(() => {
159159- const {likes, follows, followSuggestions, seen} = userActionSnapshot
160160- const likeDids = likes
161161- .map(l => new AtUri(l))
162162- .map(uri => uri.host)
163163- .filter(did => !follows.includes(did))
164164- let suggestedDids: string[] = []
165165- if (followSuggestions.length > 0) {
166166- suggestedDids = [
167167- // It's ok if these will pick the same item (weighed by its frequency)
168168- /* eslint-disable react-hooks/purity */
169169- followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
170170- followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
171171- followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
172172- followSuggestions[Math.floor(Math.random() * followSuggestions.length)],
173173- /* eslint-enable react-hooks/purity */
174174- ]
175175- }
176176- const seenDids = seen
177177- .sort(sortSeenPosts)
178178- .map(l => new AtUri(l.uri))
179179- .map(uri => uri.host)
180180- return [...new Set([...suggestedDids, ...likeDids, ...seenDids])].filter(
181181- did => did !== currentAccount?.did,
182182- )
183183- }, [userActionSnapshot, currentAccount])
184184- const {data, isLoading, error} = useProfilesQuery({
185185- handles: dids.slice(0, 16),
186186- })
187187-188188- const profiles = data
189189- ? data.profiles.filter(profile => {
190190- return !profile.viewer?.following
191191- })
192192- : []
193193-194194- return {
195195- isLoading,
196196- error,
197197- profiles: profiles.slice(0, 6),
198198- }
199199-}
200200-201110export function SuggestedFollows({feed}: {feed: FeedDescriptor}) {
202111 const {currentAccount} = useSession()
203112 const [feedType, feedUriOrDid] = feed.split('|')
···229138}
230139231140export function SuggestedFollowsHome() {
232232- const {
233233- isLoading: isSuggestionsLoading,
234234- profiles: experimentalProfiles,
235235- error: experimentalError,
236236- } = useExperimentalSuggestedUsersQuery()
141141+ const {isLoading, data, error} = useGetSuggestedUsersForDiscoverQuery()
142142+143143+ const profiles = data?.actors
237144238145 const [dismissedDids, setDismissedDids] = useState<Set<string>>(new Set())
239146···247154 recId?: string
248155 }> = []
249156250250- for (const profile of experimentalProfiles) {
251251- result.push({actor: profile, recId: undefined})
157157+ for (const profile of profiles ?? []) {
158158+ result.push({actor: profile, recId: data?.recId})
252159 }
253160254161 return result
255255- }, [experimentalProfiles])
162162+ }, [data?.recId, profiles])
256163257164 const filteredProfiles = useMemo(() => {
258165 return allProfiles.filter(p => !dismissedDids.has(p.actor.did))
···260167261168 return (
262169 <ProfileGrid
263263- isSuggestionsLoading={isSuggestionsLoading}
170170+ isSuggestionsLoading={isLoading}
264171 profiles={filteredProfiles}
265172 totalProfileCount={allProfiles.length}
266266- error={experimentalError}
173173+ error={error}
267174 viewContext="feed"
268175 onDismiss={onDismiss}
269176 />
+2-2
src/components/ProgressGuide/FollowDialog.tsx
···88import {useModerationOpts} from '#/state/preferences/moderation-opts'
99import {useActorSearch} from '#/state/queries/actor-search'
1010import {usePreferencesQuery} from '#/state/queries/preferences'
1111-import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
1111+import {useGetSuggestedUsersForSeeMoreQuery} from '#/state/queries/trending/useGetSuggestedUsersForSeeMoreQuery'
1212import {useSession} from '#/state/session'
1313import {type Follow10ProgressGuide} from '#/state/shell/progress-guide'
1414import {type ListMethods} from '#/view/com/util/List'
···141141 data: suggestions,
142142 isFetching: isFetchingSuggestions,
143143 error: suggestionsError,
144144- } = useGetSuggestedUsersQuery({
144144+ } = useGetSuggestedUsersForSeeMoreQuery({
145145 category: selectedInterest,
146146 limit: 50,
147147 })
+6-5
src/screens/Search/Explore.tsx
···2828 createGetSuggestedFeedsQueryKey,
2929 useGetSuggestedFeedsQuery,
3030} from '#/state/queries/trending/useGetSuggestedFeedsQuery'
3131-import {getSuggestedUsersQueryKeyRoot} from '#/state/queries/trending/useGetSuggestedUsersQuery'
3131+import {
3232+ getSuggestedUsersForExploreQueryKeyRoot,
3333+ useGetSuggestedUsersForExploreQuery,
3434+} from '#/state/queries/trending/useGetSuggestedUsersForExploreQuery'
3235import {createGetTrendsQueryKey} from '#/state/queries/trending/useGetTrendsQuery'
3336import {
3437 createSuggestedStarterPacksQueryKey,
···4851import {ExploreRecommendations} from '#/screens/Search/modules/ExploreRecommendations'
4952import {ExploreTrendingTopics} from '#/screens/Search/modules/ExploreTrendingTopics'
5053import {ExploreTrendingVideos} from '#/screens/Search/modules/ExploreTrendingVideos'
5151-import {useSuggestedUsers} from '#/screens/Search/util/useSuggestedUsers'
5254import {atoms as a, native, platform, useTheme} from '#/alf'
5355import {Admonition} from '#/components/Admonition'
5456import {Button} from '#/components/Button'
···242244 isLoading: suggestedUsersIsLoading,
243245 error: suggestedUsersError,
244246 isRefetching: suggestedUsersIsRefetching,
245245- } = useSuggestedUsers({
247247+ } = useGetSuggestedUsersForExploreQuery({
246248 category: selectedInterest || (useFullExperience ? null : interests[0]),
247247- search: !useFullExperience,
248249 })
249250 /* End special language handling */
250251···316317 queryKey: createSuggestedStarterPacksQueryKey(),
317318 }),
318319 qc.resetQueries({
319319- queryKey: [getSuggestedUsersQueryKeyRoot],
320320+ queryKey: [getSuggestedUsersForExploreQueryKeyRoot],
320321 }),
321322 qc.resetQueries({
322323 queryKey: [useActorSearchQueryKeyRoot],
-59
src/screens/Search/util/useSuggestedUsers.ts
···11-import {useMemo} from 'react'
22-33-import {useInterestsDisplayNames} from '#/lib/interests'
44-import {useActorSearch} from '#/state/queries/actor-search'
55-import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
66-77-/**
88- * Conditional hook, used in case a user is a non-english speaker, in which
99- * case we fall back to searching for users instead of our more curated set.
1010- */
1111-export function useSuggestedUsers({
1212- category = null,
1313- search = false,
1414-}: {
1515- category?: string | null
1616- /**
1717- * If true, we'll search for users using the translated value of `category`,
1818- * based on the user's app language setting
1919- */
2020- search?: boolean
2121-}) {
2222- const interestsDisplayNames = useInterestsDisplayNames()
2323- const curated = useGetSuggestedUsersQuery({
2424- enabled: !search,
2525- category,
2626- })
2727- const searched = useActorSearch({
2828- enabled: !!search,
2929- // use user's app language translation for this value
3030- query: category ? interestsDisplayNames[category] : '',
3131- limit: 10,
3232- })
3333-3434- return useMemo(() => {
3535- if (search) {
3636- return {
3737- // we're not paginating right now
3838- data: searched?.data
3939- ? {
4040- actors: searched.data.pages.flatMap(p => p.actors) ?? [],
4141- recId: undefined,
4242- }
4343- : undefined,
4444- isLoading: searched.isLoading,
4545- error: searched.error,
4646- isRefetching: searched.isRefetching,
4747- refetch: searched.refetch,
4848- }
4949- } else {
5050- return {
5151- data: curated.data,
5252- isLoading: curated.isLoading,
5353- error: curated.error,
5454- isRefetching: curated.isRefetching,
5555- refetch: curated.refetch,
5656- }
5757- }
5858- }, [curated, searched, search])
5959-}
+12-2
src/screens/Settings/InterestsSettings.tsx
···1919} from '#/state/queries/preferences'
2020import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
2121import {createGetSuggestedFeedsQueryKey} from '#/state/queries/trending/useGetSuggestedFeedsQuery'
2222-import {createGetSuggestedUsersQueryKey} from '#/state/queries/trending/useGetSuggestedUsersQuery'
2222+import {createGetSuggestedUsersForDiscoverQueryKey} from '#/state/queries/trending/useGetSuggestedUsersForDiscoverQuery'
2323+import {createGetSuggestedUsersForExploreQueryKey} from '#/state/queries/trending/useGetSuggestedUsersForExploreQuery'
2424+import {createGetSuggestedUsersForSeeMoreQueryKey} from '#/state/queries/trending/useGetSuggestedUsersForSeeMoreQuery'
2325import {createSuggestedStarterPacksQueryKey} from '#/state/queries/useSuggestedStarterPacksQuery'
2426import {useAgent} from '#/state/session'
2527import {atoms as a, useGutters, useTheme} from '#/alf'
···120122 await Promise.all([
121123 qc.resetQueries({queryKey: createSuggestedStarterPacksQueryKey()}),
122124 qc.resetQueries({queryKey: createGetSuggestedFeedsQueryKey()}),
123123- qc.resetQueries({queryKey: createGetSuggestedUsersQueryKey({})}),
125125+ qc.resetQueries({
126126+ queryKey: createGetSuggestedUsersForDiscoverQueryKey({}),
127127+ }),
128128+ qc.resetQueries({
129129+ queryKey: createGetSuggestedUsersForExploreQueryKey({}),
130130+ }),
131131+ qc.resetQueries({
132132+ queryKey: createGetSuggestedUsersForSeeMoreQueryKey({}),
133133+ }),
124134 ])
125135126136 Toast.show(
+6-2
src/state/cache/profile-shadow.ts
···2626import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '#/state/queries/profile-follows'
2727import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '#/state/queries/suggested-follows'
2828import {findAllProfilesInQueryData as findAllProfilesInSuggestedOnboardingUsersQueryData} from '#/state/queries/trending/useGetSuggestedOnboardingUsersQuery'
2929-import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersQueryData} from '#/state/queries/trending/useGetSuggestedUsersQuery'
2929+import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersForDiscoverQueryData} from '#/state/queries/trending/useGetSuggestedUsersForDiscoverQuery'
3030+import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersForExploreQueryData} from '#/state/queries/trending/useGetSuggestedUsersForExploreQuery'
3131+import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersForSeeMoreQueryData} from '#/state/queries/trending/useGetSuggestedUsersForSeeMoreQuery'
3032import {findAllProfilesInQueryData as findAllProfilesInPostThreadV2QueryData} from '#/state/queries/usePostThread/queryCache'
3133import type * as bsky from '#/types/bsky'
3234import {castAsShadow, type Shadow} from './types'
···249251 yield* findAllProfilesInProfileFollowersQueryData(queryClient, did)
250252 yield* findAllProfilesInProfileFollowsQueryData(queryClient, did)
251253 yield* findAllProfilesInSuggestedOnboardingUsersQueryData(queryClient, did)
252252- yield* findAllProfilesInSuggestedUsersQueryData(queryClient, did)
254254+ yield* findAllProfilesInSuggestedUsersForDiscoverQueryData(queryClient, did)
255255+ yield* findAllProfilesInSuggestedUsersForExploreQueryData(queryClient, did)
256256+ yield* findAllProfilesInSuggestedUsersForSeeMoreQueryData(queryClient, did)
253257 yield* findAllProfilesInSuggestedFollowsQueryData(queryClient, did)
254258 yield* findAllProfilesInActorSearchQueryData(queryClient, did)
255259 yield* findAllProfilesInListConvosQueryData(queryClient, did)