add useContext to allow changing display state from two places

- buttons on the map
- sidebar buttons
This commit is contained in:
Mateusz Konieczny 2022-12-06 09:03:06 +01:00
parent 38c75ac1a3
commit e885d758dc
20 changed files with 313 additions and 181 deletions

View File

@ -6,6 +6,7 @@ import './app.css';
import { AuthRoute, PrivateRoute } from './route';
import { AuthProvider } from './auth-context';
import { DisplayPreferencesProvider } from './displayPreferences-context';
import { Header } from './header';
import { MapApp } from './map-app';
import { Building, UserVerified } from './models/building';
@ -53,41 +54,43 @@ export const App: React.FC<AppProps> = props => {
const mapAppPaths = ['/', '/:mode(view|edit|multi-edit)/:category/:building(\\d+)?/(history)?'];
return (
<AuthProvider preloadedUser={props.user}>
<Switch>
<Route exact path={mapAppPaths}>
<Header animateLogo={false} />
</Route>
<Route>
<Header animateLogo={true} />
</Route>
</Switch>
<Switch>
<Route exact path="/about.html" component={AboutPage} />
<AuthRoute exact path="/login.html" component={Login} />
<AuthRoute exact path="/forgotten-password.html" component={ForgottenPassword} />
<AuthRoute exact path="/password-reset.html" component={PasswordReset} />
<AuthRoute exact path="/sign-up.html" component={SignUp} />
<PrivateRoute exact path="/my-account.html" component={MyAccountPage} />
<Route exact path="/privacy-policy.html" component={PrivacyPolicyPage} />
<Route exact path="/contributor-agreement.html" component={ContributorAgreementPage} />
<Route exact path="/ordnance-survey-licence.html" component={OrdnanceSurveyLicencePage} />
<Route exact path="/ordnance-survey-uprn.html" component={OrdnanceSurveyUprnPage} />
<Route exact path="/data-accuracy.html" component={DataAccuracyPage} />
<Route exact path="/data-extracts.html" component={DataExtracts} />
<Route exact path="/contact.html" component={ContactPage} />
<Route exact path="/code-of-conduct.html" component={CodeOfConductPage} />
<Route exact path="/leaderboard.html" component={LeaderboardPage} />
<Route exact path="/history.html" component={ChangesPage} />
<Route exact path={mapAppPaths} >
<MapApp
building={props.building}
user_verified={props.user_verified}
revisionId={props.revisionId}
/>
</Route>
<Route component={NotFound} />
</Switch>
</AuthProvider>
<DisplayPreferencesProvider>
<AuthProvider preloadedUser={props.user}>
<Switch>
<Route exact path={mapAppPaths}>
<Header animateLogo={false} />
</Route>
<Route>
<Header animateLogo={true} />
</Route>
</Switch>
<Switch>
<Route exact path="/about.html" component={AboutPage} />
<AuthRoute exact path="/login.html" component={Login} />
<AuthRoute exact path="/forgotten-password.html" component={ForgottenPassword} />
<AuthRoute exact path="/password-reset.html" component={PasswordReset} />
<AuthRoute exact path="/sign-up.html" component={SignUp} />
<PrivateRoute exact path="/my-account.html" component={MyAccountPage} />
<Route exact path="/privacy-policy.html" component={PrivacyPolicyPage} />
<Route exact path="/contributor-agreement.html" component={ContributorAgreementPage} />
<Route exact path="/ordnance-survey-licence.html" component={OrdnanceSurveyLicencePage} />
<Route exact path="/ordnance-survey-uprn.html" component={OrdnanceSurveyUprnPage} />
<Route exact path="/data-accuracy.html" component={DataAccuracyPage} />
<Route exact path="/data-extracts.html" component={DataExtracts} />
<Route exact path="/contact.html" component={ContactPage} />
<Route exact path="/code-of-conduct.html" component={CodeOfConductPage} />
<Route exact path="/leaderboard.html" component={LeaderboardPage} />
<Route exact path="/history.html" component={ChangesPage} />
<Route exact path={mapAppPaths} >
<MapApp
building={props.building}
user_verified={props.user_verified}
revisionId={props.revisionId}
/>
</Route>
<Route component={NotFound} />
</Switch>
</AuthProvider>
</DisplayPreferencesProvider>
);
};

View File

@ -58,6 +58,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
const [userError, setUserError] = useState<string>(undefined);
const [isLoading, setIsLoading] = useState(false);
const login = useCallback(async (data: UserLoginData, cb: (err) => void = noop) => {
if(isAuthenticated) {
return;
@ -199,7 +200,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
logout,
signup,
generateApiKey,
deleteAccount
deleteAccount,
}}>
{children}
</AuthContext.Provider>

View File

@ -9,12 +9,12 @@
.map-switcher-inline {
border-radius: 4px;
}
.map-switcher-inline .btn {
.map-switcher-inline {
background: #FFC0CB;
margin: 0;
min-width: 280px;
}
.map-switcher-inline.night .btn {
.map-switcher-inline.night {
background: #FFC0CB;
color: #fff;
background-color: #343a40;

View File

@ -15,9 +15,9 @@ import SelectDataEntry from '../data-components/select-data-entry';
import Verification from '../data-components/verification';
import withCopyEdit from '../data-container';
import PlanningDataOfficialDataEntry from '../data-components/planning-data-entry';
import { CategoryViewProps } from './category-view-props';
import { Category } from '../../config/categories-config';
import { useDisplayPreferences } from '../../displayPreferences-context';
const currentTimestamp = new Date().valueOf();
const milisecondsInYear = 1000 * 60 * 60 * 24 * 365;
@ -48,6 +48,7 @@ function isArchived(item) {
}
const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
const { flood, floodSwitchOnClick, housing, housingSwitchOnClick, creative, creativeSwitchOnClick, vista, vistaSwitchOnClick } = useDisplayPreferences();
const communityLinkUrl = `/${props.mode}/${Category.Community}/${props.building.building_id}`;
return (
<Fragment>
@ -121,12 +122,6 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
/>
</DataEntryGroup>
<DataEntryGroup name="Possible future applications (crowdsourced data)" collapsed={true} >
<form className={`map-switcher-inline`}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Click to see the data mapped
</button>
</form>
<UserOpinionEntry
slug='community_expected_planning_application'
title={buildingUserFields.community_expected_planning_application.title}
@ -149,56 +144,37 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
value={null}
disabled={true}
/>
{
<form className={`map-switcher-inline`}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Click to see the data mapped
</button>
</form>
}
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={floodSwitchOnClick}>
{(flood === 'enabled')? 'Click to hide overlay' : 'Click to see the data mapped'}
</button>
<LogicalDataEntry
title="Is the building in a Housing Zone?"
slug="planning_live_application"
value={null}
disabled={true}
/>
{
<form className={`map-switcher-inline`}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Click to see the data mapped
</button>
</form>
}
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={housingSwitchOnClick}>
{(housing === 'enabled')? 'Click to hide overlay' : 'Click to see the data mapped'}
</button>
<LogicalDataEntry
title="Is the building in a Creative Enterprise Zone?"
slug="planning_live_application"
value={null}
disabled={true}
/>
{
<form className={`map-switcher-inline`}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Click to see the data mapped
</button>
</form>
}
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={creativeSwitchOnClick}>
{(creative === 'enabled')? 'Click to hide overlay' : 'Click to see the data mapped'}
</button>
<LogicalDataEntry
title="Is the building within a Protected Vista?"
slug="planning_live_application"
value={null}
disabled={true}
/>
{
<form className={`map-switcher-inline`}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Click to see the data mapped
</button>
</form>
}
<br/>
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={vistaSwitchOnClick}>
{(vista === 'enabled')? 'Click to hide overlay' : 'Click to see the data mapped'}
</button>
{/*
<DataEntry
title={dataFields.planning_glher_url.title}

View File

@ -10,21 +10,7 @@ export const initialMapViewport: MapViewport = {
export type MapTheme = 'light' | 'night' | 'night_outlines';
export type BoroughEnablementState = 'enabled' | 'disabled';
export type ParcelEnablementState = 'enabled' | 'disabled';
export type FloodEnablementState = 'enabled' | 'disabled';
export type ConservationAreasEnablementState = 'enabled' | 'disabled';
export type HistoricDataEnablementState = 'enabled' | 'disabled';
export type VistaEnablementState = 'enabled' | 'disabled';
export type HousingEnablementState = 'enabled' | 'disabled';
export type CreativeEnablementState = 'enabled' | 'disabled';
export type LayerEnablementState = 'enabled' | 'disabled';
export const mapBackgroundColor: Record<MapTheme, string> = {
light: '#F0EEEB',

View File

@ -0,0 +1,160 @@
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { LayerEnablementState } from './config/map-config';
interface DisplayPreferencesContextState {
vista: LayerEnablementState;
vistaSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
vistaSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
flood: LayerEnablementState;
floodSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
floodSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
creative: LayerEnablementState;
creativeSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
creativeSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
housing: LayerEnablementState;
housingSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
housingSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
}
const stub = (): never => {
throw new Error('DisplayPreferencesProvider not set up');
};
export const DisplayPreferencesContext = createContext<DisplayPreferencesContextState>({
vista: undefined,
vistaSwitch: stub,
vistaSwitchOnClick: undefined,
flood: undefined,
floodSwitch: stub,
floodSwitchOnClick: undefined,
creative: undefined,
creativeSwitch: stub,
creativeSwitchOnClick: undefined,
housing: undefined,
housingSwitch: stub,
housingSwitchOnClick: undefined,
/*
conservation: undefined,
conservationSwitch: stub,
conservationSwitchOnClick: undefined,
parcel: undefined,
parcelSwitch: stub,
parcelSwitchOnClick: undefined,
borough: undefined,
boroughSwitch: stub,
boroughSwitchOnClick: undefined,
not needed right now
historicData
*/
});
const noop = () => {};
export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
const [vista, setVista] = useState<LayerEnablementState>('disabled');
const [flood, setFlood] = useState<LayerEnablementState>('disabled');
const [creative, setCreative] = useState<LayerEnablementState>('disabled');
const [housing, setHousing] = useState<LayerEnablementState>('disabled');
/*
const [borough, setBorough] = useState<LayerEnablementState>('enabled');
const [parcel, setParcel] = useState<LayerEnablementState>('disabled');
const [conservation, setConservation] = useState<LayerEnablementState>('disabled');
const [historicData, setHistoricData] = useState<LayerEnablementState>('disabled');
*/
const vistaSwitch = useCallback(
(e) => {
e.preventDefault();
const newVista = (vista === 'enabled')? 'disabled' : 'enabled';
setVista(newVista);
},
[vista],
)
const vistaSwitchOnClick = (e) => {
e.preventDefault();
const newVista = (vista === 'enabled')? 'disabled' : 'enabled';
setVista(newVista);
}
const floodSwitch = useCallback(
(e) => {
e.preventDefault();
const newFlood = (flood === 'enabled')? 'disabled' : 'enabled';
setFlood(newFlood);
},
[flood],
)
const floodSwitchOnClick = (e) => {
e.preventDefault();
const newFlood = (flood === 'enabled')? 'disabled' : 'enabled';
setFlood(newFlood);
}
const housingSwitch = useCallback(
(e) => {
e.preventDefault();
const newHousing = (housing === 'enabled')? 'disabled' : 'enabled';
setHousing(newHousing);
},
[housing],
)
const housingSwitchOnClick = (e) => {
e.preventDefault();
const newHousing = (housing === 'enabled')? 'disabled' : 'enabled';
setHousing(newHousing);
}
const creativeSwitch = useCallback(
(e) => {
e.preventDefault();
const newCreative = (creative === 'enabled')? 'disabled' : 'enabled';
setCreative(newCreative);
},
[creative],
)
const creativeSwitchOnClick = (e) => {
e.preventDefault();
const newCreative = (creative === 'enabled')? 'disabled' : 'enabled';
setCreative(newCreative);
}
return (
<DisplayPreferencesContext.Provider value={{
vista,
vistaSwitch,
vistaSwitchOnClick,
flood,
floodSwitch,
floodSwitchOnClick,
creative,
creativeSwitch,
creativeSwitchOnClick,
housing,
housingSwitch,
housingSwitchOnClick
}}>
{children}
</DisplayPreferencesContext.Provider>
);
};
export const useDisplayPreferences = (): DisplayPreferencesContextState => {
return useContext(DisplayPreferencesContext);
};

View File

@ -1,19 +1,20 @@
import React from 'react';
import './creative-switcher.css';
import { useDisplayPreferences } from '../displayPreferences-context';
interface CreativeSwitcherProps {
currentDisplay: string;
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
}
const CreativeSwitcherProps: React.FC<CreativeSwitcherProps> = (props) => (
<form className={`creative-switcher ${props.currentDisplay}`} onSubmit={props.onSubmit}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Creative Enterprise Zones display ({(props.currentDisplay === 'enabled')? 'Enabled' : 'Disabled'})
</button>
</form>
);
const CreativeSwitcherProps: React.FC<CreativeSwitcherProps> = (props) => {
const { creative, creativeSwitch } = useDisplayPreferences();
return (
<form className={`creative-switcher ${creative}`} onSubmit={creativeSwitch}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Creative Enterprise Zones display ({(creative === 'enabled')? 'Enabled' : 'Disabled'})
</button>
</form>
);
}
export default CreativeSwitcherProps;

View File

@ -1,19 +1,20 @@
import React from 'react';
import './flood-switcher.css';
import { useDisplayPreferences } from '../displayPreferences-context';
interface FloodSwitcherProps {
currentDisplay: string;
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
}
const FloodSwitcherProps: React.FC<FloodSwitcherProps> = (props) => (
<form className={`flood-switcher ${props.currentDisplay}`} onSubmit={props.onSubmit}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Switch flood zone overlay ({(props.currentDisplay === 'enabled')? 'Enabled' : 'Disabled'})
</button>
</form>
);
const FloodSwitcherProps: React.FC<FloodSwitcherProps> = (props) => {
const { flood, floodSwitch } = useDisplayPreferences();
return (
<form className={`flood-switcher ${flood}`} onSubmit={floodSwitch}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Switch flood zone overlay ({(flood === 'enabled')? 'Enabled' : 'Disabled'})
</button>
</form>
);
}
export default FloodSwitcherProps;

View File

@ -1,19 +1,21 @@
import React from 'react';
import './housing-switcher.css';
import { useDisplayPreferences } from '../displayPreferences-context';
interface HousingSwitcherProps {
currentDisplay: string;
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
}
const HousingSwitcherProps: React.FC<HousingSwitcherProps> = (props) => (
<form className={`housing-switcher ${props.currentDisplay}`} onSubmit={props.onSubmit}>
const HousingSwitcherProps: React.FC<HousingSwitcherProps> = (props) => {
const { housing, housingSwitch } = useDisplayPreferences();
return (
<form className={`housing-switcher ${housing}`} onSubmit={housingSwitch}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Housing Zone display ({(props.currentDisplay === 'enabled')? 'Enabled' : 'Disabled'})
Housing Zone display ({(housing === 'enabled')? 'Enabled' : 'Disabled'})
</button>
</form>
);
);
}
export default HousingSwitcherProps;

View File

@ -1,10 +1,10 @@
import { GeoJsonObject } from 'geojson';
import React, { useEffect, useState } from 'react';
import { GeoJSON } from 'react-leaflet';
import { BoroughEnablementState } from '../../config/map-config';
import { LayerEnablementState } from '../../config/map-config';
import { apiGet } from '../../apiHelpers';
export function BoroughBoundaryLayer({enablement}: {enablement: BoroughEnablementState}) {
export function BoroughBoundaryLayer({enablement}: {enablement: LayerEnablementState}) {
const [boundaryGeojson, setBoundaryGeojson] = useState<GeoJsonObject>(null);
useEffect(() => {

View File

@ -1,10 +1,10 @@
import { GeoJsonObject } from 'geojson';
import React, { useEffect, useState } from 'react';
import { GeoJSON } from 'react-leaflet';
import { ConservationAreasEnablementState } from '../../config/map-config';
import { LayerEnablementState } from '../../config/map-config';
import { apiGet } from '../../apiHelpers';
export function ConservationAreaBoundaryLayer({enablement}: {enablement: ConservationAreasEnablementState}) {
export function ConservationAreaBoundaryLayer({enablement}: {enablement: LayerEnablementState}) {
const [boundaryGeojson, setBoundaryGeojson] = useState<GeoJsonObject>(null);
useEffect(() => {

View File

@ -1,25 +1,26 @@
import { GeoJsonObject } from 'geojson';
import React, { useEffect, useState } from 'react';
import { GeoJSON } from 'react-leaflet';
import { CreativeEnablementState } from '../../config/map-config';
import { apiGet } from '../../apiHelpers';
import { useDisplayPreferences } from '../../displayPreferences-context';
export function CreativeBoundaryLayer({enablement}: {enablement: CreativeEnablementState}) {
export function CreativeBoundaryLayer() {
const [boundaryGeojson, setBoundaryGeojson] = useState<GeoJsonObject>(null);
const { creative } = useDisplayPreferences();
useEffect(() => {
apiGet('/geometries/creative_enterprise_zones.geojson')
.then(data => setBoundaryGeojson(data as GeoJsonObject));
}, []);
if(enablement == "enabled") {
if(creative == "enabled") {
return boundaryGeojson &&
<GeoJSON
attribution="Creative Enterprise Zones data from <a href=https://apps.london.gov.uk/planning/?_gl=1*avicz4*_ga*MTg1MjY3MzMuMTY2NzcxMjIwMg..*_ga_PY4SWZN1RJ*MTY2NzcxMjI1NS4xLjAuMTY2NzcxMjI1NS42MC4wLjA>PLanning Datamap</a> licence: <a href=https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/>Open Government Licence v3.0</a> The boundaries are based on Ordnance Survey mapping and the data is published under Ordnance Survey's 'presumption to publish'. Contains OS data © Crown copyright and database rights 2019."
data={boundaryGeojson}
style={{color: '#f0f', fill: true, weight: 1, opacity: 0.6}}
/>;
} else if (enablement == "disabled") {
} else if (creative == "disabled") {
return <div></div>
}
}

View File

@ -1,25 +1,26 @@
import { GeoJsonObject } from 'geojson';
import React, { useEffect, useState } from 'react';
import { GeoJSON } from 'react-leaflet';
import { FloodEnablementState } from '../../config/map-config';
import { apiGet } from '../../apiHelpers';
import { useDisplayPreferences } from '../../displayPreferences-context';
export function FloodBoundaryLayer({enablement}: {enablement: FloodEnablementState}) {
export function FloodBoundaryLayer() {
const [boundaryGeojson, setBoundaryGeojson] = useState<GeoJsonObject>(null);
const { flood } = useDisplayPreferences();
useEffect(() => {
apiGet('/geometries/flood_zones_simplified.geojson')
.then(data => setBoundaryGeojson(data as GeoJsonObject));
}, []);
if(enablement == "enabled") {
if(flood == "enabled") {
return boundaryGeojson &&
<GeoJSON
attribution='Flood zone from <a href=https://data.london.gov.uk/dataset/flood-risk-zones>London Datastore</a>: © Environment Agency copyright and/or database right 2017. All rights reserved. Some features of this map are based on digital spatial data from the Centre for Ecology & Hydrology, © NERC (CEH) © Crown copyright and database rights 2017 Ordnance Survey 100024198'
data={boundaryGeojson}
style={{color: '#00f', fill: true, weight: 1, opacity: 0.6}}
/>;
} else if (enablement == "disabled") {
} else if (flood == "disabled") {
return <div></div>
// do not display anything
return boundaryGeojson &&

View File

@ -1,9 +1,9 @@
import * as React from 'react';
import { TileLayer } from 'react-leaflet';
import { HistoricDataEnablementState } from '../../config/map-config';
import { LayerEnablementState } from '../../config/map-config';
import { BuildingBaseLayer } from './building-base-layer';
export function HistoricDataLayer({enablement}: {enablement: HistoricDataEnablementState}) {
export function HistoricDataLayer({enablement}: {enablement: LayerEnablementState}) {
if(enablement == "enabled") {
return <><TileLayer
url="https://mapseries-tilesets.s3.amazonaws.com/london_1890s/{z}/{x}/{y}.png"

View File

@ -1,25 +1,26 @@
import { GeoJsonObject } from 'geojson';
import React, { useEffect, useState } from 'react';
import { GeoJSON } from 'react-leaflet';
import { HousingEnablementState } from '../../config/map-config';
import { apiGet } from '../../apiHelpers';
import { useDisplayPreferences } from '../../displayPreferences-context';
export function HousingBoundaryLayer({enablement}: {enablement: HousingEnablementState}) {
export function HousingBoundaryLayer() {
const [boundaryGeojson, setBoundaryGeojson] = useState<GeoJsonObject>(null);
const { housing } = useDisplayPreferences();
useEffect(() => {
apiGet('/geometries/housing_zones.geojson')
.then(data => setBoundaryGeojson(data as GeoJsonObject));
}, []);
if(enablement == "enabled") {
if(housing == "enabled") {
return boundaryGeojson &&
<GeoJSON
attribution="Housing Zones from <a href=https://data.london.gov.uk/dataset/housing_zones>London Datastore</a>. The boundaries are based on Ordnance Survey mapping and the data is published under Ordnance Survey's 'presumption to publish'. Contains OS data © Crown copyright and database rights 2019. Greater London Authority - Contains public sector information licensed under the <a href=https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/>Open Government Licence v3.0</a>'"
data={boundaryGeojson}
style={{color: '#FF8000', fill: true, weight: 1, opacity: 0.6}}
/>;
} else if (enablement == "disabled") {
} else if (housing == "disabled") {
return <div></div>
}
}

View File

@ -1,10 +1,10 @@
import { GeoJsonObject } from 'geojson';
import React, { useEffect, useState } from 'react';
import { GeoJSON } from 'react-leaflet';
import { ParcelEnablementState } from '../../config/map-config';
import { LayerEnablementState } from '../../config/map-config';
import { apiGet } from '../../apiHelpers';
export function ParcelBoundaryLayer({enablement}: {enablement: ParcelEnablementState}) {
export function ParcelBoundaryLayer({enablement}: {enablement: LayerEnablementState}) {
const [boundaryGeojson, setBoundaryGeojson] = useState<GeoJsonObject>(null);
useEffect(() => {

View File

@ -1,25 +1,26 @@
import { GeoJsonObject } from 'geojson';
import React, { useEffect, useState } from 'react';
import { GeoJSON } from 'react-leaflet';
import { FloodEnablementState } from '../../config/map-config';
import { apiGet } from '../../apiHelpers';
import { useDisplayPreferences } from '../../displayPreferences-context';
export function VistaBoundaryLayer({enablement}: {enablement: FloodEnablementState}) {
export function VistaBoundaryLayer() {
const [boundaryGeojson, setBoundaryGeojson] = useState<GeoJsonObject>(null);
const { vista } = useDisplayPreferences();
useEffect(() => {
apiGet('/geometries/protected_vistas.geojson')
.then(data => setBoundaryGeojson(data as GeoJsonObject));
}, []);
if(enablement == "enabled") {
if(vista == "enabled") {
return boundaryGeojson &&
<GeoJSON
attribution=' London Views Management Framework (LVMF) Extended background vistas from <a href=https://data.london.gov.uk/dataset/london-views-management-framework-lvmf-extended-background-vistas>London Datastore</a>: <a href=https://creativecommons.org/licenses/by/4.0/legalcode>CC-BY-SA 4.0</a> by Greater London Authority (GLA)'
data={boundaryGeojson}
style={{color: '#0f0', fill: true, weight: 1, opacity: 0.6}}
/>;
} else if (enablement == "disabled") {
return <div></div>
} else {
return <></>
}
}

View File

@ -8,7 +8,8 @@ import { apiGet } from '../apiHelpers';
import { HelpIcon } from '../components/icons';
import { categoryMapsConfig } from '../config/category-maps-config';
import { Category } from '../config/categories-config';
import { initialMapViewport, mapBackgroundColor, MapTheme, BoroughEnablementState, ParcelEnablementState, FloodEnablementState, ConservationAreasEnablementState, HistoricDataEnablementState, CreativeEnablementState, HousingEnablementState, VistaEnablementState } from '../config/map-config';
import { initialMapViewport, mapBackgroundColor, MapTheme, LayerEnablementState } from '../config/map-config';
import { Building } from '../models/building';
import { CityBaseMapLayer } from './layers/city-base-map-layer';
@ -55,16 +56,16 @@ export const ColouringMap : FC<ColouringMapProps> = ({
selectedBuildingId,
children
}) => {
const [theme, setTheme] = useState<MapTheme>('night');
const [borough, setBorough] = useState<BoroughEnablementState>('enabled');
const [parcel, setParcel] = useState<ParcelEnablementState>('disabled');
const [flood, setFlood] = useState<FloodEnablementState>('disabled');
const [conservation, setConservation] = useState<ConservationAreasEnablementState>('disabled');
const [historicData, setHistoricData] = useState<HistoricDataEnablementState>('disabled');
const [creative, setCreative] = useState<CreativeEnablementState>('disabled');
const [housing, setHousing] = useState<HousingEnablementState>('disabled');
const [vista, setVista] = useState<VistaEnablementState>('disabled');
{/* TODO start change remaining ones */}
const [borough, setBorough] = useState<LayerEnablementState>('enabled');
const [parcel, setParcel] = useState<LayerEnablementState>('disabled');
const [flood, setFlood] = useState<LayerEnablementState>('disabled');
const [conservation, setConservation] = useState<LayerEnablementState>('disabled');
const [historicData, setHistoricData] = useState<LayerEnablementState>('disabled');
const [creative, setCreative] = useState<LayerEnablementState>('disabled');
const [housing, setHousing] = useState<LayerEnablementState>('disabled');
{/* TODO end */}
const [position, setPosition] = useState(initialMapViewport.position);
const [zoom, setZoom] = useState(initialMapViewport.zoom);
@ -97,6 +98,7 @@ export const ColouringMap : FC<ColouringMapProps> = ({
[theme],
)
{/* change remaining ones */}
const boroughSwitch = useCallback(
(e) => {
e.preventDefault();
@ -142,15 +144,6 @@ export const ColouringMap : FC<ColouringMapProps> = ({
[historicData],
)
const vistaSwitch = useCallback(
(e) => {
e.preventDefault();
const newVista = (vista === 'enabled')? 'disabled' : 'enabled';
setVista(newVista);
},
[vista],
)
const housingSwitch = useCallback(
(e) => {
e.preventDefault();
@ -168,6 +161,7 @@ export const ColouringMap : FC<ColouringMapProps> = ({
},
[creative],
)
{/* TODO end */}
const categoryMapDefinitions = useMemo(() => categoryMapsConfig[category], [category]);
@ -220,11 +214,11 @@ export const ColouringMap : FC<ColouringMapProps> = ({
<HistoricDataLayer enablement={historicData}/>
<BoroughBoundaryLayer enablement={borough}/>
<ParcelBoundaryLayer enablement={parcel}/>
<FloodBoundaryLayer enablement={flood}/>
<FloodBoundaryLayer />
<ConservationAreaBoundaryLayer enablement={conservation}/>
<VistaBoundaryLayer enablement={vista}/>
<HousingBoundaryLayer enablement={housing}/>
<CreativeBoundaryLayer enablement={creative}/>
<VistaBoundaryLayer />
<HousingBoundaryLayer />
<CreativeBoundaryLayer />
<BuildingNumbersLayer revisionId={revisionId} />
{
selectedBuildingId &&
@ -249,14 +243,16 @@ export const ColouringMap : FC<ColouringMapProps> = ({
}
<Legend mapColourScaleDefinitions={categoryMapDefinitions} mapColourScale={mapColourScale} onMapColourScale={setMapColourScale}/>
<ThemeSwitcher onSubmit={themeSwitch} currentTheme={theme} />
{/* TODO change remaining ones*/}
<BoroughSwitcher onSubmit={boroughSwitch} currentDisplay={borough} />
<ParcelSwitcher onSubmit={parcelSwitch} currentDisplay={parcel} />
<FloodSwitcher onSubmit={floodSwitch} currentDisplay={flood} />
<FloodSwitcher />
<ConservationAreaSwitcher onSubmit={conservationSwitch} currentDisplay={conservation} />
<HistoricDataSwitcher onSubmit={historicDataSwitch} currentDisplay={historicData} />
<VistaSwitcher onSubmit={vistaSwitch} currentDisplay={vista} />
<HousingSwitcher onSubmit={housingSwitch} currentDisplay={housing} />
<CreativeSwitcher onSubmit={creativeSwitch} currentDisplay={creative} />
<VistaSwitcher />
<HousingSwitcher />
<CreativeSwitcher />
<SearchBox onLocate={handleLocate} />
</>
}

View File

@ -11,7 +11,7 @@ const ParcelSwitcher: React.FC<ParcelSwitcherProps> = (props) => (
<form className={`parcel-switcher ${props.currentDisplay}`} onSubmit={props.onSubmit}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Switch parcel overlay ({(props.currentDisplay === 'enabled')? 'Enabled' : 'Disabled'})
{(props.currentDisplay === 'enabled')? 'Switch off Parcel overlay' : 'Switch on Parcel overlay'}
</button>
</form>
);

View File

@ -1,19 +1,21 @@
import React from 'react';
import './vista-switcher.css';
import { useDisplayPreferences } from '../displayPreferences-context';
interface VistaSwitcherProps {
currentDisplay: string;
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
}
const VistaSwitcherProps: React.FC<VistaSwitcherProps> = (props) => (
<form className={`vista-switcher ${props.currentDisplay}`} onSubmit={props.onSubmit}>
const VistaSwitcherProps: React.FC<VistaSwitcherProps> = (props) => {
const { vista, vistaSwitch } = useDisplayPreferences();
return (
<form className={`vista-switcher ${vista}`} onSubmit={vistaSwitch}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
Protected Vistas ({(props.currentDisplay === 'enabled')? 'Enabled' : 'Disabled'})
Protected Vistas ({(vista === 'enabled')? 'Enabled' : 'Disabled'})
</button>
</form>
);
);
}
export default VistaSwitcherProps;
export default VistaSwitcherProps; // TODO remove