Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: download waypoints geojson, user profile update and other UI fixes #196

Merged
merged 9 commits into from
Sep 9, 2024
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