diff --git a/src/state/queries/usePostThread/__tests__/queryCache.test.ts b/src/state/queries/usePostThread/__tests__/queryCache.test.ts new file mode 100644 index 0000000000..95f5e17424 --- /dev/null +++ b/src/state/queries/usePostThread/__tests__/queryCache.test.ts @@ -0,0 +1,4 @@ +import {describe, it} from '@jest/globals' + +describe(`insert`, () => { +}) diff --git a/src/state/queries/usePostThread/index.ts b/src/state/queries/usePostThread/index.ts index 88cd2ccb60..09c2c05012 100644 --- a/src/state/queries/usePostThread/index.ts +++ b/src/state/queries/usePostThread/index.ts @@ -1,7 +1,7 @@ import {useQuery, useQueryClient} from '@tanstack/react-query' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {getThreadPlaceholder} from '#/state/queries/usePostThread/queryCache' +import {getThreadPlaceholder, createCacheMutator} from '#/state/queries/usePostThread/queryCache' import {flatten,sort} from '#/state/queries/usePostThread/traversal' import { createPostThreadQueryKey, @@ -30,13 +30,14 @@ export function usePostThread({ const mergeThreadgateHiddenReplies = useMergeThreadgateHiddenReplies() const enabled = isEnabled !== false && !!uri && !!moderationOpts + const queryKey = createPostThreadQueryKey({ + uri, + params, + }) const query = useQuery({ enabled, - queryKey: createPostThreadQueryKey({ - uri, - params, - }), + queryKey, async queryFn() { const {data} = await agent.app.bsky.unspecced.getPostThreadV2({ uri: uri!, @@ -82,12 +83,17 @@ export function usePostThread({ }, ) + const mutator = createCacheMutator({ + queryKey, + queryClient: qc, + }) + return { ...query, data: { slices: items, threadgate: query.data?.threadgate, }, - insertReplies: () => {}, + insertReplies: mutator.insertReplies, } } diff --git a/src/state/queries/usePostThread/queryCache.ts b/src/state/queries/usePostThread/queryCache.ts index 94bf838df7..0e8efdb80d 100644 --- a/src/state/queries/usePostThread/queryCache.ts +++ b/src/state/queries/usePostThread/queryCache.ts @@ -11,13 +11,73 @@ import {findAllPostsInQueryData as findAllPostsInNotifsQueryData} from '#/state/ import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '#/state/queries/post-feed' import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes' import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '#/state/queries/search-posts' -import {postThreadQueryKeyRoot} from '#/state/queries/usePostThread/types' +import { + postThreadQueryKeyRoot, + createPostThreadQueryKey, +} from '#/state/queries/usePostThread/types' import { embedViewToThreadPlaceholder, postViewToThreadPlaceholder, } from '#/state/queries/usePostThread/views' import {didOrHandleUriMatches, getEmbeddedPost} from '#/state/queries/util' +export function createCacheMutator({ + queryKey, + queryClient, +}: { + queryKey: ReturnType + queryClient: QueryClient +}) { + return { + insertReplies( + parent: AppBskyUnspeccedDefs.ThreadItemPost, + replies: AppBskyUnspeccedDefs.ThreadItemPost[], + ) { + queryClient.setQueryData( + queryKey, + queryData => { + if (!queryData) return + + const thread = [...queryData.thread] + + for (let i = 0; i < thread.length; i++) { + const anchor = thread[i] + if (!AppBskyUnspeccedDefs.isThreadItemPost(anchor)) continue + if (anchor.uri !== parent.uri) continue + + /* + * Update parent data + */ + anchor.post = { + ...anchor.post, + replyCount: parent.post.replyCount, + } + + /* + * Splice in new replies + */ + for (let ri = 0; ri < replies.length; ri++) { + const reply = replies[ri] + reply.depth = anchor.depth + 1 + ri + const insertIndex = i + 1 + ri + thread.splice(insertIndex, 0, { + $type: 'app.bsky.unspecced.defs#threadItemPost', + ...reply, + }) + } + } + + return { + ...queryData, + thread, + } + }, + ) + }, + deletePost(post: AppBskyUnspeccedDefs.ThreadItemPost) {}, + } +} + export function getThreadPlaceholder( queryClient: QueryClient, uri: string, diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index f0fefc0b89..763f19681d 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -407,15 +407,15 @@ export const ComposePost = ({ posts = await retry(5, _e => true, async () => { const res = await agent.app.bsky.unspecced.getPostThreadV2({ uri: postUri!, - above: 0, + above: 1, below: thread.posts.length - 1, branchingFactor: 1, }) - if (res.data.thread.length !== thread.posts.length) { + const parent = res.data.thread.at(0) + if (!AppBskyUnspeccedDefs.isThreadItemPost(parent)) { throw new Error(`Not ready`) } - const anchor = res.data.thread.at(0) - if (!AppBskyUnspeccedDefs.isThreadItemPost(anchor)) { + if (res.data.thread.length !== thread.posts.length + 1) { throw new Error(`Not ready`) } return res.data.thread diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index a26512dd7d..943ce5ae23 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -161,8 +161,12 @@ export function Inner({uri}: {uri: string | undefined}) { ({post}: {post: AppBskyUnspeccedDefs.ThreadItemPost}) => (_: any, posts: AppBskyUnspeccedDefs.ThreadItemPost[]) => { if (posts.length) { - // TODO get parent and update reply count? - insertReplies(post.uri, posts) + console.log('insert', posts) + const parent = posts.at(0) + const replies = posts.slice(1) + if (parent && replies.length) { + insertReplies(parent, replies) + } } }