Skip to content

Commit

Permalink
Merge pull request #196 from hotosm/feat/add-project-image
Browse files Browse the repository at this point in the history
Feat: download waypoints geojson, user profile update and other UI fixes
  • Loading branch information
nrjadkry authored Sep 9, 2024
2 parents 96befe9 + ceb1065 commit 5009c99
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useParams } from 'react-router-dom';
import { motion } from 'framer-motion';
import { Button } from '@Components/RadixComponents/Button';
import Tab from '@Components/common/Tabs';
import { useGetIndividualTaskQuery } from '@Api/tasks';
import { useGetIndividualTaskQuery, useGetTaskWaypointQuery } from '@Api/tasks';
import { useTypedDispatch, useTypedSelector } from '@Store/hooks';
import { setSecondPageState } from '@Store/actions/droneOperatorTask';
import hasErrorBoundary from '@Utils/hasErrorBoundary';
Expand All @@ -23,6 +23,16 @@ const DroneOperatorDescriptionBox = () => {
const { data: taskDescription }: Record<string, any> =
useGetIndividualTaskQuery(taskId as string);

const { data: taskWayPoints }: any = useGetTaskWaypointQuery(
projectId as string,
taskId as string,
{
select: (data: any) => {
return data.data.features;
},
},
);

useEffect(() => {
setAnimated(true);
setTimeout(() => {
Expand Down Expand Up @@ -110,22 +120,52 @@ const DroneOperatorDescriptionBox = () => {
);
};

const downloadGeojson = () => {
if (!taskWayPoints) return;
const waypointGeojson = {
type: 'FeatureCollection',
features: taskWayPoints,
};
const fileBlob = new Blob([JSON.stringify(waypointGeojson)], {
type: 'application/json',
});
const url = window.URL.createObjectURL(fileBlob);
const link = document.createElement('a');
link.href = url;
link.download = 'waypoint.geojson';
document.body.appendChild(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
};

return (
<>
<div className="naxatw-flex naxatw-w-full naxatw-flex-col naxatw-items-start naxatw-gap-3 lg:naxatw-gap-5">
<div className="naxatw-flex naxatw-w-full naxatw-items-center naxatw-justify-between naxatw-self-stretch">
<p className="naxatw-text-[0.875rem] naxatw-font-normal naxatw-leading-normal naxatw-text-[#484848]">
Task #{taskDescription?.project_task_index}
</p>
<Button
variant="ghost"
className="naxatw-border naxatw-border-[#D73F3F] naxatw-text-[0.875rem] naxatw-text-[#D73F3F]"
leftIcon="download"
iconClassname="naxatw-text-[1.125rem]"
onClick={() => handleDownloadFlightPlan()}
>
Download Flight Plan
</Button>
<div className="naxatw-flex naxatw-gap-1">
<Button
variant="ghost"
className="naxatw-border naxatw-border-[#D73F3F] naxatw-text-[0.875rem] naxatw-text-[#D73F3F]"
leftIcon="download"
iconClassname="naxatw-text-[1.125rem]"
onClick={() => downloadGeojson()}
>
Download Geojson
</Button>
<Button
variant="ghost"
className="naxatw-border naxatw-border-[#D73F3F] naxatw-text-[0.875rem] naxatw-text-[#D73F3F]"
leftIcon="download"
iconClassname="naxatw-text-[1.125rem]"
onClick={() => handleDownloadFlightPlan()}
>
Download Flight Plan
</Button>
</div>
</div>
<Tab
onTabChange={value => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function VectorLayerWithCluster({
filter: ['!', ['has', 'point_count']],
paint: {
'circle-color': '#11b4da',
'circle-radius': 6,
'circle-radius': 8,
'circle-stroke-width': 1,
'circle-stroke-color': '#fff',
},
Expand Down
69 changes: 48 additions & 21 deletions src/frontend/src/components/Projects/MapSection/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
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 getBbox from '@turf/bbox';
import { useCallback, useEffect, useState } from 'react';
import { FeatureCollection } from 'geojson';
import AsyncPopup from '@Components/common/MapLibreComponents/AsyncPopup';
import { LngLatBoundsLike, Map } from 'maplibre-gl';
import VectorLayerWithCluster from './VectorLayerWithCluster';

const ProjectsMapSection = () => {
const [projectProperties, setProjectProperties] = useState<
Record<string, any>
>({});
const navigate = useNavigate();
const { map, isMapLoaded } = useMapLibreGLMap({
containerId: 'dashboard-map',
mapOptions: {
zoom: 5,
center: [84.124, 28.3949],
zoom: 0,
center: [0, 0],
maxZoom: 19,
},
disableRotation: true,
Expand All @@ -23,7 +33,17 @@ const ProjectsMapSection = () => {
(acc: Record<string, any>, current: Record<string, any>) => {
return {
...acc,
features: [...acc.features, centroid(current.outline)],
features: [
...acc.features,
{
...centroid(current.outline),
properties: {
id: current?.id,
name: current?.name,
slug: current?.slug,
},
},
],
};
},
{
Expand All @@ -35,11 +55,19 @@ const ProjectsMapSection = () => {
},
});

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

const getPopupUI = useCallback(() => {
return (
<div>
<h3>{projectProperties?.name}</h3>
</div>
);
}, [projectProperties]);

return (
<MapContainer
Expand All @@ -61,21 +89,20 @@ const ProjectsMapSection = () => {
geojson={projectsList}
/>

{/* <VectorLayer
<AsyncPopup
map={map as Map}
isMapLoaded={isMapLoaded}
id="uploaded-project-area"
geojson={projectsList as GeojsonType}
visibleOnMap={true}
layerOptions={{
type: 'fill',
paint: {
'fill-color': '#328ffd',
'fill-outline-color': '#000000',
'fill-opacity': 0.8,
},
title={projectProperties?.slug}
showPopup={(feature: Record<string, any>) =>
feature?.layer?.id === 'unclustered-point'
}
popupUI={getPopupUI}
fetchPopupData={(properties: Record<string, any>) => {
setProjectProperties(properties);
}}
/> */}
buttonText="Go To Project"
handleBtnClick={() => navigate(`./${projectProperties?.id}`)}
getCoordOnProperties
/>
</MapContainer>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/components/Projects/ProjectCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function ProjectCard({
<div
role="presentation"
onClick={onProjectCardClick}
className="!naxatw-col-span-1 naxatw-h-[16rem] naxatw-cursor-pointer naxatw-rounded-md naxatw-border naxatw-border-grey-400 naxatw-p-[0.625rem] naxatw-transition-all naxatw-duration-300 naxatw-ease-in-out hover:-naxatw-translate-y-1 hover:naxatw-scale-100 hover:naxatw-shadow-xl"
className="!naxatw-col-span-1 naxatw-cursor-pointer naxatw-rounded-md naxatw-border naxatw-border-grey-400 naxatw-p-[0.625rem] naxatw-transition-all naxatw-duration-300 naxatw-ease-in-out hover:-naxatw-translate-y-1 hover:naxatw-scale-100 hover:naxatw-shadow-xl"
>
<p className="naxatw-flex naxatw-h-[10rem] naxatw-w-full naxatw-items-center naxatw-justify-center naxatw-bg-grey-50">
{imageUrl ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ export default function BasicDetails({ formProps }: { formProps: any }) {
<FormControl>
<Label required>Phone number</Label>
<div className="naxatw-flex naxatw-space-x-1">
<Input
{/* <Input
placeholder="+977"
className="naxatw-mt-1 naxatw-w-14"
{...register('country_code', {
required: 'Phone Number is Required',
})}
/>
/> */}
<Input
placeholder="Enter Phone number"
className="naxatw-mt-1 naxatw-w-full"
Expand Down
4 changes: 2 additions & 2 deletions src/frontend/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const projectCreatorKeys = [
'organization_address',
'job_title',
'confirm_password',
'country_code',
// 'country_code',
];

// keys only present in drone operator form
Expand All @@ -77,5 +77,5 @@ export const droneOperatorKeys = [
'certified_drone_operator',
'drone_you_own',
'confirm_password',
'country_code',
// 'country_code',
];
2 changes: 1 addition & 1 deletion src/frontend/src/store/slices/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const initialState: CommonState = {
modalContent: null,
showPromptDialog: false,
promptDialogContent: null,
showMap: false,
showMap: true,
openSignInMenu: false,
userProfileActiveTab: 1,
isCertifiedDroneUser: 'no',
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/src/views/Projects/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ const Projects = () => {
<div className="naxatw-grid naxatw-gap-2 md:naxatw-flex md:naxatw-h-[calc(100vh-8.5rem)]">
<div
className={`scrollbar naxatw-grid naxatw-grid-rows-[16rem] naxatw-gap-3 naxatw-overflow-y-auto naxatw-py-2 ${showMap ? 'naxatw-w-full naxatw-grid-cols-1 md:naxatw-w-1/2 md:naxatw-grid-cols-2 lg:naxatw-grid-cols-3' : 'naxatw-w-full naxatw-grid-cols-1 sm:naxatw-grid-cols-2 md:naxatw-grid-cols-4 lg:naxatw-grid-cols-6'}`}
style={{ gridAutoRows: '16rem' }}
>
{isLoading ? (
<>
{Array.from({ length: 8 }, (_, index) => (
{Array.from({ length: 6 }, (_, index) => (
<ProjectCardSkeleton key={index} />
))}
</>
Expand Down
16 changes: 9 additions & 7 deletions src/frontend/src/views/UserProfile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,20 @@ const UserProfile = () => {
const userProfileActiveTab = useTypedSelector(
state => state.common.userProfileActiveTab,
);

const userProfile = getLocalStorageValue('userprofile');

const initialState = {
name: userProfile?.name,
country: '',
city: null,
country: userProfile?.country || null,
city: userProfile?.city || null,
password: null,
confirm_password: null,
phone_number: null,
// country_code: userProfile?.country_code || null,
phone_number: userProfile?.phone_number || null,
// for project creators
organization_name: null,
organization_address: null,
job_title: null,
organization_name: userProfile?.organization_name || null,
organization_address: userProfile?.organization_address || null,
job_title: userProfile?.job_title || null,
// for drone operators
notify_for_projects_within_km: null,
experience_years: null,
Expand All @@ -92,6 +92,7 @@ const UserProfile = () => {
mutationFn: payloadDataObject => postUserProfile(payloadDataObject),
onSuccess: () => {
toast.success('UserProfile Updated Successfully');
dispatch(setCommonState({ userProfileActiveTab: 1 }));
navigate('/projects');
},
onError: err => {
Expand All @@ -107,6 +108,7 @@ const UserProfile = () => {
);
return;
}

const finalFormData = isDroneOperator
? removeKeysFromObject(formData, projectCreatorKeys)
: removeKeysFromObject(formData, droneOperatorKeys);
Expand Down

0 comments on commit 5009c99

Please sign in to comment.