Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
1import {
2 type AppBskyActorDefs,
3 type AppBskyUnspeccedGetSuggestedUsers,
4} from '@atproto/api'
5import {type QueryClient, useQuery} from '@tanstack/react-query'
6
7import {
8 aggregateUserInterests,
9 createBskyTopicsHeader,
10} from '#/lib/api/feed/utils'
11import {logger} from '#/logger'
12import {getContentLanguages} from '#/state/preferences/languages'
13import {STALE} from '#/state/queries'
14import {usePreferencesQuery} from '#/state/queries/preferences'
15import {useAgent} from '#/state/session'
16
17export type QueryProps = {
18 category?: string | null
19 limit?: number
20 enabled?: boolean
21}
22
23export const getSuggestedUsersQueryKeyRoot = 'unspecced-suggested-users'
24export const createGetSuggestedUsersQueryKey = (props: QueryProps) => [
25 getSuggestedUsersQueryKeyRoot,
26 props.category,
27 props.limit,
28]
29
30export function useGetSuggestedUsersQuery(props: QueryProps) {
31 const agent = useAgent()
32 const {data: preferences} = usePreferencesQuery()
33
34 return useQuery({
35 enabled: !!preferences && props.enabled !== false,
36 staleTime: STALE.MINUTES.THREE,
37 queryKey: createGetSuggestedUsersQueryKey(props),
38 queryFn: async () => {
39 const contentLangs = getContentLanguages().join(',')
40 const userInterests = aggregateUserInterests(preferences)
41
42 const {data} = await agent.app.bsky.unspecced.getSuggestedUsers(
43 {
44 category: props.category ?? undefined,
45 limit: props.limit || 10,
46 },
47 {
48 headers: {
49 ...createBskyTopicsHeader(userInterests),
50 'Accept-Language': contentLangs,
51 },
52 },
53 )
54 // FALLBACK: if no results for 'all', try again with no interests specified
55 if (!props.category && data.actors.length === 0) {
56 logger.error(
57 `Did not get any suggested users, falling back - interests: ${userInterests}`,
58 )
59 const {data: fallbackData} =
60 await agent.app.bsky.unspecced.getSuggestedUsers(
61 {
62 category: props.category ?? undefined,
63 limit: props.limit || 10,
64 },
65 {
66 headers: {
67 'Accept-Language': contentLangs,
68 },
69 },
70 )
71 return fallbackData
72 }
73
74 return data
75 },
76 })
77}
78
79export function* findAllProfilesInQueryData(
80 queryClient: QueryClient,
81 did: string,
82): Generator<AppBskyActorDefs.ProfileView, void> {
83 const responses =
84 queryClient.getQueriesData<AppBskyUnspeccedGetSuggestedUsers.OutputSchema>({
85 queryKey: [getSuggestedUsersQueryKeyRoot],
86 })
87 for (const [_key, response] of responses) {
88 if (!response) {
89 continue
90 }
91
92 for (const actor of response.actors) {
93 if (actor.did === did) {
94 yield actor
95 }
96 }
97 }
98}