about summary refs log tree commit diff
path: root/src/state
diff options
context:
space:
mode:
Diffstat (limited to 'src/state')
-rw-r--r--src/state/cache/post-shadow.ts4
-rw-r--r--src/state/cache/profile-shadow.ts2
-rw-r--r--src/state/queries/post-quotes.ts124
-rw-r--r--src/state/shell/composer.tsx1
4 files changed, 131 insertions, 0 deletions
diff --git a/src/state/cache/post-shadow.ts b/src/state/cache/post-shadow.ts
index 48183739b..b37e9bd42 100644
--- a/src/state/cache/post-shadow.ts
+++ b/src/state/cache/post-shadow.ts
@@ -6,6 +6,7 @@ import EventEmitter from 'eventemitter3'
 import {batchedUpdates} from '#/lib/batchedUpdates'
 import {findAllPostsInQueryData as findAllPostsInNotifsQueryData} from '../queries/notifications/feed'
 import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '../queries/post-feed'
+import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '../queries/post-quotes'
 import {findAllPostsInQueryData as findAllPostsInThreadQueryData} from '../queries/post-thread'
 import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '../queries/search-posts'
 import {castAsShadow, Shadow} from './types'
@@ -130,4 +131,7 @@ function* findPostsInCache(
   for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
     yield post
   }
+  for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) {
+    yield post
+  }
 }
diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts
index dc907664e..dda7a749e 100644
--- a/src/state/cache/profile-shadow.ts
+++ b/src/state/cache/profile-shadow.ts
@@ -12,6 +12,7 @@ import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryDat
 import {findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData} from '../queries/my-muted-accounts'
 import {findAllProfilesInQueryData as findAllProfilesInFeedsQueryData} from '../queries/post-feed'
 import {findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData} from '../queries/post-liked-by'
+import {findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData} from '../queries/post-quotes'
 import {findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData} from '../queries/post-reposted-by'
 import {findAllProfilesInQueryData as findAllProfilesInPostThreadQueryData} from '../queries/post-thread'
 import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '../queries/profile'
@@ -104,6 +105,7 @@ function* findProfilesInCache(
   yield* findAllProfilesInMyMutedAccountsQueryData(queryClient, did)
   yield* findAllProfilesInPostLikedByQueryData(queryClient, did)
   yield* findAllProfilesInPostRepostedByQueryData(queryClient, did)
+  yield* findAllProfilesInPostQuotesQueryData(queryClient, did)
   yield* findAllProfilesInProfileQueryData(queryClient, did)
   yield* findAllProfilesInProfileFollowersQueryData(queryClient, did)
   yield* findAllProfilesInProfileFollowsQueryData(queryClient, did)
diff --git a/src/state/queries/post-quotes.ts b/src/state/queries/post-quotes.ts
new file mode 100644
index 000000000..be51eaab0
--- /dev/null
+++ b/src/state/queries/post-quotes.ts
@@ -0,0 +1,124 @@
+import {
+  AppBskyActorDefs,
+  AppBskyEmbedRecord,
+  AppBskyFeedDefs,
+  AppBskyFeedGetQuotes,
+  AtUri,
+} from '@atproto/api'
+import {
+  InfiniteData,
+  QueryClient,
+  QueryKey,
+  useInfiniteQuery,
+} from '@tanstack/react-query'
+
+import {useAgent} from '#/state/session'
+import {
+  didOrHandleUriMatches,
+  embedViewRecordToPostView,
+  getEmbeddedPost,
+} from './util'
+
+const PAGE_SIZE = 30
+type RQPageParam = string | undefined
+
+const RQKEY_ROOT = 'post-quotes'
+export const RQKEY = (resolvedUri: string) => [RQKEY_ROOT, resolvedUri]
+
+export function usePostQuotesQuery(resolvedUri: string | undefined) {
+  const agent = useAgent()
+  return useInfiniteQuery<
+    AppBskyFeedGetQuotes.OutputSchema,
+    Error,
+    InfiniteData<AppBskyFeedGetQuotes.OutputSchema>,
+    QueryKey,
+    RQPageParam
+  >({
+    queryKey: RQKEY(resolvedUri || ''),
+    async queryFn({pageParam}: {pageParam: RQPageParam}) {
+      const res = await agent.api.app.bsky.feed.getQuotes({
+        uri: resolvedUri || '',
+        limit: PAGE_SIZE,
+        cursor: pageParam,
+      })
+      return res.data
+    },
+    initialPageParam: undefined,
+    getNextPageParam: lastPage => lastPage.cursor,
+    enabled: !!resolvedUri,
+    select: data => {
+      return {
+        ...data,
+        pages: data.pages.map(page => {
+          return {
+            ...page,
+            posts: page.posts.filter(post => {
+              if (post.embed && AppBskyEmbedRecord.isView(post.embed)) {
+                if (AppBskyEmbedRecord.isViewDetached(post.embed.record)) {
+                  return false
+                }
+              }
+              return true
+            }),
+          }
+        }),
+      }
+    },
+  })
+}
+
+export function* findAllProfilesInQueryData(
+  queryClient: QueryClient,
+  did: string,
+): Generator<AppBskyActorDefs.ProfileView, void> {
+  const queryDatas = queryClient.getQueriesData<
+    InfiniteData<AppBskyFeedGetQuotes.OutputSchema>
+  >({
+    queryKey: [RQKEY_ROOT],
+  })
+  for (const [_queryKey, queryData] of queryDatas) {
+    if (!queryData?.pages) {
+      continue
+    }
+    for (const page of queryData?.pages) {
+      for (const item of page.posts) {
+        if (item.author.did === did) {
+          yield item.author
+        }
+        const quotedPost = getEmbeddedPost(item.embed)
+        if (quotedPost?.author.did === did) {
+          yield quotedPost.author
+        }
+      }
+    }
+  }
+}
+
+export function* findAllPostsInQueryData(
+  queryClient: QueryClient,
+  uri: string,
+): Generator<AppBskyFeedDefs.PostView, undefined> {
+  const queryDatas = queryClient.getQueriesData<
+    InfiniteData<AppBskyFeedGetQuotes.OutputSchema>
+  >({
+    queryKey: [RQKEY_ROOT],
+  })
+  const atUri = new AtUri(uri)
+  for (const [_queryKey, queryData] of queryDatas) {
+    if (!queryData?.pages) {
+      continue
+    }
+    for (const page of queryData?.pages) {
+      for (const post of page.posts) {
+        if (didOrHandleUriMatches(atUri, post)) {
+          yield post
+        }
+
+        const quotedPost = getEmbeddedPost(post.embed)
+        if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
+          yield embedViewRecordToPostView(quotedPost)
+        }
+      }
+    }
+  }
+}
diff --git a/src/state/shell/composer.tsx b/src/state/shell/composer.tsx
index e28d6b4ac..c99005489 100644
--- a/src/state/shell/composer.tsx
+++ b/src/state/shell/composer.tsx
@@ -34,6 +34,7 @@ export interface ComposerOpts {
   replyTo?: ComposerOptsPostRef
   onPost?: (postUri: string | undefined) => void
   quote?: ComposerOptsQuote
+  quoteCount?: number
   mention?: string // handle of user to mention
   openPicker?: (pos: DOMRect | undefined) => void
   text?: string