Skip to content

Commit

Permalink
Fix crash activating contextual layers
Browse files Browse the repository at this point in the history
  • Loading branch information
JoaquinTrinanes committed Aug 30, 2022
1 parent 21270a9 commit fb9072d
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const Legend: React.FC = () => {

const dispatch = useAppDispatch();
const { data: upstreamLayers } = useContextualLayers();

const { layers } = useAppSelector(analysisMap);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback, useMemo } from 'react';

import { useAppDispatch } from 'store/hooks';
import { setLayer } from 'store/features/analysis/map';
import { setLayer, setLayerDeckGLProps } from 'store/features/analysis/map';

import LegendItem from 'components/legend/item';
import type { Layer } from 'types';
Expand All @@ -10,6 +10,7 @@ import LegendTypeCategorical from 'components/legend/types/categorical';
import LegendTypeChoropleth from 'components/legend/types/choropleth';
import LegendTypeGradient from 'components/legend/types/gradient';
import { useContextualLayer } from 'hooks/layers/contextual';
import useContextualLayers from 'hooks/layers/getContextualLayers';

interface ContextualLegendItemProps {
layer: Layer;
Expand All @@ -18,11 +19,13 @@ interface ContextualLegendItemProps {
const ContextualLegendItem: React.FC<ContextualLegendItemProps> = ({ layer }) => {
const dispatch = useAppDispatch();

const { isLoading } = useContextualLayer(layer.id);
const { isFetching: areLayersLoading } = useContextualLayers();
const { isFetching: isFetchingData } = useContextualLayer(layer.id);

const handleActive = useCallback(
(active) => {
(active: boolean) => {
dispatch(setLayer({ id: layer.id, layer: { active } }));
dispatch(setLayerDeckGLProps({ id: layer.id, props: { visible: active } }));
},
[dispatch, layer],
);
Expand Down Expand Up @@ -60,7 +63,7 @@ const ContextualLegendItem: React.FC<ContextualLegendItemProps> = ({ layer }) =>

return (
<LegendItem
isLoading={isLoading}
isLoading={areLayersLoading || isFetchingData}
name="Baseline water stress"
info={layer.metadata.description}
opacity={layer.opacity}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,36 +84,41 @@ const AnalysisMap: React.FC = () => {
const contextualData = useAllContextualLayersData();

const layers = useMemo(() => {
const legends = Object.values(layerDeckGLProps).map((props) => {
const layerInfo = layersMetadata[props.id];

const data = layerInfo.isContextual ? contextualData.get(props.id)?.data : impactData;

return new H3HexagonLayer({
...props,
data,
getHexagon: (d) => d.h,
getFillColor: (d) => d.c,
getLineColor: (d) => d.c,
onHover: ({ object, x, y, viewport }) => {
dispatch(
setTooltipPosition({
x,
y,
viewport: viewport ? { width: viewport.width, height: viewport.height } : null,
}),
);
dispatch(
setTooltipData({
id: props.id,
name: layerInfo.metadata?.name || layerInfo.metadata?.legend.name,
value: object?.v,
unit: layerInfo.metadata?.legend.unit,
}),
);
},
});
});
const legends = Object.values(layerDeckGLProps)
.map((props) => {
const layerInfo = layersMetadata[props.id];
if (!layerInfo) {
return null;
}

const data = layerInfo.isContextual ? contextualData.get(props.id)?.data : impactData;

return new H3HexagonLayer({
...props,
data,
getHexagon: (d) => d.h,
getFillColor: (d) => d.c,
getLineColor: (d) => d.c,
onHover: ({ object, x, y, viewport }) => {
dispatch(
setTooltipPosition({
x,
y,
viewport: viewport ? { width: viewport.width, height: viewport.height } : null,
}),
);
dispatch(
setTooltipData({
id: props.id,
name: layerInfo.metadata?.name || layerInfo.metadata?.legend.name,
value: object?.v,
unit: layerInfo.metadata?.legend.unit,
}),
);
},
});
})
.filter((l) => !!l);
return sortBy(legends, (l) => layersMetadata[l.id].order).reverse();
}, [contextualData, dispatch, impactData, layerDeckGLProps, layersMetadata]);

Expand Down
18 changes: 6 additions & 12 deletions client/src/hooks/h3-data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,7 @@ const fetchContextualLayerData: QueryFunction<
// Adding color to the response
.then((response) => responseContextualParser(response));

export const useH3ContextualData = (
id: string,
// params: Partial<WaterH3APIParams>,
options: Partial<UseQueryOptions>,
): H3ContextualResponse => {
export const useH3ContextualData = (id: string, options: Partial<UseQueryOptions> = {}) => {
const filters = useAppSelector(analysisFilters);
const { startYear, materials, indicator, suppliers, origins, locationTypes } = filters;
const urlParams = {
Expand All @@ -200,6 +196,7 @@ export const useH3ContextualData = (
...(locationTypes?.length ? { locationTypes: locationTypes?.map(({ value }) => value) } : {}),
resolution: origins?.length ? 6 : 4,
};

const query = useQuery(['h3-data-contextual', id, urlParams], fetchContextualLayerData, {
...DEFAULT_QUERY_OPTIONS,
placeholderData: {
Expand All @@ -213,7 +210,7 @@ export const useH3ContextualData = (
},
},
...options,
enabled: options.enabled && !!id && !!urlParams.year,
enabled: (options.enabled ?? true) && !!id && !!urlParams.year,
});

const { data, isError } = query;
Expand All @@ -228,7 +225,7 @@ export const useH3ContextualData = (
);
};

export const useAllContextualLayersData = (options?: Partial<UseQueryOptions>) => {
export const useAllContextualLayersData = (options: Partial<UseQueryOptions> = {}) => {
const { layers } = useAppSelector(analysisMap);
const filters = useAppSelector(analysisFilters);
const { startYear, materials, indicator, suppliers, origins, locationTypes } = filters;
Expand All @@ -250,11 +247,8 @@ export const useAllContextualLayersData = (options?: Partial<UseQueryOptions>) =
queryFn: fetchContextualLayerData,
...DEFAULT_QUERY_OPTIONS,
...options,
enabled:
('enabled' in (options || {}) ? options.enabled : true) &&
layer.active &&
!!layer.id &&
!!urlParams.year,
keepPreviousData: true,
enabled: (options.enabled ?? true) && layer.active && !!layer.id && !!urlParams.year,
select: (data: H3APIResponse) => ({ ...data, layerId: layer.id }),
})),
);
Expand Down
64 changes: 13 additions & 51 deletions client/src/hooks/layers/contextual.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,30 @@
import { useEffect } from 'react';

import { useAppDispatch, useAppSelector } from 'store/hooks';
import { analysisMap, setLayer, setLayerDeckGLProps } from 'store/features/analysis/map';
import { analysisMap, setLayerDeckGLProps } from 'store/features/analysis/map';

import { useH3ContextualData } from 'hooks/h3-data';
import type { Layer } from 'types';

export const useContextualLayer: (id: Layer['id']) => ReturnType<typeof useH3ContextualData> = (
id,
) => {
export const useContextualLayer = (id: Layer['id']) => {
const dispatch = useAppDispatch();
const {
layers: { [id]: layerInfo },
} = useAppSelector(analysisMap);

const query = useH3ContextualData(id, { enabled: layerInfo.active });
const { data, isFetching, isFetched } = query;

// Populating legend
useEffect(() => {
if (data && isFetching) {
const query = useH3ContextualData(id, {
enabled: layerInfo.active,
onSuccess: () => {
dispatch(
setLayer({
id,
layer: {
loading: isFetching,
},
}),
);
}
if (data && isFetched) {
dispatch(
setLayer({
id,
layer: {
loading: isFetching,
setLayerDeckGLProps({
id: layerInfo.id,
props: {
id: layerInfo.id,
opacity: layerInfo.opacity,
visible: layerInfo.active,
},
}),
);
}
}, [data, isFetched, dispatch, isFetching, id]);

useEffect(() => {
if (!isFetched) return;
dispatch(
setLayerDeckGLProps({
id: layerInfo.id,
props: {
id: layerInfo.id,
opacity: layerInfo.opacity,
visible: layerInfo.active,
// data: data.data,
},
}),
);
}, [
data.data,
dispatch,
isFetched,
layerInfo.active,
layerInfo.id,
layerInfo.metadata.name,
layerInfo.opacity,
]);
},
});

return query;
};
15 changes: 14 additions & 1 deletion client/src/hooks/layers/getContextualLayers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { UseQueryResult } from 'react-query';
import { useQuery } from 'react-query';
import { apiRawService } from 'services/api';
import { setLayer } from 'store/features/analysis/map';
import { useAppDispatch } from 'store/hooks';
import type { LayerMetadata } from 'types';

interface ContextualLayerApiResponse {
Expand All @@ -15,12 +17,23 @@ interface ApiResponse {
}

const useContextualLayers = () => {
const dispatch = useAppDispatch();
const query = useQuery<UseQueryResult<ApiResponse>, unknown, ContextualLayerApiResponse[]>(
['contextual-layers'],
async () => apiRawService.get('/contextual-layers/categories'),
() => apiRawService.get('/contextual-layers/categories'),
{
select: ({ data }) =>
data.data.flatMap((d) => d.layers).map((layer, i) => ({ ...layer, order: i + 1 })),
onSuccess: (data) => {
data.forEach((layer) => {
dispatch(
setLayer({
id: layer.id,
layer: { ...layer, isContextual: true },
}),
);
});
},
},
);

Expand Down
46 changes: 22 additions & 24 deletions client/src/store/features/analysis/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,40 +108,38 @@ export const analysisMapSlice = createSlice({
layer: Partial<Layer>;
}>,
) => {
// only one contextual layer active at the same time, set the rest as disabled
if (
'active' in action.payload.layer &&
action.payload.layer.active &&
(('isContextual' in action.payload.layer && action.payload.layer.isContextual) ||
state.layers[action.payload.id]?.isContextual)
) {
Object.keys(state.layers).forEach((layerId) => {
const layer = state.layers[layerId];
if (layer.active && layerId !== action.payload.id && layer.isContextual) {
layer.active = false;
}
});
}
const layers = {
...state.layers,
[action.payload.id]: {
...DEFAULT_LAYER_ATTRIBUTES,
...state.layers[action.payload.id],
...action.payload.layer,
},
};

state.layers[action.payload.id] = {
...DEFAULT_LAYER_ATTRIBUTES,
...state.layers[action.payload.id],
...action.payload.layer,
return {
...state,
layers,
};
},
setLayerDeckGLProps: (
state,
action: PayloadAction<{
id: Layer['id'];
props: DeckGLConstructorProps;
props: Partial<DeckGLConstructorProps>;
}>,
) => {
state.layerDeckGLProps[action.payload.id] = {
...DEFAULT_DECKGL_PROPS,
...state.layerDeckGLProps[action.payload.id],
...action.payload.props,
return {
...state,
layerDeckGLProps: {
...state.layerDeckGLProps,
[action.payload.id]: {
...DEFAULT_DECKGL_PROPS,
...state.layerDeckGLProps[action.payload.id],
...action.payload.props,
},
},
};
return state;
},
setLayerOrder: (state, action: PayloadAction<Layer['id'][]>) => {
Object.values(state.layers).forEach((layer) => {
Expand Down

1 comment on commit fb9072d

@vercel
Copy link

@vercel vercel bot commented on fb9072d Aug 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.