From cfdbf37605b9a2043b515b1137b3b1c3b17a1533 Mon Sep 17 00:00:00 2001 From: Nishit Suwal <81785002+NSUWAL123@users.noreply.github.com> Date: Thu, 5 Oct 2023 23:14:39 +0545 Subject: [PATCH] Feat mobile UI project details (#874) * fix (create new project): create new project url updated * fix (create new project): upload area - select a file issue solved * fix (create new project): data extract - select a file issue solved * fix (radiobutton): option selection on label click, UI fix * fix (create new project): initial values for project details form added * feat (select): custom select component added * fix (create new project): data extract - shadcn select replaced with customselect * fix (custom select): updated props * fix (create new project): project detials - shadcn select replaced with customselect * fix (select): shadcn components export removed * fix (create new project): select form - shadcn select replaced with customselect * fix: style fixes on input field * fix radiobutton): - value prop added * fix (create new project): upload area - value prop added to radiobutton, map added * fix (create new project): event cleanup added * fix (create new project): geojson file cleanup added * fix (create new project): upload area - drawgeojson added, geojson file clear when option changed * Feat create new project (#844) * fix (create new project): create new project url updated * fix (create new project): upload area - select a file issue solved * fix (create new project): data extract - select a file issue solved * fix (radiobutton): option selection on label click, UI fix * fix (create new project): initial values for project details form added * feat (select): custom select component added * fix (create new project): data extract - shadcn select replaced with customselect * fix (custom select): updated props * fix (create new project): project detials - shadcn select replaced with customselect * fix (select): shadcn components export removed * fix (create new project): select form - shadcn select replaced with customselect * fix radiobutton): - value prop added * fix (create new project): upload area - value prop added to radiobutton, map added * fix (create new project): event cleanup added * fix (create project): uploadArea/dataExtract - reset and select same file issue solved * feat(select): added responsive * feat(validation) : added validation file on new create project * feat(data-extract): data extract useform integration * fix(dataextract): removed formcategory actions * feat (create project): upload area - total area calculation on upload area drawn * feat: changed step from data extract to select form * feat: changes on steps of create project * feat(File Input): file input component addition * feat(component) : used component for fileinput * feat/fix (create new project): split tasks - radiobutton state changed with redux state, useForm setup * fix (create new project): merge conflict solved * fix (Accordion): custom accordion added * fix (project details): project options accordion added for small screen * fix (project detials): map full screen for small screen on project details section * feat (project details): map legends accordion added for small screen * fix (project details): map legend lock icon size fixed * feat (modal): shadcn modal integrated * feat (project details): map tasks popup replaced with modal * feat (project details): tasks section modal replaced with tasks section popup * feat (project details): map scroll in view added when map clicked * fix (project details): medium device task popup border rounded fixed * fix (project details): map legend hidden for small screens * fix (project details): map section - task section visible on task map click from small and large screen * fix (project-details): project area layer view on grid icon click * fix (project-details): map button icons replaced and made center * fix (project-details): current location marker toggle on map on location button click * fix (project-details): description on dropdown not shown issue solved * fix (project info): mobile responsive design --------- Co-authored-by: Varun --- src/frontend/src/api/Project.js | 2 +- src/frontend/src/assets/images/grid.png | Bin 1144 -> 176 bytes src/frontend/src/assets/images/location.png | Bin 1151 -> 764 bytes src/frontend/src/components/OpenLayersMap.jsx | 94 ++++++++++++------ .../ProjectDetails/TaskSectionPopup.tsx | 2 +- .../ProjectInfo/ProjectInfoCountCard.jsx | 75 +++++--------- .../ProjectInfo/ProjectInfoSidebar.jsx | 70 ++++++------- .../components/ProjectInfo/ProjectInfomap.jsx | 4 +- src/frontend/src/components/TasksLayer.jsx | 2 + src/frontend/src/index.css | 3 + src/frontend/src/views/ProjectDetails.jsx | 30 +++++- src/frontend/src/views/ProjectInfo.tsx | 30 +++--- 12 files changed, 171 insertions(+), 141 deletions(-) mode change 100755 => 100644 src/frontend/src/assets/images/grid.png mode change 100755 => 100644 src/frontend/src/assets/images/location.png diff --git a/src/frontend/src/api/Project.js b/src/frontend/src/api/Project.js index 2c29146b69..04e1aab27a 100755 --- a/src/frontend/src/api/Project.js +++ b/src/frontend/src/api/Project.js @@ -43,7 +43,7 @@ export const ProjectById = (url, existingProjectList, projectId) => { priority_str: resp.priority_str || 'MEDIUM', title: resp.project_info?.[0]?.name, location_str: resp.location_str, - description: resp.description, + description: resp.project_info[0]?.description, num_contributors: resp.num_contributors, total_tasks: resp.total_tasks, tasks_mapped: resp.tasks_mapped, diff --git a/src/frontend/src/assets/images/grid.png b/src/frontend/src/assets/images/grid.png old mode 100755 new mode 100644 index 5b79d1afc745db0465d2131692ea167af0648e40..17449a8e6b658d7a47b27c02f7b2e51e8fece095 GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`j)FbFd;%$g$s6l5$8 za(7}_cTVOdki(Mh=7pV?_cl*BY3z#Pm5d>Nh+y4)$MZZDiW3^uhlFgHar3&67@v Rvp@qGJYD@<);T3K0RUt)Fj)Wq literal 1144 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 ZiMa*1^?1Kh{{hs);OXk;vd$@?2>`z} { - const lat = position.coords.latitude; - const lng = position.coords.longitude; - const convertedCoordinates = transform([lng, lat], sourceProjection, targetProjection); - const positionFeature = new ol.Feature(new Point(convertedCoordinates)); - const positionLayer = new Vector({ - source: new VectorSource({ - features: [positionFeature], - }), + if (!toggleCurrentLoc) { + navigator.geolocation.getCurrentPosition((position) => { + const lat = position.coords.latitude; + const lng = position.coords.longitude; + const convertedCoordinates = transform([lng, lat], sourceProjection, targetProjection); + const positionFeature = new ol.Feature(new Point(convertedCoordinates)); + const positionLayer = new Vector({ + source: new VectorSource({ + features: [positionFeature], + }), + }); + positionFeature.setStyle(markerStyle); + setCurrentLocLayer(positionLayer); }); - positionFeature.setStyle(markerStyle); - setCurrentLocLayer(positionLayer); - }); + } else { + setCurrentLocLayer(null); + } } - setToggleCurrentLoc(!toggleCurrentLoc); + // setToggleCurrentLoc(!toggleCurrentLoc); // map.getView().setZoom(15); } else if (e.target.id == 'taskBoundries') { - if (state.projectTaskBoundries.length != 0 && map != undefined) { - if (state.projectTaskBoundries.findIndex((project) => project.id == environment.decode(params.id)) != -1) { - const index = state.projectTaskBoundries.findIndex( - (project) => project.id == environment.decode(params.id), - ); - const centroid = - state.projectTaskBoundries[index].taskBoundries[ - state.projectTaskBoundries[index].taskBoundries.length - 1 - ].outline_centroid.geometry.coordinates; - - mainView.animate({ - center: centroid, - duration: 2000, - easing: elastic, - }); + const layers = map.getAllLayers(); + let extent; + layers.map((layer) => { + if (layer instanceof VectorLayer) { + const layerName = layer.getProperties().name; + if (layerName === 'project-area') { + extent = layer.getSource().getExtent(); + } } - } + }); + map.getView().fit(extent, { + padding: [10, 10, 10, 10], + }); + + // if (state.projectTaskBoundries.length != 0 && map != undefined) { + // if (state.projectTaskBoundries.findIndex((project) => project.id == environment.decode(params.id)) != -1) { + // const index = state.projectTaskBoundries.findIndex( + // (project) => project.id == environment.decode(params.id), + // ); + // const centroid = + // state.projectTaskBoundries[index].taskBoundries[ + // state.projectTaskBoundries[index].taskBoundries.length - 1 + // ].outline_centroid.geometry.coordinates; + + // mainView.animate({ + // center: centroid, + // duration: 2000, + // easing: elastic, + // }); + // } + // } map.getTargetElement().classList.remove('spinner'); } @@ -123,15 +143,27 @@ const OpenLayersMap = ({ img.id = `${elmnt}`; img.addEventListener('click', handleOnClick, false); btn.appendChild(img); + btn.style.display = 'flex'; + btn.style.alignItems = 'center'; + btn.style.justifyContent = 'center'; + + if (!toggleCurrentLoc) { + btn.style.backgroundColor = 'white'; + } else { + btn.style.backgroundColor = '#E6E6E6'; + } } else if (elmnt == 'taskBoundries') { let img = document.createElement('img'); img.src = gridIcon; img.id = `${elmnt}`; img.addEventListener('click', handleOnClick, false); btn.appendChild(img); + btn.style.display = 'flex'; + btn.style.alignItems = 'center'; + btn.style.justifyContent = 'center'; } btn.id = `${elmnt}`; - btn.style.backgroundColor = 'white'; + // btn.style.backgroundColor = 'white'; btn.style.boxShadow = `0 2px 2px 0 ${defaultTheme.palette.info['main']}`; btn.style.width = '40px'; btn.style.height = '40px'; @@ -274,7 +306,7 @@ const OpenLayersMap = ({ map.addControl(controlx); } - }, [map]); + }, [map, toggleCurrentLoc]); useEffect(() => { if (!map) return; diff --git a/src/frontend/src/components/ProjectDetails/TaskSectionPopup.tsx b/src/frontend/src/components/ProjectDetails/TaskSectionPopup.tsx index c101032594..06c704ef55 100644 --- a/src/frontend/src/components/ProjectDetails/TaskSectionPopup.tsx +++ b/src/frontend/src/components/ProjectDetails/TaskSectionPopup.tsx @@ -24,7 +24,7 @@ const TaskSectionPopup = ({ body }) => { > -
+
{body}
diff --git a/src/frontend/src/components/ProjectInfo/ProjectInfoCountCard.jsx b/src/frontend/src/components/ProjectInfo/ProjectInfoCountCard.jsx index cb3837ba6d..b85d6f9046 100644 --- a/src/frontend/src/components/ProjectInfo/ProjectInfoCountCard.jsx +++ b/src/frontend/src/components/ProjectInfo/ProjectInfoCountCard.jsx @@ -11,69 +11,48 @@ const ProjectInfoCountCard = () => { { count: taskData.task_count, title: 'Total Tasks', - icon: , + icon: , }, { count: taskData.submission_count, title: 'Total Submissions', - icon: , + icon: , }, { count: taskData.feature_count, title: 'Total Features', - icon: , + icon: , }, ]; return ( - -
- {isTaskLoading ? ( - - ) : ( -
- {totalTaskInfoCount.map((taskInfo) => ( -
- -
+ {isTaskLoading ? ( + + ) : ( +
+ {totalTaskInfoCount.map((taskInfo, i) => ( +
+ +
+

-

- {taskInfo.count} -

-
-

{taskInfo.title}

- {taskInfo.icon} -
+ {taskInfo.count} + +
+

{taskInfo.title}

+ {taskInfo.icon}
- -
- ))} -
- )} -
- +
+
+
+ ))} +
+ )} +
); }; diff --git a/src/frontend/src/components/ProjectInfo/ProjectInfoSidebar.jsx b/src/frontend/src/components/ProjectInfo/ProjectInfoSidebar.jsx index 317f2456df..27bb104036 100644 --- a/src/frontend/src/components/ProjectInfo/ProjectInfoSidebar.jsx +++ b/src/frontend/src/components/ProjectInfo/ProjectInfoSidebar.jsx @@ -35,32 +35,17 @@ const ProjectInfoSidebar = ({ projectId, taskInfo }) => { sx={{ display: 'flex', flexDirection: 'column', - background: '#F0F0F0', - width: '60%', + background: 'white', + width: '100%', gap: 2, }} + className="fmtm-mb-5" > - +
{isTaskLoading ? (
{Array.from({ length: 5 }).map((i) => ( -
+
))} @@ -76,38 +61,41 @@ const ProjectInfoSidebar = ({ projectId, taskInfo }) => { }} onClick={() => onTaskClick(+task.task_id)} > - + #{task.task_id} - +
+ + + Go To Task Submissions + + - Go To Task Submissions + Zoom to Task - - - Zoom to Task - +
{ ))}
)} - +
{/* { flexDirection: 'column', width: '100%', gap: 2, - height: '70vh', }} + className="fmtm-h-[35vh] md:fmtm-h-[70vh]" > { style: styleFunction, zIndex: 10, }); + vectorLayer.setProperties({ name: 'project-area' }); + // Initialize variables to store the extent var minX = Infinity; var minY = Infinity; diff --git a/src/frontend/src/index.css b/src/frontend/src/index.css index 95731bf160..b802820e62 100755 --- a/src/frontend/src/index.css +++ b/src/frontend/src/index.css @@ -112,6 +112,9 @@ button { padding: 7px; margin: 250px 10px; border-radius: 4px; + @media only screen and (max-width: 640px) { + display: none; + } } .legend { diff --git a/src/frontend/src/views/ProjectDetails.jsx b/src/frontend/src/views/ProjectDetails.jsx index 2f96ab5d0d..fb7f0edf6b 100755 --- a/src/frontend/src/views/ProjectDetails.jsx +++ b/src/frontend/src/views/ProjectDetails.jsx @@ -41,6 +41,7 @@ const Home = () => { const defaultTheme = CoreModules.useAppSelector((state) => state.theme.hotTheme); const state = CoreModules.useAppSelector((state) => state.project); + const taskModalStatus = CoreModules.useAppSelector((state) => state.project.taskModalStatus); const projectInfo = CoreModules.useAppSelector((state) => state.home.selectedProject); const stateDialog = CoreModules.useAppSelector((state) => state.home.dialogStatus); @@ -221,11 +222,30 @@ const Home = () => { }, [params.id]); useEffect(() => { - if (map != undefined) { - const topX = map.getTargetElement().getBoundingClientRect().y; - setTop(topX); - } - }, [map, y]); + if (!map) return; + map.on('click', function (event) { + map.forEachFeatureAtPixel(event.pixel, function (feature) { + let extent = feature.getGeometry().getExtent(); + if (windowSize.width < 768) { + map.getView().fit(extent, { + padding: [10, 20, 300, 20], + }); + } else { + map.getView().fit(extent, { + padding: [20, 350, 50, 10], + }); + } + }); + }); + return () => {}; + }, [taskModalStatus, windowSize.width]); + + // useEffect(() => { + // if (map != undefined) { + // const topX = map.getTargetElement().getBoundingClientRect().y; + // setTop(topX); + // } + // }, [map, y]); useEffect(() => { if (!map) return; diff --git a/src/frontend/src/views/ProjectInfo.tsx b/src/frontend/src/views/ProjectInfo.tsx index cc50ac28b6..ec74874697 100644 --- a/src/frontend/src/views/ProjectInfo.tsx +++ b/src/frontend/src/views/ProjectInfo.tsx @@ -169,13 +169,13 @@ const ProjectInfo = () => { { {projectInfo?.title} - - - - +
+ +
+ Upload to JOSM @@ -227,27 +228,31 @@ const ProjectInfo = () => { background: isMonitoring ? 'green' : 'red', width: '15px', height: '15px', - mr: 1, borderRadius: '50%', ...(isMonitoring && boxStyles), }} /> - Monitoring + Monitoring
- + +
+ +
+ {/* Project Info side bar */} - +
+ +
{ justifyContent: 'center', gap: 2, }} + className="fmtm-mt-4" > Convert