Skip to content

Commit

Permalink
Merge pull request #193 from hotosm/feat/add-project-image
Browse files Browse the repository at this point in the history
Feat: Add project image, base-layer switcher and locate user
  • Loading branch information
nrjadkry authored Sep 5, 2024
2 parents ddc2080 + d8137e5 commit f5ae21e
Show file tree
Hide file tree
Showing 24 changed files with 477 additions and 215 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ const CreateprojectLayout = () => {
const measurementType = useTypedSelector(
state => state.createproject.measurementType,
);
const projectImage = useTypedSelector(
state => state.createproject.projectMapImage,
);
const capturedProjectMap = useTypedSelector(
state => state.createproject.capturedProjectMap,
);

const initialState: FieldValues = {
name: '',
Expand Down Expand Up @@ -202,6 +208,7 @@ const CreateprojectLayout = () => {
}

if (activeStep === 4 && !splitGeojson) return;

if (activeStep !== 5) {
dispatch(setCreateProjectState({ activeStep: activeStep + 1 }));
return;
Expand All @@ -225,6 +232,8 @@ const CreateprojectLayout = () => {
// make form data with value JSON stringify to combine value on single json / form data with only 2 keys (backend didn't found project_info on non-stringified data)
const formData = new FormData();
formData.append('project_info', JSON.stringify({ ...refactoredData }));
formData.append('image', projectImage.projectMapImage);

if (isTerrainFollow) {
formData.append('dem', data?.dem?.[0]?.file);
}
Expand Down Expand Up @@ -265,7 +274,8 @@ const CreateprojectLayout = () => {
className="!naxatw-bg-red !naxatw-text-white"
rightIcon="chevron_right"
withLoader
isLoading={isLoading || isCreatingProject}
isLoading={isLoading || isCreatingProject || !capturedProjectMap}
disabled={isLoading || isCreatingProject || !capturedProjectMap}
>
{activeStep === 5 ? 'Save' : 'Next'}
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { contributionsInfo } from '@Constants/createProject';

export default function Contributions() {
return (
<div className="naxatw-px-10 naxatw-py-5">
<p className="naxatw-text-body-btn">Conditions for Contributions</p>
<p className="naxatw-mt-2 naxatw-text-body-md">
Fill in your project basic information such as name, description,
hashtag, etc.
</p>
return contributionsInfo?.map(info => (
<div className="naxatw-px-10 naxatw-py-5" key={info.key}>
<p className="naxatw-text-body-btn">{info.key}</p>
<p className="naxatw-mt-2 naxatw-text-body-md">{info.description}</p>
</div>
);
));
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { DefineAOIInfo } from '@Constants/createProject';

export default function DefineAOI() {
return (
<div className="naxatw-px-10 naxatw-py-5">
<p className="naxatw-text-body-btn">Define Area Of Interest (AOI)</p>
<p className="naxatw-mt-2 naxatw-text-body-md">
Fill in your project basic information such as name, description,
hashtag, etc.
</p>
return DefineAOIInfo?.map(info => (
<div className="naxatw-px-2 naxatw-py-2" key={info.key}>
<p className="naxatw-text-body-btn">{info.key}</p>
<p className="naxatw-py-1 naxatw-text-body-md">{info.description}</p>
</div>
);
));
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export default function GenerateTask() {
return (
<div className="naxatw-px-10 naxatw-py-5">
<p className="naxatw-text-body-btn">Conditions for Contributions</p>
<p className="naxatw-text-body-btn">Generate task</p>
<p className="naxatw-mt-2 naxatw-text-body-md">
Fill in your project basic information such as name, description,
hashtag, etc.
Split the task into smaller chunks based on the given dimensions to
ensure more efficient and precise data collection and analysis.
</p>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { useTypedSelector } from '@Store/hooks';
import { FlexColumn, FlexRow } from '@Components/common/Layouts';
import { keyParamsDescriptions } from '@Constants/createProject';
import {
keyParametersInfo,
keyParamsDescriptions,
} from '@Constants/createProject';

export default function KeyParameters() {
const keyParamOption = useTypedSelector(
state => state.createproject.keyParamOption,
);

return (
<>
<div className="scrollbar naxatw-max-h-[65vh] naxatw-overflow-y-auto naxatw-px-2">
{keyParamOption === 'basic' ? (
<div className="naxatw-animate-fade-up naxatw-p-5">
<p className="naxatw-text-body-btn">
Ground Sampling Distance (meter)
</p>
<p className="naxatw-mt-2 naxatw-text-body-md">
Fill in your project basic information such as name, description,
hashtag, etc.
</p>
</div>
keyParametersInfo?.map(info => (
<div className="naxatw-animate-fade-up naxatw-py-2" key={info.key}>
<p className="naxatw-text-body-btn">{info.key}</p>
<p className="naxatw-py-1 naxatw-text-body-md">
{info.description}
</p>
</div>
))
) : (
<FlexColumn gap={2} className="naxatw-animate-fade-up">
{keyParamsDescriptions.map(desc => (
Expand All @@ -31,6 +34,6 @@ export default function KeyParameters() {
))}
</FlexColumn>
)}
</>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import useDrawTool from '@Components/common/MapLibreComponents/useDrawTool';
import { drawStyles } from '@Constants/map';
import { setCreateProjectState } from '@Store/actions/createproject';
import hasErrorBoundary from '@Utils/hasErrorBoundary';
import BaseLayerSwitcherUI from '@Components/common/BaseLayerSwitcher';
import LocateUser from '@Components/common/MapLibreComponents/LocateUser';

const MapSection = ({
onResetButtonClick,
Expand Down Expand Up @@ -104,6 +106,9 @@ const MapSection = ({
position: 'relative',
}}
>
<BaseLayerSwitcherUI />
<LocateUser isMapLoaded={isMapLoaded} />

{(drawNoFlyZoneEnable || drawProjectAreaEnable) && (
<div className="naxatw-absolute naxatw-right-[calc(50%_-_75px)] naxatw-top-2 naxatw-z-50 naxatw-flex naxatw-h-9 naxatw-w-[150px] naxatw-rounded-lg naxatw-bg-white">
<div className="naxatw-flex naxatw-w-full naxatw-items-center naxatw-justify-evenly">
Expand Down Expand Up @@ -173,8 +178,6 @@ const MapSection = ({
},
}}
/>

<BaseLayerSwitcher />
</MapContainer>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useCallback, useEffect } from 'react';
import { useTypedSelector } from '@Store/hooks';
import { LngLatBoundsLike, Map } from 'maplibre-gl';
import { useMapLibreGLMap } from '@Components/common/MapLibreComponents';
Expand All @@ -9,13 +9,20 @@ import { GeojsonType } from '@Components/common/MapLibreComponents/types';
import getBbox from '@turf/bbox';
import { FeatureCollection } from 'geojson';
import hasErrorBoundary from '@Utils/hasErrorBoundary';
import { useTypedDispatch } from '@UserModule/store/hooks';
import {
saveProjectImageFile,
setCreateProjectState,
} from '@Store/actions/createproject';

const MapSection = () => {
const dispatch = useTypedDispatch();
const { map, isMapLoaded } = useMapLibreGLMap({
mapOptions: {
zoom: 5,
center: [84.124, 28.3949],
maxZoom: 19,
preserveDrawingBuffer: true,
},
disableRotation: true,
});
Expand All @@ -26,13 +33,50 @@ const MapSection = () => {
const splitGeojson = useTypedSelector(
state => state.createproject.splitGeojson,
);
const capturedProjectMap = useTypedSelector(
state => state.createproject.capturedProjectMap,
);

useEffect(() => {
if (!projectArea) return;
const bbox = getBbox(projectArea as FeatureCollection);
map?.fitBounds(bbox as LngLatBoundsLike, { padding: 25 });
}, [map, projectArea]);

// eslint-disable-next-line no-unused-vars
const takeScreenshot = useCallback(async () => {
if (!map || !isMapLoaded || !splitGeojson) return;
// const data = map.getCanvas().toDataURL('image/jpeg', 0.95);
map.getCanvas().toBlob(
(blob: any) => {
const file = new File([blob], 'project.png', { type: blob.type });
dispatch(
saveProjectImageFile({
projectMapImage: file,
}),
);
dispatch(
setCreateProjectState({
capturedProjectMap: true,
}),
);
},
'image/png',
0.95,
);
}, [map, dispatch, isMapLoaded, splitGeojson]);

useEffect(() => {
if (!map || !isMapLoaded || !splitGeojson || capturedProjectMap)
return () => {};
// wait 1sec for split geojson is loaded and visible on map and capture
const captureTimeout = setTimeout(() => {
takeScreenshot();
}, 1000);

return () => clearTimeout(captureTimeout);
}, [map, takeScreenshot, isMapLoaded, splitGeojson, capturedProjectMap]);

return (
<MapContainer
map={map}
Expand All @@ -42,6 +86,7 @@ const MapSection = () => {
height: '448px',
}}
>
<BaseLayerSwitcher />
{!splitGeojson && (
<VectorLayer
map={map as Map}
Expand Down Expand Up @@ -69,12 +114,24 @@ const MapSection = () => {
type: 'fill',
paint: {
'fill-color': '#328ffd',
'fill-outline-color': '#D33A38',
'fill-opacity': 0.2,
},
}}
/>
<BaseLayerSwitcher />
<VectorLayer
map={map as Map}
isMapLoaded={isMapLoaded}
id="split-area-outline"
geojson={splitGeojson as GeojsonType}
visibleOnMap={!!splitGeojson}
layerOptions={{
type: 'line',
paint: {
'line-color': '#D33A38',
'line-width': 1,
},
}}
/>
</MapContainer>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export default function GenerateTask({ formProps }: { formProps: any }) {
className="naxatw-mt-4 naxatw-bg-red"
onClick={() => {
if (!projectArea) return;
dispatch(
setCreateProjectState({
splitGeojson: null,
capturedProjectMap: false,
}),
);
mutate(payload);
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ import PreviewImage from './PreviewImage';

const ImageBoxPopOver = () => {
const dispatch = useTypedDispatch();
const { projectId, taskId } = useParams();

// const { taskId, projectId } = useParams();
const pathname = window.location.pathname?.split('/');
const projectId = pathname?.[2];
const taskId = pathname?.[4];

const uploadedFilesNumber = useRef(0);
const [imageObject, setImageObject] = useState<any[]>([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { useGetTaskWaypointQuery } from '@Api/tasks';
import getBbox from '@turf/bbox';
import { coordAll } from '@turf/meta';
import { useMapLibreGLMap } from '@Components/common/MapLibreComponents';
import BaseLayerSwitcher from '@Components/common/MapLibreComponents/BaseLayerSwitcher';
import VectorLayer from '@Components/common/MapLibreComponents/Layers/VectorLayer';
import MapContainer from '@Components/common/MapLibreComponents/MapContainer';
import { GeojsonType } from '@Components/common/MapLibreComponents/types';
import right from '@Assets/images/rightArrow.png';
import marker from '@Assets/images/marker.png';
import hasErrorBoundary from '@Utils/hasErrorBoundary';
import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup';
import BaseLayerSwitcherUI from '@Components/common/BaseLayerSwitcher';
import LocateUser from '@Components/common/MapLibreComponents/LocateUser';

const MapSection = () => {
const { projectId, taskId } = useParams();
Expand Down Expand Up @@ -99,6 +100,9 @@ const MapSection = () => {
height: '100%',
}}
>
<BaseLayerSwitcherUI />
<LocateUser isMapLoaded={isMapLoaded} />

{taskWayPoints && (
<>
{/* render line */}
Expand Down Expand Up @@ -182,8 +186,6 @@ const MapSection = () => {
hideButton
getCoordOnProperties
/>

<BaseLayerSwitcher />
</MapContainer>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ 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 BaseLayerSwitcher from '@Components/common/MapLibreComponents/BaseLayerSwitcher';
import { GeojsonType } from '@Components/common/MapLibreComponents/types';
import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup';
import getBbox from '@turf/bbox';
import { FeatureCollection } from 'geojson';
import { LngLatBoundsLike, Map } from 'maplibre-gl';
import { GeolocateControl, LngLatBoundsLike, Map } from 'maplibre-gl';
import { setProjectState } from '@Store/actions/project';
import {
useGetProjectsDetailQuery,
Expand All @@ -23,6 +22,9 @@ import { postTaskStatus } from '@Services/project';
import { useMutation } from '@tanstack/react-query';
import { toast } from 'react-toastify';
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 Legend from './Legend';

const MapSection = () => {
Expand Down Expand Up @@ -156,6 +158,9 @@ const MapSection = () => {
height: '100%',
}}
>
<BaseLayerSwitcherUI isMapLoaded={isMapLoaded} />
<LocateUser isMapLoaded={isMapLoaded} />

{projectArea && (
<VectorLayer
map={map as Map}
Expand Down Expand Up @@ -288,7 +293,6 @@ const MapSection = () => {
}
/>
<Legend />
<BaseLayerSwitcher />
</MapContainer>
);
};
Expand Down
Loading

0 comments on commit f5ae21e

Please sign in to comment.