Skip to content

Commit

Permalink
Merge pull request #5749 from hotosm/fix/5738-simultaneous-stats-display
Browse files Browse the repository at this point in the history
- Display TM stats on the landing page simultaneously
- Add test coverage for stats section
  • Loading branch information
HelNershingThapa authored May 5, 2023
2 parents 7784648 + 815f9e8 commit b5ec128
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 21 deletions.
39 changes: 22 additions & 17 deletions frontend/src/components/homepage/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import shortNumber from 'short-number';

import messages from './messages';
import { HOMEPAGE_STATS_API_URL } from '../../config';
import { useFetchWithAbort } from '../../hooks/UseFetch';
import { fetchLocalJSONAPIWithAbort } from '../../network/genericJSONRequest';

export const StatsNumber = (props) => {
const value = shortNumber(props.value);
Expand All @@ -24,7 +24,7 @@ export const StatsColumn = ({ label, value }: Object) => {
return (
<div className={`tc`}>
<div className="fw5 red barlow-condensed stat-number">
<StatsNumber value={value} />
{value !== undefined ? <StatsNumber value={value} /> : <>&#8211;</>}
</div>
<div className="db blue-grey f6 fw7">
<FormattedMessage {...label} />
Expand All @@ -34,24 +34,29 @@ export const StatsColumn = ({ label, value }: Object) => {
};

export const StatsSection = () => {
/* eslint-disable-next-line */
const [_tmStatsError, _tmStatsLoading, tmStats] = useFetchWithAbort('system/statistics/');
const [stats, setStats] = useState({ edits: 0, buildings: 0, roads: 0 });
const [osmStats, setOsmStats] = useState({});
const [tmStats, setTmStats] = useState({});

useEffect(() => {
// Using axios over the useFetch hook for external API endpoint
const abortController = new AbortController();
axios
.get(HOMEPAGE_STATS_API_URL, {
// Using axios over the useFetch hook for external API endpoint
const fetchOsmStats = () =>
axios.get(HOMEPAGE_STATS_API_URL, {
signal: abortController.signal,
})
.then((res) => {
const { edits, building_count_add: buildings, road_km_add: roads } = res.data;
setStats({
});

const fetchSystemStats = () =>
fetchLocalJSONAPIWithAbort('system/statistics/', null, abortController.signal);

Promise.all([fetchOsmStats(), fetchSystemStats()])
.then(([osmStats, tmStats]) => {
const { edits, building_count_add: buildings, road_km_add: roads } = osmStats.data;
setOsmStats({
edits,
buildings,
roads,
});
setTmStats(tmStats);
})
.catch((err) => console.error(err));
return () => {
Expand All @@ -61,11 +66,11 @@ export const StatsSection = () => {

return (
<div className="pt5 pb2 ph6-l ph4 flex justify-around flex-wrap flex-nowrap-ns stats-container">
<StatsColumn label={messages.buildingsStats} value={stats.buildings} />
<StatsColumn label={messages.roadsStats} value={stats.roads} />
<StatsColumn label={messages.editsStats} value={stats.edits} />
<StatsColumn label={messages.communityStats} value={tmStats.totalMappers || 0} />
<StatsColumn label={messages.mappersStats} value={tmStats.mappersOnline || 0} />
<StatsColumn label={messages.buildingsStats} value={osmStats?.buildings} />
<StatsColumn label={messages.roadsStats} value={osmStats?.roads} />
<StatsColumn label={messages.editsStats} value={osmStats?.edits} />
<StatsColumn label={messages.communityStats} value={tmStats?.totalMappers} />
<StatsColumn label={messages.mappersStats} value={tmStats?.mappersOnline} />
</div>
);
};
21 changes: 18 additions & 3 deletions frontend/src/components/homepage/tests/stats.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import '@testing-library/jest-dom';
import { render, screen, waitFor } from '@testing-library/react';
import { FormattedNumber } from 'react-intl';

import { StatsNumber } from '../stats';
import { createComponentWithIntl } from '../../../utils/testWithIntl';
import { StatsNumber, StatsSection } from '../stats';
import { IntlProviders, createComponentWithIntl } from '../../../utils/testWithIntl';

it('test number formatting in English', () => {
const testNumber = createComponentWithIntl(<StatsNumber value={744531} />);
Expand All @@ -17,3 +18,17 @@ it('test number formatting smaller than 1000', () => {
expect(testInstance.findByType(FormattedNumber).props.value).toBe(744);
expect(testInstance.children).not.toContain('K');
});

describe('Stats Section', () => {
it('should display OSM and TM stats', async () => {
render(
<IntlProviders>
<StatsSection />
</IntlProviders>,
);
// A stat from OSM's TM Stat
await waitFor(() => expect(screen.getByText('101.4M')).toBeInTheDocument());
// A stat from TM Stat
await waitFor(() => expect(screen.getByText(3)).toBeInTheDocument());
});
});
7 changes: 7 additions & 0 deletions frontend/src/network/tests/mockData/miscellaneous.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@ export const josmRemote = {
application: 'JOSM RemoteControl',
version: 18646,
};

export const systemStats = {
mappersOnline: 0,
tasksMapped: 14,
totalMappers: 3,
totalProjects: 10,
};
5 changes: 4 additions & 1 deletion frontend/src/network/tests/server-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import {
} from './mockData/teams';
import { userTasks } from './mockData/tasksStats';
import { homepageStats } from './mockData/homepageStats';
import { banner, countries, josmRemote } from './mockData/miscellaneous';
import { banner, countries, josmRemote, systemStats } from './mockData/miscellaneous';
import tasksGeojson from '../../utils/tests/snippets/tasksGeometry';
import { API_URL } from '../../config';
import { notifications, ownCountUnread } from './mockData/notifications';
Expand Down Expand Up @@ -314,6 +314,9 @@ const handlers = [
rest.post(API_URL + 'projects/:projectId/tasks/actions/extend/', (req, res, ctx) => {
return res(ctx.json(extendTask));
}),
rest.get(API_URL + 'system/statistics/', (req, res, ctx) => {
return res(ctx.json(systemStats));
}),
// EXTERNAL API
rest.get('https://osmstats-api.hotosm.org/wildcard', (req, res, ctx) => {
return res(ctx.json(homepageStats));
Expand Down

0 comments on commit b5ec128

Please sign in to comment.