fix(catalog): reuse board feed identity when idle

This commit is contained in:
Tommaso Casaburi
2026-04-18 17:29:33 +07:00
parent 80f41f00db
commit 58a4be1be7
2 changed files with 34 additions and 12 deletions
+18 -9
View File
@@ -45,7 +45,7 @@ const testState = vi.hoisted(() => ({
} as Record<string, { address: string; features?: Record<string, unknown> }>, } as Record<string, { address: string; features?: Record<string, unknown> }>,
directories: [{ address: 'music-posting.eth', title: '/mu/ - Music' }] as Array<{ address: string; title?: string }>, directories: [{ address: 'music-posting.eth', title: '/mu/ - Music' }] as Array<{ address: string; title?: string }>,
feed: [] as TestComment[], feed: [] as TestComment[],
feedOptionsCalls: [] as Array<{ communitiesLength?: number; newerThan?: number; postsPerPage?: number; sortType?: string }>, feedOptionsCalls: [] as Array<{ communitiesLength?: number; filterKey?: string; newerThan?: number; postsPerPage?: number; sortType?: string }>,
filterItems: [] as FilterItem[], filterItems: [] as FilterItem[],
filteredDirectoryAddresses: ['music-posting.eth'] as string[], filteredDirectoryAddresses: ['music-posting.eth'] as string[],
hasMore: false, hasMore: false,
@@ -121,7 +121,12 @@ const getScopedAccountComments = (options?: { commentIndices?: number[]; communi
return scopedComments; return scopedComments;
}; };
const getScopedFeed = (options?: { filter?: { filter: (comment: TestComment) => boolean }; newerThan?: number; postsPerPage?: number }) => { type FeedFilter = {
filter: (comment: TestComment) => boolean;
key?: string;
};
const getScopedFeed = (options?: { filter?: FeedFilter; newerThan?: number; postsPerPage?: number }) => {
let scopedFeed = [...testState.feed]; let scopedFeed = [...testState.feed];
if (typeof options?.newerThan === 'number') { if (typeof options?.newerThan === 'number') {
@@ -146,15 +151,10 @@ vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
testState.accountCommentsCalls.push(options); testState.accountCommentsCalls.push(options);
return { accountComments: getScopedAccountComments(options) }; return { accountComments: getScopedAccountComments(options) };
}, },
useFeed: (options: { useFeed: (options: { communities?: unknown[]; filter?: FeedFilter; newerThan?: number; postsPerPage?: number; sortType?: string }) => {
communities?: unknown[];
filter?: { filter: (comment: TestComment) => boolean };
newerThan?: number;
postsPerPage?: number;
sortType?: string;
}) => {
testState.feedOptionsCalls.push({ testState.feedOptionsCalls.push({
communitiesLength: options.communities?.length, communitiesLength: options.communities?.length,
filterKey: options.filter?.key,
newerThan: options.newerThan, newerThan: options.newerThan,
postsPerPage: options.postsPerPage, postsPerPage: options.postsPerPage,
sortType: options.sortType, sortType: options.sortType,
@@ -679,6 +679,15 @@ describe('Catalog', () => {
expect(Array.from(container.querySelectorAll('[data-testid="catalog-row"]')).map((element) => element.textContent)).toEqual(['row:local-cats-post,network-post']); expect(Array.from(container.querySelectorAll('[data-testid="catalog-row"]')).map((element) => element.textContent)).toEqual(['row:local-cats-post,network-post']);
}); });
it('reuses the board feed identity when catalog search and filters are inactive', async () => {
testState.sortType = 'active';
testState.feed = [{ cid: 'network-post', title: 'cats on stage', communityAddress: 'music-posting.eth' }];
await renderCatalog({ initialEntry: '/mu/catalog', routePath: '/:boardIdentifier/catalog' });
expect(testState.feedOptionsCalls).toEqual(expect.arrayContaining([expect.objectContaining({ filterKey: 'exclude-archived' })]));
});
it('chunks catalog rows safely even when the viewport is narrower than one card', async () => { it('chunks catalog rows safely even when the viewport is narrower than one card', async () => {
testState.windowWidth = 0; testState.windowWidth = 0;
testState.feed = [ testState.feed = [
+16 -3
View File
@@ -278,6 +278,17 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
const subscriptions = account?.subscriptions; const subscriptions = account?.subscriptions;
const accountCommunityAddresses = useAccountCommunityAddresses(); const accountCommunityAddresses = useAccountCommunityAddresses();
const filteredDirectoryAddresses = useFilteredDirectoryAddresses(); const filteredDirectoryAddresses = useFilteredDirectoryAddresses();
const excludeArchivedFilter = useMemo(
() => ({
filter: (comment: Comment) => !isCommentArchived(comment),
key: 'exclude-archived',
}),
[],
);
const hasActiveCatalogFiltering = useMemo(
() => searchText.trim().length > 0 || filterItems.some((item) => item.enabled && item.text.trim() !== ''),
[filterItems, searchText],
);
const communityAddresses = useMemo(() => { const communityAddresses = useMemo(() => {
if (isInAllView) { if (isInAllView) {
@@ -337,12 +348,13 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
communities, communities,
sortType: feedSortType, sortType: feedSortType,
postsPerPage: isMultiboard ? multiboardCatalogPostsPerPage : paginationFeedPostsPerPage, postsPerPage: isMultiboard ? multiboardCatalogPostsPerPage : paginationFeedPostsPerPage,
filter: createCombinedFilter(filterItems, searchText, communityAddress || 'all', handleFilterMatch), filter: hasActiveCatalogFiltering ? createCombinedFilter(filterItems, searchText, communityAddress || 'all', handleFilterMatch) : excludeArchivedFilter,
newerThan: multiboardTimeFilterSeconds, newerThan: multiboardTimeFilterSeconds,
}; };
}, [ }, [
communities, communities,
feedSortType, feedSortType,
hasActiveCatalogFiltering,
isMultiboard, isMultiboard,
paginationFeedPostsPerPage, paginationFeedPostsPerPage,
multiboardCatalogPostsPerPage, multiboardCatalogPostsPerPage,
@@ -351,6 +363,7 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
communityAddress, communityAddress,
handleFilterMatch, handleFilterMatch,
multiboardTimeFilterSeconds, multiboardTimeFilterSeconds,
excludeArchivedFilter,
]); ]);
const { feed, hasMore, loadMore, reset, expandTimeWindow } = useFeed(feedOptions); const { feed, hasMore, loadMore, reset, expandTimeWindow } = useFeed(feedOptions);
@@ -364,8 +377,8 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
const shouldProbeMonthlyFeed = shouldProbeSuggestionFeeds && currentTimeFilterSeconds < MONTH_IN_SECONDS; const shouldProbeMonthlyFeed = shouldProbeSuggestionFeeds && currentTimeFilterSeconds < MONTH_IN_SECONDS;
const shouldProbeYearlyFeed = shouldProbeSuggestionFeeds && currentTimeFilterSeconds < YEAR_IN_SECONDS; const shouldProbeYearlyFeed = shouldProbeSuggestionFeeds && currentTimeFilterSeconds < YEAR_IN_SECONDS;
const suggestionFilter = useMemo( const suggestionFilter = useMemo(
() => createCombinedFilter(filterItems, searchText, communityAddress || 'all', undefined, false), () => (hasActiveCatalogFiltering ? createCombinedFilter(filterItems, searchText, communityAddress || 'all', undefined, false) : excludeArchivedFilter),
[communityAddress, filterItems, searchText], [communityAddress, excludeArchivedFilter, filterItems, hasActiveCatalogFiltering, searchText],
); );
// Keep suggestion feeds on a stable hook identity; the loader widens them by paging, not by recreating the feed. // Keep suggestion feeds on a stable hook identity; the loader widens them by paging, not by recreating the feed.
const suggestionPostsPerPage = multiboardCatalogPostsPerPage; const suggestionPostsPerPage = multiboardCatalogPostsPerPage;