Skip to content

Commit

Permalink
Merge pull request #63 from naxa-developers/enhancement/6241-redesign…
Browse files Browse the repository at this point in the history
…-user-stats

enhancement/6241 redesign user stats
  • Loading branch information
royallsilwallz authored Mar 1, 2024
2 parents 600c539 + eba3996 commit 0236f8d
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 16 deletions.
20 changes: 19 additions & 1 deletion frontend/src/api/stats.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useQuery } from '@tanstack/react-query';
import { fetchExternalJSONAPI } from '../network/genericJSONRequest';

import api from './apiClient';
import { OHSOME_STATS_BASE_URL } from '../config';
Expand Down Expand Up @@ -42,7 +43,7 @@ export const useOsmStatsQuery = () => {
queryKey: ['osm-stats'],
queryFn: fetchOsmStats,
useErrorBoundary: true,
select: (data) => data.data.result
select: (data) => data.data.result,
});
};

Expand All @@ -61,3 +62,20 @@ export const useOsmHashtagStatsQuery = (defaultComment) => {
select: (data) => data.data.result,
});
};

export const useUserOsmStatsQuery = (id) => {
const fetchUserOsmStats = () => {
return fetchExternalJSONAPI(
`${OHSOME_STATS_BASE_URL}/topic/poi,highway,building,waterway/user?userId=${id}`,
true,
);
};

return useQuery({
queryKey: ['user-osm-stats'],
queryFn: fetchUserOsmStats,
useErrorBoundary: true,
select: (data) => data.result,
enabled: !!id,
});
};
14 changes: 14 additions & 0 deletions frontend/src/assets/styles/_extra.scss
Original file line number Diff line number Diff line change
Expand Up @@ -621,3 +621,17 @@ a[href="https://www.mapbox.com/map-feedback/"]
.code {
font-family: inherit;
}

// margin auto
.mt-auto {
margin-top: auto;
}
.mb-auto {
margin-bottom: auto;
}
.ml-auto {
margin-left: auto;
}
.ml-auto {
margin-right: auto;
}
46 changes: 46 additions & 0 deletions frontend/src/components/statsCard.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { FormattedNumber } from 'react-intl';
import shortNumber from 'short-number';

export const StatsCard = ({ icon, description, value, className, invertColors = false }) => {
return (
Expand All @@ -25,3 +26,48 @@ export const StatsCardContent = ({ value, label, className, invertColors = false
<span className={`ma0 h2 f7 fw5 ${invertColors ? 'white' : 'blue-grey'}`}>{label}</span>
</div>
);

function getFormattedNumber(num) {
if (typeof num !== 'number') return '-';
const value = shortNumber(num);
return typeof value === 'number' ? (
<FormattedNumber value={Math.abs(Math.trunc(value))} />
) : (
value
);
}

export const DetailedStatsCard = ({ icon, description, mapped, created, modified, deleted }) => (
<div
className="cf pa3 br1 flex bg-white red shadow-6 flex-column justify-between"
style={{ height: '10.5rem' }}
>
<div className="flex items-center mb-auto">
<div className="w-25 fl ml2">{icon}</div>
<div>
<h3 className="ma0 mb1 barlow-condensed f2 fw6 red">{getFormattedNumber(mapped)}</h3>
<span className="ma0 h2 f7 fw5 blue-grey">{description}</span>
</div>
</div>

{/* seperator line */}
<div className="flex justify-center">
<div className="bg-red mv2" style={{ height: '1px', width: '96%' }} />
</div>

<div className="flex w-100 items-center mt-auto" style={{ justifyContent: 'space-evenly' }}>
<div className="flex flex-column items-center">
<h3 className="ma0 mb2 barlow-condensed fw6 red">{getFormattedNumber(created)}</h3>
<span className="f7 fw5 blue-grey">Created</span>
</div>
<div className="flex flex-column items-center">
<h3 className="ma0 mb2 barlow-condensed fw6 red">{getFormattedNumber(modified)}</h3>
<span className="f7 fw5 blue-grey">Modified</span>
</div>
<div className="flex flex-column items-center">
<h3 className="ma0 mb2 barlow-condensed fw6 red">{getFormattedNumber(deleted)}</h3>
<span className="f7 fw5 blue-grey">Deleted</span>
</div>
</div>
</div>
);
2 changes: 2 additions & 0 deletions frontend/src/components/userDetail/editsByNumbers.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const EditsByNumbers = ({ osmStats }) => {
},
];

if (!osmStats) return '';

const data = formatChartData(reference, osmStats);

return (
Expand Down
30 changes: 21 additions & 9 deletions frontend/src/components/userDetail/elementsMapped.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
MappedIcon,
ValidatedIcon,
} from '../svgIcons';
import { StatsCard } from '../statsCard';
import { StatsCard, DetailedStatsCard } from '../statsCard';
import StatsTimestamp from '../statsTimestamp';

export const TaskStats = ({ userStats, username }) => {
Expand Down Expand Up @@ -133,25 +133,37 @@ export const ElementsMapped = ({ userStats, osmStats }) => {
description={<FormattedMessage {...messages.timeSpentMapping} />}
value={duration}
/>
<StatsCard
<DetailedStatsCard
icon={<HomeIcon className={iconClass} style={iconStyle} />}
description={<FormattedMessage {...messages.buildingsMapped} />}
value={osmStats.buildings || 0}
mapped={osmStats?.building?.value}
created={osmStats?.building?.added}
modified={osmStats?.building?.modified?.count_modified}
deleted={osmStats?.building?.deleted}
/>
<StatsCard
<DetailedStatsCard
icon={<RoadIcon className={iconClass} style={iconStyle} />}
description={<FormattedMessage {...messages.roadMapped} />}
value={osmStats.roads || 0}
mapped={osmStats?.highway?.value}
created={osmStats?.highway?.added}
modified={osmStats?.highway?.modified?.count_modified}
deleted={osmStats?.highway?.deleted}
/>
<StatsCard
<DetailedStatsCard
icon={<MarkerIcon className={iconClass} style={iconStyle} />}
description={<FormattedMessage {...messages.poiMapped} />}
value={osmStats.total_poi_count_add || '-'}
mapped={osmStats?.poi?.value}
created={osmStats?.poi?.added}
modified={osmStats?.poi?.modified?.count_modified}
deleted={osmStats?.poi?.deleted}
/>
<StatsCard
<DetailedStatsCard
icon={<WavesIcon className={iconClass} style={iconStyle} />}
description={<FormattedMessage {...messages.waterwaysMapped} />}
value={osmStats.total_waterway_km_add || '-'}
mapped={osmStats?.waterway?.value}
created={osmStats?.waterway?.added}
modified={osmStats?.waterway?.modified?.count_modified}
deleted={osmStats?.waterway?.deleted}
/>
</div>
<div className="cf w-100 relative tr pt3 pr3">
Expand Down
13 changes: 7 additions & 6 deletions frontend/src/views/userDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import { CountriesMapped } from '../components/userDetail/countriesMapped';
import { TopProjects } from '../components/userDetail/topProjects';
import { ContributionTimeline } from '../components/userDetail/contributionTimeline';
import { NotFound } from './notFound';
import { OHSOME_STATS_BASE_URL, OSM_SERVER_URL } from '../config';
import { OSM_SERVER_URL } from '../config';
import { fetchExternalJSONAPI } from '../network/genericJSONRequest';
import { useFetch } from '../hooks/UseFetch';
import { useSetTitleTag } from '../hooks/UseMetaTags';
import { useUserOsmStatsQuery } from '../api/stats';

const TopCauses = React.lazy(() =>
import('../components/userDetail/topCauses' /* webpackChunkName: "topCauses" */),
Expand All @@ -32,7 +33,6 @@ export const UserDetail = ({ withHeader = true }) => {
useSetTitleTag(username);
const token = useSelector((state) => state.auth.token);
const currentUser = useSelector((state) => state.auth.userDetails);
const [osmStats, setOsmStats] = useState({});
const [userOsmDetails, setUserOsmDetails] = useState({});
const [errorDetails, loadingDetails, userDetails] = useFetch(
`users/queries/${username}/`,
Expand All @@ -46,6 +46,7 @@ export const UserDetail = ({ withHeader = true }) => {
`projects/queries/${username}/touched/`,
username !== undefined,
);
const { data: osmStats } = useUserOsmStatsQuery(userDetails.id);

useEffect(() => {
if (!token) {
Expand All @@ -58,9 +59,6 @@ export const UserDetail = ({ withHeader = true }) => {
fetchExternalJSONAPI(`${OSM_SERVER_URL}/api/0.6/user/${userDetails.id}.json`, false)
.then((res) => setUserOsmDetails(res?.user))
.catch((e) => console.log(e));
fetchExternalJSONAPI(`${OHSOME_STATS_BASE_URL}/hot-tm-user?userId=${userDetails.id}`, true)
.then((res) => setOsmStats(res.result))
.catch((e) => console.log(e));
}
}, [userDetails.id]);

Expand All @@ -78,7 +76,10 @@ export const UserDetail = ({ withHeader = true }) => {
rows={5}
ready={!errorDetails && !loadingDetails}
>
<HeaderProfile userDetails={userDetails} changesets={userOsmDetails?.changesets?.count} />
<HeaderProfile
userDetails={userDetails}
changesets={userOsmDetails?.changesets?.count}
/>
</ReactPlaceholder>
</div>
)}
Expand Down

0 comments on commit 0236f8d

Please sign in to comment.