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(front): upload shapefile on new project [MARXAN-519] #333

Merged
merged 23 commits into from
Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion app/hooks/map/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,37 @@
import { useMemo } from 'react';
import {
UseAdminPreviewLayer, UsePUGridLayer, UsePUGridPreviewLayer, UseWDPAPreviewLayer,
UseAdminPreviewLayer, UseGeoJSONLayer, UsePUGridLayer, UsePUGridPreviewLayer, UseWDPAPreviewLayer,
} from './types';

// GeoJSON
export function useGeoJsonLayer({
id, active, data,
}: UseGeoJSONLayer) {
return useMemo(() => {
if (!active || !id || !data) return null;

return {
id: `${id}`,
type: 'geojson',
source: {
type: 'geojson',
data,
},
render: {
layers: [
{
type: 'line',
paint: {
'line-color': '#FFF',
'line-width': 3,
},
},
],
},
};
}, [id, active, data]);
}

// AdminPreview
export function useAdminPreviewLayer({
active, country, region, subregion,
Expand Down
5 changes: 5 additions & 0 deletions app/hooks/map/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export interface UseGeoJSONLayer {
id: string;
active?: boolean;
data: Record<string, unknown>;
}
export interface UseAdminPreviewLayer {
active?: boolean;
bbox?: number[];
Expand Down
32 changes: 32 additions & 0 deletions app/hooks/projects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ItemProps } from 'components/projects/item/component';
import { PublishedItemProps } from 'components/projects/published-item/component';

import PROJECTS from 'services/projects';
import UPLOADS from 'services/uploads';

import {
UseProjectsOptionsProps,
Expand All @@ -20,6 +21,8 @@ import {
SaveProjectProps,
UseDeleteProjectProps,
DeleteProjectProps,
UseUploadProjectPAProps,
UploadProjectPAProps,
UsePublishedProjectsProps,
} from './types';

Expand Down Expand Up @@ -222,6 +225,35 @@ export function useDeleteProject({
});
}

export function useUploadProjectPA({
requestConfig = {
method: 'POST',
},
}: UseUploadProjectPAProps) {
const [session] = useSession();

const uploadProjectPAShapefile = ({ data }: UploadProjectPAProps) => {
return UPLOADS.request({
url: '/projects/planning-area/shapefile',
data,
headers: {
Authorization: `Bearer ${session.accessToken}`,
'Content-Type': 'multipart/form-data',
},
...requestConfig,
});
};

return useMutation(uploadProjectPAShapefile, {
onSuccess: (data: any, variables, context) => {
console.info('Succces', data, variables, context);
},
onError: (error, variables, context) => {
console.info('Error', error, variables, context);
},
});
}

export function usePublishedProjects(options: UsePublishedProjectsProps = {}) {
const [session] = useSession();

Expand Down
9 changes: 9 additions & 0 deletions app/hooks/projects/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ export interface DeleteProjectProps {
id: string
}

// useUploadProjectPA
export interface UseUploadProjectPAProps {
requestConfig?: AxiosRequestConfig
}
export interface UploadProjectPAProps {
id?: string,
data: any,
}

// usePublicProjects
export interface UsePublishedProjectsProps {
search?: string;
Expand Down
133 changes: 85 additions & 48 deletions app/layout/projects/new/form/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import Link from 'next/link';

import ProjectNewMap from 'layout/projects/new/map';

import Icon from 'components/icon';
import Field from 'components/forms/field';
import Label from 'components/forms/label';
import Input from 'components/forms/input';
import Textarea from 'components/forms/textarea';
import Button from 'components/button';
import InfoButton from 'components/info-button';

import UPLOAD_SHAPEFILE_SVG from 'svgs/ui/upload.svg?sprite';
import CountryRegionSelector from 'layout/projects/new/form/country-region-selector';
import PlanningAreaSelector from 'layout/projects/new/form/planning-area-selector';
import PlanningAreaUploader from 'layout/projects/new/form/planning-area-uploader';

import {
composeValidators,
Expand All @@ -24,9 +25,10 @@ import { useOrganizations } from 'hooks/organizations';
import { useSaveProject } from 'hooks/projects';
import { useToasts } from 'hooks/toast';

import { setBbox, setMaxPuAreaSize, setMinPuAreaSize } from 'store/slices/projects/new';
import {
setBbox, setMaxPuAreaSize, setMinPuAreaSize, setUploadingPlanningArea,
} from 'store/slices/projects/new';

import PlanningAreaSelector from './planning-area-selector';
import ProjectFormProps from './types';
import { DEFAULT_AREA } from './constants';

Expand All @@ -46,6 +48,7 @@ const ProjectForm: React.FC<ProjectFormProps> = () => {
dispatch(setBbox(null));
dispatch(setMinPuAreaSize(null));
dispatch(setMaxPuAreaSize(null));
dispatch(setUploadingPlanningArea(null));
};
}, [dispatch]);

Expand Down Expand Up @@ -86,14 +89,27 @@ const ProjectForm: React.FC<ProjectFormProps> = () => {
});
};

const resetPlanningArea = (form) => {
dispatch(setUploadingPlanningArea(null));
dispatch(setBbox(null));

const registeredFields = form.getRegisteredFields();
registeredFields.forEach((f) => {
const omitFields = ['name', 'description', 'planningUnitGridShape'];
if (!omitFields.includes(f)) {
form.change(f, null);
}
});
};

return (
<FormRFF
onSubmit={onSubmit}
initialValues={{
...DEFAULT_AREA,
}}
>
{({ handleSubmit, values }) => (
{({ form, handleSubmit, values }) => (
<form
onSubmit={handleSubmit}
autoComplete="off"
Expand Down Expand Up @@ -140,54 +156,76 @@ const ProjectForm: React.FC<ProjectFormProps> = () => {
</div>

{/* PLANNING AREA */}
<div className="flex items-center justify-between mt-6">
<div className="flex items-center">
<Label theme="dark" className="mr-2 uppercase text-xxs">Planning area</Label>
<InfoButton>
<span>Planning area info button.</span>
</InfoButton>
</div>
{/* TEMPORARILY HIDDEN, it will be implemented in the future */}
<div className="hidden">
<Button
className="w-20 h-6 mr-4"
size="xs"
theme={!hasPlanningArea ? 'white' : 'secondary'}
onClick={() => setHasPlanningArea(false)}
>
No
</Button>
<Button
className="w-20 h-6"
size="xs"
theme={hasPlanningArea ? 'white' : 'secondary'}
onClick={() => setHasPlanningArea(true)}
>
Yes
</Button>
<div className="flex flex-col justify-between mt-6">
<h2 className="mb-5 text-lg font-medium font-heading">Do you have a planning region shapefile of your own?</h2>

<div className="flex flex-row items-center justify-between">
<div className="flex flex-row">
<Label theme="dark" className="mr-2 uppercase text-xxs">Planning area</Label>
<InfoButton>
<span>Planning area info button.</span>
</InfoButton>
</div>
<div className="flex flex-row">
<Button
className="w-20 h-6 mr-4"
size="xs"
theme={hasPlanningArea !== null && !hasPlanningArea ? 'white' : 'secondary'}
onClick={() => {
setHasPlanningArea(false);
resetPlanningArea(form);
}}
>
No
</Button>
<Button
className="w-20 h-6"
size="xs"
theme={hasPlanningArea ? 'white' : 'secondary'}
onClick={() => {
setHasPlanningArea(true);
resetPlanningArea(form);
}}
>
Yes
</Button>
</div>
</div>
</div>

{!hasPlanningArea && (
<PlanningAreaSelector
values={values}
/>
{hasPlanningArea !== null && !hasPlanningArea && (
<>
<CountryRegionSelector
country={values.countryId}
region={values.adminAreaLevel1Id}
subRegion={values.adminAreaLevel2Id}
/>
<PlanningAreaSelector
values={values}
/>
</>
)}

{hasPlanningArea && (
<Button
className="flex w-full mt-4"
theme="secondary"
size="base"
onClick={() => console.info('Upload shapefile')}
>
<span className="w-full">
Upload shapefile
</span>
<Icon
icon={UPLOAD_SHAPEFILE_SVG}
/>
</Button>
<>
<FieldRFF
name="planningAreaId"
validate={composeValidators([{ presence: true }])}
>
{(fprops) => {
return (
<PlanningAreaUploader
{...fprops}
resetPlanningArea={resetPlanningArea}
form={form}
/>
);
}}
</FieldRFF>
<PlanningAreaSelector
values={values}
/>
</>
)}
</div>
<div className="absolute bottom-0 left-0 z-10 w-full h-6 pointer-events-none bg-gradient-to-t from-gray-700 via-gray-700" />
Expand Down Expand Up @@ -224,7 +262,6 @@ const ProjectForm: React.FC<ProjectFormProps> = () => {
subregion={values.adminAreaLevel2Id}
planningUnitGridShape={values.planningUnitGridShape}
planningUnitAreakm2={values.planningUnitAreakm2}

/>
</div>
</form>
Expand Down
19 changes: 5 additions & 14 deletions app/layout/projects/new/form/planning-area-selector/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,18 @@ import {

import { useSelector } from 'react-redux';

import { PlanningAreaSelectorProps } from './types';
import PlanningUnitGrid from 'layout/projects/new/form/planning-area-selector/planning-unit-grid';
import PlanningUnitAreaSize from 'layout/projects/new/form/planning-area-selector/planning-unit-area-size';

import CountryRegionSelector from './country-region-selector';
import PlanningUnitGrid from './planning-unit-grid';
import PlanningUnitAreaSize from './planning-unit-area-size';
import { PlanningAreaSelectorProps } from './types';

export const PlanningAreaSelector: React.FC<PlanningAreaSelectorProps> = ({
values,
}: PlanningAreaSelectorProps) => {
const {
countryId,
adminAreaLevel1Id,
adminAreaLevel2Id,
planningUnitGridShape,
planningAreaId,
} = values;

const {
Expand All @@ -31,13 +29,7 @@ export const PlanningAreaSelector: React.FC<PlanningAreaSelectorProps> = ({

return (
<div>
<CountryRegionSelector
country={countryId}
region={adminAreaLevel1Id}
subRegion={adminAreaLevel2Id}
/>

{!!countryId && (
{(!!countryId || !!planningAreaId) && (
<div className="flex">
<div className="flex w-1/2">
<FieldRFF
Expand All @@ -49,7 +41,6 @@ export const PlanningAreaSelector: React.FC<PlanningAreaSelectorProps> = ({
<PlanningUnitGrid
unit={planningUnitGridShape}
onChange={(value) => {
// React Final Form onChange
fprops.input.onChange(value);
}}
/>
Expand Down
Loading