Fix optimistic deletion for thread

This commit is contained in:
Eric Bailey
2025-06-10 15:15:44 -05:00
parent 8ffc38e955
commit dec4fb129e
@@ -36,6 +36,11 @@ import {Link} from '#/view/com/util/Link'
import {formatCount} from '#/view/com/util/numeric/format' import {formatCount} from '#/view/com/util/numeric/format'
import {PostEmbeds, PostEmbedViewContext} from '#/view/com/util/post-embeds' import {PostEmbeds, PostEmbedViewContext} from '#/view/com/util/post-embeds'
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
import {
LINEAR_AVI_WIDTH,
OUTER_SPACE,
REPLY_LINE_WIDTH,
} from '#/screens/PostThread/const'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {colors} from '#/components/Admonition' import {colors} from '#/components/Admonition'
import {Button} from '#/components/Button' import {Button} from '#/components/Button'
@@ -65,9 +70,11 @@ export function ThreadAnchor({
threadgateRecord?: AppBskyFeedThreadgate.Record threadgateRecord?: AppBskyFeedThreadgate.Record
}) { }) {
const postShadow = usePostShadow(item.value.post) const postShadow = usePostShadow(item.value.post)
const threadRootUri = item.value.post.record.reply?.root?.uri || item.uri
const isRoot = threadRootUri === item.uri
if (postShadow === POST_TOMBSTONE) { if (postShadow === POST_TOMBSTONE) {
return <PostThreadItemDeleted /> return <PostThreadItemDeleted isRoot={isRoot} />
} }
return ( return (
@@ -75,6 +82,7 @@ export function ThreadAnchor({
// Safeguard from clobbering per-post state below: // Safeguard from clobbering per-post state below:
key={postShadow.uri} key={postShadow.uri}
item={item} item={item}
isRoot={isRoot}
postShadow={postShadow} postShadow={postShadow}
onPostSuccess={onPostSuccess} onPostSuccess={onPostSuccess}
threadgateRecord={threadgateRecord} threadgateRecord={threadgateRecord}
@@ -82,34 +90,80 @@ export function ThreadAnchor({
) )
} }
function PostThreadItemDeleted({hideTopBorder}: {hideTopBorder?: boolean}) { function PostThreadItemDeleted({isRoot}: {isRoot: boolean}) {
const t = useTheme() const t = useTheme()
return ( return (
<>
<ThreadItemAnchorParentReplyLine isRoot={isRoot} />
<View <View
style={[ style={[
t.atoms.bg, {
t.atoms.border_contrast_low, paddingHorizontal: OUTER_SPACE,
a.p_xl, paddingBottom: OUTER_SPACE,
a.pl_lg, },
a.flex_row, isRoot && [a.pt_lg],
a.gap_md,
!hideTopBorder && a.border_t,
]}> ]}>
<TrashIcon style={[t.atoms.text]} /> <View
<Text style={[t.atoms.text_contrast_medium, a.mt_2xs]}> style={[
<Trans>This post has been deleted.</Trans> a.flex_row,
a.align_center,
a.py_md,
a.rounded_sm,
t.atoms.bg_contrast_25,
]}>
<View
style={[
a.flex_row,
a.align_center,
a.justify_center,
{
width: LINEAR_AVI_WIDTH,
},
]}>
<TrashIcon style={[t.atoms.text_contrast_medium]} />
</View>
<Text style={[a.text_md, a.font_bold, t.atoms.text_contrast_medium]}>
<Trans>Post has been deleted</Trans>
</Text> </Text>
</View> </View>
</View>
</>
) )
} }
function ThreadItemAnchorParentReplyLine({isRoot}: {isRoot: boolean}) {
const t = useTheme()
return !isRoot ? (
<View style={[a.pl_lg, a.flex_row, a.pb_xs, {height: a.pt_lg.paddingTop}]}>
<View style={{width: 42}}>
<View
style={[
{
width: REPLY_LINE_WIDTH,
marginLeft: 'auto',
marginRight: 'auto',
flexGrow: 1,
backgroundColor: t.atoms.border_contrast_low.borderColor,
},
]}
/>
</View>
</View>
) : null
}
let PostThreadItemLoaded = ({ let PostThreadItemLoaded = ({
item, item,
isRoot,
postShadow, postShadow,
onPostSuccess, onPostSuccess,
threadgateRecord, threadgateRecord,
}: { }: {
item: Extract<ThreadItem, {type: 'threadPost'}> item: Extract<ThreadItem, {type: 'threadPost'}>
isRoot: boolean
postShadow: Shadow<AppBskyFeedDefs.PostView> postShadow: Shadow<AppBskyFeedDefs.PostView>
onPostSuccess?: (data: OnPostSuccessData) => void onPostSuccess?: (data: OnPostSuccessData) => void
threadgateRecord?: AppBskyFeedThreadgate.Record threadgateRecord?: AppBskyFeedThreadgate.Record
@@ -134,7 +188,6 @@ let PostThreadItemLoaded = ({
) )
const threadRootUri = record.reply?.root?.uri || post.uri const threadRootUri = record.reply?.root?.uri || post.uri
const isThreadRoot = threadRootUri === post.uri
const authorHref = makeProfileLink(post.author) const authorHref = makeProfileLink(post.author)
const authorTitle = post.author.handle const authorTitle = post.author.handle
const isThreadAuthor = getThreadAuthor(post, record) === currentAccount?.did const isThreadAuthor = getThreadAuthor(post, record) === currentAccount?.did
@@ -191,31 +244,15 @@ let PostThreadItemLoaded = ({
return ( return (
<> <>
{!isThreadRoot && ( <ThreadItemAnchorParentReplyLine isRoot={isRoot} />
<View
style={[a.pl_lg, a.flex_row, a.pb_xs, {height: a.pt_lg.paddingTop}]}>
<View style={{width: 42}}>
<View
style={[
{
width: 2,
marginLeft: 'auto',
marginRight: 'auto',
flexGrow: 1,
backgroundColor: t.atoms.border_contrast_low.borderColor,
},
]}
/>
</View>
</View>
)}
<View <View
testID={`postThreadItem-by-${post.author.handle}`} testID={`postThreadItem-by-${post.author.handle}`}
style={[ style={[
a.px_lg, {
t.atoms.border_contrast_low, paddingHorizontal: OUTER_SPACE,
isThreadRoot && [a.pt_lg], },
isRoot && [a.pt_lg],
]}> ]}>
<View style={[a.flex_row, a.gap_md, a.pb_md]}> <View style={[a.flex_row, a.gap_md, a.pb_md]}>
<PreviewableUserAvatar <PreviewableUserAvatar