diff --git a/src/frontend/src/api/Project.ts b/src/frontend/src/api/Project.ts index 46fd4e15a..da4b8ecc7 100755 --- a/src/frontend/src/api/Project.ts +++ b/src/frontend/src/api/Project.ts @@ -372,3 +372,46 @@ export const GetGeometryLog = (url: string) => { await getProjectActivity(url); }; }; + +export const SyncTaskState = ( + url: string, + params: { project_id: string }, + taskBoundaryFeatures: any, + geojsonStyles: any, +) => { + return async (dispatch: AppDispatch) => { + const syncTaskState = async () => { + try { + dispatch(ProjectActions.SyncTaskStateLoading(true)); + const response: AxiosResponse = await axios.get(url, { params }); + + response.data.map((task) => { + const feature = taskBoundaryFeatures?.find((feature) => feature.getId() === task.id); + const previousProperties = feature.getProperties(); + feature.setProperties({ + ...previousProperties, + task_state: task.task_state, + actioned_by_uid: task.actioned_by_uid, + actioned_by_username: task.actioned_by_username, + }); + + feature.setStyle(geojsonStyles[task.task_state]); + + dispatch( + ProjectActions.UpdateProjectTaskBoundries({ + projectId: params.project_id, + taskId: task.id, + actioned_by_uid: task.actioned_by_uid, + actioned_by_username: task.actioned_by_username, + task_state: task.task_state, + }), + ); + }); + } catch (error) { + } finally { + dispatch(ProjectActions.SyncTaskStateLoading(false)); + } + }; + await syncTaskState(); + }; +}; diff --git a/src/frontend/src/store/slices/ProjectSlice.ts b/src/frontend/src/store/slices/ProjectSlice.ts index ee6dcd2db..380e96662 100755 --- a/src/frontend/src/store/slices/ProjectSlice.ts +++ b/src/frontend/src/store/slices/ProjectSlice.ts @@ -35,6 +35,7 @@ const initialState: ProjectStateTypes = { newGeomFeatureCollection: { type: 'FeatureCollection', features: [] }, badGeomLogList: [], getGeomLogLoading: false, + syncTaskStateLoading: false, }; const ProjectSlice = createSlice({ @@ -170,6 +171,9 @@ const ProjectSlice = createSlice({ SetGeometryLogLoading(state, action: PayloadAction) { state.getGeomLogLoading = action.payload; }, + SyncTaskStateLoading(state, action: PayloadAction) { + state.syncTaskStateLoading = action.payload; + }, }, }); diff --git a/src/frontend/src/store/types/IProject.ts b/src/frontend/src/store/types/IProject.ts index b367bf875..f8275fe30 100644 --- a/src/frontend/src/store/types/IProject.ts +++ b/src/frontend/src/store/types/IProject.ts @@ -40,6 +40,7 @@ export type ProjectStateTypes = { newGeomFeatureCollection: FeatureCollectionType; badGeomLogList: geometryLogResponseType[]; getGeomLogLoading: boolean; + syncTaskStateLoading: boolean; }; type projectCommentsListTypes = { diff --git a/src/frontend/src/views/ProjectDetailsV2.tsx b/src/frontend/src/views/ProjectDetailsV2.tsx index eebc4aeb4..d55e1761e 100644 --- a/src/frontend/src/views/ProjectDetailsV2.tsx +++ b/src/frontend/src/views/ProjectDetailsV2.tsx @@ -3,7 +3,7 @@ import '../../node_modules/ol/ol.css'; import '../styles/home.scss'; import WindowDimension from '@/hooks/WindowDimension'; import ActivitiesPanel from '@/components/ProjectDetailsV2/ActivitiesPanel'; -import { ProjectById, GetEntityStatusList, GetGeometryLog } from '@/api/Project'; +import { ProjectById, GetEntityStatusList, GetGeometryLog, SyncTaskState } from '@/api/Project'; import { ProjectActions } from '@/store/slices/ProjectSlice'; import CustomizedSnackbar from '@/utilities/CustomizedSnackbar'; import { HomeActions } from '@/store/slices/HomeSlice'; @@ -36,6 +36,7 @@ import { Geolocation } from '@/utilfunctions/Geolocation'; import Instructions from '@/components/ProjectDetailsV2/Instructions'; import useDocumentTitle from '@/utilfunctions/useDocumentTitle'; import { Style, Stroke } from 'ol/style'; +import MapStyles from '@/hooks/MapStyles'; const ProjectDetailsV2 = () => { useDocumentTitle('Project Details'); @@ -45,6 +46,8 @@ const ProjectDetailsV2 = () => { const { windowSize } = WindowDimension(); const [divRef, toggle, handleToggle] = useOutsideClick(); + const geojsonStyles = MapStyles(); + const [selectedTaskArea, setSelectedTaskArea] = useState | null>(null); const [selectedTaskFeature, setSelectedTaskFeature] = useState(); const [dataExtractUrl, setDataExtractUrl] = useState(); @@ -69,6 +72,7 @@ const ProjectDetailsV2 = () => { const entityOsmMapLoading = useAppSelector((state) => state?.project?.entityOsmMapLoading); const badGeomFeatureCollection = useAppSelector((state) => state?.project?.badGeomFeatureCollection); const getGeomLogLoading = useAppSelector((state) => state?.project?.getGeomLogLoading); + const syncTaskStateLoading = useAppSelector((state) => state?.project?.syncTaskStateLoading); useEffect(() => { if (state.projectInfo.name) { @@ -259,6 +263,24 @@ const ProjectDetailsV2 = () => { dispatch(GetGeometryLog(`${import.meta.env.VITE_API_URL}/projects/${projectId}/geometry/records`)); }; + const syncTaskState = () => { + const taskBoundaryLayer = map + .getLayers() + .getArray() + .find((layer: any) => layer.get('name') == 'project-area'); + const taskBoundaryFeatures = taskBoundaryLayer.getSource().getFeatures(); + + projectId && + dispatch( + SyncTaskState( + `${import.meta.env.VITE_API_URL}/tasks`, + { project_id: projectId }, + taskBoundaryFeatures, + geojsonStyles, + ), + ); + }; + useEffect(() => { getEntityStatusList(); getGeometryLog(); @@ -299,6 +321,7 @@ const ProjectDetailsV2 = () => { const syncStatus = () => { getEntityStatusList(); getGeometryLog(); + syncTaskState(); }; return ( @@ -462,7 +485,6 @@ const ProjectDetailsV2 = () => { size: map?.getSize(), padding: [50, 50, 50, 50], constrainResolution: true, - duration: 2000, }} layerProperties={{ name: 'project-area' }} mapOnClick={projectClickOnTaskArea} @@ -532,14 +554,16 @@ const ProjectDetailsV2 = () => {