Improve navigation handling in new map app

This commit is contained in:
Maciej Ziarkowski 2021-02-24 07:48:09 +00:00
parent 305f2f1671
commit 2afc7f8c8f
7 changed files with 39 additions and 36 deletions

View File

@ -129,7 +129,7 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
}, },
}, },
[Category.Sustainability]: { [Category.Sustainability]: {
mapStyle: 'sust_Dec', mapStyle: 'sust_dec',
legend: { legend: {
title: 'Sustainability', title: 'Sustainability',
description: 'DEC Rating', description: 'DEC Rating',

View File

@ -1,6 +1,6 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { Building } from '../models/building'; import { Building, BuildingAttributeVerificationCounts } from '../models/building';
import { apiGet } from '../apiHelpers'; import { apiGet } from '../apiHelpers';
export function useBuildingData(buildingId: number, preloadedData: Building): [Building, (updatedBuilding: Building) => void, () => void] { export function useBuildingData(buildingId: number, preloadedData: Building): [Building, (updatedBuilding: Building) => void, () => void] {
@ -29,6 +29,13 @@ export function useBuildingData(buildingId: number, preloadedData: Building): [B
setIsOld(false); setIsOld(false);
}, [buildingId]); }, [buildingId]);
const updateData = useCallback((building: Building) => {
if(building.verified == undefined) {
building.verified = {} as BuildingAttributeVerificationCounts;
}
setBuildingData(building);
}, []);
useEffect(() => { useEffect(() => {
return () => { return () => {
setIsOld(true); setIsOld(true);
@ -43,5 +50,5 @@ export function useBuildingData(buildingId: number, preloadedData: Building): [B
const reloadData = useCallback(() => setIsOld(true), []); const reloadData = useCallback(() => setIsOld(true), []);
return [buildingData, setBuildingData, reloadData]; return [buildingData, updateData, reloadData];
} }

View File

@ -1,7 +1,11 @@
import { usePrevious } from './use-previous'; import { useEffect, useState } from 'react';
export function useLastNotEmpty<T>(value: T): T { export function useLastNotEmpty<T>(value: T): T {
const previousValue = usePrevious(value); const [notEmpty, setNotEmpty] = useState(value);
useEffect(() => {
if(value != undefined) {
setNotEmpty(value);
}
}, [value]);
return value ?? previousValue; return notEmpty;
} }

View File

@ -1,10 +0,0 @@
import { useEffect, useRef } from 'react';
export function usePrevious<T>(value: T) {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
}

View File

@ -46,14 +46,14 @@ function setOrToggle<T>(currentValue: T, newValue: T): T {
export const MapApp: React.FC<MapAppProps> = props => { export const MapApp: React.FC<MapAppProps> = props => {
const [categoryUrlParam] = useUrlCategoryParam(); const [categoryUrlParam] = useUrlCategoryParam();
const [selectedBuildingId, setSelectedBuildingId] = useUrlBuildingParam();
const [mode] = useUrlModeParam();
const [currentCategory, setCategory] = useState<Category>(); const [currentCategory, setCategory] = useState<Category>();
useEffect(() => setCategory(unless(categoryUrlParam, 'categories')), [categoryUrlParam]); useEffect(() => setCategory(unless(categoryUrlParam, 'categories')), [categoryUrlParam]);
const displayCategory = useLastNotEmpty(currentCategory) ?? defaultMapCategory; const displayCategory = useLastNotEmpty(currentCategory) ?? defaultMapCategory;
const [selectedBuildingId, setSelectedBuildingId] = useUrlBuildingParam('view', displayCategory);
const [building, updateBuilding, reloadBuilding] = useBuildingData(selectedBuildingId, props.building); const [building, updateBuilding, reloadBuilding] = useBuildingData(selectedBuildingId, props.building);
const [buildingLike, updateBuildingLike] = useBuildingLikeData(selectedBuildingId, props.building_like); const [buildingLike, updateBuildingLike] = useBuildingLikeData(selectedBuildingId, props.building_like);
const [userVerified, updateUserVerified, reloadUserVerified] = useUserVerifiedData(selectedBuildingId, props.user_verified); const [userVerified, updateUserVerified, reloadUserVerified] = useUserVerifiedData(selectedBuildingId, props.user_verified);
@ -63,13 +63,15 @@ export const MapApp: React.FC<MapAppProps> = props => {
updateRevisionId(building?.revision_id) updateRevisionId(building?.revision_id)
}, [building]); }, [building]);
const [mode] = useUrlModeParam();
const viewEditMode = unless(mode, 'multi-edit'); const viewEditMode = unless(mode, 'multi-edit');
const [multiEditData, multiEditError] = useMultiEditData(); const [multiEditData, multiEditError] = useMultiEditData();
const selectBuilding = useCallback((selectedBuilding: Building) => { const selectBuilding = useCallback((selectedBuilding: Building) => {
updateBuilding(Object.assign({}, building, selectedBuilding)); const currentId = selectedBuildingId;
setSelectedBuildingId(setOrToggle(selectedBuildingId, selectedBuilding?.building_id)); updateBuilding(selectedBuilding);
setSelectedBuildingId(setOrToggle(currentId, selectedBuilding?.building_id));
}, [selectedBuildingId, setSelectedBuildingId, updateBuilding, building]); }, [selectedBuildingId, setSelectedBuildingId, updateBuilding, building]);
const colourBuilding = useCallback(async (building: Building) => { const colourBuilding = useCallback(async (building: Building) => {

View File

@ -1,6 +1,7 @@
import { Category } from '../config/categories-config';
import { intParamTransform } from './url-param-transform'; import { intParamTransform } from './url-param-transform';
import { useUrlParam } from './use-url-param'; import { useUrlParam } from './use-url-param';
export function useUrlBuildingParam() { export function useUrlBuildingParam(defaultMode: 'view' | 'edit' | 'multi-edit', defaultCategory: Category | 'categories' = 'categories') {
return useUrlParam('building', intParamTransform); return useUrlParam('building', intParamTransform, '/:mode/:category/:building?', {mode: defaultMode, category: defaultCategory});
} }

View File

@ -5,7 +5,9 @@ import { UrlParamTransform } from './url-param-transform';
export function useUrlParam<T>( export function useUrlParam<T>(
param: string, param: string,
paramTransform: UrlParamTransform<T> paramTransform: UrlParamTransform<T>,
pathPattern?: string,
defaultParams: { [key: string]: string} = {}
): [T, (newParam: T) => void] { ): [T, (newParam: T) => void] {
const match = useRouteMatch(); const match = useRouteMatch();
const history = useHistory(); const history = useHistory();
@ -19,15 +21,12 @@ export function useUrlParam<T>(
}, [param, paramTransform, match.url]); }, [param, paramTransform, match.url]);
const setUrlParam = useCallback((value: T) => { const setUrlParam = useCallback((value: T) => {
const stringValue = value == undefined ? '' : paramTransform.toParam(value); const newParams = Object.assign({}, defaultParams, match.params);
const newPath = generatePath(match.path, { newParams[param] = value == undefined ? undefined : paramTransform.toParam(value);
...match.params,
...{ const newPath = generatePath(pathPattern ?? match.path, newParams);
[param]: stringValue
}
});
history.push(newPath); history.push(newPath);
}, [param, paramTransform, match.url]); }, [param, paramTransform, pathPattern, defaultParams, match.url]);
return [paramValue, setUrlParam]; return [paramValue, setUrlParam];
} }