mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(thread-page): make thread auto updates opt-in (#1115)
* fix(thread-page): make thread auto updates opt-in Wire `Auto` and `Update` to the same manual refresh path and cover the thread flow with an e2e harness. * fix(thread-page): address PR review findings
This commit is contained in:
+76
-10
@@ -16,18 +16,32 @@ import { PageFooterDesktop, ThreadFooterFirstRow, ThreadFooterStyleRow, ThreadFo
|
||||
import PostDesktop from '../../components/post-desktop';
|
||||
import PostMobile from '../../components/post-mobile';
|
||||
import { getRequestedThreadTopCid, scrollThreadContainerToTop } from '../../lib/utils/thread-scroll-utils';
|
||||
import useThreadLiveUpdatesStore from '../../stores/use-thread-live-updates-store';
|
||||
import styles from './post.module.css';
|
||||
|
||||
type CommentWithRefresh = Comment & {
|
||||
refresh?: () => Promise<void>;
|
||||
state?: string;
|
||||
error?: Error;
|
||||
errors?: Error[];
|
||||
};
|
||||
|
||||
// useComment may not return cached feed data immediately due to its updatedAt comparison logic.
|
||||
// This hook falls back to the communities pages store (populated by useFeed) so content
|
||||
// from the catalog appears instantly instead of going through a loading phase.
|
||||
const useCommentWithFeedCache = (options: { commentCid: string | undefined }) => {
|
||||
const useCommentWithFeedCache = (options: { commentCid: string | undefined; autoUpdate?: boolean }): CommentWithRefresh | undefined => {
|
||||
const comment = useComment(options);
|
||||
const cachedComment = useCommunitiesPagesStore((state) => state.comments[options?.commentCid || '']);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!cachedComment || comment?.timestamp) return comment;
|
||||
return { ...cachedComment, state: comment?.state, error: comment?.error, errors: comment?.errors } as Comment;
|
||||
return {
|
||||
...cachedComment,
|
||||
refresh: comment?.refresh,
|
||||
state: comment?.state,
|
||||
error: comment?.error,
|
||||
errors: comment?.errors,
|
||||
} as CommentWithRefresh;
|
||||
}, [comment, cachedComment]);
|
||||
};
|
||||
|
||||
@@ -134,13 +148,20 @@ const PostPage = () => {
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const { commentCid } = params;
|
||||
const autoUpdateEnabled = useThreadLiveUpdatesStore((state) => state.enabled);
|
||||
const updateRequestId = useThreadLiveUpdatesStore((state) => state.updateRequestId);
|
||||
const startUpdate = useThreadLiveUpdatesStore((state) => state.startUpdate);
|
||||
const finishUpdate = useThreadLiveUpdatesStore((state) => state.finishUpdate);
|
||||
const resetThreadLiveUpdates = useThreadLiveUpdatesStore((state) => state.resetState);
|
||||
const resolvedCommunityAddress = useResolvedCommunityAddress();
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
|
||||
const comment = useCommentWithFeedCache({ commentCid });
|
||||
const comment = useCommentWithFeedCache({ commentCid, autoUpdate: autoUpdateEnabled });
|
||||
const commentCommunityAddress = getCommentCommunityAddress(comment);
|
||||
const communityAddress = resolvedCommunityAddress ?? commentCommunityAddress;
|
||||
const consumedThreadTopScrollRef = useRef<string | null>(null);
|
||||
const previousThreadCidRef = useRef<string>();
|
||||
const lastProcessedUpdateRequestIdRef = useRef(0);
|
||||
|
||||
const navigate = useNavigate();
|
||||
useEffect(() => {
|
||||
@@ -154,13 +175,8 @@ const PostPage = () => {
|
||||
const directories = useDirectories();
|
||||
|
||||
// if the comment is a reply, return the post comment instead, then the reply will be highlighted in the thread
|
||||
const postComment = useCommentWithFeedCache({ commentCid: comment?.postCid });
|
||||
let post: Comment;
|
||||
if (comment.parentCid) {
|
||||
post = postComment;
|
||||
} else {
|
||||
post = comment;
|
||||
}
|
||||
const postComment = useCommentWithFeedCache({ commentCid: comment?.postCid, autoUpdate: autoUpdateEnabled });
|
||||
const post = comment?.parentCid ? postComment : comment;
|
||||
const requestedThreadTopCid = getRequestedThreadTopCid(location.state);
|
||||
|
||||
const { error } = post || {};
|
||||
@@ -212,6 +228,56 @@ const PostPage = () => {
|
||||
|
||||
const targetReplyCid = comment?.parentCid ? comment?.cid : undefined;
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
resetThreadLiveUpdates();
|
||||
};
|
||||
}, [resetThreadLiveUpdates]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!post?.cid) return;
|
||||
if (previousThreadCidRef.current && previousThreadCidRef.current !== post.cid) {
|
||||
lastProcessedUpdateRequestIdRef.current = 0;
|
||||
consumedThreadTopScrollRef.current = null;
|
||||
resetThreadLiveUpdates();
|
||||
}
|
||||
previousThreadCidRef.current = post.cid;
|
||||
}, [post?.cid, resetThreadLiveUpdates]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!post?.cid || updateRequestId <= lastProcessedUpdateRequestIdRef.current) return;
|
||||
|
||||
const refreshByCid = new Map<string, () => Promise<void>>();
|
||||
if (comment?.cid && typeof comment.refresh === 'function') {
|
||||
refreshByCid.set(comment.cid, comment.refresh);
|
||||
}
|
||||
if (post?.cid && typeof post.refresh === 'function') {
|
||||
refreshByCid.set(post.cid, post.refresh);
|
||||
}
|
||||
if (refreshByCid.size === 0) return;
|
||||
|
||||
lastProcessedUpdateRequestIdRef.current = updateRequestId;
|
||||
let cancelled = false;
|
||||
startUpdate();
|
||||
|
||||
void (async () => {
|
||||
const results = await Promise.allSettled(Array.from(refreshByCid.values(), (refresh) => refresh()));
|
||||
if (cancelled) return;
|
||||
|
||||
const hasSuccessfulRefresh = results.some((result) => result.status === 'fulfilled');
|
||||
finishUpdate(updateRequestId, hasSuccessfulRefresh);
|
||||
|
||||
const rejectedResult = results.find((result) => result.status === 'rejected');
|
||||
if (rejectedResult?.status === 'rejected') {
|
||||
console.error('Failed to refresh thread comments:', rejectedResult.reason);
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [comment?.cid, comment?.refresh, finishUpdate, post?.cid, post?.refresh, startUpdate, updateRequestId]);
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
{shouldShowPostError && (
|
||||
|
||||
Reference in New Issue
Block a user