Bluesky app fork with some witchin' additions 💫

Fix bug where replying to grandparents re-orders thread (#8662)

* Fix bug where optimistic replies were inserted above the root post

* Rename variables for clarity

authored by

Eric Bailey and committed by
GitHub
00b01780 d13a2e5f

+32 -23
+26 -23
src/state/queries/usePostThread/queryCache.ts
··· 77 77 78 78 function mutator<T>(thread: ApiThreadItem[]): T[] { 79 79 for (let i = 0; i < thread.length; i++) { 80 - const existingParent = thread[i] 81 - if (!AppBskyUnspeccedDefs.isThreadItemPost(existingParent.value)) 82 - continue 83 - if (existingParent.uri !== parentUri) continue 80 + const parent = thread[i] 81 + 82 + if (!AppBskyUnspeccedDefs.isThreadItemPost(parent.value)) continue 83 + if (parent.uri !== parentUri) continue 84 84 85 85 /* 86 86 * Update parent data 87 87 */ 88 - existingParent.value.post = { 89 - ...existingParent.value.post, 90 - replyCount: (existingParent.value.post.replyCount || 0) + 1, 88 + parent.value.post = { 89 + ...parent.value.post, 90 + replyCount: (parent.value.post.replyCount || 0) + 1, 91 91 } 92 92 93 - const opDid = getRootPostAtUri(existingParent.value.post)?.host 94 - const nextItem = thread.at(i + 1) 95 - const isReplyToRoot = existingParent.depth === 0 93 + const opDid = getRootPostAtUri(parent.value.post)?.host 94 + const nextPreexistingItem = thread.at(i + 1) 96 95 const isEndOfReplyChain = 97 - !nextItem || nextItem.depth <= existingParent.depth 98 - const firstReply = replies.at(0) 96 + !nextPreexistingItem || nextPreexistingItem.depth <= parent.depth 97 + const isParentRoot = parent.depth === 0 98 + const isParentBelowRoot = parent.depth > 0 99 + const optimisticReply = replies.at(0) 99 100 const opIsReplier = AppBskyUnspeccedDefs.isThreadItemPost( 100 - firstReply?.value, 101 + optimisticReply?.value, 101 102 ) 102 - ? opDid === firstReply.value.post.author.did 103 + ? opDid === optimisticReply.value.post.author.did 103 104 : false 104 105 105 106 /* 106 - * Always insert replies if the following conditions are met. 107 + * Always insert replies if the following conditions are met. Max 108 + * depth checks are handled below. 107 109 */ 108 - const shouldAlwaysInsertReplies = 109 - isReplyToRoot || 110 - params.view === 'tree' || 110 + const canAlwaysInsertReplies = 111 + isParentRoot || 112 + (params.view === 'tree' && isParentBelowRoot) || 111 113 (params.view === 'linear' && isEndOfReplyChain) 112 114 /* 113 - * Maybe insert replies if the replier is the OP and certain conditions are met 115 + * Maybe insert replies if we're in linear view, the replier is the 116 + * OP, and certain conditions are met 114 117 */ 115 118 const shouldReplaceWithOPReplies = 116 - !isReplyToRoot && params.view === 'linear' && opIsReplier 119 + params.view === 'linear' && opIsReplier && isParentBelowRoot 117 120 118 - if (shouldAlwaysInsertReplies || shouldReplaceWithOPReplies) { 119 - const branch = getBranch(thread, i, existingParent.depth) 121 + if (canAlwaysInsertReplies || shouldReplaceWithOPReplies) { 122 + const branch = getBranch(thread, i, parent.depth) 120 123 /* 121 124 * OP insertions replace other replies _in linear view_. 122 125 */ 123 126 const itemsToRemove = shouldReplaceWithOPReplies ? branch.length : 0 124 127 const itemsToInsert = replies 125 128 .map((r, ri) => { 126 - r.depth = existingParent.depth + 1 + ri 129 + r.depth = parent.depth + 1 + ri 127 130 return r 128 131 }) 129 132 .filter(r => {
+6
src/state/queries/usePostThread/utils.ts
··· 33 33 AppBskyFeedPost.isRecord, 34 34 ) 35 35 ) { 36 + /** 37 + * If the record has no `reply` field, it is a root post. 38 + */ 39 + if (!post.record.reply) { 40 + return new AtUri(post.uri) 41 + } 36 42 if (post.record.reply?.root?.uri) { 37 43 return new AtUri(post.record.reply.root.uri) 38 44 }