Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client

Update onboarding user suggestions with new endpoint (#9872)

authored by

DS Boyce and committed by
GitHub
ac939dc8 b12d7033

+177 -19
+3 -2
src/screens/Onboarding/StepSuggestedAccounts/index.tsx
··· 20 20 OnboardingTitleText, 21 21 } from '#/screens/Onboarding/Layout' 22 22 import {useOnboardingInternalState} from '#/screens/Onboarding/state' 23 - import {useSuggestedUsers} from '#/screens/Search/util/useSuggestedUsers' 23 + import {useSuggestedOnboardingUsers} from '#/screens/Search/util/useSuggestedOnboardingUsers' 24 24 import {atoms as a, tokens, useBreakpoints, useTheme, web} from '#/alf' 25 25 import {Admonition} from '#/components/Admonition' 26 26 import {Button, ButtonIcon, ButtonText} from '#/components/Button' ··· 64 64 const interests = Object.keys(interestsDisplayNames) 65 65 .sort(boostInterests(popularInterests)) 66 66 .sort(boostInterests(state.interestsStepResults.selectedInterests)) 67 + 67 68 const { 68 69 data: suggestedUsers, 69 70 isLoading, 70 71 error, 71 72 isRefetching, 72 73 refetch, 73 - } = useSuggestedUsers({ 74 + } = useSuggestedOnboardingUsers({ 74 75 category: selectedInterest || (useFullExperience ? null : interests[0]), 75 76 search: !useFullExperience, 76 77 overrideInterests: state.interestsStepResults.selectedInterests,
+66
src/screens/Search/util/useSuggestedOnboardingUsers.ts
··· 1 + import {useMemo} from 'react' 2 + 3 + import {useInterestsDisplayNames} from '#/lib/interests' 4 + import {useActorSearch} from '#/state/queries/actor-search' 5 + import {useGetSuggestedOnboardingUsersQuery} from '#/state/queries/trending/useGetSuggestedOnboardingUsersQuery' 6 + 7 + /** 8 + * Conditional hook, used in case a user is a non-english speaker, in which 9 + * case we fall back to searching for users instead of our more curated set. 10 + */ 11 + export function useSuggestedOnboardingUsers({ 12 + category = null, 13 + search = false, 14 + overrideInterests, 15 + }: { 16 + category?: string | null 17 + /** 18 + * If true, we'll search for users using the translated value of `category`, 19 + * based on the user's app language setting 20 + */ 21 + search?: boolean 22 + /** 23 + * In onboarding, interests haven't been saved to prefs yet, so we need to 24 + * pass them down through here 25 + */ 26 + overrideInterests: string[] 27 + }) { 28 + const interestsDisplayNames = useInterestsDisplayNames() 29 + const curated = useGetSuggestedOnboardingUsersQuery({ 30 + enabled: !search, 31 + category, 32 + overrideInterests, 33 + }) 34 + const searched = useActorSearch({ 35 + enabled: !!search, 36 + // use user's app language translation for this value 37 + query: category ? interestsDisplayNames[category] : '', 38 + limit: 10, 39 + }) 40 + 41 + return useMemo(() => { 42 + if (search) { 43 + return { 44 + // we're not paginating right now 45 + data: searched?.data 46 + ? { 47 + actors: searched.data.pages.flatMap(p => p.actors) ?? [], 48 + recId: undefined, 49 + } 50 + : undefined, 51 + isLoading: searched.isLoading, 52 + error: searched.error, 53 + isRefetching: searched.isRefetching, 54 + refetch: searched.refetch, 55 + } 56 + } else { 57 + return { 58 + data: curated.data, 59 + isLoading: curated.isLoading, 60 + error: curated.error, 61 + isRefetching: curated.isRefetching, 62 + refetch: curated.refetch, 63 + } 64 + } 65 + }, [curated, searched, search]) 66 + }
+1 -8
src/screens/Search/util/useSuggestedUsers.ts
··· 11 11 export function useSuggestedUsers({ 12 12 category = null, 13 13 search = false, 14 - overrideInterests, 15 14 }: { 16 15 category?: string | null 17 16 /** 18 17 * If true, we'll search for users using the translated value of `category`, 19 - * based on the user's "app language setting 18 + * based on the user's app language setting 20 19 */ 21 20 search?: boolean 22 - /** 23 - * In onboarding, interests haven't been saved to prefs yet, so we need to 24 - * pass them down through here 25 - */ 26 - overrideInterests?: string[] 27 21 }) { 28 22 const interestsDisplayNames = useInterestsDisplayNames() 29 23 const curated = useGetSuggestedUsersQuery({ 30 24 enabled: !search, 31 25 category, 32 - overrideInterests, 33 26 }) 34 27 const searched = useActorSearch({ 35 28 enabled: !!search,
+2
src/state/cache/profile-shadow.ts
··· 25 25 import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '#/state/queries/profile-followers' 26 26 import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '#/state/queries/profile-follows' 27 27 import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '#/state/queries/suggested-follows' 28 + import {findAllProfilesInQueryData as findAllProfilesInSuggestedOnboardingUsersQueryData} from '#/state/queries/trending/useGetSuggestedOnboardingUsersQuery' 28 29 import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersQueryData} from '#/state/queries/trending/useGetSuggestedUsersQuery' 29 30 import {findAllProfilesInQueryData as findAllProfilesInPostThreadV2QueryData} from '#/state/queries/usePostThread/queryCache' 30 31 import type * as bsky from '#/types/bsky' ··· 247 248 yield* findAllProfilesInProfileQueryData(queryClient, did) 248 249 yield* findAllProfilesInProfileFollowersQueryData(queryClient, did) 249 250 yield* findAllProfilesInProfileFollowsQueryData(queryClient, did) 251 + yield* findAllProfilesInSuggestedOnboardingUsersQueryData(queryClient, did) 250 252 yield* findAllProfilesInSuggestedUsersQueryData(queryClient, did) 251 253 yield* findAllProfilesInSuggestedFollowsQueryData(queryClient, did) 252 254 yield* findAllProfilesInActorSearchQueryData(queryClient, did)
+103
src/state/queries/trending/useGetSuggestedOnboardingUsersQuery.ts
··· 1 + import { 2 + type AppBskyActorDefs, 3 + type AppBskyUnspeccedGetSuggestedOnboardingUsers, 4 + } from '@atproto/api' 5 + import {type QueryClient, useQuery} from '@tanstack/react-query' 6 + 7 + import {createBskyTopicsHeader} from '#/lib/api/feed/utils' 8 + import {logger} from '#/logger' 9 + import {getContentLanguages} from '#/state/preferences/languages' 10 + import {STALE} from '#/state/queries' 11 + import {usePreferencesQuery} from '#/state/queries/preferences' 12 + import {useAgent} from '#/state/session' 13 + 14 + export type QueryProps = { 15 + category?: string | null 16 + limit?: number 17 + enabled?: boolean 18 + overrideInterests: string[] 19 + } 20 + 21 + export const getSuggestedOnboardingUsersQueryKeyRoot = 22 + 'unspecced-suggested-onboarding-users' 23 + export const createGetSuggestedOnboardingUsersQueryKey = ( 24 + props: QueryProps, 25 + ) => [ 26 + getSuggestedOnboardingUsersQueryKeyRoot, 27 + props.category, 28 + props.limit, 29 + props.overrideInterests.join(','), 30 + ] 31 + 32 + export function useGetSuggestedOnboardingUsersQuery(props: QueryProps) { 33 + const agent = useAgent() 34 + const {data: preferences} = usePreferencesQuery() 35 + 36 + return useQuery({ 37 + enabled: !!preferences && props.enabled !== false, 38 + staleTime: STALE.MINUTES.THREE, 39 + queryKey: createGetSuggestedOnboardingUsersQueryKey(props), 40 + queryFn: async () => { 41 + const contentLangs = getContentLanguages().join(',') 42 + 43 + const overrideInterests = props.overrideInterests.join(',') 44 + 45 + const {data} = await agent.app.bsky.unspecced.getSuggestedOnboardingUsers( 46 + { 47 + category: props.category ?? undefined, 48 + limit: props.limit || 10, 49 + }, 50 + { 51 + headers: { 52 + ...createBskyTopicsHeader(overrideInterests), 53 + 'Accept-Language': contentLangs, 54 + }, 55 + }, 56 + ) 57 + // FALLBACK: if no results for 'all', try again with no interests specified 58 + if (!props.category && data.actors.length === 0) { 59 + logger.error( 60 + `Did not get any suggested onboarding users, falling back - interests: ${overrideInterests}`, 61 + ) 62 + const {data: fallbackData} = 63 + await agent.app.bsky.unspecced.getSuggestedOnboardingUsers( 64 + { 65 + category: props.category ?? undefined, 66 + limit: props.limit || 10, 67 + }, 68 + { 69 + headers: { 70 + 'Accept-Language': contentLangs, 71 + }, 72 + }, 73 + ) 74 + return fallbackData 75 + } 76 + 77 + return data 78 + }, 79 + }) 80 + } 81 + 82 + export function* findAllProfilesInQueryData( 83 + queryClient: QueryClient, 84 + did: string, 85 + ): Generator<AppBskyActorDefs.ProfileView, void> { 86 + const responses = 87 + queryClient.getQueriesData<AppBskyUnspeccedGetSuggestedOnboardingUsers.OutputSchema>( 88 + { 89 + queryKey: [getSuggestedOnboardingUsersQueryKeyRoot], 90 + }, 91 + ) 92 + for (const [_key, response] of responses) { 93 + if (!response) { 94 + continue 95 + } 96 + 97 + for (const actor of response.actors) { 98 + if (actor.did === did) { 99 + yield actor 100 + } 101 + } 102 + } 103 + }
+2 -9
src/state/queries/trending/useGetSuggestedUsersQuery.ts
··· 18 18 category?: string | null 19 19 limit?: number 20 20 enabled?: boolean 21 - overrideInterests?: string[] 22 21 } 23 22 24 23 export const getSuggestedUsersQueryKeyRoot = 'unspecced-suggested-users' ··· 26 25 getSuggestedUsersQueryKeyRoot, 27 26 props.category, 28 27 props.limit, 29 - props.overrideInterests?.join(','), 30 28 ] 31 29 32 30 export function useGetSuggestedUsersQuery(props: QueryProps) { ··· 41 39 const contentLangs = getContentLanguages().join(',') 42 40 const userInterests = aggregateUserInterests(preferences) 43 41 44 - const interests = 45 - props.overrideInterests && props.overrideInterests.length > 0 46 - ? props.overrideInterests.join(',') 47 - : userInterests 48 - 49 42 const {data} = await agent.app.bsky.unspecced.getSuggestedUsers( 50 43 { 51 44 category: props.category ?? undefined, ··· 53 46 }, 54 47 { 55 48 headers: { 56 - ...createBskyTopicsHeader(interests), 49 + ...createBskyTopicsHeader(userInterests), 57 50 'Accept-Language': contentLangs, 58 51 }, 59 52 }, ··· 61 54 // FALLBACK: if no results for 'all', try again with no interests specified 62 55 if (!props.category && data.actors.length === 0) { 63 56 logger.error( 64 - `Did not get any suggested users, falling back - interests: ${interests}`, 57 + `Did not get any suggested users, falling back - interests: ${userInterests}`, 65 58 ) 66 59 const {data: fallbackData} = 67 60 await agent.app.bsky.unspecced.getSuggestedUsers(