forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 type AppBskyActorDefs,
3 type AppBskyGraphDefs,
4 type AppBskyGraphGetList,
5 type BskyAgent,
6} from '@atproto/api'
7import {
8 type InfiniteData,
9 type QueryClient,
10 type QueryKey,
11 useInfiniteQuery,
12 useQuery,
13} from '@tanstack/react-query'
14
15import {STALE} from '#/state/queries'
16import {useAgent} from '#/state/session'
17
18const PAGE_SIZE = 30
19type RQPageParam = string | undefined
20
21const RQKEY_ROOT = 'list-members'
22const RQKEY_ROOT_ALL = 'list-members-all'
23export const RQKEY = (uri: string) => [RQKEY_ROOT, uri]
24export const RQKEY_ALL = (uri: string) => [RQKEY_ROOT_ALL, uri]
25
26export function useListMembersQuery(uri?: string, limit: number = PAGE_SIZE) {
27 const agent = useAgent()
28 return useInfiniteQuery<
29 AppBskyGraphGetList.OutputSchema,
30 Error,
31 InfiniteData<AppBskyGraphGetList.OutputSchema>,
32 QueryKey,
33 RQPageParam
34 >({
35 staleTime: STALE.MINUTES.ONE,
36 queryKey: RQKEY(uri ?? ''),
37 async queryFn({pageParam}: {pageParam: RQPageParam}) {
38 const res = await agent.app.bsky.graph.getList({
39 list: uri!, // the enabled flag will prevent this from running until uri is set
40 limit,
41 cursor: pageParam,
42 })
43 return res.data
44 },
45 initialPageParam: undefined,
46 getNextPageParam: lastPage => lastPage.cursor,
47 enabled: Boolean(uri),
48 })
49}
50
51export function useAllListMembersQuery(uri?: string) {
52 const agent = useAgent()
53 return useQuery({
54 staleTime: STALE.MINUTES.ONE,
55 queryKey: RQKEY_ALL(uri ?? ''),
56 queryFn: async () => {
57 return getAllListMembers(agent, uri!)
58 },
59 enabled: Boolean(uri),
60 })
61}
62
63export async function getAllListMembers(agent: BskyAgent, uri: string) {
64 let hasMore = true
65 let cursor: string | undefined
66 const listItems: AppBskyGraphDefs.ListItemView[] = []
67 // We want to cap this at 6 pages, just for anything weird happening with the api
68 let i = 0
69 while (hasMore && i < 6) {
70 const res = await agent.app.bsky.graph.getList({
71 list: uri,
72 limit: 50,
73 cursor,
74 })
75 listItems.push(...res.data.items)
76 hasMore = Boolean(res.data.cursor)
77 cursor = res.data.cursor
78 i++
79 }
80 return listItems
81}
82
83export async function invalidateListMembersQuery({
84 queryClient,
85 uri,
86}: {
87 queryClient: QueryClient
88 uri: string
89}) {
90 await queryClient.invalidateQueries({queryKey: RQKEY(uri)})
91}
92
93export function* findAllProfilesInQueryData(
94 queryClient: QueryClient,
95 did: string,
96): Generator<AppBskyActorDefs.ProfileView, void> {
97 const queryDatas = queryClient.getQueriesData<
98 InfiniteData<AppBskyGraphGetList.OutputSchema>
99 >({
100 queryKey: [RQKEY_ROOT],
101 })
102 for (const [_queryKey, queryData] of queryDatas) {
103 if (!queryData?.pages) {
104 continue
105 }
106 for (const page of queryData?.pages) {
107 if (page.list.creator.did === did) {
108 yield page.list.creator
109 }
110 for (const item of page.items) {
111 if (item.subject.did === did) {
112 yield item.subject
113 }
114 }
115 }
116 }
117
118 const allQueryData = queryClient.getQueriesData<
119 AppBskyGraphDefs.ListItemView[]
120 >({
121 queryKey: [RQKEY_ROOT_ALL],
122 })
123 for (const [_queryKey, queryData] of allQueryData) {
124 if (!queryData) {
125 continue
126 }
127 for (const item of queryData) {
128 if (item.subject.did === did) {
129 yield item.subject
130 }
131 }
132 }
133}