diff --git a/src/screens/Post/PostLikedBy.tsx b/src/screens/Post/PostLikedBy.tsx index e1a482452f..b8a2302468 100644 --- a/src/screens/Post/PostLikedBy.tsx +++ b/src/screens/Post/PostLikedBy.tsx @@ -7,7 +7,7 @@ import { type NativeStackScreenProps, } from '#/lib/routes/types' import {makeRecordUri} from '#/lib/strings/url-helpers' -import {usePostThreadQuery} from '#/state/queries/post-thread' +import {usePostQuery} from '#/state/queries/post' import {useSetMinimalShellMode} from '#/state/shell' import {PostLikedBy as PostLikedByComponent} from '#/view/com/post-thread/PostLikedBy' import * as Layout from '#/components/Layout' @@ -17,11 +17,11 @@ export const PostLikedByScreen = ({route}: Props) => { const setMinimalShellMode = useSetMinimalShellMode() const {name, rkey} = route.params const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) - const {data: post} = usePostThreadQuery(uri) + const {data: post} = usePostQuery(uri) let likeCount - if (post?.thread.type === 'post') { - likeCount = post.thread.post.likeCount + if (post) { + likeCount = post.likeCount } useFocusEffect( diff --git a/src/screens/Post/PostQuotes.tsx b/src/screens/Post/PostQuotes.tsx index 3fa5d80275..33ebe94f33 100644 --- a/src/screens/Post/PostQuotes.tsx +++ b/src/screens/Post/PostQuotes.tsx @@ -7,7 +7,7 @@ import { type NativeStackScreenProps, } from '#/lib/routes/types' import {makeRecordUri} from '#/lib/strings/url-helpers' -import {usePostThreadQuery} from '#/state/queries/post-thread' +import {usePostQuery} from '#/state/queries/post' import {useSetMinimalShellMode} from '#/state/shell' import {PostQuotes as PostQuotesComponent} from '#/view/com/post-thread/PostQuotes' import * as Layout from '#/components/Layout' @@ -17,11 +17,11 @@ export const PostQuotesScreen = ({route}: Props) => { const setMinimalShellMode = useSetMinimalShellMode() const {name, rkey} = route.params const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) - const {data: post} = usePostThreadQuery(uri) + const {data: post} = usePostQuery(uri) let quoteCount - if (post?.thread.type === 'post') { - quoteCount = post.thread.post.quoteCount + if (post) { + quoteCount = post.quoteCount } useFocusEffect( diff --git a/src/screens/Post/PostRepostedBy.tsx b/src/screens/Post/PostRepostedBy.tsx index d79321d0a9..37f31ce22b 100644 --- a/src/screens/Post/PostRepostedBy.tsx +++ b/src/screens/Post/PostRepostedBy.tsx @@ -7,7 +7,7 @@ import { type NativeStackScreenProps, } from '#/lib/routes/types' import {makeRecordUri} from '#/lib/strings/url-helpers' -import {usePostThreadQuery} from '#/state/queries/post-thread' +import {usePostQuery} from '#/state/queries/post' import {useSetMinimalShellMode} from '#/state/shell' import {PostRepostedBy as PostRepostedByComponent} from '#/view/com/post-thread/PostRepostedBy' import * as Layout from '#/components/Layout' @@ -17,11 +17,11 @@ export const PostRepostedByScreen = ({route}: Props) => { const {name, rkey} = route.params const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) const setMinimalShellMode = useSetMinimalShellMode() - const {data: post} = usePostThreadQuery(uri) + const {data: post} = usePostQuery(uri) let quoteCount - if (post?.thread.type === 'post') { - quoteCount = post.thread.post.repostCount + if (post) { + quoteCount = post.repostCount } useFocusEffect( diff --git a/src/state/cache/post-shadow.ts b/src/state/cache/post-shadow.ts index 312bc6df8d..05a702cd5f 100644 --- a/src/state/cache/post-shadow.ts +++ b/src/state/cache/post-shadow.ts @@ -12,7 +12,6 @@ import {findAllPostsInQueryData as findAllPostsInExploreFeedPreviewsQueryData} f import {findAllPostsInQueryData as findAllPostsInNotifsQueryData} from '#/state/queries/notifications/feed' import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '#/state/queries/post-feed' import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes' -import {findAllPostsInQueryData as findAllPostsInThreadQueryData} from '#/state/queries/post-thread' import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '#/state/queries/search-posts' import {findAllPostsInQueryData as findAllPostsInThreadV2QueryData} from '#/state/queries/usePostThread/queryCache' import {castAsShadow, type Shadow} from './types' @@ -176,11 +175,6 @@ function* findPostsInCache( for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) { yield post } - for (let node of findAllPostsInThreadQueryData(queryClient, uri)) { - if (node.type === 'post') { - yield node.post - } - } for (let post of findAllPostsInThreadV2QueryData(queryClient, uri)) { yield post } diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index 1489e65fd9..168661e0d1 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -16,7 +16,6 @@ import {findAllProfilesInQueryData as findAllProfilesInFeedsQueryData} from '#/s import {findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData} from '#/state/queries/post-liked-by' import {findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData} from '#/state/queries/post-quotes' import {findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData} from '#/state/queries/post-reposted-by' -import {findAllProfilesInQueryData as findAllProfilesInPostThreadQueryData} from '#/state/queries/post-thread' import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '#/state/queries/profile' import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '#/state/queries/profile-followers' import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '#/state/queries/profile-follows' @@ -173,7 +172,6 @@ function* findProfilesInCache( yield* findAllProfilesInActorSearchQueryData(queryClient, did) yield* findAllProfilesInListConvosQueryData(queryClient, did) yield* findAllProfilesInFeedsQueryData(queryClient, did) - yield* findAllProfilesInPostThreadQueryData(queryClient, did) yield* findAllProfilesInPostThreadV2QueryData(queryClient, did) yield* findAllProfilesInKnownFollowersQueryData(queryClient, did) yield* findAllProfilesInExploreFeedPreviewsQueryData(queryClient, did) diff --git a/src/state/queries/post-thread.ts b/src/state/queries/post-thread.ts deleted file mode 100644 index 551fedc8b4..0000000000 --- a/src/state/queries/post-thread.ts +++ /dev/null @@ -1,631 +0,0 @@ -import { - type AppBskyActorDefs, - type AppBskyEmbedRecord, - AppBskyFeedDefs, - type AppBskyFeedGetPostThread, - AppBskyFeedPost, - AtUri, - moderatePost, - type ModerationDecision, - type ModerationOpts, -} from '@atproto/api' -import {type QueryClient, useQuery, useQueryClient} from '@tanstack/react-query' - -import { - findAllPostsInQueryData as findAllPostsInExploreFeedPreviewsQueryData, - findAllProfilesInQueryData as findAllProfilesInExploreFeedPreviewsQueryData, -} from '#/state/queries/explore-feed-previews' -import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes' -import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types' -import { - findAllPostsInQueryData as findAllPostsInSearchQueryData, - findAllProfilesInQueryData as findAllProfilesInSearchQueryData, -} from '#/state/queries/search-posts' -import {useAgent} from '#/state/session' -import * as bsky from '#/types/bsky' -import { - findAllPostsInQueryData as findAllPostsInNotifsQueryData, - findAllProfilesInQueryData as findAllProfilesInNotifsQueryData, -} from './notifications/feed' -import { - findAllPostsInQueryData as findAllPostsInFeedQueryData, - findAllProfilesInQueryData as findAllProfilesInFeedQueryData, -} from './post-feed' -import { - didOrHandleUriMatches, - embedViewRecordToPostView, - getEmbeddedPost, -} from './util' - -const REPLY_TREE_DEPTH = 10 -export const RQKEY_ROOT = 'post-thread' -export const RQKEY = (uri: string) => [RQKEY_ROOT, uri] -type ThreadViewNode = AppBskyFeedGetPostThread.OutputSchema['thread'] - -export interface ThreadCtx { - depth: number - isHighlightedPost?: boolean - hasMore?: boolean - isParentLoading?: boolean - isChildLoading?: boolean - isSelfThread?: boolean - hasMoreSelfThread?: boolean -} - -export type ThreadPost = { - type: 'post' - _reactKey: string - uri: string - post: AppBskyFeedDefs.PostView - record: AppBskyFeedPost.Record - parent: ThreadNode | undefined - replies: ThreadNode[] | undefined - hasOPLike: boolean | undefined - ctx: ThreadCtx -} - -export type ThreadNotFound = { - type: 'not-found' - _reactKey: string - uri: string - ctx: ThreadCtx -} - -export type ThreadBlocked = { - type: 'blocked' - _reactKey: string - uri: string - ctx: ThreadCtx -} - -export type ThreadUnknown = { - type: 'unknown' - uri: string -} - -export type ThreadNode = - | ThreadPost - | ThreadNotFound - | ThreadBlocked - | ThreadUnknown - -export type ThreadModerationCache = WeakMap - -export type PostThreadQueryData = { - thread: ThreadNode - threadgate?: AppBskyFeedDefs.ThreadgateView -} - -export function usePostThreadQuery(uri: string | undefined) { - const queryClient = useQueryClient() - const agent = useAgent() - return useQuery({ - gcTime: 0, - queryKey: RQKEY(uri || ''), - async queryFn() { - const res = await agent.getPostThread({ - uri: uri!, - depth: REPLY_TREE_DEPTH, - }) - if (res.success) { - const thread = responseToThreadNodes(res.data.thread) - annotateSelfThread(thread) - return { - thread, - threadgate: res.data.threadgate as - | AppBskyFeedDefs.ThreadgateView - | undefined, - } - } - return {thread: {type: 'unknown', uri: uri!}} - }, - enabled: !!uri, - placeholderData: () => { - if (!uri) return - const post = findPostInQueryData(queryClient, uri) - if (post) { - return {thread: post} - } - return undefined - }, - }) -} - -export function fillThreadModerationCache( - cache: ThreadModerationCache, - node: ThreadNode, - moderationOpts: ModerationOpts, -) { - if (node.type === 'post') { - cache.set(node, moderatePost(node.post, moderationOpts)) - if (node.parent) { - fillThreadModerationCache(cache, node.parent, moderationOpts) - } - if (node.replies) { - for (const reply of node.replies) { - fillThreadModerationCache(cache, reply, moderationOpts) - } - } - } -} - -export function sortThread( - node: ThreadNode, - opts: UsePreferencesQueryResponse['threadViewPrefs'], - modCache: ThreadModerationCache, - currentDid: string | undefined, - justPostedUris: Set, - threadgateRecordHiddenReplies: Set, - fetchedAtCache: Map, - fetchedAt: number, - randomCache: Map, -): ThreadNode { - if (node.type !== 'post') { - return node - } - if (node.replies) { - node.replies.sort((a: ThreadNode, b: ThreadNode) => { - if (a.type !== 'post') { - return 1 - } - if (b.type !== 'post') { - return -1 - } - - if (node.ctx.isHighlightedPost || opts.lab_treeViewEnabled) { - const aIsJustPosted = - a.post.author.did === currentDid && justPostedUris.has(a.post.uri) - const bIsJustPosted = - b.post.author.did === currentDid && justPostedUris.has(b.post.uri) - if (aIsJustPosted && bIsJustPosted) { - return a.post.indexedAt.localeCompare(b.post.indexedAt) // oldest - } else if (aIsJustPosted) { - return -1 // reply while onscreen - } else if (bIsJustPosted) { - return 1 // reply while onscreen - } - } - - const aIsByOp = a.post.author.did === node.post?.author.did - const bIsByOp = b.post.author.did === node.post?.author.did - if (aIsByOp && bIsByOp) { - return a.post.indexedAt.localeCompare(b.post.indexedAt) // oldest - } else if (aIsByOp) { - return -1 // op's own reply - } else if (bIsByOp) { - return 1 // op's own reply - } - - const aIsBySelf = a.post.author.did === currentDid - const bIsBySelf = b.post.author.did === currentDid - if (aIsBySelf && bIsBySelf) { - return a.post.indexedAt.localeCompare(b.post.indexedAt) // oldest - } else if (aIsBySelf) { - return -1 // current account's reply - } else if (bIsBySelf) { - return 1 // current account's reply - } - - const aHidden = threadgateRecordHiddenReplies.has(a.uri) - const bHidden = threadgateRecordHiddenReplies.has(b.uri) - if (aHidden && !aIsBySelf && !bHidden) { - return 1 - } else if (bHidden && !bIsBySelf && !aHidden) { - return -1 - } - - const aBlur = Boolean(modCache.get(a)?.ui('contentList').blur) - const bBlur = Boolean(modCache.get(b)?.ui('contentList').blur) - if (aBlur !== bBlur) { - if (aBlur) { - return 1 - } - if (bBlur) { - return -1 - } - } - - const aPin = Boolean(a.record.text.trim() === '📌') - const bPin = Boolean(b.record.text.trim() === '📌') - if (aPin !== bPin) { - if (aPin) { - return 1 - } - if (bPin) { - return -1 - } - } - - if (opts.prioritizeFollowedUsers) { - const af = a.post.author.viewer?.following - const bf = b.post.author.viewer?.following - if (af && !bf) { - return -1 - } else if (!af && bf) { - return 1 - } - } - - // Split items from different fetches into separate generations. - let aFetchedAt = fetchedAtCache.get(a.uri) - if (aFetchedAt === undefined) { - fetchedAtCache.set(a.uri, fetchedAt) - aFetchedAt = fetchedAt - } - let bFetchedAt = fetchedAtCache.get(b.uri) - if (bFetchedAt === undefined) { - fetchedAtCache.set(b.uri, fetchedAt) - bFetchedAt = fetchedAt - } - - if (aFetchedAt !== bFetchedAt) { - return aFetchedAt - bFetchedAt // older fetches first - } else if (opts.sort === 'hotness') { - const aHotness = getHotness(a, aFetchedAt) - const bHotness = getHotness(b, bFetchedAt /* same as aFetchedAt */) - return bHotness - aHotness - } else if (opts.sort === 'oldest') { - return a.post.indexedAt.localeCompare(b.post.indexedAt) - } else if (opts.sort === 'newest') { - return b.post.indexedAt.localeCompare(a.post.indexedAt) - } else if (opts.sort === 'most-likes') { - if (a.post.likeCount === b.post.likeCount) { - return b.post.indexedAt.localeCompare(a.post.indexedAt) // newest - } else { - return (b.post.likeCount || 0) - (a.post.likeCount || 0) // most likes - } - } else if (opts.sort === 'random') { - let aRandomScore = randomCache.get(a.uri) - if (aRandomScore === undefined) { - aRandomScore = Math.random() - randomCache.set(a.uri, aRandomScore) - } - let bRandomScore = randomCache.get(b.uri) - if (bRandomScore === undefined) { - bRandomScore = Math.random() - randomCache.set(b.uri, bRandomScore) - } - // this is vaguely criminal but we can get away with it - return aRandomScore - bRandomScore - } else { - return b.post.indexedAt.localeCompare(a.post.indexedAt) - } - }) - node.replies.forEach(reply => - sortThread( - reply, - opts, - modCache, - currentDid, - justPostedUris, - threadgateRecordHiddenReplies, - fetchedAtCache, - fetchedAt, - randomCache, - ), - ) - } - return node -} - -// internal methods -// = - -// Inspired by https://join-lemmy.org/docs/contributors/07-ranking-algo.html -// We want to give recent comments a real chance (and not bury them deep below the fold) -// while also surfacing well-liked comments from the past. In the future, we can explore -// something more sophisticated, but we don't have much data on the client right now. -function getHotness(threadPost: ThreadPost, fetchedAt: number) { - const {post, hasOPLike} = threadPost - const hoursAgo = Math.max( - 0, - (new Date(fetchedAt).getTime() - new Date(post.indexedAt).getTime()) / - (1000 * 60 * 60), - ) - const likeCount = post.likeCount ?? 0 - const likeOrder = Math.log(3 + likeCount) * (hasOPLike ? 1.45 : 1.0) - const timePenaltyExponent = 1.5 + 1.5 / (1 + Math.log(1 + likeCount)) - const opLikeBoost = hasOPLike ? 0.8 : 1.0 - const timePenalty = Math.pow(hoursAgo + 2, timePenaltyExponent * opLikeBoost) - return likeOrder / timePenalty -} - -function responseToThreadNodes( - node: ThreadViewNode, - depth = 0, - direction: 'up' | 'down' | 'start' = 'start', -): ThreadNode { - if ( - AppBskyFeedDefs.isThreadViewPost(node) && - bsky.dangerousIsType( - node.post.record, - AppBskyFeedPost.isRecord, - ) - ) { - const post = node.post - // These should normally be present. They're missing only for - // posts that were *just* created. Ideally, the backend would - // know to return zeros. Fill them in manually to compensate. - post.replyCount ??= 0 - post.likeCount ??= 0 - post.repostCount ??= 0 - return { - type: 'post', - _reactKey: node.post.uri, - uri: node.post.uri, - post: post, - record: node.post.record, - parent: - node.parent && direction !== 'down' - ? responseToThreadNodes(node.parent, depth - 1, 'up') - : undefined, - replies: - node.replies?.length && direction !== 'up' - ? node.replies - .map(reply => responseToThreadNodes(reply, depth + 1, 'down')) - // do not show blocked posts in replies - .filter(node => node.type !== 'blocked') - : undefined, - hasOPLike: Boolean(node?.threadContext?.rootAuthorLike), - ctx: { - depth, - isHighlightedPost: depth === 0, - hasMore: - direction === 'down' && !node.replies?.length && !!post.replyCount, - isSelfThread: false, // populated `annotateSelfThread` - hasMoreSelfThread: false, // populated in `annotateSelfThread` - }, - } - } else if (AppBskyFeedDefs.isBlockedPost(node)) { - return {type: 'blocked', _reactKey: node.uri, uri: node.uri, ctx: {depth}} - } else if (AppBskyFeedDefs.isNotFoundPost(node)) { - return {type: 'not-found', _reactKey: node.uri, uri: node.uri, ctx: {depth}} - } else { - return {type: 'unknown', uri: ''} - } -} - -function annotateSelfThread(thread: ThreadNode) { - if (thread.type !== 'post') { - return - } - const selfThreadNodes: ThreadPost[] = [thread] - - let parent: ThreadNode | undefined = thread.parent - while (parent) { - if ( - parent.type !== 'post' || - parent.post.author.did !== thread.post.author.did - ) { - // not a self-thread - return - } - selfThreadNodes.unshift(parent) - parent = parent.parent - } - - let node = thread - for (let i = 0; i < 10; i++) { - const reply = node.replies?.find( - r => r.type === 'post' && r.post.author.did === thread.post.author.did, - ) - if (reply?.type !== 'post') { - break - } - selfThreadNodes.push(reply) - node = reply - } - - if (selfThreadNodes.length > 1) { - for (const selfThreadNode of selfThreadNodes) { - selfThreadNode.ctx.isSelfThread = true - } - const last = selfThreadNodes[selfThreadNodes.length - 1] - if ( - last && - last.ctx.depth === REPLY_TREE_DEPTH && // at the edge of the tree depth - last.post.replyCount && // has replies - !last.replies?.length // replies were not hydrated - ) { - last.ctx.hasMoreSelfThread = true - } - } -} - -function findPostInQueryData( - queryClient: QueryClient, - uri: string, -): ThreadNode | void { - let partial - for (let item of findAllPostsInQueryData(queryClient, uri)) { - if (item.type === 'post') { - // Currently, the backend doesn't send full post info in some cases - // (for example, for quoted posts). We use missing `likeCount` - // as a way to detect that. In the future, we should fix this on - // the backend, which will let us always stop on the first result. - const hasAllInfo = item.post.likeCount != null - if (hasAllInfo) { - return item - } else { - partial = item - // Keep searching, we might still find a full post in the cache. - } - } - } - return partial -} - -export function* findAllPostsInQueryData( - queryClient: QueryClient, - uri: string, -): Generator { - const atUri = new AtUri(uri) - - const queryDatas = queryClient.getQueriesData({ - queryKey: [RQKEY_ROOT], - }) - for (const [_queryKey, queryData] of queryDatas) { - if (!queryData) { - continue - } - const {thread} = queryData - for (const item of traverseThread(thread)) { - if (item.type === 'post' && didOrHandleUriMatches(atUri, item.post)) { - const placeholder = threadNodeToPlaceholderThread(item) - if (placeholder) { - yield placeholder - } - } - const quotedPost = - item.type === 'post' ? getEmbeddedPost(item.post.embed) : undefined - if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) { - yield embedViewRecordToPlaceholderThread(quotedPost) - } - } - } - for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) { - // Check notifications first. If you have a post in notifications, - // it's often due to a like or a repost, and we want to prioritize - // a post object with >0 likes/reposts over a stale version with no - // metrics in order to avoid a notification->post scroll jump. - yield postViewToPlaceholderThread(post) - } - for (let post of findAllPostsInFeedQueryData(queryClient, uri)) { - yield postViewToPlaceholderThread(post) - } - for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) { - yield postViewToPlaceholderThread(post) - } - for (let post of findAllPostsInSearchQueryData(queryClient, uri)) { - yield postViewToPlaceholderThread(post) - } - for (let post of findAllPostsInExploreFeedPreviewsQueryData( - queryClient, - uri, - )) { - yield postViewToPlaceholderThread(post) - } -} - -export function* findAllProfilesInQueryData( - queryClient: QueryClient, - did: string, -): Generator { - const queryDatas = queryClient.getQueriesData({ - queryKey: [RQKEY_ROOT], - }) - for (const [_queryKey, queryData] of queryDatas) { - if (!queryData) { - continue - } - const {thread} = queryData - for (const item of traverseThread(thread)) { - if (item.type === 'post' && item.post.author.did === did) { - yield item.post.author - } - const quotedPost = - item.type === 'post' ? getEmbeddedPost(item.post.embed) : undefined - if (quotedPost?.author.did === did) { - yield quotedPost?.author - } - } - } - for (let profile of findAllProfilesInFeedQueryData(queryClient, did)) { - yield profile - } - for (let profile of findAllProfilesInNotifsQueryData(queryClient, did)) { - yield profile - } - for (let profile of findAllProfilesInSearchQueryData(queryClient, did)) { - yield profile - } - for (let profile of findAllProfilesInExploreFeedPreviewsQueryData( - queryClient, - did, - )) { - yield profile - } -} - -function* traverseThread(node: ThreadNode): Generator { - if (node.type === 'post') { - if (node.parent) { - yield* traverseThread(node.parent) - } - yield node - if (node.replies?.length) { - for (const reply of node.replies) { - yield* traverseThread(reply) - } - } - } -} - -function threadNodeToPlaceholderThread( - node: ThreadNode, -): ThreadNode | undefined { - if (node.type !== 'post') { - return undefined - } - return { - type: node.type, - _reactKey: node._reactKey, - uri: node.uri, - post: node.post, - record: node.record, - parent: undefined, - replies: undefined, - hasOPLike: undefined, - ctx: { - depth: 0, - isHighlightedPost: true, - hasMore: false, - isParentLoading: !!node.record.reply, - isChildLoading: !!node.post.replyCount, - }, - } -} - -function postViewToPlaceholderThread( - post: AppBskyFeedDefs.PostView, -): ThreadNode { - return { - type: 'post', - _reactKey: post.uri, - uri: post.uri, - post: post, - record: post.record as AppBskyFeedPost.Record, // validated in notifs - parent: undefined, - replies: undefined, - hasOPLike: undefined, - ctx: { - depth: 0, - isHighlightedPost: true, - hasMore: false, - isParentLoading: !!(post.record as AppBskyFeedPost.Record).reply, - isChildLoading: true, // assume yes (show the spinner) just in case - }, - } -} - -function embedViewRecordToPlaceholderThread( - record: AppBskyEmbedRecord.ViewRecord, -): ThreadNode { - return { - type: 'post', - _reactKey: record.uri, - uri: record.uri, - post: embedViewRecordToPostView(record), - record: record.value as AppBskyFeedPost.Record, // validated in getEmbeddedPost - parent: undefined, - replies: undefined, - hasOPLike: undefined, - ctx: { - depth: 0, - isHighlightedPost: true, - hasMore: false, - isParentLoading: !!(record.value as AppBskyFeedPost.Record).reply, - isChildLoading: true, // not available, so assume yes (to show the spinner) - }, - } -} diff --git a/src/state/queries/threadgate/index.ts b/src/state/queries/threadgate/index.ts index 305acc5d05..86f1e8d1fd 100644 --- a/src/state/queries/threadgate/index.ts +++ b/src/state/queries/threadgate/index.ts @@ -10,7 +10,6 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import {networkRetry, retry} from '#/lib/async/retry' import {until} from '#/lib/async/until' import {STALE} from '#/state/queries' -import {RQKEY_ROOT as postThreadQueryKeyRoot} from '#/state/queries/post-thread' import {type ThreadgateAllowUISetting} from '#/state/queries/threadgate/types' import { createThreadgateRecord, @@ -293,9 +292,6 @@ export function useSetThreadgateAllowMutation() { }, ) - queryClient.invalidateQueries({ - queryKey: [postThreadQueryKeyRoot], - }) queryClient.invalidateQueries({ queryKey: [threadgateRecordQueryKeyRoot], })