diff --git a/src/frontend/src/assets/images/lock.png b/src/frontend/src/assets/images/lock.png new file mode 100644 index 00000000..30f68fa1 Binary files /dev/null and b/src/frontend/src/assets/images/lock.png differ diff --git a/src/frontend/src/components/IndividualProject/MapSection/index.tsx b/src/frontend/src/components/IndividualProject/MapSection/index.tsx index fbca9d8a..8dedc669 100644 --- a/src/frontend/src/components/IndividualProject/MapSection/index.tsx +++ b/src/frontend/src/components/IndividualProject/MapSection/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-nested-ternary */ /* eslint-disable no-unused-vars */ import { useParams } from 'react-router-dom'; import { useCallback, useEffect, useState } from 'react'; @@ -11,15 +12,17 @@ import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup'; import getBbox from '@turf/bbox'; import { FeatureCollection } from 'geojson'; import { LngLatBoundsLike, Map } from 'maplibre-gl'; -import PopupUI from '@Components/common/MapLibreComponents/PopupUI'; import { setProjectState } from '@Store/actions/project'; import { useGetTaskStatesQuery } from '@Api/projects'; +import DTMLogo from '@Assets/images/lock.png'; +import { postTaskStatus } from '@Services/project'; +import { useMutation } from '@tanstack/react-query'; +import { toast } from 'react-toastify'; export default function MapSection() { const { id } = useParams(); const dispatch = useTypedDispatch(); - - const [tasksBoundaryLayer, setTasksBoundaryLayer] = useState | null>(null); @@ -42,10 +45,22 @@ export default function MapSection() { enabled: !!tasksData, }); - // create combined geojson from individual tasks from the API - useEffect(() => { - if (!map || !tasksData) return; + const { mutate: lockTask } = useMutation({ + mutationFn: postTaskStatus, + onSuccess: (res: any) => { + toast.success('Task Requested for Mapping'); + setTaskStatusObj({ + ...taskStatusObj, + [res.data.task_id]: 'REQUEST_FOR_MAPPING', + }); + }, + onError: (err: any) => { + toast.error(err.message); + }, + }); + useEffect(() => { + if (!map || !taskStates) return; // @ts-ignore const taskStatus: Record = taskStates?.reduce( (acc: Record, task: Record) => { @@ -54,45 +69,55 @@ export default function MapSection() { }, {}, ); - const features = tasksData?.map(taskObj => { - return { - type: 'Feature', - geometry: { ...taskObj.outline_geojson.geometry }, - properties: { - ...taskObj.outline_geojson.properties, - state: taskStatus?.[`${taskObj.id}`] || null, - }, - }; - }); - const taskBoundariesFeatcol = { - type: 'FeatureCollection', - SRID: { - type: 'name', - properties: { - name: 'EPSG:3857', - }, - }, - features, - }; - setTasksBoundaryLayer(taskBoundariesFeatcol); - }, [map, taskStates, tasksData]); + setTaskStatusObj(taskStatus); + }, [map, taskStates]); // zoom to layer in the project area useEffect(() => { - if (!tasksBoundaryLayer) return; - const bbox = getBbox(tasksBoundaryLayer as FeatureCollection); + if (!tasksData) return; + const tasksCollectiveGeojson = tasksData?.reduce( + (acc, curr) => { + return { + ...acc, + features: [...acc.features, curr.outline_geojson], + }; + }, + { + type: 'FeatureCollection', + features: [], + }, + ); + const bbox = getBbox(tasksCollectiveGeojson as FeatureCollection); map?.fitBounds(bbox as LngLatBoundsLike, { padding: 25 }); - }, [map, tasksBoundaryLayer]); + }, [map, tasksData]); - const getPopUpButtonText = (taskState: string) => { - if (taskState === 'UNLOCKED_FOR_MAP') return 'Request for Mapping'; - if (taskState === '') return ''; - return 'nothing'; - }; + const getPopupUI = useCallback( + (properties: Record) => { + const status = taskStatusObj?.[properties?.id]; + const popupText = (taskStatus: string) => { + switch (taskStatus) { + case 'UNLOCKED_TO_MAP': + return 'This task is available for mapping'; + case 'REQUEST_FOR_MAPPING': + return 'This task is Requested for mapping'; + case 'LOCKED_FOR_MAPPING': + return 'This task is locked for mapping'; + default: + return 'This Task is completed'; + } + }; + return
{popupText(status)}
; + }, + [taskStatusObj], + ); - const getPopupUI = useCallback((properties: Record) => { - return
This task is available for mapping
; - }, []); + const handleTaskLockClick = () => { + lockTask({ + projectId: id, + taskId: selectedTaskId, + data: { event: 'request' }, + }); + }; return ( - {tasksBoundaryLayer && ( - - )} + {tasksData && + tasksData?.map((task: Record) => { + return ( + + ); + })} + ) => { dispatch(setProjectState({ selectedTaskId: properties.id })); }} + hideButton={taskStatusObj?.[selectedTaskId] !== 'UNLOCKED_TO_MAP'} buttonText="Lock Task" + handleBtnClick={() => handleTaskLockClick()} /> diff --git a/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx b/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx index e51aea64..e4e464da 100644 --- a/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx +++ b/src/frontend/src/components/common/MapLibreComponents/AsyncPopup/index.tsx @@ -24,6 +24,7 @@ export default function AsyncPopup({ isLoading = false, onClose, buttonText = 'View More', + hideButton = false, }: IAsyncPopup) { const [properties, setProperties] = useState | null>( null, @@ -68,7 +69,10 @@ export default function AsyncPopup({ if (!properties) return
; return ( -
+
{isLoading ? ( @@ -86,7 +90,7 @@ export default function AsyncPopup({
- {!isLoading && ( + {!isLoading && !hideButton && (