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

[FE] (feat): Inventory panel: Protected Areas [MRXN23-239] #1456

Merged
merged 28 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4c5ef48
WIP
andresgnlez Aug 28, 2023
ae500b8
fix data empty
anamontiaga Aug 28, 2023
3ca3b82
list protected areas by mock
anamontiaga Aug 28, 2023
c57998d
bulk remove
anamontiaga Aug 28, 2023
53c6c12
rname folder
anamontiaga Aug 28, 2023
8fb75e3
edit protected area
anamontiaga Aug 28, 2023
4748efa
sort by full name
anamontiaga Aug 29, 2023
abece78
fix data item types
anamontiaga Aug 29, 2023
064c636
save visible protected areas in store
anamontiaga Aug 29, 2023
843268f
show preview protected areas on inventory map
anamontiaga Aug 29, 2023
f1c42ab
protected areas modal ui
anamontiaga Aug 29, 2023
155741e
upload shapefile and csv wdpas hooks
anamontiaga Aug 29, 2023
0e21210
add search to params
anamontiaga Aug 29, 2023
116dc9a
remove csv uploader
anamontiaga Aug 29, 2023
90336c3
fix naming on toggle map
anamontiaga Aug 29, 2023
fd77e57
header item scalability
anamontiaga Aug 30, 2023
e01d8ca
pass classname to column
anamontiaga Aug 31, 2023
cb55062
remove promise all from edit
anamontiaga Aug 31, 2023
5483990
update get protected areas response
anamontiaga Sep 5, 2023
6094cf7
remove selector from wdpa categories hook
anamontiaga Sep 5, 2023
a15b063
delete single item
anamontiaga Sep 5, 2023
217e3e4
edit name
anamontiaga Sep 5, 2023
502a6cc
disable header checkbox if there is no custom items
anamontiaga Sep 5, 2023
5ad8b4a
update list
anamontiaga Sep 6, 2023
36d3438
invalidate query after upload
anamontiaga Sep 6, 2023
58c08dd
ui
anamontiaga Sep 6, 2023
d0919e5
custom filtering
anamontiaga Sep 6, 2023
90ea9d3
fix upload info btn content
anamontiaga Sep 11, 2023
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
2 changes: 1 addition & 1 deletion app/constants/file-uploader-size-limits.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
export const PLANNING_UNIT_UPLOADER_MAX_SIZE = 1048576; // 1MiB
export const PLANNING_AREA_UPLOADER_MAX_SIZE = 1048576; // 1MiB
export const PLANNING_AREA_GRID_UPLOADER_MAX_SIZE = 10485760; // 10MiB
export const PROTECTED_AREA_UPLOADER_MAX_SIZE = 10485760; // 10MiB
export const PROTECTED_AREA_UPLOADER_SHAPEFILE_MAX_SIZE = 10485760; // 10MiB
export const FEATURES_UPLOADER_SHAPEFILE_MAX_SIZE = 20971520; // 20MiB
export const FEATURES_UPLOADER_CSV_MAX_SIZE = 52428800; // 50MiB
export const COST_SURFACE_UPLOADER_MAX_SIZE = 20971520; // 20MiB
Expand Down
1 change: 0 additions & 1 deletion app/hooks/map/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ export function useWDPAPreviewLayer({
options,
}: UseWDPAPreviewLayer) {
const { opacity = 1, visibility = true } = options || {};

return useMemo(() => {
if (!active || !bbox) return null;

Expand Down
127 changes: 105 additions & 22 deletions app/hooks/wdpa/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import { useMemo } from 'react';

import { useMutation, useQuery } from 'react-query';
import { useMutation, useQuery, QueryObserverOptions, useQueryClient } from 'react-query';

import { AxiosRequestConfig } from 'axios';
import { useSession } from 'next-auth/react';

import SCENARIOS from 'services/scenarios';
import WDPA from 'services/wdpa';
import { Project } from 'types/api/project';
import { Scenario } from 'types/api/scenario';
import { WDPA } from 'types/api/wdpa';

import {
UseWDPACategoriesProps,
UseSaveScenarioProtectedAreasProps,
SaveScenarioProtectedAreasProps,
} from './types';
import { API } from 'services/api';
import SCENARIOS from 'services/scenarios';
import UPLOADS from 'services/uploads';

export function useWDPACategories({
adminAreaId,
customAreaId,
scenarioId,
}: UseWDPACategoriesProps) {
}: {
adminAreaId?: WDPA['id'];
customAreaId?: WDPA['id'];
scenarioId: Scenario['id'];
}) {
const { data: session } = useSession();

return useQuery(
['protected-areas', adminAreaId, customAreaId],
async () =>
WDPA.request({
API.request({
method: 'GET',
url: `/${scenarioId}/protected-areas`,
url: `scenarios/${scenarioId}/protected-areas`,
params: {
...(adminAreaId && {
'filter[adminAreaId]': adminAreaId,
Expand All @@ -40,7 +42,6 @@ export function useWDPACategories({
}).then(({ data }) => data),
{
enabled: !!adminAreaId || !!customAreaId,
select: ({ data }) => data,
}
);
}
Expand All @@ -49,10 +50,24 @@ export function useSaveScenarioProtectedAreas({
requestConfig = {
method: 'POST',
},
}: UseSaveScenarioProtectedAreasProps) {
}: {
requestConfig?: AxiosRequestConfig;
}) {
const { data: session } = useSession();

const saveScenarioProtectedAreas = ({ id, data }: SaveScenarioProtectedAreasProps) => {
const saveScenarioProtectedAreas = ({
id,
data,
}: {
id: Scenario['id'];
data: {
areas: {
id: string;
selected: boolean;
}[];
threshold: number;
};
}) => {
return SCENARIOS.request({
url: `/${id}/protected-areas`,
data,
Expand All @@ -63,12 +78,80 @@ export function useSaveScenarioProtectedAreas({
});
};

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

export function useProjectWDPAs<T = WDPA[]>(
pid: Project['id'],
params: { search?: string; sort?: string; filters?: Record<string, unknown> } = {},
queryOptions: QueryObserverOptions<WDPA[], Error, T> = {}
) {
const { data: session } = useSession();

return useQuery({
queryKey: ['wdpas', pid],
queryFn: async () =>
API.request<{ data: WDPA[] }>({
method: 'GET',
url: `/projects/${pid}/protected-areas`,
headers: {
Authorization: `Bearer ${session.accessToken}`,
},
params,
}).then(({ data }) => data.data),
enabled: Boolean(pid),
...queryOptions,
});
}

export function useEditWDPA({
requestConfig = {
method: 'PATCH',
},
}) {
const { data: session } = useSession();

const saveProjectWDPA = ({ wdpaId, data }: { wdpaId: string; data: { name: string } }) => {
return API.request({
method: 'PATCH',
url: `/protected-areas/${wdpaId}`,
data,
headers: {
Authorization: `Bearer ${session.accessToken}`,
},
...requestConfig,
});
};

return useMutation(saveProjectWDPA);
}

export function useUploadWDPAsShapefile({
requestConfig = {
method: 'POST',
},
}: {
requestConfig?: AxiosRequestConfig<FormData>;
}) {
const queryClient = useQueryClient();
const { data: session } = useSession();

const uploadWDPAShapefile = ({ id, data }: { id: Project['id']; data: FormData }) => {
return UPLOADS.request<{ success: true }>({
url: `/projects/${id}/protected-areas/shapefile`,
data,
headers: {
Authorization: `Bearer ${session.accessToken}`,
'Content-Type': 'multipart/form-data',
},
...requestConfig,
} as typeof requestConfig);
};

return useMutation(uploadWDPAShapefile, {
onSuccess: async (data, variables) => {
const { id: projectId } = variables;
await queryClient.invalidateQueries(['wdpas', projectId]);
},
});
}
16 changes: 0 additions & 16 deletions app/hooks/wdpa/types.ts

This file was deleted.

24 changes: 24 additions & 0 deletions app/layout/info/upload-wdpas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export const UploadWDPAsInfoButtonContent = (): JSX.Element => {
return (
<div className="space-y-2.5 text-xs">
<h4 className="mb-2.5 font-heading">
When uploading shapefiles of protected areas, please make sure that:
</h4>
<ul className="list-disc space-y-1 pl-6">
<li>this is a single zip file that includes all the components of a single shapefile;</li>
<li>
all the components are added to the “root”/top-level of the zip file itself (that is, not
within any folder within the zip file);
</li>
<li>
user-defined shapefile attributes are only considered for shapefiles of features, while
they are ignored for any other kind of shapefile (planning grid, lock-in/out, etc), so you
may consider excluding any attributes from shapefiles other than for features, in order to
keep the shapefile’s file size as small as possible.
</li>
</ul>
</div>
);
};

export default UploadWDPAsInfoButtonContent;
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ const InventoryTable = ({
}: InventoryTable): JSX.Element => {
const noData = !loading && data?.length === 0;

const noDataCustom = !loading && data?.every((item) => !item.isCustom);

return (
<>
{loading && !data.length && (
{loading && !data?.length && (
<div className="relative min-h-[200px]">
<Loading
visible={true}
Expand All @@ -43,6 +45,7 @@ const InventoryTable = ({
theme="light"
className="block h-4 w-4 checked:bg-blue-400"
onChange={onSelectAll}
disabled={noDataCustom}
/>
</th>
{columns.map((column) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const RowItem = ({
className="block h-4 w-4 checked:bg-blue-400"
onChange={onSelectRow}
value={id}
checked={selectedIds.includes(id)}
checked={isCustom && selectedIds.includes(id)}
disabled={!isCustom}
/>
</td>
Expand Down Expand Up @@ -70,7 +70,13 @@ const RowItem = ({
{isCustom && (
<Popover>
<PopoverTrigger asChild>
<button type="button" className="h-5 w-5">
<button
type="button"
className={cn({
'h-5 w-5': true,
invisible: !isCustom,
})}
>
<HiDotsHorizontal className="h-4 w-4 text-white" />
</button>
</PopoverTrigger>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ChangeEvent } from 'react';

import { WDPAAttributes } from 'types/api/wdpa';

export type DataItem = {
id: string;
attributes?: WDPAAttributes;
name: string;
scenarios: number;
tag?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import FeatureUploadModal from './features/modals/upload';
import { InventoryPanel } from './types';
import ProtectedAreasTable from './wdpas';
import ProtectedAreasFooter from './wdpas/footer';
import WDPAUploadModal from './wdpas/modals/upload';

export const INVENTORY_TABS = {
'protected-areas': {
Expand All @@ -17,6 +18,7 @@ export const INVENTORY_TABS = {
noData: 'No protected areas found.',
TableComponent: ProtectedAreasTable,
FooterComponent: ProtectedAreasFooter,
UploadModalComponent: WDPAUploadModal,
},
'cost-surface': {
title: 'Cost Surface',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ const InventoryPanelFeatures = ({ noData: noDataMessage }: { noData: string }):
const handleSort = useCallback(
(_sortType: (typeof filters)['sort']) => {
const sort = filters.sort === _sortType ? `-${_sortType}` : _sortType;

setFilters((prevFilters) => ({
...prevFilters,
sort,
Expand Down
Loading
Loading