about summary refs log tree commit diff
path: root/src/state/queries/list-members.ts
blob: 152c7a5be860955e9b7d4229bf3a748571c59aa1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import {
  type AppBskyActorDefs,
  type AppBskyGraphDefs,
  type AppBskyGraphGetList,
  type BskyAgent,
} from '@atproto/api'
import {
  type InfiniteData,
  type QueryClient,
  type QueryKey,
  useInfiniteQuery,
  useQuery,
} from '@tanstack/react-query'

import {STALE} from '#/state/queries'
import {useAgent} from '#/state/session'

const PAGE_SIZE = 30
type RQPageParam = string | undefined

const RQKEY_ROOT = 'list-members'
const RQKEY_ROOT_ALL = 'list-members-all'
export const RQKEY = (uri: string) => [RQKEY_ROOT, uri]
export const RQKEY_ALL = (uri: string) => [RQKEY_ROOT_ALL, uri]

export function useListMembersQuery(uri?: string, limit: number = PAGE_SIZE) {
  const agent = useAgent()
  return useInfiniteQuery<
    AppBskyGraphGetList.OutputSchema,
    Error,
    InfiniteData<AppBskyGraphGetList.OutputSchema>,
    QueryKey,
    RQPageParam
  >({
    staleTime: STALE.MINUTES.ONE,
    queryKey: RQKEY(uri ?? ''),
    async queryFn({pageParam}: {pageParam: RQPageParam}) {
      const res = await agent.app.bsky.graph.getList({
        list: uri!, // the enabled flag will prevent this from running until uri is set
        limit,
        cursor: pageParam,
      })
      return res.data
    },
    initialPageParam: undefined,
    getNextPageParam: lastPage => lastPage.cursor,
    enabled: Boolean(uri),
  })
}

export function useAllListMembersQuery(uri?: string) {
  const agent = useAgent()
  return useQuery({
    staleTime: STALE.MINUTES.ONE,
    queryKey: RQKEY_ALL(uri ?? ''),
    queryFn: async () => {
      return getAllListMembers(agent, uri!)
    },
    enabled: Boolean(uri),
  })
}

export async function getAllListMembers(agent: BskyAgent, uri: string) {
  let hasMore = true
  let cursor: string | undefined
  const listItems: AppBskyGraphDefs.ListItemView[] = []
  // We want to cap this at 6 pages, just for anything weird happening with the api
  let i = 0
  while (hasMore && i < 6) {
    const res = await agent.app.bsky.graph.getList({
      list: uri,
      limit: 50,
      cursor,
    })
    listItems.push(...res.data.items)
    hasMore = Boolean(res.data.cursor)
    cursor = res.data.cursor
    i++
  }
  return listItems
}

export async function invalidateListMembersQuery({
  queryClient,
  uri,
}: {
  queryClient: QueryClient
  uri: string
}) {
  await queryClient.invalidateQueries({queryKey: RQKEY(uri)})
}

export function* findAllProfilesInQueryData(
  queryClient: QueryClient,
  did: string,
): Generator<AppBskyActorDefs.ProfileView, void> {
  const queryDatas = queryClient.getQueriesData<
    InfiniteData<AppBskyGraphGetList.OutputSchema>
  >({
    queryKey: [RQKEY_ROOT],
  })
  for (const [_queryKey, queryData] of queryDatas) {
    if (!queryData?.pages) {
      continue
    }
    for (const page of queryData?.pages) {
      if (page.list.creator.did === did) {
        yield page.list.creator
      }
      for (const item of page.items) {
        if (item.subject.did === did) {
          yield item.subject
        }
      }
    }
  }

  const allQueryData = queryClient.getQueriesData<
    AppBskyGraphDefs.ListItemView[]
  >({
    queryKey: [RQKEY_ROOT_ALL],
  })
  for (const [_queryKey, queryData] of allQueryData) {
    if (!queryData) {
      continue
    }
    for (const item of queryData) {
      if (item.subject.did === did) {
        yield item.subject
      }
    }
  }
}