Skip to content

Commit

Permalink
Merge pull request #144 from hotosm/feat/task-description
Browse files Browse the repository at this point in the history
Feat: implement api on task description and download flight plan
  • Loading branch information
varun2948 authored Aug 14, 2024
2 parents acf93d0 + 23dad7d commit d454edd
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 27 deletions.
17 changes: 15 additions & 2 deletions src/frontend/src/api/tasks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */
import { getTaskWaypoint } from '@Services/tasks';
import { getIndividualTask, getTaskWaypoint } from '@Services/tasks';
import { useQuery, UseQueryOptions } from '@tanstack/react-query';

export const useGetTaskWaypointQuery = (
Expand All @@ -8,10 +8,23 @@ export const useGetTaskWaypointQuery = (
queryOptions?: Partial<UseQueryOptions>,
) => {
return useQuery({
queryKey: ['task-description'],
queryKey: ['task-waypoints'],
enabled: !!(projectId && taskId),
queryFn: () => getTaskWaypoint(projectId, taskId),
select: (res: any) => res.data,
...queryOptions,
});
};

export const useGetIndividualTaskQuery = (
taskId: string,
queryOptions?: Partial<UseQueryOptions>,
) => {
return useQuery({
queryKey: ['task-description'],
enabled: !!taskId,
queryFn: () => getIndividualTask(taskId),
select: (res: any) => res.data,
...queryOptions,
});
};
Binary file added src/frontend/src/assets/images/marker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { v4 as uuidv4 } from 'uuid';

interface IDescriptionBoxComponentProps {
title: string;
data: {
Expand All @@ -21,7 +19,7 @@ const DescriptionBoxComponent = ({
{data?.map(item => (
<div
className="naxatw-flex naxatw-w-full naxatw-gap-2"
key={uuidv4()}
key={item.name}
>
<p className="naxatw-w-[6.875rem] naxatw-text-[0.75rem] naxatw-text-[#484848]">
{item.name}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,76 @@
import { v4 as uuidv4 } from 'uuid';

import { useParams } from 'react-router-dom';
import { useGetIndividualTaskQuery } from '@Api/tasks';
import { useTypedSelector } from '@Store/hooks';

import { descriptionData, descriptionTitle } from '@Constants/droneOperator';
import DescriptionBoxComponent from './DescriptionComponent';
import QuestionBox from '../QuestionBox';

const DescriptionBox = () => {
const secondPageStates = useTypedSelector(state => state.droneOperatorTask);
const { secondPage } = secondPageStates;
const { taskId } = useParams();

const { data: taskDescription }: Record<string, any> =
useGetIndividualTaskQuery(taskId as string, {
select: (data: any) => {
const { data: taskData } = data;
return [
{
id: 1,
title: 'Task Description',
data: [
{
name: 'Total task area',
value: taskData?.task_area ? `${taskData?.task_area} km²` : '-',
},
{
name: 'Est. flight time',
value: taskData?.flight_time || '-',
},
],
},
{
id: 2,
title: 'Flight Parameters',
data: [
{ name: 'Altitude', value: taskData?.altitude || '-' },
{
name: 'Gimble Angle',
value: taskData?.gimble_angles_degrees
? `${taskData?.gimble_angles_degrees} degree`
: '-',
},
{
name: 'Front Overlap',
value: taskData?.front_overlap
? `${taskData?.front_overlap}%`
: '-',
},
{
name: 'Side Overlap',
value: taskData?.side_overlap
? `${taskData?.side_overlap}%`
: '-',
},
{
name: 'Starting Point Altitude',
value: taskData?.starting_point_altitude
? `${taskData?.starting_point_altitude}%`
: '-',
},
],
},
];
},
});

return (
<>
{/* --------------Generates Description Boxes --------------------- */}
<div className="naxatw-flex naxatw-flex-col naxatw-gap-5">
{descriptionData.map((details, index) => (
{taskDescription?.map((description: Record<string, any>) => (
<DescriptionBoxComponent
title={descriptionTitle[index]}
data={details}
key={uuidv4()}
key={description.id}
title={description.title}
data={description?.data}
/>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
/* eslint-disable no-nested-ternary */
import { useState, useEffect } from 'react';
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 { useTypedDispatch, useTypedSelector } from '@Store/hooks';
import { setSecondPageState } from '@Store/actions/droneOperatorTask';

import UploadsBox from './UploadsBox';
import DescriptionBox from './DescriptionBox';

const { BASE_URL } = process.env;

const DroneOperatorDescriptionBox = () => {
const { taskId, projectId } = useParams();
const secondPageStates = useTypedSelector(state => state.droneOperatorTask);
const { secondPageState, secondPage } = secondPageStates;
const [animated, setAnimated] = useState(false);

const { data: taskDescription }: Record<string, any> =
useGetIndividualTaskQuery(taskId as string);

useEffect(() => {
setAnimated(true);
setTimeout(() => {
Expand All @@ -24,6 +31,7 @@ const DroneOperatorDescriptionBox = () => {
open: { opacity: 1, y: 0 },
closed: { opacity: 0, y: '50%' },
};

const renderComponent = (role: string) => {
switch (role) {
case 'description':
Expand Down Expand Up @@ -73,18 +81,28 @@ const DroneOperatorDescriptionBox = () => {
},
];

const handleDownloadFlightPlan = () => {
const link = document.createElement('a');
link.setAttribute('download', '');
link.href = `${BASE_URL}/waypoint/task/${taskId}/?project_id=${projectId}&download=true`;
document.body.appendChild(link);
link.click();
link.remove();
};

return (
<>
<div className="naxatw-flex naxatw-w-full naxatw-flex-col naxatw-items-start 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 #74936
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>
Expand Down
19 changes: 16 additions & 3 deletions src/frontend/src/components/DroneOperatorTask/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import { useGetIndividualTaskQuery } from '@Api/tasks';
import { useNavigate, useParams } from 'react-router-dom';

const DroneOperatorTaskHeader = () => {
const navigate = useNavigate();
const { taskId } = useParams();

const { data: taskDescription }: Record<string, any> =
useGetIndividualTaskQuery(taskId as string);

return (
<>
<div className="naxatw-self-stretch naxatw-py-3">
<div className="naxatw-flex naxatw-items-center naxatw-gap-1">
<p className="naxatw-text-sm naxatw-font-normal naxatw-leading-normal naxatw-tracking-[0.0175rem] naxatw-text-[#212121]">
Dashboard
<p
className="naxatw-cursor-pointer naxatw-text-sm naxatw-font-normal naxatw-leading-normal naxatw-tracking-[0.0175rem] naxatw-text-[#212121] hover:naxatw-underline"
role="presentation"
onClick={() => navigate('/projects')}
>
Projects
</p>
<p className="naxatw-text-sm naxatw-font-normal naxatw-leading-normal naxatw-tracking-[0.0175rem] naxatw-text-[#212121]">
/
</p>
<p className="naxatw-text-sm naxatw-font-semibold naxatw-leading-normal naxatw-tracking-[0.0175rem] naxatw-text-[#212121]">
St. Lucia Damage Assessment Drone Survey
{taskDescription?.project_name || '-'}
</p>
</div>
</div>
Expand Down
20 changes: 16 additions & 4 deletions src/frontend/src/components/DroneOperatorTask/MapSection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import VectorLayer from '@Components/common/MapLibreComponents/Layers/VectorLaye
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';

const MapSection = () => {
const { projectId, taskId } = useParams();
Expand Down Expand Up @@ -95,7 +96,7 @@ const MapSection = () => {

return (
<>
<div className="naxatw-h-[70vh] naxatw-w-full naxatw-rounded-xl naxatw-bg-gray-200">
<div className="naxatw-h-[calc(100vh-180px)] naxatw-w-full naxatw-rounded-xl naxatw-bg-gray-200">
<MapContainer
map={map}
isMapLoaded={isMapLoaded}
Expand Down Expand Up @@ -124,9 +125,13 @@ const MapSection = () => {
hasImage
image={right}
symbolPlacement="line"
iconAnchor="center"
/>
{taskWayPoints?.geojsonListOfPoint?.map(
(point: any, index: number) => {
const lastPoint =
Number(taskWayPoints?.geojsonListOfPoint?.length) - 1;

return (
<VectorLayer
key={`waypoint-points-vtLayer-${index}`}
Expand All @@ -138,11 +143,18 @@ const MapSection = () => {
layerOptions={{
type: 'circle',
paint: {
'circle-color': index === 0 ? 'red' : '#176149',
'circle-opacity': 0.8,
'circle-radius': index === 0 ? 9 : 6,
'circle-color': '#176149',
'circle-stroke-width': 2,
'circle-stroke-color': 'red',
'circle-stroke-opacity':
index === 0 || index === lastPoint ? 0 : 1,
'circle-opacity':
index === 0 || index === lastPoint ? 0 : 1,
},
}}
hasImage={index === 0}
image={marker}
iconAnchor="bottom"
/>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default function VectorLayer({
hasImage = false,
image,
symbolPlacement = 'point',
iconAnchor = 'center',
}: IVectorLayer) {
const sourceId = useMemo(() => id.toString(), [id]);
const hasInteractions = useRef(false);
Expand Down Expand Up @@ -61,8 +62,9 @@ export default function VectorLayer({
layout: {
'symbol-placement': symbolPlacement,
'icon-image': imageId,
'icon-size': 1,
'icon-size': 0.8,
'icon-overlap': 'always',
'icon-anchor': iconAnchor,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ export interface IVectorLayer extends ILayer {
hasImage?: boolean;
image?: any;
symbolPlacement?: 'point' | 'line' | 'line-center';
iconAnchor?:
| 'center'
| 'left'
| 'right'
| 'top'
| 'bottom'
| 'top-left'
| 'top-right'
| 'bottom-left'
| 'bottom-right';
}

type InteractionsType = 'hover' | 'select';
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/src/services/tasks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* eslint-disable import/prefer-default-export */
import { api, authenticated } from '.';

export const getTaskWaypoint = (projectId: string, taskId: string) =>
authenticated(api).get(
`/waypoint/task/${taskId}/?project_id=${projectId}&download=false`,
);

export const getIndividualTask = (taskId: string) =>
authenticated(api).get(`/tasks/${taskId}/`);
2 changes: 1 addition & 1 deletion src/frontend/src/views/TaskDescription/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import MapSection from '@Components/DroneOperatorTask/MapSection';
const TaskDescription = () => {
return (
<>
<div className="naxatw-min-h-[calc(100vh-99px)]">
<div className="naxatw-min-h-[calc(100vh-60px)]">
<div className="naxatw-mx-auto naxatw-w-11/12 naxatw-max-w-[90rem] naxatw-px-8 naxatw-pb-[2.9375rem] naxatw-pt-3">
<div className="naxatw-flex naxatw-flex-col naxatw-gap-3">
<DroneOperatorTaskHeader />
Expand Down

0 comments on commit d454edd

Please sign in to comment.