From c03f908247bb8605783550f89654aa7030de3c4f Mon Sep 17 00:00:00 2001 From: Nishit Suwal <81785002+NSUWAL123@users.noreply.github.com> Date: Wed, 17 Jan 2024 18:03:27 +0545 Subject: [PATCH] fix: editable vector layer in ol for project creation (#1102) * fix: backend import error fix * fix (vectorLayer): style - conditionaly apply style on onModify present * fix (splitTasks): map - edit added to splitted taskLayer * fix (splitTasks): onModify - edited geojson set to dividedTaskGeojson state * feat (createNewProject): only enable generate task btn if fgb file fetch is completed * fix (createNewProject): splitTasks - logic fix * fix (createNewProject): splitTasks - clear dividedTaskGeojson, splitTasksSelection, and dataExtractGeojson state on previous click * feat (createNewProject): splitTasks - show loader and message until FGB file is fetching * fix (createNewProject): taskSplit - display error on taskSplit fail * fix vectorLayer: on modifyEnd return area of boundary as well * fix button: loading text added to the button * fix NewDefineAreaMap: removed data extraction in progress message from mapComponent * fix (createNewProject): splitTasks - clearing state on step toggle remove * fix (createNewProject): uploadArea - clear step4 & step5 step on AOI edit * fix (createNewProject): dataExtract - generateTaskBTN added, disable next until taskGeneration success, state logic changed to track extractWays & featureType state validation * fix (createNewProject): dataExtract - clear file state on reset click or if generateDataExtract click * fix (createNewProject): customLine, customPolygon file state clear on AOI edit * fix (createNewProject): dataExtract - clear previous extractGeojson, customLine, customPolygon on generate extract, btn disable state update --- src/frontend/src/api/CreateProjectService.ts | 8 + .../OpenLayersComponent/Layers/VectorLayer.js | 41 ++--- src/frontend/src/components/common/Button.tsx | 19 ++- .../createnewproject/DataExtract.tsx | 153 +++++++++++++++--- .../createnewproject/SplitTasks.tsx | 12 +- .../createnewproject/UploadArea.tsx | 5 +- .../src/store/slices/CreateProjectSlice.ts | 10 ++ .../src/store/types/ICreateProject.ts | 1 + src/frontend/src/views/CreateNewProject.tsx | 10 +- src/frontend/src/views/NewDefineAreaMap.tsx | 7 +- 10 files changed, 215 insertions(+), 51 deletions(-) diff --git a/src/frontend/src/api/CreateProjectService.ts b/src/frontend/src/api/CreateProjectService.ts index 6750c5bcec..ff0581e30c 100755 --- a/src/frontend/src/api/CreateProjectService.ts +++ b/src/frontend/src/api/CreateProjectService.ts @@ -352,6 +352,14 @@ const TaskSplittingPreviewService: Function = ( dispatch(CreateProjectActions.SetIsTasksGenerated({ key: 'task_splitting_algorithm', value: true })); dispatch(CreateProjectActions.GetTaskSplittingPreview(resp)); } catch (error) { + dispatch( + CommonActions.SetSnackBar({ + open: true, + message: 'Task generation failed. Please try again', + variant: 'error', + duration: 2000, + }), + ); dispatch(CreateProjectActions.GetTaskSplittingPreviewLoading(false)); } finally { dispatch(CreateProjectActions.GetTaskSplittingPreviewLoading(false)); diff --git a/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js b/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js index 546bd7fddf..e3cb4c26d7 100644 --- a/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js +++ b/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js @@ -74,8 +74,10 @@ const VectorLayer = ({ dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857', }); + const geometry = vectorLayer.getSource().getFeatures()?.[0].getGeometry(); + const area = formatArea(geometry); - onModify(geoJSONString); + onModify(geoJSONString, area); }); map.addInteraction(modify); map.addInteraction(select); @@ -191,22 +193,26 @@ const VectorLayer = ({ useEffect(() => { if (!vectorLayer || !style.visibleOnMap || setStyle) return; - vectorLayer.setStyle((feature, resolution) => [ - new Style({ - image: new CircleStyle({ - radius: 5, - fill: new Fill({ - color: 'orange', - }), - }), - geometry: function (feature) { - // return the coordinates of the first ring of the polygon - const coordinates = feature.getGeometry().getCoordinates()[0]; - return new MultiPoint(coordinates); - }, - }), - getStyles({ style, feature, resolution }), - ]); + vectorLayer.setStyle((feature, resolution) => { + return onModify + ? [ + new Style({ + image: new CircleStyle({ + radius: 5, + fill: new Fill({ + color: 'orange', + }), + }), + geometry: function (feature) { + // return the coordinates of the first ring of the polygon + const coordinates = feature.getGeometry().getCoordinates()[0]; + return new MultiPoint(coordinates); + }, + }), + getStyles({ style, feature, resolution }), + ] + : [getStyles({ style, feature, resolution })]; + }); }, [vectorLayer, style, setStyle]); useEffect(() => { @@ -254,7 +260,6 @@ const VectorLayer = ({ }); function pointerMovefn(event) { vectorLayer.getFeatures(event.pixel).then((features) => { - console.log(selection, 'selection'); if (!features.length) { selection = {}; hoverEffect(undefined, vectorLayer); diff --git a/src/frontend/src/components/common/Button.tsx b/src/frontend/src/components/common/Button.tsx index 49168f80e7..a5f69f748d 100644 --- a/src/frontend/src/components/common/Button.tsx +++ b/src/frontend/src/components/common/Button.tsx @@ -12,6 +12,7 @@ interface IButton { icon?: React.ReactNode; isLoading?: boolean; disabled?: boolean; + loadingText?: string; } const btnStyle = (btnType, className) => { @@ -24,13 +25,25 @@ const btnStyle = (btnType, className) => { case 'other': return `fmtm-py-1 fmtm-px-5 fmtm-bg-red-500 fmtm-text-white fmtm-rounded-lg hover:fmtm-bg-red-600`; case 'disabled': - return `fmtm-py-1 fmtm-px-4 fmtm-text-white fmtm-rounded-lg fmtm-bg-gray-400 fmtm-cursor-not-allowed`; + return `fmtm-py-1 fmtm-px-4 fmtm-text-white fmtm-rounded-lg fmtm-bg-gray-400 fmtm-cursor-not-allowed ${className}`; default: return 'fmtm-primary'; } }; -const Button = ({ btnText, btnType, type, onClick, disabled, className, count, dataTip, icon, isLoading }: IButton) => ( +const Button = ({ + btnText, + btnType, + type, + onClick, + disabled, + className, + count, + dataTip, + icon, + isLoading, + loadingText, +}: IButton) => (
diff --git a/src/frontend/src/components/createnewproject/SplitTasks.tsx b/src/frontend/src/components/createnewproject/SplitTasks.tsx index 22234d128d..55e92b5ff6 100644 --- a/src/frontend/src/components/createnewproject/SplitTasks.tsx +++ b/src/frontend/src/components/createnewproject/SplitTasks.tsx @@ -61,6 +61,7 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo (state) => state.createproject.taskSplittingGeojsonLoading, ); const isTasksGenerated = CoreModules.useAppSelector((state) => state.createproject.isTasksGenerated); + const isFgbFetching = CoreModules.useAppSelector((state) => state.createproject.isFgbFetching); const toggleStep = (step, url) => { dispatch(CommonActions.SetCurrentStepFormStep({ flag: flag, step: step })); @@ -130,7 +131,6 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo } else { projectData = { ...projectData, task_split_dimension: projectDetails.dimension }; } - console.log(projectData, 'projectData'); dispatch( CreateProjectService( `${import.meta.env.VITE_API_URL}/projects/create_project`, @@ -379,8 +379,9 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo className="" icon={} disabled={ - splitTasksSelection === task_split_type['task_splitting_algorithm'] && - !formValues?.average_buildings_per_task + (splitTasksSelection === task_split_type['task_splitting_algorithm'] && + !formValues?.average_buildings_per_task) || + isFgbFetching ? true : false } @@ -426,6 +427,11 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo splittedGeojson={dividedTaskGeojson} uploadedOrDrawnGeojsonFile={drawnGeojson} buildingExtractedGeojson={dataExtractGeojson} + onModify={(geojson) => { + handleCustomChange('drawnGeojson', geojson); + dispatch(CreateProjectActions.SetDividedTaskGeojson(JSON.parse(geojson))); + setGeojsonFile(null); + }} />
{generateProjectLog ? ( diff --git a/src/frontend/src/components/createnewproject/UploadArea.tsx b/src/frontend/src/components/createnewproject/UploadArea.tsx index 01f3c93281..2bcba1ce65 100644 --- a/src/frontend/src/components/createnewproject/UploadArea.tsx +++ b/src/frontend/src/components/createnewproject/UploadArea.tsx @@ -31,7 +31,7 @@ const uploadAreaOptions = [ }, ]; -const UploadArea = ({ flag, geojsonFile, setGeojsonFile }) => { +const UploadArea = ({ flag, geojsonFile, setGeojsonFile, setCustomLineUpload, setCustomPolygonUpload }) => { const dispatch = useDispatch(); const navigate = useNavigate(); // const [uploadAreaFile, setUploadAreaFile] = useState(null); @@ -264,6 +264,9 @@ const UploadArea = ({ flag, geojsonFile, setGeojsonFile }) => { handleCustomChange('drawnGeojson', geojson); dispatch(CreateProjectActions.SetDrawnGeojson(JSON.parse(geojson))); dispatch(CreateProjectActions.SetTotalAreaSelection(area)); + dispatch(CreateProjectActions.ClearProjectStepState()); + setCustomLineUpload(null); + setCustomPolygonUpload(null); setGeojsonFile(null); }} /> diff --git a/src/frontend/src/store/slices/CreateProjectSlice.ts b/src/frontend/src/store/slices/CreateProjectSlice.ts index 7f9cc75856..5de2a1cea2 100755 --- a/src/frontend/src/store/slices/CreateProjectSlice.ts +++ b/src/frontend/src/store/slices/CreateProjectSlice.ts @@ -48,6 +48,7 @@ export const initialState: CreateProjectStateTypes = { isUnsavedChanges: false, canSwitchCreateProjectSteps: false, isTasksGenerated: { divide_on_square: false, task_splitting_algorithm: false }, + isFgbFetching: false, }; const CreateProject = createSlice({ @@ -215,6 +216,15 @@ const CreateProject = createSlice({ [action.payload.key]: action.payload.value, }; }, + SetFgbFetchingStatus(state, action) { + state.isFgbFetching = action.payload; + }, + ClearProjectStepState(state) { + state.dividedTaskGeojson = null; + state.splitTasksSelection = null; + state.dataExtractGeojson = null; + state.projectDetails = { ...state.projectDetails, customLineUpload: null, customPolygonUpload: null }; + }, }, }); diff --git a/src/frontend/src/store/types/ICreateProject.ts b/src/frontend/src/store/types/ICreateProject.ts index 900dff66de..bd7fd27e08 100644 --- a/src/frontend/src/store/types/ICreateProject.ts +++ b/src/frontend/src/store/types/ICreateProject.ts @@ -34,6 +34,7 @@ export type CreateProjectStateTypes = { isUnsavedChanges: boolean; canSwitchCreateProjectSteps: boolean; isTasksGenerated: {}; + isFgbFetching: boolean; }; export type ValidateCustomFormResponse = { detail: { message: string; possible_reason: string }; diff --git a/src/frontend/src/views/CreateNewProject.tsx b/src/frontend/src/views/CreateNewProject.tsx index 14f6ac96bb..271d9b4dc1 100644 --- a/src/frontend/src/views/CreateNewProject.tsx +++ b/src/frontend/src/views/CreateNewProject.tsx @@ -61,7 +61,15 @@ const CreateNewProject = () => { case '/create-project': return ; case '/upload-area': - return ; + return ( + + ); case '/select-form': return ( void; + onDraw?: (geojson: any, area: number) => void; + onModify?: (geojson: any, area?: number) => void; }; const NewDefineAreaMap = ({ drawToggle, @@ -51,7 +52,7 @@ const NewDefineAreaMap = ({ constrainResolution: true, duration: 500, }} - zoomToLayer + onModify={onModify} /> )} {isDrawOrGeojsonFile && !splittedGeojson && (