forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 type AppBskyActorDefs,
3 AppBskyEmbedRecord,
4 type AppBskyFeedDefs,
5 type AppBskyFeedGetQuotes,
6 AtUri,
7} from '@atproto/api'
8import {
9 type InfiniteData,
10 type QueryClient,
11 type QueryKey,
12 useInfiniteQuery,
13} from '@tanstack/react-query'
14
15import {useAgent} from '#/state/session'
16import {
17 didOrHandleUriMatches,
18 embedViewRecordToPostView,
19 getEmbeddedPost,
20} from './util'
21
22const PAGE_SIZE = 30
23type RQPageParam = string | undefined
24
25const RQKEY_ROOT = 'post-quotes'
26export const RQKEY = (resolvedUri: string) => [RQKEY_ROOT, resolvedUri]
27
28export function usePostQuotesQuery(resolvedUri: string | undefined) {
29 const agent = useAgent()
30 return useInfiniteQuery<
31 AppBskyFeedGetQuotes.OutputSchema,
32 Error,
33 InfiniteData<AppBskyFeedGetQuotes.OutputSchema>,
34 QueryKey,
35 RQPageParam
36 >({
37 queryKey: RQKEY(resolvedUri || ''),
38 async queryFn({pageParam}: {pageParam: RQPageParam}) {
39 const res = await agent.api.app.bsky.feed.getQuotes({
40 uri: resolvedUri || '',
41 limit: PAGE_SIZE,
42 cursor: pageParam,
43 })
44 return res.data
45 },
46 initialPageParam: undefined,
47 getNextPageParam: lastPage => lastPage.cursor,
48 enabled: !!resolvedUri,
49 select: data => {
50 return {
51 ...data,
52 pages: data.pages.map(page => {
53 return {
54 ...page,
55 posts: page.posts.filter(post => {
56 if (post.embed && AppBskyEmbedRecord.isView(post.embed)) {
57 if (AppBskyEmbedRecord.isViewDetached(post.embed.record)) {
58 return false
59 }
60 }
61 return true
62 }),
63 }
64 }),
65 }
66 },
67 })
68}
69
70export function* findAllProfilesInQueryData(
71 queryClient: QueryClient,
72 did: string,
73): Generator<AppBskyActorDefs.ProfileViewBasic, void> {
74 const queryDatas = queryClient.getQueriesData<
75 InfiniteData<AppBskyFeedGetQuotes.OutputSchema>
76 >({
77 queryKey: [RQKEY_ROOT],
78 })
79 for (const [_queryKey, queryData] of queryDatas) {
80 if (!queryData?.pages) {
81 continue
82 }
83 for (const page of queryData?.pages) {
84 for (const item of page.posts) {
85 if (item.author.did === did) {
86 yield item.author
87 }
88 const quotedPost = getEmbeddedPost(item.embed)
89 if (quotedPost?.author.did === did) {
90 yield quotedPost.author
91 }
92 }
93 }
94 }
95}
96
97export function* findAllPostsInQueryData(
98 queryClient: QueryClient,
99 uri: string,
100): Generator<AppBskyFeedDefs.PostView, undefined> {
101 const queryDatas = queryClient.getQueriesData<
102 InfiniteData<AppBskyFeedGetQuotes.OutputSchema>
103 >({
104 queryKey: [RQKEY_ROOT],
105 })
106 const atUri = new AtUri(uri)
107 for (const [_queryKey, queryData] of queryDatas) {
108 if (!queryData?.pages) {
109 continue
110 }
111 for (const page of queryData?.pages) {
112 for (const post of page.posts) {
113 if (didOrHandleUriMatches(atUri, post)) {
114 yield post
115 }
116
117 const quotedPost = getEmbeddedPost(post.embed)
118 if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
119 yield embedViewRecordToPostView(quotedPost)
120 }
121 }
122 }
123 }
124}