mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
merge: all feed initial load stability
This commit is contained in:
@@ -867,7 +867,7 @@ describe('Board', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps propagated board posts in active order when hook updates are appended', async () => {
|
it('preserves hook order when multiboard updates are appended during hydration', async () => {
|
||||||
const currentTimestamp = Math.floor(Date.now() / 1000);
|
const currentTimestamp = Math.floor(Date.now() / 1000);
|
||||||
testState.pageSizes = {
|
testState.pageSizes = {
|
||||||
guiPostsPerPage: 6,
|
guiPostsPerPage: 6,
|
||||||
@@ -876,19 +876,22 @@ describe('Board', () => {
|
|||||||
paginationFeedPostsPerPage: 6,
|
paginationFeedPostsPerPage: 6,
|
||||||
};
|
};
|
||||||
testState.feed = [
|
testState.feed = [
|
||||||
{ cid: 'pinned-post', pinned: true, communityAddress: 'music-posting.eth', timestamp: currentTimestamp - 300 },
|
{ cid: 'first-visible-post', communityAddress: 'music-posting.eth', lastReplyTimestamp: currentTimestamp - 200, timestamp: currentTimestamp - 200 },
|
||||||
{ cid: 'older-post', communityAddress: 'music-posting.eth', lastReplyTimestamp: currentTimestamp - 200, timestamp: currentTimestamp - 200 },
|
{ cid: 'second-visible-post', communityAddress: 'music-posting.eth', lastReplyTimestamp: currentTimestamp - 100, timestamp: currentTimestamp - 100 },
|
||||||
{ cid: 'newly-propagated-post', communityAddress: 'music-posting.eth', postCid: 'newly-propagated-post', timestamp: currentTimestamp },
|
{ cid: 'later-appended-newer-post', communityAddress: 'sports-posting.bso', postCid: 'later-appended-newer-post', timestamp: currentTimestamp },
|
||||||
{ cid: 'middle-post', communityAddress: 'music-posting.eth', lastReplyTimestamp: currentTimestamp - 100, timestamp: currentTimestamp - 100 },
|
|
||||||
];
|
];
|
||||||
|
testState.filteredDirectoryAddresses = ['music-posting.eth', 'sports-posting.bso'];
|
||||||
|
|
||||||
await renderBoard({ initialEntry: '/mu', routePath: '/:boardIdentifier/*' });
|
await renderBoard({
|
||||||
|
boardProps: { viewType: 'all' },
|
||||||
|
initialEntry: '/all',
|
||||||
|
routePath: '/all/*',
|
||||||
|
});
|
||||||
|
|
||||||
expect(Array.from(container.querySelectorAll('[data-testid="post"]')).map((element) => element.textContent)).toEqual([
|
expect(Array.from(container.querySelectorAll('[data-testid="post"]')).map((element) => element.textContent)).toEqual([
|
||||||
'pinned-post',
|
'first-visible-post',
|
||||||
'newly-propagated-post',
|
'second-visible-post',
|
||||||
'middle-post',
|
'later-appended-newer-post',
|
||||||
'older-post',
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+14
-30
@@ -53,32 +53,17 @@ const EMPTY_COMMUNITIES_PAGES = {};
|
|||||||
/** Board feed always uses 'active' sort; catalog dropdown does not affect board ordering. */
|
/** Board feed always uses 'active' sort; catalog dropdown does not affect board ordering. */
|
||||||
const BOARD_SORT_TYPE = 'active' as const;
|
const BOARD_SORT_TYPE = 'active' as const;
|
||||||
|
|
||||||
const toFiniteNumber = (value: unknown) => (typeof value === 'number' && Number.isFinite(value) ? value : 0);
|
const mergeVisibleLocalAccountComments = (feed: Comment[], visibleLocalAccountComments: Comment[]) => {
|
||||||
|
if (visibleLocalAccountComments.length === 0) {
|
||||||
const compareBoardActivePosts = (firstPost: Comment, secondPost: Comment) => {
|
return feed;
|
||||||
const activeDifference =
|
|
||||||
toFiniteNumber(secondPost?.lastReplyTimestamp ?? secondPost?.timestamp) - toFiniteNumber(firstPost?.lastReplyTimestamp ?? firstPost?.timestamp);
|
|
||||||
if (activeDifference !== 0) return activeDifference;
|
|
||||||
|
|
||||||
const upvoteDifference = toFiniteNumber(secondPost?.upvoteCount) - toFiniteNumber(firstPost?.upvoteCount);
|
|
||||||
if (upvoteDifference !== 0) return upvoteDifference;
|
|
||||||
|
|
||||||
return toFiniteNumber(secondPost?.timestamp) - toFiniteNumber(firstPost?.timestamp);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortBoardActiveFeed = (posts: Comment[]) => {
|
|
||||||
const pinnedPosts: Comment[] = [];
|
|
||||||
const regularPosts: Comment[] = [];
|
|
||||||
|
|
||||||
for (const post of posts) {
|
|
||||||
if (post?.pinned) {
|
|
||||||
pinnedPosts.push(post);
|
|
||||||
} else {
|
|
||||||
regularPosts.push(post);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...pinnedPosts, ...regularPosts.toSorted(compareBoardActivePosts)];
|
let firstRegularPostIndex = 0;
|
||||||
|
while (firstRegularPostIndex < feed.length && feed[firstRegularPostIndex]?.pinned) {
|
||||||
|
firstRegularPostIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...feed.slice(0, firstRegularPostIndex), ...visibleLocalAccountComments, ...feed.slice(firstRegularPostIndex)];
|
||||||
};
|
};
|
||||||
|
|
||||||
type RefreshHoldState = {
|
type RefreshHoldState = {
|
||||||
@@ -487,21 +472,20 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
|
|||||||
return [nonokoPendingAccountComment, ...filteredComments.filter((comment) => comment.cid !== nonokoPendingAccountComment.cid)];
|
return [nonokoPendingAccountComment, ...filteredComments.filter((comment) => comment.cid !== nonokoPendingAccountComment.cid)];
|
||||||
}, [nonokoPendingAccountComment, filteredComments]);
|
}, [nonokoPendingAccountComment, filteredComments]);
|
||||||
|
|
||||||
const sortedFeed = useMemo(() => sortBoardActiveFeed(feed), [feed]);
|
const canShowRecentLocalAccountComments = !isSingleCommunityBoard || feed.length > 0 || isRawBoardThreadStateFullyLoaded;
|
||||||
const canShowRecentLocalAccountComments = !isSingleCommunityBoard || sortedFeed.length > 0 || isRawBoardThreadStateFullyLoaded;
|
|
||||||
const feedWithLocalAccountComments = useMemo(() => {
|
const feedWithLocalAccountComments = useMemo(() => {
|
||||||
if (isBoardRefreshPending) {
|
if (isBoardRefreshPending) {
|
||||||
return sortedFeed;
|
return feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const visibleLocalAccountComments = canShowRecentLocalAccountComments ? localAccountComments : nonokoPendingAccountComment ? localAccountComments.slice(0, 1) : [];
|
const visibleLocalAccountComments = canShowRecentLocalAccountComments ? localAccountComments : nonokoPendingAccountComment ? localAccountComments.slice(0, 1) : [];
|
||||||
|
|
||||||
if (visibleLocalAccountComments.length === 0) {
|
if (visibleLocalAccountComments.length === 0) {
|
||||||
return sortedFeed;
|
return feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortBoardActiveFeed([...feed, ...visibleLocalAccountComments]);
|
return mergeVisibleLocalAccountComments(feed, visibleLocalAccountComments);
|
||||||
}, [canShowRecentLocalAccountComments, feed, isBoardRefreshPending, localAccountComments, nonokoPendingAccountComment, sortedFeed]);
|
}, [canShowRecentLocalAccountComments, feed, isBoardRefreshPending, localAccountComments, nonokoPendingAccountComment]);
|
||||||
const combinedFeed = feedWithLocalAccountComments;
|
const combinedFeed = feedWithLocalAccountComments;
|
||||||
|
|
||||||
const cappedFeed = useMemo(
|
const cappedFeed = useMemo(
|
||||||
|
|||||||
Reference in New Issue
Block a user