fix(replies): make thread replies update instantly for pending and confirmed states

Aligned 5chan’s flat thread reply behavior with plebones by using `useReplies` in flat-old mode with appending account comments and rendering from `updatedReplies` when available. Reply rows now subscribe to `useAccountComment` by `index`, so pending replies transition to confirmed automatically after challenge verification without requiring manual update or refresh.
This commit is contained in:
plebeius
2026-02-13 19:42:38 +08:00
parent 98f7a52e9b
commit 14c6bf8f3a
2 changed files with 50 additions and 20 deletions
+20 -9
View File
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { Comment, useAuthorAvatar, useEditedComment, useReplies, useAccount } from '@plebbit/plebbit-react-hooks';
import { Comment, useAuthorAvatar, useEditedComment, useReplies, useAccount, useAccountComment } from '@plebbit/plebbit-react-hooks';
import Plebbit from '@plebbit/plebbit-js';
import styles from '../../views/post/post.module.css';
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
@@ -581,9 +581,13 @@ const Reply = ({
quotedByMap,
directRepliesByParentCid,
}: PostProps & { directRepliesByParentCid?: Map<string, Comment[]> }) => {
let post = reply;
const accountReply = useAccountComment({
commentIndex: typeof reply?.index === 'number' ? reply.index : undefined,
});
const hasReplyIndex = typeof reply?.index === 'number';
let post = hasReplyIndex && accountReply?.index === reply.index ? accountReply : reply;
// handle pending mod or author edit
const { editedComment } = useEditedComment({ comment: reply });
const { editedComment } = useEditedComment({ comment: post });
if (editedComment) {
post = editedComment;
}
@@ -666,8 +670,15 @@ const PostDesktop = ({
const { hidden, unhide, hide } = useHide({ cid });
const isHidden = hidden && !isInPostPageView;
const repliesResult = useReplies({ comment: post, flat: true, accountComments: { newerThan: Infinity } });
const repliesResult = useReplies({
comment: post,
sortType: 'old',
flat: true,
accountComments: { newerThan: Infinity, append: true },
});
const { replies, hasMore, loadMore } = repliesResult;
const updatedReplies = (repliesResult as { updatedReplies?: Comment[] }).updatedReplies;
const repliesForRender = updatedReplies?.length ? updatedReplies : replies || [];
const reset = (repliesResult as { reset?: () => Promise<void> }).reset;
const setResetFunction = useFeedResetStore((s) => s.setResetFunction);
useEffect(() => {
@@ -680,7 +691,7 @@ const PostDesktop = ({
const registerComments = usePostNumberStore((s) => s.registerComments);
const prevCidsRef = useRef<string>('');
useEffect(() => {
const all = post ? [post, ...(replies || [])] : replies || [];
const all = post ? [post, ...repliesForRender] : repliesForRender;
if (!all.length) return;
const cidsKey = all
.map((c) => c?.cid)
@@ -690,10 +701,10 @@ const PostDesktop = ({
if (cidsKey === prevCidsRef.current) return;
prevCidsRef.current = cidsKey;
registerComments(all);
}, [post, replies, registerComments]);
}, [post, repliesForRender, registerComments]);
const visiblelinksCount = useCountLinksInReplies(post, 5);
const totalLinksCount = useCountLinksInReplies(post);
const replyCount = replies?.length;
const replyCount = repliesForRender.length;
const repliesCount = pinned ? replyCount : replyCount - 5;
const linksCount = pinned ? totalLinksCount : totalLinksCount - visiblelinksCount;
@@ -706,7 +717,7 @@ const PostDesktop = ({
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
// Filter out deleted replies with no children for both virtuoso and non-virtuoso rendering
const filteredReplies = useMemo(() => (replies || []).filter((reply) => !(reply.deleted && (reply.replyCount === 0 || !reply.replyCount))), [replies]);
const filteredReplies = useMemo(() => repliesForRender.filter((reply) => !(reply.deleted && (reply.replyCount === 0 || !reply.replyCount))), [repliesForRender]);
const directRepliesByParentCid = useMemo(() => {
const map = new Map<string, Comment[]>();
for (const reply of filteredReplies) {
@@ -894,7 +905,7 @@ const PostDesktop = ({
!showAllReplies &&
!(pinned && !isInPostPageView && !showOmittedReplies[cid]) &&
!isInPendingPostView &&
replies &&
repliesForRender &&
showReplies &&
(showOmittedReplies[cid] ? filteredReplies : filteredReplies.slice(-5)).map((reply, index) => (
<div key={index} className={styles.replyContainer}>
+30 -11
View File
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { Comment, useAuthorAvatar, useEditedComment, useReplies, useAccount, usePublishCommentModeration } from '@plebbit/plebbit-react-hooks';
import { Comment, useAuthorAvatar, useEditedComment, useReplies, useAccount, usePublishCommentModeration, useAccountComment } from '@plebbit/plebbit-react-hooks';
import Plebbit from '@plebbit/plebbit-js';
import styles from '../../views/post/post.module.css';
import { shouldShowSnow } from '../../lib/snow';
@@ -387,7 +387,15 @@ const PostMediaContent = ({ post, link }: { post: any; link: string }) => {
const ReplyBacklinks = ({ post, quotedByMap }: PostProps) => {
const { cid, parentCid } = post || {};
const { replies } = useReplies({ comment: post, flat: true, accountComments: { newerThan: Infinity } });
const repliesResult = useReplies({
comment: post,
sortType: 'old',
flat: true,
accountComments: { newerThan: Infinity, append: true },
});
const { replies } = repliesResult;
const updatedReplies = (repliesResult as { updatedReplies?: Comment[] }).updatedReplies;
const repliesForRender = updatedReplies?.length ? updatedReplies : replies || [];
const opBacklinks =
cid &&
@@ -400,9 +408,9 @@ const ReplyBacklinks = ({ post, quotedByMap }: PostProps) => {
)
.filter(Boolean);
const replyBacklinks = cid && parentCid && ((replies?.length || 0) > 0 || quotedByMap?.get(cid)?.length) && (
const replyBacklinks = cid && parentCid && ((repliesForRender?.length || 0) > 0 || quotedByMap?.get(cid)?.length) && (
<>
{replies?.map(
{repliesForRender?.map(
(reply: Comment, index: number) =>
reply?.parentCid === cid && reply?.cid && !(reply?.deleted || reply?.removed) && <ReplyQuotePreview key={index} isBacklinkReply={true} backlinkReply={reply} />,
)}
@@ -426,9 +434,13 @@ const ReplyBacklinks = ({ post, quotedByMap }: PostProps) => {
};
const Reply = ({ postReplyCount, reply, roles, threadNumber, quotedByMap }: PostProps) => {
let post = reply;
const accountReply = useAccountComment({
commentIndex: typeof reply?.index === 'number' ? reply.index : undefined,
});
const hasReplyIndex = typeof reply?.index === 'number';
let post = hasReplyIndex && accountReply?.index === reply.index ? accountReply : reply;
// handle pending mod or author edit
const { editedComment } = useEditedComment({ comment: reply });
const { editedComment } = useEditedComment({ comment: post });
if (editedComment) {
post = editedComment;
}
@@ -481,8 +493,15 @@ const PostMobile = ({
const directories = useDirectories();
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, directories) : undefined;
const linksCount = useCountLinksInReplies(post);
const repliesResult = useReplies({ comment: post, accountComments: { newerThan: Infinity } });
const repliesResult = useReplies({
comment: post,
sortType: 'old',
flat: true,
accountComments: { newerThan: Infinity, append: true },
});
const { replies, hasMore, loadMore } = repliesResult;
const updatedReplies = (repliesResult as { updatedReplies?: Comment[] }).updatedReplies;
const repliesForRender = updatedReplies?.length ? updatedReplies : replies || [];
const reset = (repliesResult as { reset?: () => Promise<void> }).reset;
const setResetFunction = useFeedResetStore((s) => s.setResetFunction);
useEffect(() => {
@@ -495,7 +514,7 @@ const PostMobile = ({
const registerComments = usePostNumberStore((s) => s.registerComments);
const prevCidsRef = useRef<string>('');
useEffect(() => {
const all = post ? [post, ...(replies || [])] : replies || [];
const all = post ? [post, ...repliesForRender] : repliesForRender;
if (!all.length) return;
const cidsKey = all
.map((c) => c?.cid)
@@ -505,7 +524,7 @@ const PostMobile = ({
if (cidsKey === prevCidsRef.current) return;
prevCidsRef.current = cidsKey;
registerComments(all);
}, [post, replies, registerComments]);
}, [post, repliesForRender, registerComments]);
const isInPostPageView = isPostPageView(location.pathname, params);
const { hidden, unhide } = useHide({ cid });
@@ -514,7 +533,7 @@ const PostMobile = ({
const hasFailedState = state === 'failed';
// Filter out deleted replies with no children for both virtuoso and non-virtuoso rendering
const filteredReplies = useMemo(() => (replies || []).filter((reply) => !(reply.deleted && (reply.replyCount === 0 || !reply.replyCount))), [replies]);
const filteredReplies = useMemo(() => repliesForRender.filter((reply) => !(reply.deleted && (reply.replyCount === 0 || !reply.replyCount))), [repliesForRender]);
const quotedByMap = useQuotedByMap(filteredReplies);
@@ -660,7 +679,7 @@ const PostMobile = ({
{!(pinned && !isInPostView) &&
!showAllReplies &&
!isInPendingPostView &&
replies &&
repliesForRender &&
showReplies &&
filteredReplies.slice(-5).map((reply, index) => (
<div key={index} className={styles.replyContainer}>