mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(home): keep stats loading until directories resolve
This commit is contained in:
@@ -49,6 +49,10 @@ vi.mock('../../../hooks/use-communities-stats', () => ({
|
||||
useCommunitiesStatsStore: (selector: (state: { communityStats: typeof testState.communityStats }) => unknown) => selector({ communityStats: testState.communityStats }),
|
||||
}));
|
||||
|
||||
vi.mock('../../../components/loading-ellipsis', () => ({
|
||||
default: ({ string }: { string: string }) => createElement('span', { 'data-testid': 'loading-ellipsis' }, string),
|
||||
}));
|
||||
|
||||
vi.mock('../../../stores/use-directory-modal-store', () => ({
|
||||
default: () => ({
|
||||
closeDirectoryModal: testState.closeDirectoryModalMock,
|
||||
@@ -124,6 +128,7 @@ describe('Home', () => {
|
||||
expect(container.querySelector('[data-testid="boards-list"]')?.textContent).toBe('boards:2');
|
||||
expect(container.querySelector('[data-testid="popular-threads-box"]')?.textContent).toBe('popular:2:2');
|
||||
expect(container.querySelectorAll('[data-testid="stats-collector"]')).toHaveLength(2);
|
||||
expect(container.querySelectorAll('[data-testid="loading-ellipsis"]')).toHaveLength(0);
|
||||
expect(container.textContent).toContain('total_posts 12');
|
||||
expect(container.textContent).toContain('current_users 7');
|
||||
expect(container.textContent).toContain('boards_tracked 2');
|
||||
@@ -131,6 +136,35 @@ describe('Home', () => {
|
||||
expect(container.querySelector<HTMLAnchorElement>('a[href="/pass"]')?.textContent).toBe('support_5chan');
|
||||
});
|
||||
|
||||
it('keeps the stats values loading until every directory has loaded stats', () => {
|
||||
testState.communityStats = {
|
||||
'music-posting.eth': { allPostCount: 5, weekActiveUserCount: 2 },
|
||||
};
|
||||
|
||||
renderHome();
|
||||
|
||||
const loadingValues = Array.from(container.querySelectorAll('[data-testid="loading-ellipsis"]'));
|
||||
expect(loadingValues).toHaveLength(3);
|
||||
expect(loadingValues.map((value) => value.textContent)).toEqual(['loading', 'loading', 'loading']);
|
||||
expect(container.textContent).not.toContain('total_posts 5');
|
||||
expect(container.textContent).not.toContain('current_users 2');
|
||||
expect(container.textContent).not.toContain('boards_tracked 1');
|
||||
});
|
||||
|
||||
it('shows zero totals after every directory has loaded zero-count stats', () => {
|
||||
testState.communityStats = {
|
||||
'music-posting.eth': { allPostCount: 0, weekActiveUserCount: 0 },
|
||||
'tech-posting.eth': { allPostCount: 0, weekActiveUserCount: 0 },
|
||||
};
|
||||
|
||||
renderHome();
|
||||
|
||||
expect(container.querySelectorAll('[data-testid="loading-ellipsis"]')).toHaveLength(0);
|
||||
expect(container.textContent).toContain('total_posts 0');
|
||||
expect(container.textContent).toContain('current_users 0');
|
||||
expect(container.textContent).toContain('boards_tracked 2');
|
||||
});
|
||||
|
||||
it('navigates to the canonical board path when the search form is submitted', async () => {
|
||||
renderHome();
|
||||
|
||||
|
||||
+28
-12
@@ -7,6 +7,7 @@ import { CommunityStatsCollector, useCommunitiesStatsStore } from '../../hooks/u
|
||||
import PopularThreadsBox from './popular-threads-box';
|
||||
import BoardsList from './boards-list';
|
||||
import SiteLegalMeta from '../../components/site-legal-meta';
|
||||
import LoadingEllipsis from '../../components/loading-ellipsis';
|
||||
import useDirectoryModalStore from '../../stores/use-directory-modal-store';
|
||||
import DisclaimerModal from '../../components/disclaimer-modal';
|
||||
import DirectoryModal from '../../components/directory-modal';
|
||||
@@ -84,27 +85,42 @@ const InfoBox = () => {
|
||||
);
|
||||
};
|
||||
|
||||
interface StatValueProps {
|
||||
isLoaded: boolean;
|
||||
loadingLabel: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
const StatValue = ({ isLoaded, loadingLabel, value }: StatValueProps) => (isLoaded ? <>{value}</> : <LoadingEllipsis string={loadingLabel} />);
|
||||
|
||||
const Stats = ({ directoryAddresses }: { directoryAddresses: string[] }) => {
|
||||
const { t } = useTranslation();
|
||||
const communitiesStats = useCommunitiesStatsStore((state) => state.communityStats);
|
||||
|
||||
const { totalPosts, currentUsers, boardsTracked } = useMemo(() => {
|
||||
const { totalPosts, currentUsers, boardsTracked, allDirectoryStatsLoaded } = useMemo(() => {
|
||||
let totalPosts = 0;
|
||||
let currentUsers = 0;
|
||||
let boardsTracked = 0;
|
||||
let allDirectoryStatsLoaded = directoryAddresses.length > 0;
|
||||
|
||||
directoryAddresses.forEach((address) => {
|
||||
for (const address of directoryAddresses) {
|
||||
const stat = communitiesStats[address];
|
||||
if (stat) {
|
||||
totalPosts += stat.allPostCount || 0;
|
||||
currentUsers += stat.weekActiveUserCount || 0;
|
||||
boardsTracked++;
|
||||
}
|
||||
});
|
||||
|
||||
return { totalPosts, currentUsers, boardsTracked };
|
||||
if (!stat || stat.allPostCount === undefined) {
|
||||
allDirectoryStatsLoaded = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
totalPosts += stat.allPostCount || 0;
|
||||
currentUsers += stat.weekActiveUserCount || 0;
|
||||
boardsTracked++;
|
||||
}
|
||||
|
||||
return { totalPosts, currentUsers, boardsTracked, allDirectoryStatsLoaded };
|
||||
}, [communitiesStats, directoryAddresses]);
|
||||
|
||||
const loadingLabel = t('loading');
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Render collectors to fetch stats for each community */}
|
||||
@@ -117,13 +133,13 @@ const Stats = ({ directoryAddresses }: { directoryAddresses: string[] }) => {
|
||||
</div>
|
||||
<div className={`${styles.boxContent} ${styles.stats}`}>
|
||||
<div className={styles.stat}>
|
||||
<b>{t('total_posts')}</b> {totalPosts}
|
||||
<b>{t('total_posts')}</b> <StatValue isLoaded={allDirectoryStatsLoaded} loadingLabel={loadingLabel} value={totalPosts} />
|
||||
</div>
|
||||
<div className={styles.stat}>
|
||||
<b>{t('current_users')}</b> {currentUsers}
|
||||
<b>{t('current_users')}</b> <StatValue isLoaded={allDirectoryStatsLoaded} loadingLabel={loadingLabel} value={currentUsers} />
|
||||
</div>
|
||||
<div className={styles.stat}>
|
||||
<b>{t('boards_tracked')}</b> {boardsTracked}
|
||||
<b>{t('boards_tracked')}</b> <StatValue isLoaded={allDirectoryStatsLoaded} loadingLabel={loadingLabel} value={boardsTracked} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user