From 9d8d2695c117d25d5cafd68b63dff7139ae80f55 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Thu, 17 Oct 2024 10:23:17 +0545 Subject: [PATCH 01/23] Remove `Map Swipe` tab if MapSwipe group ID not present --- frontend/src/views/partnersStats.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/partnersStats.js b/frontend/src/views/partnersStats.js index 9da9d83d4b..2eefb7a6fd 100644 --- a/frontend/src/views/partnersStats.js +++ b/frontend/src/views/partnersStats.js @@ -86,6 +86,11 @@ export const PartnersStats = () => { .filter((key) => key.startsWith('link')) .filter((link) => partner[link]); + // remove Map Swipe tab if mapswipe_group_id not present + const modifiedTabData = !partner?.mapswipe_group_id + ? tabData.filter((tab) => tab.id !== 'mapswipe') + : tabData; + return ( { )}
- {tabData.map(({ id: tabId, title }) => ( + {modifiedTabData.map(({ id: tabId, title }) => (
Date: Thu, 17 Oct 2024 11:09:48 +0545 Subject: [PATCH 02/23] Add MapSwipe group name to overview section in MapSwipe stats --- frontend/src/components/partnerMapswipeStats/overview.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/components/partnerMapswipeStats/overview.js b/frontend/src/components/partnerMapswipeStats/overview.js index 0eeaf21818..22b51365a8 100644 --- a/frontend/src/components/partnerMapswipeStats/overview.js +++ b/frontend/src/components/partnerMapswipeStats/overview.js @@ -82,6 +82,9 @@ export const Overview = () => { customPlaceholder={} ready={!isLoading && !isRefetching} > +

+ {data?.nameInsideProvider} +

Date: Thu, 17 Oct 2024 11:13:15 +0545 Subject: [PATCH 03/23] Change `ds` to `days` in MapSwipe Stats page --- frontend/src/components/partnerMapswipeStats/overview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/partnerMapswipeStats/overview.js b/frontend/src/components/partnerMapswipeStats/overview.js index 22b51365a8..723b2d1882 100644 --- a/frontend/src/components/partnerMapswipeStats/overview.js +++ b/frontend/src/components/partnerMapswipeStats/overview.js @@ -30,7 +30,7 @@ export const formatSecondsToTwoUnits = (seconds, shortFormat = false) => { years: 'yrs', months: 'mos', weeks: 'wks', - days: 'ds', + days: 'days', hours: 'hrs', minutes: 'mins', seconds: 'secs', From 631d1b13d63b3016f69d00857b6c934b600d44c3 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Mon, 21 Oct 2024 13:51:44 +0545 Subject: [PATCH 04/23] Fix content overflowing responsive issue in MapSwipe Stats page --- .../partnerMapswipeStats/overview.js | 2 +- .../projectTypeAreaStats.js | 2 +- .../swipesByOrganization.js | 3 +- .../swipesByProjectType.js | 2 +- frontend/src/views/partnersMapswipeStats.css | 17 -------- frontend/src/views/partnersMapswipeStats.js | 10 ++--- frontend/src/views/partnersMapswipeStats.scss | 42 +++++++++++++++++++ 7 files changed, 51 insertions(+), 27 deletions(-) delete mode 100644 frontend/src/views/partnersMapswipeStats.css create mode 100644 frontend/src/views/partnersMapswipeStats.scss diff --git a/frontend/src/components/partnerMapswipeStats/overview.js b/frontend/src/components/partnerMapswipeStats/overview.js index 723b2d1882..eb88287fa6 100644 --- a/frontend/src/components/partnerMapswipeStats/overview.js +++ b/frontend/src/components/partnerMapswipeStats/overview.js @@ -86,7 +86,7 @@ export const Overview = () => { {data?.nameInsideProvider}
diff --git a/frontend/src/components/partnerMapswipeStats/swipesByOrganization.js b/frontend/src/components/partnerMapswipeStats/swipesByOrganization.js index 9209740dc3..7a94ae5956 100644 --- a/frontend/src/components/partnerMapswipeStats/swipesByOrganization.js +++ b/frontend/src/components/partnerMapswipeStats/swipesByOrganization.js @@ -80,11 +80,10 @@ export const SwipesByOrganization = ({ contributionsByOrganization = [] }) => { }, []); return ( -
+

-
{contributionsByOrganization.length === 0 && ( diff --git a/frontend/src/components/partnerMapswipeStats/swipesByProjectType.js b/frontend/src/components/partnerMapswipeStats/swipesByProjectType.js index 399c00f608..5d79f22cc6 100644 --- a/frontend/src/components/partnerMapswipeStats/swipesByProjectType.js +++ b/frontend/src/components/partnerMapswipeStats/swipesByProjectType.js @@ -82,7 +82,7 @@ export const SwipesByProjectType = ({ contributionsByProjectType = [] }) => { }, []); return ( -
+

diff --git a/frontend/src/views/partnersMapswipeStats.css b/frontend/src/views/partnersMapswipeStats.css deleted file mode 100644 index 3bf7e57d23..0000000000 --- a/frontend/src/views/partnersMapswipeStats.css +++ /dev/null @@ -1,17 +0,0 @@ -.mapswipe-stats-info-banner { - background-color: #d9d7d7; - width: fit-content; - margin-left: 20px; - border-radius: 3px; -} - -.mapswipe-stats-info-banner::before { - content: ''; - position: absolute; - left: -20px; - top: 0; - bottom: 0; - width: 20px; - background-color: #d9d7d7; - clip-path: polygon(100% 0, 0 50%, 100% 100%); -} diff --git a/frontend/src/views/partnersMapswipeStats.js b/frontend/src/views/partnersMapswipeStats.js index c9015d3640..9d067cc6d8 100644 --- a/frontend/src/views/partnersMapswipeStats.js +++ b/frontend/src/views/partnersMapswipeStats.js @@ -19,7 +19,7 @@ import { SwipesByProjectType } from '../components/partnerMapswipeStats/swipesBy import { SwipesByOrganization } from '../components/partnerMapswipeStats/swipesByOrganization'; import messages from './messages'; import { fetchLocalJSONAPI } from '../network/genericJSONRequest'; -import './partnersMapswipeStats.css'; +import './partnersMapswipeStats.scss'; const PagePlaceholder = () => (
@@ -141,16 +141,16 @@ export const PartnersMapswipeStats = () => {
-
+
{getSwipes()}
-
+
{getTimeSpentContributing()} @@ -158,7 +158,7 @@ export const PartnersMapswipeStats = () => {
-
+
Date: Mon, 21 Oct 2024 19:18:50 +0545 Subject: [PATCH 05/23] Use `/stats` route instead of `/stats/leaderboard` for Partner Stats --- frontend/src/components/partners/partners.js | 2 +- frontend/src/views/partnersStats.js | 21 +++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/partners/partners.js b/frontend/src/components/partners/partners.js index 3557a5e7d0..2a01708188 100644 --- a/frontend/src/components/partners/partners.js +++ b/frontend/src/components/partners/partners.js @@ -95,7 +95,7 @@ export function PartnersCard({ details }) { - + { const [partnerStats, setPartnerStats] = useState(null); const [error, loading, partner] = useFetch(`partners/${id}/`); - // navigate to /leaderboard path when no tab param present - useEffect(() => { - if (!tabname) { - navigate('leaderboard'); - } - }, [navigate, tabname]); - const fetchData = async (name) => { try { let hashtag = name.trim(); @@ -73,12 +66,10 @@ export const PartnersStats = () => { function getTabContent() { switch (tabname) { - case 'leaderboard': - return ; case 'mapswipe': return ; default: - return <>; + return ; } } @@ -91,6 +82,8 @@ export const PartnersStats = () => { ? tabData.filter((tab) => tab.id !== 'mapswipe') : tabData; + const activeTab = tabname === 'mapswipe' ? 'mapswipe' : 'leaderboard'; + return ( { role="button" tabIndex={0} className={`flex items-center pointer partners-tab-item ${ - tabname === tabId ? 'bg-tan blue-dark' : 'bg-grey-dark white' + activeTab === tabId ? 'bg-tan blue-dark' : 'bg-grey-dark white' }`} - onClick={() => navigate(`/partners/${id}/stats/${tabId}`)} + onClick={() => + tabId === 'leaderboard' + ? navigate(`/partners/${id}/stats`) + : navigate(`/partners/${id}/stats/${tabId}`) + } onKeyDown={() => {}} >

{title}

From 6e1d75211e1e100e169738eac05c9580ae34f540 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 22 Oct 2024 14:29:03 +0545 Subject: [PATCH 06/23] Move the stats info footer to the top of the stats cards --- .../src/components/partners/leaderboard.js | 3 ++ .../src/components/partners/partnersStats.js | 2 - .../src/components/statsInfoFooter/index.jsx | 40 ++++++++++++------- .../components/userDetail/elementsMapped.js | 4 +- frontend/src/views/partnersMapswipeStats.js | 2 +- frontend/src/views/partnersMapswipeStats.scss | 3 ++ 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/frontend/src/components/partners/leaderboard.js b/frontend/src/components/partners/leaderboard.js index aeb2cb7087..c2cddd1920 100644 --- a/frontend/src/components/partners/leaderboard.js +++ b/frontend/src/components/partners/leaderboard.js @@ -4,10 +4,13 @@ import messages from '../../views/messages'; import { StatsSection } from './partnersStats'; import { Activity } from './partnersActivity'; import { CurrentProjects } from './currentProjects'; +import StatsInfoFooter from '../statsInfoFooter'; export const Leaderboard = ({ partner, partnerStats }) => { return (
+ +

{partner.primary_hashtag diff --git a/frontend/src/components/partners/partnersStats.js b/frontend/src/components/partners/partnersStats.js index c4758eed8a..8724511215 100644 --- a/frontend/src/components/partners/partnersStats.js +++ b/frontend/src/components/partners/partnersStats.js @@ -4,7 +4,6 @@ import shortNumber from 'short-number'; import messages from './messages'; import { StatsCard } from '../statsCard'; import { MappingIcon, EditIcon, RoadIcon, HomeIcon } from '../svgIcons'; -import StatsInfoFooter from '../statsInfoFooter'; const iconClass = 'h-50 w-50'; const iconStyle = { height: '45px' }; @@ -71,7 +70,6 @@ export const StatsSection = ({ partner }) => { className={'w-25-l w-50-m w-100 mv1'} />

-
); }; diff --git a/frontend/src/components/statsInfoFooter/index.jsx b/frontend/src/components/statsInfoFooter/index.jsx index abe69a640a..b3cf5a2ea3 100644 --- a/frontend/src/components/statsInfoFooter/index.jsx +++ b/frontend/src/components/statsInfoFooter/index.jsx @@ -2,27 +2,37 @@ import { useIntl } from 'react-intl'; import { useOsmStatsMetadataQuery } from '../../api/stats'; import { dateOptions } from '../statsTimestamp'; +import { InfoIcon } from '../svgIcons'; +import '../../views/partnersMapswipeStats.scss'; -export default function StatsInfoFooter() { +export default function StatsInfoFooter({ className }) { const intl = useIntl(); const { data: osmStatsMetadata } = useOsmStatsMetadataQuery(); return ( -
- - These statistics come from{' '} - - ohsomeNow Stats - {' '} - and were last updated at{' '} - {intl.formatDate(osmStatsMetadata?.max_timestamp, dateOptions)} ( - {intl.timeZone}). +
+ + + + These statistics come from{' '} + + ohsomeNow Stats + {' '} + and were last updated at{' '} + + {intl.formatDate(osmStatsMetadata?.max_timestamp, dateOptions)} + {' '} + ({intl.timeZone}) +
); diff --git a/frontend/src/components/userDetail/elementsMapped.js b/frontend/src/components/userDetail/elementsMapped.js index 1e1655c56f..6dc4b3bc31 100644 --- a/frontend/src/components/userDetail/elementsMapped.js +++ b/frontend/src/components/userDetail/elementsMapped.js @@ -125,6 +125,8 @@ export const ElementsMapped = ({ userStats, osmStats }) => { return (
+ +
{ unitLess={osmStats?.waterway?.modified?.unit_less} />
- -
); }; diff --git a/frontend/src/views/partnersMapswipeStats.js b/frontend/src/views/partnersMapswipeStats.js index 9d067cc6d8..b3b097b804 100644 --- a/frontend/src/views/partnersMapswipeStats.js +++ b/frontend/src/views/partnersMapswipeStats.js @@ -46,7 +46,7 @@ const PagePlaceholder = () => ( const InfoBanner = () => { return ( -
+
diff --git a/frontend/src/views/partnersMapswipeStats.scss b/frontend/src/views/partnersMapswipeStats.scss index e38842aee8..186a7cb92a 100644 --- a/frontend/src/views/partnersMapswipeStats.scss +++ b/frontend/src/views/partnersMapswipeStats.scss @@ -13,6 +13,9 @@ background-color: #d9d7d7; clip-path: polygon(100% 0, 0 50%, 100% 100%); } + .stats-info-datetime { + letter-spacing: -0.4px; + } } $medium: 960px; From 2aae1cbc3886dc305b4d96def287f68a12b51232 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Thu, 24 Oct 2024 19:35:51 +0545 Subject: [PATCH 07/23] Change stats info design in homepage, project & feature stats page --- frontend/src/components/homepage/stats.js | 9 ++-- frontend/src/components/projectStats/edits.js | 50 ++++++++++--------- .../components/teamsAndOrgs/featureStats.js | 5 +- frontend/src/views/home.js | 4 -- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/frontend/src/components/homepage/stats.js b/frontend/src/components/homepage/stats.js index 1901fa35f4..c970ed5ed9 100644 --- a/frontend/src/components/homepage/stats.js +++ b/frontend/src/components/homepage/stats.js @@ -3,6 +3,7 @@ import shortNumber from 'short-number'; import messages from './messages'; import { useOsmStatsQuery, useSystemStatisticsQuery } from '../../api/stats'; +import StatsInfoFooter from '../statsInfoFooter'; export const StatsNumber = (props) => { const value = shortNumber(props.value); @@ -38,8 +39,10 @@ export const StatsSection = () => { const hasStatsLoaded = hasTmStatsLoaded && hasOsmStatsLoaded; return ( - <> -
+
+ + +
{ value={hasStatsLoaded ? tmStatsData.data.mappersOnline : undefined} />
- +
); }; diff --git a/frontend/src/components/projectStats/edits.js b/frontend/src/components/projectStats/edits.js index 9059c5ba76..b3bdb46d11 100644 --- a/frontend/src/components/projectStats/edits.js +++ b/frontend/src/components/projectStats/edits.js @@ -4,7 +4,7 @@ import projectMessages from './messages'; import userDetailMessages from '../userDetail/messages'; import { MappingIcon, HomeIcon, RoadIcon, EditIcon } from '../svgIcons'; import { StatsCard } from '../statsCard'; -import StatsTimestamp from '../statsTimestamp'; +import StatsInfoFooter from '../statsInfoFooter'; export const EditsStats = ({ data }) => { const { changesets, buildings, roads, edits } = data; @@ -18,30 +18,32 @@ export const EditsStats = ({ data }) => {

-
-
- } - description={} - value={changesets || 0} - /> - } - description={} - value={edits || 0} - /> - } - description={} - value={buildings || 0} - /> - } - description={} - value={roads || 0} - /> +
+ +
+ } + description={} + value={changesets || 0} + /> + } + description={} + value={edits || 0} + /> + } + description={} + value={buildings || 0} + /> + } + description={} + value={roads || 0} + /> +
); diff --git a/frontend/src/components/teamsAndOrgs/featureStats.js b/frontend/src/components/teamsAndOrgs/featureStats.js index b5b31ca9c3..8a3dbdd3ed 100644 --- a/frontend/src/components/teamsAndOrgs/featureStats.js +++ b/frontend/src/components/teamsAndOrgs/featureStats.js @@ -7,7 +7,7 @@ import userDetailMessages from '../userDetail/messages'; import { OHSOME_STATS_BASE_URL, defaultChangesetComment } from '../../config'; import { RoadIcon, HomeIcon, WavesIcon, MarkerIcon } from '../svgIcons'; import { StatsCard } from '../statsCard'; -import StatsTimestamp from '../statsTimestamp'; +import StatsInfoFooter from '../statsInfoFooter'; export const FeatureStats = () => { const [stats, setStats] = useState({ edits: 0, buildings: 0, roads: 0, pois: 0, waterways: 0 }); @@ -42,9 +42,10 @@ export const FeatureStats = () => {

-
+ + } description={} diff --git a/frontend/src/views/home.js b/frontend/src/views/home.js index 2d423e0b89..7b40ac7c5c 100644 --- a/frontend/src/views/home.js +++ b/frontend/src/views/home.js @@ -8,7 +8,6 @@ import { WhoIsMapping } from '../components/homepage/whoIsMapping'; import { Testimonials } from '../components/homepage/testimonials'; import { Alert } from '../components/alert'; import homeMessages from '../components/homepage/messages'; -import StatsTimestamp from '../components/statsTimestamp/'; export function Home() { return ( @@ -24,9 +23,6 @@ export function Home() { } > -
- -
From cd346160476417fdc1390ebc635acc450bcb23e2 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Fri, 25 Oct 2024 10:25:26 +0545 Subject: [PATCH 08/23] Change cards layout in large screen size in Manage Stats --- .../components/teamsAndOrgs/featureStats.js | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/frontend/src/components/teamsAndOrgs/featureStats.js b/frontend/src/components/teamsAndOrgs/featureStats.js index 8a3dbdd3ed..5522e0f66a 100644 --- a/frontend/src/components/teamsAndOrgs/featureStats.js +++ b/frontend/src/components/teamsAndOrgs/featureStats.js @@ -46,30 +46,32 @@ export const FeatureStats = () => {
- } - description={} - value={stats.buildings || 0} - className={'w-25-l w-50-m w-100 mv1'} - /> - } - description={} - value={stats.roads || 0} - className={'w-25-l w-50-m w-100 mv1'} - /> - } - description={} - value={stats.pois || 0} - className={'w-25-l w-50-m w-100 mv1'} - /> - } - description={} - value={stats.waterways || 0} - className={'w-25-l w-50-m w-100 mv1'} - /> +
+ } + description={} + value={stats.buildings || 0} + className={'w-25-l w-50-m w-100 mv1'} + /> + } + description={} + value={stats.roads || 0} + className={'w-25-l w-50-m w-100 mv1'} + /> + } + description={} + value={stats.pois || 0} + className={'w-25-l w-50-m w-100 mv1'} + /> + } + description={} + value={stats.waterways || 0} + className={'w-25-l w-50-m w-100 mv1'} + /> +
); From 60bd532d6732e3b70a82c958e7020388dd5ef8a3 Mon Sep 17 00:00:00 2001 From: Christian Quest Date: Sat, 26 Oct 2024 11:28:06 +0200 Subject: [PATCH 09/23] typo fixed --- frontend/src/locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index f9b8216015..70eb86236f 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -92,7 +92,7 @@ "serviceWorker.dialog.newVersion": "Un nouveau Gestionnaire de Tâches est disponible !", "serviceWorker.dialog.update": "Mettre à jour maintenant", "serviceWorker.dialog.remindMeLater": "Rappelez-moi plus tard", - "home.mainSection.title": "Cartographier pour les personnes en diffculté", + "home.mainSection.title": "Cartographier pour les personnes en difficulté", "home.mainSection.lead": "Faites partie d'une communauté mondiale cartographiant les populations et lieux les plus vulnérables au monde quant aux désastres et la pauvreté pour soutenir l'aide humanitaire et le développement durable à travers le monde.", "home.callToAction.title": "Nous ne pouvons pas le faire sans vous", "home.callToAction.firstLeadLine": "Tout le monde peut contribuer à la carte. Si vous n'avez jamais cartographié auparavant et vous souhaitez commencer, visitez notre page {link}. ", From 571f76df60c0487f8e88921d2df6ba0760ec1d70 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Mon, 23 Sep 2024 11:13:32 +0545 Subject: [PATCH 10/23] Create different route paths for `Instructions` & `Contributions` - Add `tabname` param to `/projects/:id/` route - Change local tab state to route param tabname - Remove footer for instructions & contributions route --- frontend/src/components/footer/index.js | 2 ++ frontend/src/components/taskSelection/index.js | 17 +++++++++++++---- frontend/src/routes.js | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/footer/index.js b/frontend/src/components/footer/index.js index 0aa8118eac..e91613ee09 100644 --- a/frontend/src/components/footer/index.js +++ b/frontend/src/components/footer/index.js @@ -36,6 +36,8 @@ export function Footer() { const footerDisabledPaths = [ 'projects/:id/tasks', + 'projects/:id/instructions', + 'projects/:id/contributions', 'projects/:id/map', 'projects/:id/validate', 'projects/:id/live', diff --git a/frontend/src/components/taskSelection/index.js b/frontend/src/components/taskSelection/index.js index 6803d5f24b..f12860906e 100644 --- a/frontend/src/components/taskSelection/index.js +++ b/frontend/src/components/taskSelection/index.js @@ -1,5 +1,5 @@ -import { lazy, useState, useEffect, Suspense } from 'react'; -import { useLocation } from 'react-router-dom'; +import { lazy, useState, useEffect, useCallback, Suspense } from 'react'; +import { useLocation, useParams, useNavigate } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { useQueryParam, StringParam } from 'use-query-params'; import Popup from 'reactjs-popup'; @@ -53,13 +53,14 @@ const getRandomTaskByAction = (activities, taskAction) => { export function TaskSelection({ project }: Object) { useSetProjectPageTitleTag(project); const { projectId } = project; + const { tabname: activeSection } = useParams(); + const navigate = useNavigate(); const location = useLocation(); const dispatch = useDispatch(); const user = useSelector((state) => state.auth.userDetails); const userOrgs = useSelector((state) => state.auth.organisations); const lockedTasks = useGetLockedTasks(); const [zoomedTaskId, setZoomedTaskId] = useState(null); - const [activeSection, setActiveSection] = useState(null); const [selected, setSelectedTasks] = useState([]); const [mapInit, setMapInit] = useState(false); const [taskAction, setTaskAction] = useState('mapATask'); @@ -119,6 +120,14 @@ export function TaskSelection({ project }: Object) { } }, [tasksData, activities, refetchTasks]); + // use route instead of local state for active tab states + const setActiveSection = useCallback( + (section) => { + navigate(`/projects/${projectId}/${section}`); + }, + [navigate, projectId], + ); + // show the tasks tab when the page loads if the user has already contributed // to the project. If no, show the instructions tab. useEffect(() => { @@ -130,7 +139,7 @@ export function TaskSelection({ project }: Object) { setActiveSection('instructions'); } } - }, [contributions, user.username, user, activeSection, textSearch]); + }, [contributions, user.username, user, activeSection, textSearch, setActiveSection]); useEffect(() => { // run it only when the component is initialized diff --git a/frontend/src/routes.js b/frontend/src/routes.js index 7495186182..3647b56f87 100644 --- a/frontend/src/routes.js +++ b/frontend/src/routes.js @@ -54,7 +54,7 @@ export const router = createBrowserRouter( }} /> { const { SelectTask } = await import( './views/taskSelection' /* webpackChunkName: "taskSelection" */ From ca077ffe8a179d0810909ea0009b25cd3ded27bc Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Mon, 23 Sep 2024 15:32:20 +0545 Subject: [PATCH 11/23] Add button to navigate to `Instructions` page from `Project Detail` page --- frontend/src/components/projectDetail/index.js | 9 ++++++++- frontend/src/components/projectDetail/messages.js | 4 ++++ frontend/src/components/projectDetail/styles.scss | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/projectDetail/index.js b/frontend/src/components/projectDetail/index.js index c40ab63ad0..5a1d22fe26 100644 --- a/frontend/src/components/projectDetail/index.js +++ b/frontend/src/components/projectDetail/index.js @@ -1,5 +1,5 @@ import { lazy, Suspense, useState } from 'react'; -import { Link } from 'react-router-dom'; +import { Link, useParams } from 'react-router-dom'; import ReactPlaceholder from 'react-placeholder'; import centroid from '@turf/centroid'; import { FormattedMessage } from 'react-intl'; @@ -139,6 +139,7 @@ export const ProjectDetailLeft = ({ project, contributors, className, type }) => export const ProjectDetail = (props) => { useSetProjectPageTitleTag(props.project); const size = useWindowSize(); + const { id: projectId } = useParams(); const { data: contributors, status: contributorsStatus } = useProjectContributionsQuery( props.project.projectId, ); @@ -181,6 +182,12 @@ export const ProjectDetail = (props) => { className="ph4 w-60-l w-80-m w-100 lh-title markdown-content blue-dark-abbey" dangerouslySetInnerHTML={htmlDescription} /> + + + diff --git a/frontend/src/components/projectDetail/messages.js b/frontend/src/components/projectDetail/messages.js index cd457852c4..bd1826ad37 100644 --- a/frontend/src/components/projectDetail/messages.js +++ b/frontend/src/components/projectDetail/messages.js @@ -344,4 +344,8 @@ export default defineMessages({ id: 'project.noSimilarProjectsFound', defaultMessage: 'Could not find any similar projects for this project', }, + viewProjectSpecificInstructions: { + id: 'project.viewProjectSpecificInstructions', + defaultMessage: 'View project specific instructions', + }, }); diff --git a/frontend/src/components/projectDetail/styles.scss b/frontend/src/components/projectDetail/styles.scss index 41c4a8b923..405ba01659 100644 --- a/frontend/src/components/projectDetail/styles.scss +++ b/frontend/src/components/projectDetail/styles.scss @@ -36,3 +36,7 @@ .react-tooltip#dueDateBoxTooltip { z-index: 999; } + +.project-instructions-link { + letter-spacing: -0.0857513px; +} From e372d2d5857b15051614156b3d2800ab9a2a37d7 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 8 Oct 2024 11:34:17 +0545 Subject: [PATCH 12/23] Show Project Detail Map instead of Task Map when not logged in - Enable task api call only when logged in - Add `taskBordersOnly` props for directly zooming to tasks in `ProjectDetailMap` - Zoom to task border initially --- frontend/src/api/projects.js | 3 +- .../src/components/projectDetail/index.js | 10 +- .../src/components/taskSelection/index.js | 92 +++++++++++-------- frontend/src/views/taskSelection.js | 27 +++++- 4 files changed, 88 insertions(+), 44 deletions(-) diff --git a/frontend/src/api/projects.js b/frontend/src/api/projects.js index 03b8af8af0..fc8083477a 100644 --- a/frontend/src/api/projects.js +++ b/frontend/src/api/projects.js @@ -39,7 +39,7 @@ export const useProjectsQuery = (fullProjectsQuery, action, queryOptions) => { }); }; -export const useProjectQuery = (projectId) => { +export const useProjectQuery = (projectId, otherOptions) => { const token = useSelector((state) => state.auth.token); const locale = useSelector((state) => state.preferences['locale']); const fetchProject = ({ signal }) => { @@ -51,6 +51,7 @@ export const useProjectQuery = (projectId) => { return useQuery({ queryKey: ['project', projectId], queryFn: fetchProject, + ...otherOptions, }); }; export const useProjectSummaryQuery = (projectId, otherOptions = {}) => { diff --git a/frontend/src/components/projectDetail/index.js b/frontend/src/components/projectDetail/index.js index 5a1d22fe26..27ffddc9f9 100644 --- a/frontend/src/components/projectDetail/index.js +++ b/frontend/src/components/projectDetail/index.js @@ -1,4 +1,4 @@ -import { lazy, Suspense, useState } from 'react'; +import { lazy, Suspense, useState, useEffect } from 'react'; import { Link, useParams } from 'react-router-dom'; import ReactPlaceholder from 'react-placeholder'; import centroid from '@turf/centroid'; @@ -35,9 +35,14 @@ import { ENABLE_EXPORT_TOOL } from '../../config/index.js'; /* lazy imports must be last import */ const ProjectTimeline = lazy(() => import('./timeline' /* webpackChunkName: "timeline" */)); -const ProjectDetailMap = (props) => { +export const ProjectDetailMap = (props) => { const [taskBordersOnly, setTaskBordersOnly] = useState(true); + useEffect(() => { + if (typeof props.taskBordersOnly !== 'boolean') return; + setTaskBordersOnly(props.taskBordersOnly); + }, [props.taskBordersOnly]); + const taskBordersGeoJSON = props.project.areaOfInterest && { type: 'FeatureCollection', features: [ @@ -442,6 +447,7 @@ ProjectDetailMap.propTypes = { type: PropTypes.string, tasksError: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), projectLoading: PropTypes.bool, + taskBordersOnly: PropTypes.bool, }; ProjectDetailLeft.propTypes = { diff --git a/frontend/src/components/taskSelection/index.js b/frontend/src/components/taskSelection/index.js index f12860906e..e6500b7bb8 100644 --- a/frontend/src/components/taskSelection/index.js +++ b/frontend/src/components/taskSelection/index.js @@ -19,6 +19,7 @@ import { TasksMapLegend } from './legend'; import { ProjectInstructions } from './instructions'; import { ChangesetCommentTags } from './changesetComment'; import { ProjectHeader } from '../projectDetail/header'; +import { ProjectDetailMap } from '../projectDetail'; import Contributions from './contributions'; import { UserPermissionErrorContent } from './permissionErrorModal'; import { Alert } from '../alert'; @@ -31,6 +32,7 @@ import { useTasksQuery, } from '../../api/projects'; import { useTeamsQuery } from '../../api/teams'; + const TaskSelectionFooter = lazy(() => import('./footer')); const getRandomTaskByAction = (activities, taskAction) => { @@ -58,6 +60,7 @@ export function TaskSelection({ project }: Object) { const location = useLocation(); const dispatch = useDispatch(); const user = useSelector((state) => state.auth.userDetails); + const token = useSelector((state) => state.auth.token); const userOrgs = useSelector((state) => state.auth.organisations); const lockedTasks = useGetLockedTasks(); const [zoomedTaskId, setZoomedTaskId] = useState(null); @@ -75,6 +78,7 @@ export function TaskSelection({ project }: Object) { }, { useErrorBoundary: true, + enabled: !!token, }, ); const { data: activities, refetch: getActivities } = useActivitiesQuery(projectId); @@ -88,6 +92,7 @@ export function TaskSelection({ project }: Object) { // Task status on the map were not being updated when coming from the action page, // so added this as a workaround. cacheTime: 0, + enabled: false, }); const { data: priorityAreas, @@ -115,10 +120,10 @@ export function TaskSelection({ project }: Object) { // update tasks geometry if there are new tasks (caused by task splits) // update tasks state (when activities have changed) useEffect(() => { - if (tasksData?.features.length !== activities?.activity.length) { + if (tasksData?.features.length !== activities?.activity.length && token) { refetchTasks(); } - }, [tasksData, activities, refetchTasks]); + }, [tasksData, activities, refetchTasks, token]); // use route instead of local state for active tab states const setActiveSection = useCallback( @@ -272,20 +277,22 @@ export function TaskSelection({ project }: Object) {
-
- -
+ {activeSection && ( +
+ +
+ )} {activeSection === 'instructions' ? ( <> {project.enforceRandomTaskSelection && ( @@ -300,6 +307,7 @@ export function TaskSelection({ project }: Object) { ) : null} + {activeSection === 'contributions' ? (
- - - - + ) : ( + + + + + )}
diff --git a/frontend/src/views/taskSelection.js b/frontend/src/views/taskSelection.js index 2b8cfe7f9b..03db202898 100644 --- a/frontend/src/views/taskSelection.js +++ b/frontend/src/views/taskSelection.js @@ -1,25 +1,40 @@ import { useEffect } from 'react'; import { useSelector } from 'react-redux'; -import { useNavigate, useParams } from 'react-router-dom'; +import { useNavigate, useParams, useLocation } from 'react-router-dom'; import { TaskSelection } from '../components/taskSelection'; import { NotFound } from './notFound'; -import { useProjectSummaryQuery } from '../api/projects'; +import { useProjectSummaryQuery, useProjectQuery } from '../api/projects'; import { Preloader } from '../components/preloader'; export function SelectTask() { const { id } = useParams(); const navigate = useNavigate(); const token = useSelector((state) => state.auth.token); - const { data, status, error } = useProjectSummaryQuery(id, { + const { + data: projectSummaryData, + error: projectSummaryError, + status: projectSummaryStatus, + } = useProjectSummaryQuery(id, { useErrorBoundary: (error) => error.response.status !== 404, + enabled: !!token, + }); + const { + data: projectData, + error: projectError, + status: projectStatus, + } = useProjectQuery(id, { + enabled: !token, }); useEffect(() => { if (!token) { navigate('/login'); } - }, [navigate, token]); + }, [navigate, token, pathname]); + + const status = token ? projectSummaryStatus : projectStatus; + const error = token ? projectSummaryError : projectError; if (status === 'loading') { return ; @@ -31,5 +46,7 @@ export function SelectTask() { } } - return ; + const project = token ? projectSummaryData : projectData.data; + + return ; } From 8b7da1b29921992d11be58949e40569ca7c703fb Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 8 Oct 2024 12:48:57 +0545 Subject: [PATCH 13/23] Change `View Instructions` button to link --- frontend/src/components/projectDetail/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/projectDetail/index.js b/frontend/src/components/projectDetail/index.js index 27ffddc9f9..3baaa17aad 100644 --- a/frontend/src/components/projectDetail/index.js +++ b/frontend/src/components/projectDetail/index.js @@ -189,7 +189,7 @@ export const ProjectDetail = (props) => { /> From ef51caa317e2a9d2c97ed73a406f01a13feef6ba Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 8 Oct 2024 12:50:13 +0545 Subject: [PATCH 14/23] Show only `Instructions` tab when not logged in --- .../components/taskSelection/tabSelector.js | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/taskSelection/tabSelector.js b/frontend/src/components/taskSelection/tabSelector.js index fbc67be72f..c996258e7d 100644 --- a/frontend/src/components/taskSelection/tabSelector.js +++ b/frontend/src/components/taskSelection/tabSelector.js @@ -1,19 +1,25 @@ import { FormattedMessage } from 'react-intl'; +import { useSelector } from 'react-redux'; import messages from './messages'; -export const TabSelector = ({ activeSection, setActiveSection }) => ( -
- {['tasks', 'instructions', 'contributions'].map((section) => ( -
setActiveSection(section)} - > - -
- ))} -
-); +export const TabSelector = ({ activeSection, setActiveSection }) => { + const token = useSelector((state) => state.auth.token); + const tabs = token ? ['tasks', 'instructions', 'contributions'] : ['instructions']; + + return ( +
+ {tabs.map((section) => ( +
setActiveSection(section)} + > + +
+ ))} +
+ ); +}; From 5c4ef1b142a6370035fa7d1e2491c445bf8fb915 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 8 Oct 2024 13:08:38 +0545 Subject: [PATCH 15/23] Navigate to login when `Map a Task` button is clicked without login --- frontend/src/components/taskSelection/footer.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/taskSelection/footer.js b/frontend/src/components/taskSelection/footer.js index 03e6113dfe..1cb9a7b2cd 100644 --- a/frontend/src/components/taskSelection/footer.js +++ b/frontend/src/components/taskSelection/footer.js @@ -221,7 +221,17 @@ const TaskSelectionFooter = ({
- diff --git a/frontend/src/components/taskSelection/index.js b/frontend/src/components/taskSelection/index.js index f35af3cccc..650f035604 100644 --- a/frontend/src/components/taskSelection/index.js +++ b/frontend/src/components/taskSelection/index.js @@ -135,9 +135,22 @@ export function TaskSelection({ project }: Object) { [navigate, projectId, textSearch], ); + // remove history location state since react-router-dom persists state on reload + useEffect(() => { + function onBeforeUnload() { + window.history.replaceState({}, ''); + } + window.addEventListener('beforeunload', onBeforeUnload); + return () => { + window.removeEventListener('beforeunload', onBeforeUnload); + }; + }, []); + // show the tasks tab when the page loads if the user has already contributed // to the project. If no, show the instructions tab. useEffect(() => { + // do not redirect if user is not from project detail page + if (location?.state?.from !== `/projects/${projectId}`) return; if (contributions && isFirstRender.current) { const currentUserContributions = contributions.filter((u) => u.username === user.username); if (textSearch || (user.isExpert && currentUserContributions.length > 0)) { @@ -147,7 +160,7 @@ export function TaskSelection({ project }: Object) { } isFirstRender.current = false; } - }, [contributions, user.username, user, textSearch, setActiveSection]); + }, [contributions, user.username, user, textSearch, setActiveSection, location, projectId]); useEffect(() => { // run it only when the component is initialized From cb58a096aa465d23d3286995e20ee92aaa5bd2cb Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 12 Nov 2024 13:24:04 +0545 Subject: [PATCH 22/23] Add `from` state to MemoryRouter in Tasks page test cases - Fix test case failure for redirect issue in task page --- frontend/src/components/taskSelection/tests/index.test.js | 4 +++- frontend/src/views/tests/taskSelection.test.js | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/taskSelection/tests/index.test.js b/frontend/src/components/taskSelection/tests/index.test.js index f81dfea791..e069d95ed2 100644 --- a/frontend/src/components/taskSelection/tests/index.test.js +++ b/frontend/src/components/taskSelection/tests/index.test.js @@ -15,7 +15,9 @@ describe('Contributions', () => { return { user: userEvent.setup(), ...render( - + { return { user: userEvent.setup(), ...render( - + { return { user: userEvent.setup(), ...render( - + Date: Fri, 22 Nov 2024 15:37:30 +0545 Subject: [PATCH 23/23] Add PYTHONPATH and bind mount for migrations --- Dockerfile | 1 + docker-compose.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 74539ee476..9b3a7ede9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,6 +60,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PYTHONFAULTHANDLER=1 \ PATH="/home/appuser/.local/bin:$PATH" \ + PYTHONPATH="/usr/src/app:$PYTHONPATH" \ PYTHON_LIB="/home/appuser/.local/lib/python$PYTHON_IMG_TAG/site-packages" \ SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \ REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt diff --git a/docker-compose.yml b/docker-compose.yml index 89c2d175bf..e8f0c294f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,6 +40,7 @@ services: - ./pyproject.toml:/usr/src/app/pyproject.toml:ro - ./backend:/usr/src/app/backend:ro - ./tests:/usr/src/app/tests:ro + - ./migrations:/src/migrations restart: unless-stopped healthcheck: test: curl --fail http://localhost:5000 || exit 1