From 1540c17ee0222b95b5f573f2c754b09f0ae33134 Mon Sep 17 00:00:00 2001 From: Sujit Date: Tue, 24 Sep 2024 16:17:37 +0545 Subject: [PATCH 01/32] feat: add secondary button on `AsyncPopup` component --- .../MapLibreComponents/AsyncPopup/index.tsx | 42 +++++++++++++------ .../common/MapLibreComponents/types/index.ts | 9 ++-- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx b/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx index be22f596..f65bf3a4 100644 --- a/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx +++ b/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx @@ -1,13 +1,13 @@ /* eslint-disable no-unused-vars */ /* eslint-disable react/no-danger */ -import { useEffect, useRef, useState } from 'react'; -import { renderToString } from 'react-dom/server'; -import { Popup } from 'maplibre-gl'; -import type { MapMouseEvent } from 'maplibre-gl'; -import 'maplibre-gl/dist/maplibre-gl.css'; import '@Components/common/MapLibreComponents/map.css'; import { Button } from '@Components/RadixComponents/Button'; import Skeleton from '@Components/RadixComponents/Skeleton'; +import type { MapMouseEvent } from 'maplibre-gl'; +import { Popup } from 'maplibre-gl'; +import 'maplibre-gl/dist/maplibre-gl.css'; +import { useEffect, useRef, useState } from 'react'; +import { renderToString } from 'react-dom/server'; import { IAsyncPopup } from '../types'; const popup = new Popup({ @@ -26,6 +26,9 @@ export default function AsyncPopup({ buttonText = 'View More', hideButton = false, getCoordOnProperties = false, + hasSecondaryButton = false, + secondaryButtonText = '', + handleSecondaryBtnClick, showPopup = (_clickedFeature: Record) => true, }: IAsyncPopup) { const [properties, setProperties] = useState | null>( @@ -106,14 +109,27 @@ export default function AsyncPopup({
{!isLoading && !hideButton && ( -
- +
+
+ {hasSecondaryButton && ( + + )} + + +
)}
diff --git a/src/frontend/src/components/common/MapLibreComponents/types/index.ts b/src/frontend/src/components/common/MapLibreComponents/types/index.ts index 4155a0af..538e1b48 100644 --- a/src/frontend/src/components/common/MapLibreComponents/types/index.ts +++ b/src/frontend/src/components/common/MapLibreComponents/types/index.ts @@ -1,8 +1,8 @@ /* eslint-disable no-unused-vars */ -import type { ReactElement } from 'react'; -import type { Map, MapOptions } from 'maplibre-gl'; -import type { Feature, FeatureCollection, GeoJsonTypes } from 'geojson'; import type { DrawMode } from '@mapbox/mapbox-gl-draw'; +import type { Feature, FeatureCollection, GeoJsonTypes } from 'geojson'; +import type { Map, MapOptions } from 'maplibre-gl'; +import type { ReactElement } from 'react'; export type MapInstanceType = Map; @@ -83,6 +83,9 @@ export interface IAsyncPopup { hideButton?: boolean; getCoordOnProperties?: boolean; showPopup?: (clickedFeature: Record) => Boolean; + hasSecondaryButton?: boolean; + secondaryButtonText?: string; + handleSecondaryBtnClick?: (properties: Record) => void; } export type DrawModeTypes = DrawMode | null | undefined; From 87e8670e0377111b8e60e7e3d7b0193c5c75a2cb Mon Sep 17 00:00:00 2001 From: Sujit Date: Tue, 24 Sep 2024 16:39:54 +0545 Subject: [PATCH 02/32] feat(project-description): implement task unlock feature --- .../IndividualProject/MapSection/index.tsx | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/src/frontend/src/components/IndividualProject/MapSection/index.tsx b/src/frontend/src/components/IndividualProject/MapSection/index.tsx index f6e4bcdb..4ef1bd78 100644 --- a/src/frontend/src/components/IndividualProject/MapSection/index.tsx +++ b/src/frontend/src/components/IndividualProject/MapSection/index.tsx @@ -1,30 +1,29 @@ /* eslint-disable no-nested-ternary */ /* eslint-disable no-unused-vars */ -import { useNavigate, useParams } from 'react-router-dom'; -import { useCallback, useEffect, useState } from 'react'; -import { useTypedSelector, useTypedDispatch } from '@Store/hooks'; -import { useMapLibreGLMap } from '@Components/common/MapLibreComponents'; -import VectorLayer from '@Components/common/MapLibreComponents/Layers/VectorLayer'; -import MapContainer from '@Components/common/MapLibreComponents/MapContainer'; -import { GeojsonType } from '@Components/common/MapLibreComponents/types'; -import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup'; -import getBbox from '@turf/bbox'; -import { FeatureCollection } from 'geojson'; -import { GeolocateControl, LngLatBoundsLike, Map } from 'maplibre-gl'; -import { setProjectState } from '@Store/actions/project'; import { useGetProjectsDetailQuery, useGetTaskStatesQuery, useGetUserDetailsQuery, } from '@Api/projects'; import lock from '@Assets/images/lock.png'; +import BaseLayerSwitcherUI from '@Components/common/BaseLayerSwitcher'; +import { useMapLibreGLMap } from '@Components/common/MapLibreComponents'; +import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup'; +import VectorLayer from '@Components/common/MapLibreComponents/Layers/VectorLayer'; +import LocateUser from '@Components/common/MapLibreComponents/LocateUser'; +import MapContainer from '@Components/common/MapLibreComponents/MapContainer'; +import { GeojsonType } from '@Components/common/MapLibreComponents/types'; import { postTaskStatus } from '@Services/project'; +import { setProjectState } from '@Store/actions/project'; +import { useTypedDispatch, useTypedSelector } from '@Store/hooks'; import { useMutation } from '@tanstack/react-query'; -import { toast } from 'react-toastify'; +import getBbox from '@turf/bbox'; import hasErrorBoundary from '@Utils/hasErrorBoundary'; -import baseLayersData from '@Components/common/MapLibreComponents/BaseLayerSwitcher/baseLayers'; -import BaseLayerSwitcherUI from '@Components/common/BaseLayerSwitcher'; -import LocateUser from '@Components/common/MapLibreComponents/LocateUser'; +import { FeatureCollection } from 'geojson'; +import { LngLatBoundsLike, Map } from 'maplibre-gl'; +import { useCallback, useEffect, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { toast } from 'react-toastify'; import Legend from './Legend'; const MapSection = () => { @@ -85,6 +84,20 @@ const MapSection = () => { }, }); + const { mutate: unLockTask } = useMutation({ + mutationFn: postTaskStatus, + onSuccess: (res: any) => { + setTaskStatusObj({ + ...taskStatusObj, + [res.data.task_id]: 'UNLOCKED_TO_MAP', + }); + toast.success('Task Unlocked Successfully'); + }, + onError: (err: any) => { + toast.error(err.message); + }, + }); + useEffect(() => { if (!map || !taskStates) return; // @ts-ignore @@ -149,6 +162,14 @@ const MapSection = () => { }); }; + const handleTaskUnLockClick = () => { + unLockTask({ + projectId: id, + taskId: selectedTaskId, + data: { event: 'unlock' }, + }); + }; + return ( { ? handleTaskLockClick() : navigate(`/projects/${id}/tasks/${selectedTaskId}`) } + hasSecondaryButton={ + taskStatusObj?.[selectedTaskId] === 'LOCKED_FOR_MAPPING' + } + secondaryButtonText="Unlock Task" + handleSecondaryBtnClick={() => handleTaskUnLockClick()} /> From b8084069eeee5f19d6325d7c47b814556588e883 Mon Sep 17 00:00:00 2001 From: Sujit Date: Tue, 24 Sep 2024 17:29:39 +0545 Subject: [PATCH 03/32] feat: tooltip for base layer switcher --- src/frontend/src/components/common/BaseLayerSwitcher/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/components/common/BaseLayerSwitcher/index.tsx b/src/frontend/src/components/common/BaseLayerSwitcher/index.tsx index 7ca166a2..e54b5685 100644 --- a/src/frontend/src/components/common/BaseLayerSwitcher/index.tsx +++ b/src/frontend/src/components/common/BaseLayerSwitcher/index.tsx @@ -1,5 +1,5 @@ -import { useState } from 'react'; import useOutsideClick from '@Hooks/useOutsideClick'; +import { useState } from 'react'; import BaseLayerSwitcher from '../MapLibreComponents/BaseLayerSwitcher'; import baseLayersData from '../MapLibreComponents/BaseLayerSwitcher/baseLayers'; import { MapInstanceType } from '../MapLibreComponents/types'; @@ -27,6 +27,7 @@ const BaseLayerSwitcherUI = ({ handleToggle(); }} role="presentation" + title="Layer Switcher" > layers From 3756b5f760a3280a3d8cb57b4f748598fa0f2fc3 Mon Sep 17 00:00:00 2001 From: Sujit Date: Tue, 24 Sep 2024 17:30:24 +0545 Subject: [PATCH 04/32] feat(project-description): make responsive --- .../src/views/IndividualProject/index.tsx | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/frontend/src/views/IndividualProject/index.tsx b/src/frontend/src/views/IndividualProject/index.tsx index e27ceed6..7cb73892 100644 --- a/src/frontend/src/views/IndividualProject/index.tsx +++ b/src/frontend/src/views/IndividualProject/index.tsx @@ -1,19 +1,18 @@ /* eslint-disable jsx-a11y/interactive-supports-focus */ /* eslint-disable jsx-a11y/click-events-have-key-events */ -import { useParams, useNavigate } from 'react-router-dom'; -import { useTypedDispatch, useTypedSelector } from '@Store/hooks'; -import { Flex } from '@Components/common/Layouts'; +import { useGetProjectsDetailQuery } from '@Api/projects'; import Tab from '@Components/common/Tabs'; import { + Contributions, + Instructions, MapSection, Tasks, - Instructions, - Contributions, } from '@Components/IndividualProject'; -import { useGetProjectsDetailQuery } from '@Api/projects'; -import { setProjectState } from '@Store/actions/project'; import { projectOptions } from '@Constants/index'; +import { setProjectState } from '@Store/actions/project'; +import { useTypedDispatch, useTypedSelector } from '@Store/hooks'; import hasErrorBoundary from '@Utils/hasErrorBoundary'; +import { useNavigate, useParams } from 'react-router-dom'; // function to render the content based on active tab const getActiveTabContent = ( @@ -66,19 +65,19 @@ const IndividualProject = () => { }); return ( -
+
{/* <----------- temporary breadcrumb -----------> */} -
+
{ navigate('/projects'); }} > Project / - + { // @ts-ignore projectData?.name || '--' @@ -86,8 +85,8 @@ const IndividualProject = () => { {/* <----------- temporary breadcrumb -----------> */}
- -
+
+
{ activeTab={individualProjectActiveTab} clickable /> -
+
{getActiveTabContent( individualProjectActiveTab, projectData as Record, @@ -107,10 +106,10 @@ const IndividualProject = () => { )}
-
+
- +
); }; From 170afd8a4187af4d6758cc06dcd372dd12f0e9cd Mon Sep 17 00:00:00 2001 From: Sujit Date: Tue, 24 Sep 2024 17:39:10 +0545 Subject: [PATCH 05/32] feat(project-dashboard): border radius on map --- .../components/Projects/MapSection/index.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/components/Projects/MapSection/index.tsx b/src/frontend/src/components/Projects/MapSection/index.tsx index 81c2b14d..3009db9f 100644 --- a/src/frontend/src/components/Projects/MapSection/index.tsx +++ b/src/frontend/src/components/Projects/MapSection/index.tsx @@ -1,15 +1,15 @@ +import { useCallback, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { useMapLibreGLMap } from '@Components/common/MapLibreComponents'; -import MapContainer from '@Components/common/MapLibreComponents/MapContainer'; -import BaseLayerSwitcher from '@Components/common/MapLibreComponents/BaseLayerSwitcher'; -import { useGetProjectsListQuery } from '@Api/projects'; -import hasErrorBoundary from '@Utils/hasErrorBoundary'; -import centroid from '@turf/centroid'; +import { LngLatBoundsLike, Map } from 'maplibre-gl'; import getBbox from '@turf/bbox'; -import { useCallback, useEffect, useState } from 'react'; +import centroid from '@turf/centroid'; import { FeatureCollection } from 'geojson'; +import { useGetProjectsListQuery } from '@Api/projects'; +import { useMapLibreGLMap } from '@Components/common/MapLibreComponents'; import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup'; -import { LngLatBoundsLike, Map } from 'maplibre-gl'; +import BaseLayerSwitcher from '@Components/common/MapLibreComponents/BaseLayerSwitcher'; +import MapContainer from '@Components/common/MapLibreComponents/MapContainer'; +import hasErrorBoundary from '@Utils/hasErrorBoundary'; import VectorLayerWithCluster from './VectorLayerWithCluster'; const ProjectsMapSection = () => { @@ -78,6 +78,7 @@ const ProjectsMapSection = () => { style={{ width: '100%', height: '100%', + borderRadius: '8px', }} > From a28fbba4ebec5b2b60ad9eacad3426f5a4e2b92e Mon Sep 17 00:00:00 2001 From: Sujit Date: Tue, 24 Sep 2024 17:45:12 +0545 Subject: [PATCH 06/32] feat(project-description): show unlock button only if the task is locked by the same user --- .../src/components/IndividualProject/MapSection/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/components/IndividualProject/MapSection/index.tsx b/src/frontend/src/components/IndividualProject/MapSection/index.tsx index 4ef1bd78..7e907844 100644 --- a/src/frontend/src/components/IndividualProject/MapSection/index.tsx +++ b/src/frontend/src/components/IndividualProject/MapSection/index.tsx @@ -315,7 +315,8 @@ const MapSection = () => { : navigate(`/projects/${id}/tasks/${selectedTaskId}`) } hasSecondaryButton={ - taskStatusObj?.[selectedTaskId] === 'LOCKED_FOR_MAPPING' + taskStatusObj?.[selectedTaskId] === 'LOCKED_FOR_MAPPING' && + lockedUser?.id === userDetails?.id } secondaryButtonText="Unlock Task" handleSecondaryBtnClick={() => handleTaskUnLockClick()} From 2b45720f864fd247520e4e7066080e12273f7070 Mon Sep 17 00:00:00 2001 From: Sujit Date: Wed, 25 Sep 2024 10:05:24 +0545 Subject: [PATCH 07/32] fix(task-description): click event persists after the starting point is saved close the click event on component unmount --- .../DroneOperatorTask/MapSection/GetCoordinatesOnClick.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/components/DroneOperatorTask/MapSection/GetCoordinatesOnClick.tsx b/src/frontend/src/components/DroneOperatorTask/MapSection/GetCoordinatesOnClick.tsx index 66659ad5..f3a8252e 100644 --- a/src/frontend/src/components/DroneOperatorTask/MapSection/GetCoordinatesOnClick.tsx +++ b/src/frontend/src/components/DroneOperatorTask/MapSection/GetCoordinatesOnClick.tsx @@ -16,13 +16,16 @@ const GetCoordinatesOnClick = ({ useEffect(() => { if (!map || !isMapLoaded) return () => {}; map.getCanvas().style.cursor = 'crosshair'; - map.on('click', e => { + + const handleClick = (e: any) => { const latLng = e.lngLat; getCoordinates(latLng); - }); + }; + map.on('click', handleClick); return () => { map.getCanvas().style.cursor = ''; + map.off('click', handleClick); }; }, [map, isMapLoaded, getCoordinates]); return null; From b3304745b1fcfcb1c1006cdafdf6f6a3eb7ae9ae Mon Sep 17 00:00:00 2001 From: Sujit Date: Wed, 25 Sep 2024 10:08:44 +0545 Subject: [PATCH 08/32] feat(task-description): all the variables related to take-off point updation reset to initial state on component unmount --- .../src/components/DroneOperatorTask/MapSection/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/components/DroneOperatorTask/MapSection/index.tsx b/src/frontend/src/components/DroneOperatorTask/MapSection/index.tsx index 5666af81..9d12e1ab 100644 --- a/src/frontend/src/components/DroneOperatorTask/MapSection/index.tsx +++ b/src/frontend/src/components/DroneOperatorTask/MapSection/index.tsx @@ -12,7 +12,10 @@ import { GeojsonType } from '@Components/common/MapLibreComponents/types'; import { Button } from '@Components/RadixComponents/Button'; import { postTaskWaypoint } from '@Services/tasks'; import { toggleModal } from '@Store/actions/common'; -import { setSelectedTakeOffPoint } from '@Store/actions/droneOperatorTask'; +import { + setSelectedTakeOffPoint, + setSelectedTakeOffPointOption, +} from '@Store/actions/droneOperatorTask'; import { useTypedSelector } from '@Store/hooks'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import getBbox from '@turf/bbox'; @@ -81,6 +84,7 @@ const MapSection = ({ className }: { className?: string }) => { return data; }); dispatch(setSelectedTakeOffPoint(null)); + dispatch(setSelectedTakeOffPointOption('current_location')); }, onError: (err: any) => { toast.error(err?.response?.data?.detail || err.message); @@ -158,6 +162,7 @@ const MapSection = ({ className }: { className?: string }) => { useEffect( () => () => { dispatch(setSelectedTakeOffPoint(null)); + dispatch(setSelectedTakeOffPointOption('current_location')); }, [dispatch], ); From c1416bd1c05256e047997220b95983728d96e753 Mon Sep 17 00:00:00 2001 From: Sujit Date: Wed, 25 Sep 2024 14:02:03 +0545 Subject: [PATCH 09/32] feat: add `ScrollToTop` component --- .../components/common/ScrollToTop/index.tsx | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/frontend/src/components/common/ScrollToTop/index.tsx diff --git a/src/frontend/src/components/common/ScrollToTop/index.tsx b/src/frontend/src/components/common/ScrollToTop/index.tsx new file mode 100644 index 00000000..bb83d703 --- /dev/null +++ b/src/frontend/src/components/common/ScrollToTop/index.tsx @@ -0,0 +1,49 @@ +import React, { useState, useEffect } from 'react'; + +const ScrollToTop: React.FC = () => { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + const toggleVisibility = () => { + const playgroundElement = document.getElementById('app_playground'); + if (playgroundElement && playgroundElement?.scrollTop > 400) { + setIsVisible(true); + } else { + setIsVisible(false); + } + }; + + const playgroundElement = document.getElementById('app_playground'); + playgroundElement?.addEventListener('scroll', toggleVisibility); + + return () => { + playgroundElement?.removeEventListener('scroll', toggleVisibility); + }; + }, []); + + const scrollToTop = () => { + const playgroundElement = document.getElementById('app_playground'); + playgroundElement?.scrollTo({ + top: 0, + behavior: 'smooth', + }); + }; + + return ( +
+ +
+ ); +}; + +export default ScrollToTop; From ce1a88f5e65d5fa4390c98e9dc9f038cdb3a16e7 Mon Sep 17 00:00:00 2001 From: Sujit Date: Wed, 25 Sep 2024 14:05:26 +0545 Subject: [PATCH 10/32] feat: make navbar fixed height --- src/frontend/src/components/common/Navbar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/components/common/Navbar/index.tsx b/src/frontend/src/components/common/Navbar/index.tsx index ff1a955a..f0db1d0c 100644 --- a/src/frontend/src/components/common/Navbar/index.tsx +++ b/src/frontend/src/components/common/Navbar/index.tsx @@ -10,7 +10,7 @@ export default function Navbar() { const navigate = useNavigate(); return ( -
); }; From 92c2cf333ba63ad7c3f076006cb45ebde8f9bd4b Mon Sep 17 00:00:00 2001 From: Sujit Date: Wed, 25 Sep 2024 16:52:52 +0545 Subject: [PATCH 15/32] feat(user-profile): make responsive --- src/frontend/src/App.tsx | 2 +- src/frontend/src/views/UserProfile/index.tsx | 55 ++++++++++---------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index cdee7365..cfef8088 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -84,7 +84,7 @@ export default function App() {
{ const dispatch = useTypedDispatch(); const navigate = useNavigate(); - + const { width } = useWindowDimensions(); const signedInAs = localStorage.getItem('signedInAs') || 'Project Creator'; const isDroneOperator = localStorage.getItem('signedInAs') === 'Drone Operator'; @@ -123,35 +124,33 @@ const UserProfile = () => { }; return ( -
+
-
-
-
- {}} - tabOptions={tabOptions} - activeTab={userProfileActiveTab} - /> -
-
+
+
+ {}} + tabOptions={tabOptions} + activeTab={userProfileActiveTab} + /> +
+
+
{getActiveFormContent(userProfileActiveTab, signedInAs, formProps)} - {userProfileActiveTab !== 1 && ( - - )} +
+
+
-
+
); }; From 1c33145f9957d4980fc21b5f736683212459e289 Mon Sep 17 00:00:00 2001 From: Pradip-p Date: Thu, 26 Sep 2024 10:13:52 +0545 Subject: [PATCH 16/32] feat: added project name list tasks based on user endpoint --- src/backend/app/tasks/task_schemas.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backend/app/tasks/task_schemas.py b/src/backend/app/tasks/task_schemas.py index 12cba359..596e75b0 100644 --- a/src/backend/app/tasks/task_schemas.py +++ b/src/backend/app/tasks/task_schemas.py @@ -149,6 +149,7 @@ class UserTasksStatsOut(BaseModel): state: str project_id: uuid.UUID project_task_index: int + project_name: str @staticmethod async def get_tasks_by_user( @@ -160,6 +161,7 @@ async def get_tasks_by_user( tasks.id AS task_id, tasks.project_task_index AS project_task_index, task_events.project_id AS project_id, + projects.name AS project_name, ST_Area(ST_Transform(tasks.outline, 3857)) / 1000000 AS task_area, task_events.created_at, CASE @@ -173,6 +175,8 @@ async def get_tasks_by_user( task_events LEFT JOIN tasks ON task_events.task_id = tasks.id + LEFT JOIN + projects ON task_events.project_id = projects.id WHERE ( %(role)s = 'DRONE_PILOT' AND task_events.user_id = %(user_id)s From 4feef1e3385d6c36c66d437fa4d4ba3b50e335df Mon Sep 17 00:00:00 2001 From: Sujit Date: Thu, 26 Sep 2024 11:39:17 +0545 Subject: [PATCH 17/32] style(task-description): update uploaded information style --- .../DescriptionSection/UploadsInformation/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/UploadsInformation/index.tsx b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/UploadsInformation/index.tsx index 0a86a0e5..8773b675 100644 --- a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/UploadsInformation/index.tsx +++ b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/UploadsInformation/index.tsx @@ -1,8 +1,8 @@ const UploadsInformation = ({ data }: { data: Record[] }) => { return ( <> -
-
+
+

Upload Information

From 346e0413ac92a3c33a7dadd443a44f5650e3d86f Mon Sep 17 00:00:00 2001 From: Sujit Date: Thu, 26 Sep 2024 11:43:00 +0545 Subject: [PATCH 18/32] fix(task-description): task description comments --- .../components/DroneOperatorTask/DescriptionSection/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/index.tsx b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/index.tsx index f49d37d3..9151f63d 100644 --- a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/index.tsx +++ b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/index.tsx @@ -96,7 +96,6 @@ const DroneOperatorDescriptionBox = () => { .then(blob => { const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); - // link.setAttribute('download', ''); link.href = url; link.download = 'flight_plan.kmz'; document.body.appendChild(link); From be9fc15d3ca3a6489b3e449b1911102290214f87 Mon Sep 17 00:00:00 2001 From: Sujit Date: Thu, 26 Sep 2024 11:49:31 +0545 Subject: [PATCH 19/32] feat(task-description): re-fetch uploaded information and close file upload modal on file all files uploaded successfully --- .../DescriptionSection/PopoverBox/LoadingBox/index.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/PopoverBox/LoadingBox/index.tsx b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/PopoverBox/LoadingBox/index.tsx index 017905be..3911014a 100644 --- a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/PopoverBox/LoadingBox/index.tsx +++ b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/PopoverBox/LoadingBox/index.tsx @@ -1,5 +1,6 @@ import Icon from '@Components/common/Icon'; import { toggleModal } from '@Store/actions/common'; +import { useQueryClient } from '@tanstack/react-query'; import { useDispatch } from 'react-redux'; interface IFilesUploadingPopOverProps { @@ -16,12 +17,12 @@ const FilesUploadingPopOver = ({ uploadedFiles, }: IFilesUploadingPopOverProps) => { const dispatch = useDispatch(); - // const navigate = useNavigate(); + const queryClient = useQueryClient(); - // function to close modal + // function to close modal and refetch task assets to update the UI function closeModal() { + queryClient.invalidateQueries(['task-assets-info']); setTimeout(() => { - // navigate('/dashboard'); dispatch(toggleModal()); }, 2000); return null; From 1069606f5b952fa40863a6e8d010009fb3d73906 Mon Sep 17 00:00:00 2001 From: Sujit Date: Thu, 26 Sep 2024 11:50:58 +0545 Subject: [PATCH 20/32] feat(task-description): implement each-task orthophoto download --- .../DescriptionBox/index.tsx | 60 +++++++++++++++---- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/DescriptionBox/index.tsx b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/DescriptionBox/index.tsx index e62a08ea..9ad59023 100644 --- a/src/frontend/src/components/DroneOperatorTask/DescriptionSection/DescriptionBox/index.tsx +++ b/src/frontend/src/components/DroneOperatorTask/DescriptionSection/DescriptionBox/index.tsx @@ -1,20 +1,19 @@ +import { useState } from 'react'; import { useParams } from 'react-router-dom'; +import { format } from 'date-fns'; +import { toast } from 'react-toastify'; import { useGetIndividualTaskQuery, useGetTaskAssetsInfo, useGetTaskWaypointQuery, } from '@Api/tasks'; -import { useState } from 'react'; -// import { useTypedSelector } from '@Store/hooks'; -import { format } from 'date-fns'; +import { Button } from '@Components/RadixComponents/Button'; import DescriptionBoxComponent from './DescriptionComponent'; import QuestionBox from '../QuestionBox'; import UploadsInformation from '../UploadsInformation'; const DescriptionBox = () => { - // const secondPageStates = useTypedSelector(state => state.droneOperatorTask); const [flyable, setFlyable] = useState('yes'); - // const { secondPage } = secondPageStates; const { taskId, projectId } = useParams(); const { data: taskWayPoints }: any = useGetTaskWaypointQuery( @@ -98,6 +97,32 @@ const DescriptionBox = () => { }, }); + const handleDownloadResult = () => { + if (!taskAssetsInformation?.assets_url) return; + + fetch(`${taskAssetsInformation?.assets_url}`, { method: 'GET' }) + .then(response => { + if (!response.ok) { + throw new Error(`Network response was ${response.statusText}`); + } + return response.blob(); + }) + .then(blob => { + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = 'assets.zip'; + document.body.appendChild(link); + link.click(); + link.remove(); + window.URL.revokeObjectURL(url); + }) + .catch(error => + toast.error(`There wan an error while downloading file + ${error}`), + ); + }; + return ( <>
@@ -109,12 +134,13 @@ const DescriptionBox = () => { /> ))}
- {/* {!secondPage && } */} - + {taskAssetsInformation?.image_count === 0 && ( + + )} {taskAssetsInformation?.image_count > 0 && (
@@ -130,6 +156,18 @@ const DescriptionBox = () => { }, ]} /> +
+ +
)} From f9da9d1c2afc7b9f7019b24f1ea52620b28e2889 Mon Sep 17 00:00:00 2001 From: Sujit Date: Thu, 26 Sep 2024 13:46:40 +0545 Subject: [PATCH 21/32] fix(project-creation): show error message detail insted of error message on post --- .../src/components/CreateProject/CreateprojectLayout/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/components/CreateProject/CreateprojectLayout/index.tsx b/src/frontend/src/components/CreateProject/CreateprojectLayout/index.tsx index 475a9a90..67129049 100644 --- a/src/frontend/src/components/CreateProject/CreateprojectLayout/index.tsx +++ b/src/frontend/src/components/CreateProject/CreateprojectLayout/index.tsx @@ -164,7 +164,7 @@ const CreateprojectLayout = () => { dispatch(resetUploadedAndDrawnAreas()); }, onError: err => { - toast.error(err.message); + toast.error(err?.response?.data?.detail || err?.message || ''); }, }); From 9b4f5deb33864449f5fcc85be2d094b04cdea628 Mon Sep 17 00:00:00 2001 From: Sujit Date: Thu, 26 Sep 2024 16:27:02 +0545 Subject: [PATCH 22/32] feat(project-dashboard): apply projects filter by owner --- src/frontend/src/api/projects.ts | 5 ++-- .../components/Projects/MapSection/index.tsx | 22 +++++++++------ .../Projects/ProjectsHeader/index.tsx | 28 +++++++++++++++++-- src/frontend/src/services/createproject.ts | 3 +- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/frontend/src/api/projects.ts b/src/frontend/src/api/projects.ts index f3c613f1..7720efb1 100644 --- a/src/frontend/src/api/projects.ts +++ b/src/frontend/src/api/projects.ts @@ -5,11 +5,12 @@ import { getTaskStates } from '@Services/project'; import { getUserProfileInfo } from '@Services/common'; export const useGetProjectsListQuery = ( + projectsFilterByOwner: 'yes' | 'no', queryOptions?: Partial, ) => { return useQuery({ - queryKey: ['projects-list'], - queryFn: getProjectsList, + queryKey: ['projects-list', projectsFilterByOwner], + queryFn: () => getProjectsList(projectsFilterByOwner === 'yes'), select: (res: any) => res.data, ...queryOptions, }); diff --git a/src/frontend/src/components/Projects/MapSection/index.tsx b/src/frontend/src/components/Projects/MapSection/index.tsx index 3009db9f..1c39273f 100644 --- a/src/frontend/src/components/Projects/MapSection/index.tsx +++ b/src/frontend/src/components/Projects/MapSection/index.tsx @@ -5,6 +5,7 @@ import getBbox from '@turf/bbox'; import centroid from '@turf/centroid'; import { FeatureCollection } from 'geojson'; import { useGetProjectsListQuery } from '@Api/projects'; +import { useTypedSelector } from '@Store/hooks'; import { useMapLibreGLMap } from '@Components/common/MapLibreComponents'; import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup'; import BaseLayerSwitcher from '@Components/common/MapLibreComponents/BaseLayerSwitcher'; @@ -13,6 +14,9 @@ import hasErrorBoundary from '@Utils/hasErrorBoundary'; import VectorLayerWithCluster from './VectorLayerWithCluster'; const ProjectsMapSection = () => { + const projectsFilterByOwner = useTypedSelector( + state => state.createproject.ProjectsFilterByOwner, + ); const [projectProperties, setProjectProperties] = useState< Record >({}); @@ -27,7 +31,7 @@ const ProjectsMapSection = () => { disableRotation: true, }); const { data: projectsList, isLoading }: Record = - useGetProjectsListQuery({ + useGetProjectsListQuery(projectsFilterByOwner, { select: (data: any) => { // find all polygons centroid and set to geojson save to single geojson const combinedGeojson = data?.data?.reduce( @@ -83,13 +87,15 @@ const ProjectsMapSection = () => { > - + {projectsList && ( + + )} state.common.showMap); + const projectsFilterByOwner = useTypedSelector( + state => state.createproject.ProjectsFilterByOwner, + ); return (
Projects
+
+