mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {
2 AppBskyActorDefs,
3 AppBskyActorGetSuggestions,
4 AppBskyGraphGetSuggestedFollowsByActor,
5 moderateProfile,
6} from '@atproto/api'
7import {
8 InfiniteData,
9 QueryClient,
10 QueryKey,
11 useInfiniteQuery,
12 useQuery,
13} from '@tanstack/react-query'
14
15import {
16 aggregateUserInterests,
17 createBskyTopicsHeader,
18} from '#/lib/api/feed/utils'
19import {getContentLanguages} from '#/state/preferences/languages'
20import {STALE} from '#/state/queries'
21import {usePreferencesQuery} from '#/state/queries/preferences'
22import {useAgent, useSession} from '#/state/session'
23import {useModerationOpts} from '../preferences/moderation-opts'
24
25const suggestedFollowsQueryKeyRoot = 'suggested-follows'
26const suggestedFollowsQueryKey = (options?: SuggestedFollowsOptions) => [
27 suggestedFollowsQueryKeyRoot,
28 options,
29]
30
31const suggestedFollowsByActorQueryKeyRoot = 'suggested-follows-by-actor'
32const suggestedFollowsByActorQueryKey = (did: string) => [
33 suggestedFollowsByActorQueryKeyRoot,
34 did,
35]
36
37type SuggestedFollowsOptions = {limit?: number; subsequentPageLimit?: number}
38
39export function useSuggestedFollowsQuery(options?: SuggestedFollowsOptions) {
40 const {currentAccount} = useSession()
41 const agent = useAgent()
42 const moderationOpts = useModerationOpts()
43 const {data: preferences} = usePreferencesQuery()
44 const limit = options?.limit || 25
45
46 return useInfiniteQuery<
47 AppBskyActorGetSuggestions.OutputSchema,
48 Error,
49 InfiniteData<AppBskyActorGetSuggestions.OutputSchema>,
50 QueryKey,
51 string | undefined
52 >({
53 enabled: !!moderationOpts && !!preferences,
54 staleTime: STALE.HOURS.ONE,
55 queryKey: suggestedFollowsQueryKey(options),
56 queryFn: async ({pageParam}) => {
57 const contentLangs = getContentLanguages().join(',')
58 const maybeDifferentLimit =
59 options?.subsequentPageLimit && pageParam
60 ? options.subsequentPageLimit
61 : limit
62 const res = await agent.app.bsky.actor.getSuggestions(
63 {
64 limit: maybeDifferentLimit,
65 cursor: pageParam,
66 },
67 {
68 headers: {
69 ...createBskyTopicsHeader(aggregateUserInterests(preferences)),
70 'Accept-Language': contentLangs,
71 },
72 },
73 )
74
75 res.data.actors = res.data.actors
76 .filter(
77 actor =>
78 !moderateProfile(actor, moderationOpts!).ui('profileList').filter,
79 )
80 .filter(actor => {
81 const viewer = actor.viewer
82 if (viewer) {
83 if (
84 viewer.following ||
85 viewer.muted ||
86 viewer.mutedByList ||
87 viewer.blockedBy ||
88 viewer.blocking
89 ) {
90 return false
91 }
92 }
93 if (actor.did === currentAccount?.did) {
94 return false
95 }
96 return true
97 })
98
99 return res.data
100 },
101 initialPageParam: undefined,
102 getNextPageParam: lastPage => lastPage.cursor,
103 })
104}
105
106export function useSuggestedFollowsByActorQuery({did}: {did: string}) {
107 const agent = useAgent()
108 return useQuery({
109 queryKey: suggestedFollowsByActorQueryKey(did),
110 queryFn: async () => {
111 const res = await agent.app.bsky.graph.getSuggestedFollowsByActor({
112 actor: did,
113 })
114 const suggestions = res.data.isFallback
115 ? []
116 : res.data.suggestions.filter(profile => !profile.viewer?.following)
117 return {suggestions}
118 },
119 })
120}
121
122export function* findAllProfilesInQueryData(
123 queryClient: QueryClient,
124 did: string,
125): Generator<AppBskyActorDefs.ProfileView, void> {
126 yield* findAllProfilesInSuggestedFollowsQueryData(queryClient, did)
127 yield* findAllProfilesInSuggestedFollowsByActorQueryData(queryClient, did)
128}
129
130function* findAllProfilesInSuggestedFollowsQueryData(
131 queryClient: QueryClient,
132 did: string,
133) {
134 const queryDatas = queryClient.getQueriesData<
135 InfiniteData<AppBskyActorGetSuggestions.OutputSchema>
136 >({
137 queryKey: [suggestedFollowsQueryKeyRoot],
138 })
139 for (const [_queryKey, queryData] of queryDatas) {
140 if (!queryData?.pages) {
141 continue
142 }
143 for (const page of queryData?.pages) {
144 for (const actor of page.actors) {
145 if (actor.did === did) {
146 yield actor
147 }
148 }
149 }
150 }
151}
152
153function* findAllProfilesInSuggestedFollowsByActorQueryData(
154 queryClient: QueryClient,
155 did: string,
156) {
157 const queryDatas =
158 queryClient.getQueriesData<AppBskyGraphGetSuggestedFollowsByActor.OutputSchema>(
159 {
160 queryKey: [suggestedFollowsByActorQueryKeyRoot],
161 },
162 )
163 for (const [_queryKey, queryData] of queryDatas) {
164 if (!queryData) {
165 continue
166 }
167 for (const suggestion of queryData.suggestions) {
168 if (suggestion.did === did) {
169 yield suggestion
170 }
171 }
172 }
173}