Sketch out new flow (with URL change)
This commit is contained in:
parent
09b59dbf6d
commit
377149975b
@ -10,12 +10,11 @@ import BuildingEdit from './building-edit';
|
|||||||
import BuildingView from './building-view';
|
import BuildingView from './building-view';
|
||||||
import ColouringMap from './map';
|
import ColouringMap from './map';
|
||||||
import Header from './header';
|
import Header from './header';
|
||||||
import Legend from './legend';
|
import Overview from './overview';
|
||||||
import Login from './login';
|
import Login from './login';
|
||||||
import MyAccountPage from './my-account';
|
import MyAccountPage from './my-account';
|
||||||
import SignUp from './signup';
|
import SignUp from './signup';
|
||||||
import Welcome from './welcome';
|
import Welcome from './welcome';
|
||||||
import BuildingEditAny from './building-edit-any';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -83,18 +82,26 @@ class App extends React.Component {
|
|||||||
<Route exact path="/">
|
<Route exact path="/">
|
||||||
<Welcome />
|
<Welcome />
|
||||||
</Route>
|
</Route>
|
||||||
<Route exact path="/select.html">
|
<Route exact path="/view/:cat.html" render={(props) => (
|
||||||
<BuildingEditAny user={this.state.user} />
|
<Overview
|
||||||
</Route>
|
{...props}
|
||||||
<Route exact path="/map/:map.html" component={Legend} />
|
mode='view' user={this.state.user}
|
||||||
<Route exact path="/building/:building.html" render={(props) => (
|
/>
|
||||||
|
) } />
|
||||||
|
<Route exact path="/edit/:cat.html" render={(props) => (
|
||||||
|
<Overview
|
||||||
|
{...props}
|
||||||
|
mode='edit' user={this.state.user}
|
||||||
|
/>
|
||||||
|
) } />
|
||||||
|
<Route exact path="/view/:cat/building/:building.html" render={(props) => (
|
||||||
<BuildingView
|
<BuildingView
|
||||||
{...props}
|
{...props}
|
||||||
{...this.state.building}
|
{...this.state.building}
|
||||||
user={this.state.user}
|
user={this.state.user}
|
||||||
/>
|
/>
|
||||||
) } />
|
) } />
|
||||||
<Route exact path="/building/:building/edit.html" render={(props) => (
|
<Route exact path="/edit/:cat/building/:building.html" render={(props) => (
|
||||||
<BuildingEdit
|
<BuildingEdit
|
||||||
{...props}
|
{...props}
|
||||||
{...this.state.building}
|
{...this.state.building}
|
||||||
@ -106,7 +113,7 @@ class App extends React.Component {
|
|||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/(select.html|map.*|building.*)?" render={(props) => (
|
<Route exact path="/(edit.*|view.*)?" render={(props) => (
|
||||||
<ColouringMap
|
<ColouringMap
|
||||||
{...props}
|
{...props}
|
||||||
building={this.state.building}
|
building={this.state.building}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
import React from 'react';
|
|
||||||
import Sidebar from './sidebar';
|
|
||||||
import InfoBox from './info-box';
|
|
||||||
import { Redirect } from 'react-router-dom';
|
|
||||||
|
|
||||||
const BuildingEditAny = (props) => {
|
|
||||||
if (!props.user){
|
|
||||||
return <Redirect to="/sign-up.html" />
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Sidebar title="Edit data">
|
|
||||||
<InfoBox msg="Select a building to edit by clicking on the map…" />
|
|
||||||
</Sidebar>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default BuildingEditAny;
|
|
@ -1,6 +1,5 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import { Link, NavLink, Redirect } from 'react-router-dom';
|
import { Link, NavLink, Redirect } from 'react-router-dom';
|
||||||
import queryString from 'query-string';
|
|
||||||
|
|
||||||
import ErrorBox from './error-box';
|
import ErrorBox from './error-box';
|
||||||
import InfoBox from './info-box';
|
import InfoBox from './info-box';
|
||||||
@ -26,23 +25,32 @@ const BuildingEdit = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const search = (props.location && props.location.search)?
|
const cat = get_cat(props.match.url);
|
||||||
queryString.parse(props.location.search):
|
|
||||||
{};
|
|
||||||
return (
|
return (
|
||||||
<Sidebar title={`You are editing`}
|
<Sidebar
|
||||||
back={search.cat? `/building/${props.building_id}.html?cat=${search.cat}`: `/building//${props.building_id}.html`}>
|
key={props.building_id}
|
||||||
|
title={`You are editing`}
|
||||||
|
back={`/edit/${cat}.html`}>
|
||||||
{
|
{
|
||||||
CONFIG.map((conf_props) => {
|
CONFIG.map((conf_props) => {
|
||||||
return <EditForm
|
return <EditForm
|
||||||
{...conf_props} {...props}
|
{...conf_props} {...props}
|
||||||
search={search} key={conf_props.slug} />
|
cat={cat} key={conf_props.slug} />
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_cat(url) {
|
||||||
|
if (url === "/") {
|
||||||
|
return "age"
|
||||||
|
}
|
||||||
|
const matches = /^\/(view|edit)\/([^\/.]+)/.exec(url);
|
||||||
|
const cat = (matches && matches.length > 2)? matches[2] : "age";
|
||||||
|
return cat;
|
||||||
|
}
|
||||||
|
|
||||||
class EditForm extends Component {
|
class EditForm extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -116,7 +124,7 @@ class EditForm extends Component {
|
|||||||
this.setState({error: res.error})
|
this.setState({error: res.error})
|
||||||
} else {
|
} else {
|
||||||
this.props.selectBuilding(res);
|
this.props.selectBuilding(res);
|
||||||
const new_cat = this.props.search.cat;
|
const new_cat = this.props.cat;
|
||||||
this.props.history.push(`/building/${res.building_id}.html?cat=${new_cat}`);
|
this.props.history.push(`/building/${res.building_id}.html?cat=${new_cat}`);
|
||||||
}
|
}
|
||||||
}.bind(this)).catch(
|
}.bind(this)).catch(
|
||||||
@ -125,14 +133,17 @@ class EditForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const match = this.props.search.cat === this.props.slug;
|
const match = this.props.cat === this.props.slug;
|
||||||
if (!match) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<section className={(this.props.inactive)? "data-section inactive": "data-section"}>
|
<section className={(this.props.inactive)? "data-section inactive": "data-section"}>
|
||||||
<header className={(match? "active " : "") + " section-header edit"}>
|
<header className={(match? "active " : "") + " section-header edit"}>
|
||||||
<a><h3 className="h3">{this.props.title}</h3></a>
|
<NavLink
|
||||||
|
to={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}
|
||||||
|
title={(this.props.inactive)? 'Coming soon… Click the ? for more info.' :
|
||||||
|
(match)? 'Hide details' : 'Show details'}
|
||||||
|
isActive={() => match}>
|
||||||
|
<h3 className="h3">{this.props.title}</h3>
|
||||||
|
</NavLink>
|
||||||
<nav className="icon-buttons">
|
<nav className="icon-buttons">
|
||||||
{
|
{
|
||||||
this.props.help?
|
this.props.help?
|
||||||
@ -142,31 +153,34 @@ class EditForm extends Component {
|
|||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
(this.props.slug === 'like')? // special-case for likes
|
(match && this.props.slug === 'like')? // special-case for likes
|
||||||
<NavLink className="icon-button save" title="Done"
|
<NavLink className="icon-button save" title="Done"
|
||||||
to={`/building/${this.props.building_id}.html?cat=${this.props.slug}`}>
|
to={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}>
|
||||||
Done
|
Done
|
||||||
<SaveIcon />
|
<SaveIcon />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
:
|
:
|
||||||
|
match? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<NavLink className="icon-button save" title="Save Changes"
|
<NavLink className="icon-button save" title="Save Changes"
|
||||||
onClick={this.handleSubmit}
|
onClick={this.handleSubmit}
|
||||||
to={`/building/${this.props.building_id}.html?cat=${this.props.slug}`}>
|
to={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}>
|
||||||
Save
|
Save
|
||||||
<SaveIcon />
|
<SaveIcon />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink className="icon-button close-edit" title="Cancel"
|
<NavLink className="icon-button close-edit" title="Cancel"
|
||||||
to={`/building/${this.props.building_id}.html?cat=${this.props.slug}`}>
|
to={`/view/${this.props.slug}/building/${this.props.building_id}.html`}>
|
||||||
Cancel
|
Cancel
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
): null
|
||||||
}
|
}
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
{
|
||||||
<form action={`/building/${this.props.building_id}.html?cat=${this.props.slug}`}
|
match? (
|
||||||
|
<form action={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}
|
||||||
method="GET" onSubmit={this.handleSubmit}>
|
method="GET" onSubmit={this.handleSubmit}>
|
||||||
<ErrorBox msg={this.state.error} />
|
<ErrorBox msg={this.state.error} />
|
||||||
{
|
{
|
||||||
@ -216,6 +230,8 @@ class EditForm extends Component {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</form>
|
</form>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { Link, NavLink } from 'react-router-dom';
|
import { Link, NavLink } from 'react-router-dom';
|
||||||
import queryString from 'query-string';
|
|
||||||
|
|
||||||
import Sidebar from './sidebar';
|
import Sidebar from './sidebar';
|
||||||
import Tooltip from './tooltip';
|
import Tooltip from './tooltip';
|
||||||
@ -16,18 +15,18 @@ const BuildingView = (props) => {
|
|||||||
<Sidebar title="Building Not Found">
|
<Sidebar title="Building Not Found">
|
||||||
<InfoBox msg="We can't find that one anywhere - try the map again?" />
|
<InfoBox msg="We can't find that one anywhere - try the map again?" />
|
||||||
<div className="buttons-container with-space">
|
<div className="buttons-container with-space">
|
||||||
<Link to="/map/age.html" className="btn btn-secondary">Back to maps</Link>
|
<Link to="/view/age.html" className="btn btn-secondary">Back to maps</Link>
|
||||||
</div>
|
</div>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const search = (props.location && props.location.search)? queryString.parse(props.location.search): {};
|
const cat = get_cat(props.match.url);
|
||||||
return (
|
return (
|
||||||
<Sidebar title={`Data available for this building`} back={search.cat? `/map/${search.cat}.html` : "/map/age.html"}>
|
<Sidebar title={`Data available for this building`} back={`/view/${cat}.html`}>
|
||||||
{
|
{
|
||||||
CONFIG.map(section_props => (
|
CONFIG.map(section_props => (
|
||||||
<DataSection
|
<DataSection
|
||||||
key={section_props.slug} search={search}
|
key={section_props.slug} cat={cat}
|
||||||
building_id={props.building_id}
|
building_id={props.building_id}
|
||||||
{...section_props}>
|
{...section_props}>
|
||||||
{
|
{
|
||||||
@ -54,13 +53,23 @@ const BuildingView = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get_cat(url) {
|
||||||
|
if (url === "/") {
|
||||||
|
return "age"
|
||||||
|
}
|
||||||
|
const matches = /^\/(view|edit)\/([^\/.]+)/.exec(url);
|
||||||
|
const cat = (matches && matches.length > 2)? matches[2] : "age";
|
||||||
|
return cat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const DataSection = (props) => {
|
const DataSection = (props) => {
|
||||||
const match = props.search.cat === props.slug;
|
const match = props.cat === props.slug;
|
||||||
return (
|
return (
|
||||||
<section id={props.slug} className={(props.inactive)? "data-section inactive": "data-section"}>
|
<section id={props.slug} className={(props.inactive)? "data-section inactive": "data-section"}>
|
||||||
<header className={(match? "active " : "") + " section-header view"}>
|
<header className={(match? "active " : "") + " section-header view"}>
|
||||||
<NavLink
|
<NavLink
|
||||||
to={`/building/${props.building_id}.html` + ((match)? '': `?cat=${props.slug}`)}
|
to={`/view/${props.slug}/building/${props.building_id}.html`}
|
||||||
title={(props.inactive)? 'Coming soon… Click the ? for more info.' :
|
title={(props.inactive)? 'Coming soon… Click the ? for more info.' :
|
||||||
(match)? 'Hide details' : 'Show details'}
|
(match)? 'Hide details' : 'Show details'}
|
||||||
isActive={() => match}>
|
isActive={() => match}>
|
||||||
@ -77,7 +86,7 @@ const DataSection = (props) => {
|
|||||||
{
|
{
|
||||||
!props.inactive?
|
!props.inactive?
|
||||||
<NavLink className="icon-button edit" title="Edit data"
|
<NavLink className="icon-button edit" title="Edit data"
|
||||||
to={`/building/${props.building_id}/edit.html?cat=${props.slug}`}>
|
to={`/edit/${props.slug}/building/${props.building_id}.html`}>
|
||||||
Edit
|
Edit
|
||||||
<EditIcon />
|
<EditIcon />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
@ -19,10 +19,10 @@ const Header = (props) => (
|
|||||||
<a className="nav-link" href="https://pages.colouring.london/about">More about</a>
|
<a className="nav-link" href="https://pages.colouring.london/about">More about</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<NavLink to="/map/age.html" className="nav-link">View Maps</NavLink>
|
<NavLink to="/view/age.html" className="nav-link">View Maps</NavLink>
|
||||||
</li>
|
</li>
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<NavLink to="/select.html" className="nav-link">Add/Edit Data</NavLink>
|
<NavLink to="/edit/age.html" className="nav-link">Add/Edit Data</NavLink>
|
||||||
</li>
|
</li>
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<a className="nav-link" href="https://pages.colouring.london/buildingcategories">Building Categories</a>
|
<a className="nav-link" href="https://pages.colouring.london/buildingcategories">Building Categories</a>
|
||||||
|
@ -1,163 +1,73 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
import { NavLink } from 'react-router-dom';
|
|
||||||
|
|
||||||
import Sidebar from './sidebar';
|
|
||||||
import { EditIcon } from './icons';
|
|
||||||
import './legend.css';
|
import './legend.css';
|
||||||
|
|
||||||
import CONFIG from './fields-config.json';
|
|
||||||
import InfoBox from './info-box';
|
|
||||||
|
|
||||||
|
|
||||||
const LEGEND_CONFIG = {
|
const LEGEND_CONFIG = {
|
||||||
location: [
|
location: [
|
||||||
{
|
{ color: '#f0f9e8', text: '>5' },
|
||||||
title: 'Location Information (number of data entries)',
|
{ color: '#bae4bc', text: '4' },
|
||||||
slug: 'location',
|
{ color: '#7bccc4', text: '3' },
|
||||||
elements: [
|
{ color: '#43a2ca', text: '2' },
|
||||||
{ color: '#f0f9e8', text: '>5' },
|
{ color: '#0868ac', text: '1' }
|
||||||
{ color: '#bae4bc', text: '4' },
|
|
||||||
{ color: '#7bccc4', text: '3' },
|
|
||||||
{ color: '#43a2ca', text: '2' },
|
|
||||||
{ color: '#0868ac', text: '1' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
age: [
|
age: [
|
||||||
{
|
{ color: '#f0eaba', text: '≥2000' },
|
||||||
title: 'Year Built',
|
{ color: '#fae269', text: '1980–2000' },
|
||||||
slug: 'date_year',
|
{ color: '#fbaf27', text: '1960–1980' },
|
||||||
elements: [
|
{ color: '#e6711d', text: '1940–1960' },
|
||||||
{ color: '#f0eaba', text: '≥2000' },
|
{ color: '#d73d3a', text: '1920–1940' },
|
||||||
{ color: '#fae269', text: '1980–2000' },
|
{ color: '#ba221c', text: '1900–1920' },
|
||||||
{ color: '#fbaf27', text: '1960–1980' },
|
{ color: '#bb859b', text: '1880–1900' },
|
||||||
{ color: '#e6711d', text: '1940–1960' },
|
{ color: '#8b3654', text: '1860–1880' },
|
||||||
{ color: '#d73d3a', text: '1920–1940' },
|
{ color: '#8f5385', text: '1840–1860' },
|
||||||
{ color: '#ba221c', text: '1900–1920' },
|
{ color: '#56619b', text: '1820–1840' },
|
||||||
{ color: '#bb859b', text: '1880–1900' },
|
{ color: '#6793b2', text: '1800–1820' },
|
||||||
{ color: '#8b3654', text: '1860–1880' },
|
{ color: '#83c3b3', text: '1780–1800' },
|
||||||
{ color: '#8f5385', text: '1840–1860' },
|
{ color: '#adc88f', text: '1760–1780' },
|
||||||
{ color: '#56619b', text: '1820–1840' },
|
{ color: '#83a663', text: '1740–1760' },
|
||||||
{ color: '#6793b2', text: '1800–1820' },
|
{ color: '#77852d', text: '1720–1740' },
|
||||||
{ color: '#83c3b3', text: '1780–1800' },
|
{ color: '#69814e', text: '1700–1720' },
|
||||||
{ color: '#adc88f', text: '1760–1780' },
|
{ color: '#d0c291', text: '1680–1700' },
|
||||||
{ color: '#83a663', text: '1740–1760' },
|
{ color: '#918158', text: '1660–1680' },
|
||||||
{ color: '#77852d', text: '1720–1740' },
|
{ color: '#7a5732', text: '<1660' },
|
||||||
{ color: '#69814e', text: '1700–1720' },
|
|
||||||
{ color: '#d0c291', text: '1680–1700' },
|
|
||||||
{ color: '#918158', text: '1660–1680' },
|
|
||||||
{ color: '#7a5732', text: '<1660' },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
size: [
|
size: [
|
||||||
{
|
{ color: '#ffffcc', text: '≥20' },
|
||||||
title: 'Number of storeys',
|
{ color: '#ffeda0', text: '15-20' },
|
||||||
slug: 'size_storeys',
|
{ color: '#fed976', text: '10–15' },
|
||||||
elements: [
|
{ color: '#feb24c', text: '6–10' },
|
||||||
{ color: '#ffffcc', text: '≥20' },
|
{ color: '#fd8d3c', text: '5' },
|
||||||
{ color: '#ffeda0', text: '15-20' },
|
{ color: '#fc4e2a', text: '4' },
|
||||||
{ color: '#fed976', text: '10–15' },
|
{ color: '#e31a1c', text: '3' },
|
||||||
{ color: '#feb24c', text: '6–10' },
|
{ color: '#bd0026', text: '2' },
|
||||||
{ color: '#fd8d3c', text: '5' },
|
{ color: '#800026', text: '1' },
|
||||||
{ color: '#fc4e2a', text: '4' },
|
|
||||||
{ color: '#e31a1c', text: '3' },
|
|
||||||
{ color: '#bd0026', text: '2' },
|
|
||||||
{ color: '#800026', text: '1' },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
like: [
|
like: [
|
||||||
{
|
{ color: '#f65400', text: 'We like these buildings 👍 🎉 +1' },
|
||||||
title: 'Which buildings do you like?',
|
|
||||||
slug: 'like',
|
|
||||||
elements: [
|
|
||||||
{ color: '#f65400', text: 'We like these buildings 👍 🎉 +1' },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const Legend = (props) => {
|
const Legend = (props) => {
|
||||||
var data_layer = undefined;
|
let elements = LEGEND_CONFIG[props.slug];
|
||||||
if (props.match && props.match.params && props.match.params.map) {
|
|
||||||
data_layer = props.match.params.map;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sidebar title="View Maps">
|
<dl className="data-list">
|
||||||
<InfoBox msg="Click on the map to see more information about a building…" />
|
<dt>
|
||||||
{
|
{ props.title }
|
||||||
CONFIG.map((data_group) => (
|
</dt>
|
||||||
<LegendGroup {...data_group} maps={LEGEND_CONFIG[data_group.slug]}
|
<dd>
|
||||||
data_layer={data_layer} key={data_group.slug} />
|
<ul className="data-legend">
|
||||||
))
|
{
|
||||||
}
|
elements.map((data_item) => (
|
||||||
</Sidebar>
|
<LegendItem {...data_item} key={data_item.color} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LegendGroup = (props) => {
|
|
||||||
const match = props.data_layer === props.slug;
|
|
||||||
const inactive = props.inactive || !props.maps;
|
|
||||||
return (
|
|
||||||
<section className={(inactive? "inactive ": "") + "data-section legend"}>
|
|
||||||
<header className={(match? "active " : "") + " section-header view"}>
|
|
||||||
<NavLink
|
|
||||||
to={match? "/map/base.html": `/map/${props.slug}.html`}
|
|
||||||
isActive={() => match}
|
|
||||||
title={(inactive)? 'Coming soon… Click the ? for more info.' :
|
|
||||||
(match)? '' : 'Show on map'}>
|
|
||||||
<h3 className="h3">{props.title}</h3>
|
|
||||||
</NavLink>
|
|
||||||
<nav className="icon-buttons">
|
|
||||||
{
|
|
||||||
props.help?
|
|
||||||
<a className="icon-button help" href={props.help}>
|
|
||||||
More info
|
|
||||||
</a>
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
<NavLink className="icon-button edit" title="Edit data"
|
|
||||||
to={`/select.html?cat=${props.slug}`}>
|
|
||||||
Edit
|
|
||||||
<EditIcon />
|
|
||||||
</NavLink>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<dl className="data-list">
|
|
||||||
{
|
|
||||||
(match && props.maps)?
|
|
||||||
props.maps.map((data_section) => (
|
|
||||||
<LegendSection {...data_section} key={data_section.slug}>
|
|
||||||
{
|
|
||||||
data_section.elements.map((data_item) => (
|
|
||||||
<LegendItem {...data_item} key={data_item.color} />
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</LegendSection>
|
|
||||||
))
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
</dl>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
const LegendSection = (props) => (
|
|
||||||
<Fragment>
|
|
||||||
<dt>
|
|
||||||
{ props.title }
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<ul className="data-legend">
|
|
||||||
{ props.children }
|
|
||||||
</ul>
|
|
||||||
</dd>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
const LegendItem = (props) => (
|
const LegendItem = (props) => (
|
||||||
<li>
|
<li>
|
||||||
<span className="key" style={ { background: props.color } }>-</span>
|
<span className="key" style={ { background: props.color } }>-</span>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import { Map, TileLayer, ZoomControl, AttributionControl } from 'react-leaflet-universal';
|
import { Map, TileLayer, ZoomControl, AttributionControl } from 'react-leaflet-universal';
|
||||||
import queryString from 'query-string';
|
|
||||||
|
|
||||||
import '../../node_modules/leaflet/dist/leaflet.css'
|
import '../../node_modules/leaflet/dist/leaflet.css'
|
||||||
import './map.css'
|
import './map.css'
|
||||||
@ -26,14 +25,12 @@ class ColouringMap extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleClick(e) {
|
handleClick(e) {
|
||||||
if (this.props.match.url.match('edit')){
|
const is_edit = this.props.match.url.match('edit')
|
||||||
// don't navigate away from edit view
|
const mode = is_edit? 'edit': 'view';
|
||||||
return
|
const lat = e.latlng.lat
|
||||||
}
|
const lng = e.latlng.lng
|
||||||
var lat = e.latlng.lat
|
const new_cat = get_cat(this.props.match.url);
|
||||||
var lng = e.latlng.lng
|
const map_cat = new_cat || 'age';
|
||||||
const is_building = /building/.test(this.props.match.url);
|
|
||||||
const new_cat = get_cat(is_building, this.props.location, this.props.match.url);
|
|
||||||
fetch(
|
fetch(
|
||||||
'/buildings/locate?lat='+lat+'&lng='+lng
|
'/buildings/locate?lat='+lat+'&lng='+lng
|
||||||
).then(
|
).then(
|
||||||
@ -42,12 +39,11 @@ class ColouringMap extends Component {
|
|||||||
if (data && data.length){
|
if (data && data.length){
|
||||||
const building = data[0];
|
const building = data[0];
|
||||||
this.props.selectBuilding(building);
|
this.props.selectBuilding(building);
|
||||||
this.props.history.push(`/building/${building.building_id}.html`);
|
this.props.history.push(`/${mode}/${map_cat}/building/${building.building_id}.html`);
|
||||||
} else {
|
} else {
|
||||||
// deselect but keep/return to expected colour theme
|
// deselect but keep/return to expected colour theme
|
||||||
this.props.selectBuilding(undefined);
|
this.props.selectBuilding(undefined);
|
||||||
const map_cat = new_cat || 'age';
|
this.props.history.push(`/${mode}/${map_cat}.html`);
|
||||||
this.props.history.push(`/map/${map_cat}.html`);
|
|
||||||
}
|
}
|
||||||
}.bind(this)).catch(
|
}.bind(this)).catch(
|
||||||
(err) => console.error(err)
|
(err) => console.error(err)
|
||||||
@ -72,7 +68,7 @@ class ColouringMap extends Component {
|
|||||||
|
|
||||||
// colour-data tiles
|
// colour-data tiles
|
||||||
const is_building = /building/.test(this.props.match.url);
|
const is_building = /building/.test(this.props.match.url);
|
||||||
const cat = get_cat(is_building, this.props.location, this.props.match.url);
|
const cat = get_cat(this.props.match.url);
|
||||||
const tileset_by_cat = {
|
const tileset_by_cat = {
|
||||||
age: 'date_year',
|
age: 'date_year',
|
||||||
size: 'size_storeys',
|
size: 'size_storeys',
|
||||||
@ -122,18 +118,12 @@ class ColouringMap extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function get_cat(is_building, location, url) {
|
function get_cat(url) {
|
||||||
if (url === "/") {
|
if (url === "/") {
|
||||||
return "age"
|
return "age"
|
||||||
}
|
}
|
||||||
const search = (location && location.search)? queryString.parse(location.search) : {};
|
const matches = /^\/(view|edit)\/([^\/.]+)/.exec(url);
|
||||||
var cat, matches;
|
const cat = (matches && matches.length > 2)? matches[2] : "age";
|
||||||
if (is_building) {
|
|
||||||
cat = search.cat;
|
|
||||||
} else {
|
|
||||||
matches = /\/map\/([^.]+).html/.exec(url);
|
|
||||||
cat = (matches && matches.length > 1)? matches[1] : "";
|
|
||||||
}
|
|
||||||
return cat;
|
return cat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
app/src/frontend/overview.js
Normal file
68
app/src/frontend/overview.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { NavLink, Redirect } from 'react-router-dom';
|
||||||
|
|
||||||
|
import Sidebar from './sidebar';
|
||||||
|
import { EditIcon } from './icons';
|
||||||
|
import CONFIG from './fields-config.json';
|
||||||
|
|
||||||
|
const Overview = (props) => {
|
||||||
|
var data_layer = 'age'; // always default
|
||||||
|
if (props.match && props.match.params && props.match.params.cat) {
|
||||||
|
data_layer = props.match.params.cat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.mode === 'edit' && !props.user){
|
||||||
|
return <Redirect to="/sign-up.html" />
|
||||||
|
}
|
||||||
|
|
||||||
|
let title = (props.mode === 'view')? 'View maps' : 'Add or edit data';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Sidebar title={title}>
|
||||||
|
{
|
||||||
|
CONFIG.map((data_group) => (
|
||||||
|
<OverviewSection {...data_group}
|
||||||
|
data_layer={data_layer} key={data_group.slug} mode={props.mode} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</Sidebar>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const OverviewSection = (props) => {
|
||||||
|
const match = props.data_layer === props.slug;
|
||||||
|
const inactive = props.inactive;
|
||||||
|
return (
|
||||||
|
<section className={(inactive? "inactive ": "") + "data-section legend"}>
|
||||||
|
<header className={(match? "active " : "") + " section-header view"}>
|
||||||
|
<NavLink
|
||||||
|
to={`/${props.mode}/${props.slug}.html`}
|
||||||
|
isActive={() => match}
|
||||||
|
title={(inactive)? 'Coming soon… Click the ? for more info.' :
|
||||||
|
(match)? '' : 'Show on map'}>
|
||||||
|
<h3 className="h3">{props.title}</h3>
|
||||||
|
</NavLink>
|
||||||
|
<nav className="icon-buttons">
|
||||||
|
{
|
||||||
|
props.help?
|
||||||
|
<a className="icon-button help" href={props.help}>
|
||||||
|
More info
|
||||||
|
</a>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
props.mode === 'view'?
|
||||||
|
<NavLink className="icon-button edit" title="Edit data"
|
||||||
|
to={`/edit/${props.slug}.html`}>
|
||||||
|
Edit
|
||||||
|
<EditIcon />
|
||||||
|
</NavLink>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Overview;
|
@ -15,7 +15,7 @@ function strictParseInt(value) {
|
|||||||
|
|
||||||
|
|
||||||
function parseBuildingURL(url){
|
function parseBuildingURL(url){
|
||||||
const re = /^\/building\/([^\/]+)(\/edit)?.html/;
|
const re = /\/building\/([^\/]+).html/;
|
||||||
const matches = re.exec(url);
|
const matches = re.exec(url);
|
||||||
|
|
||||||
if (matches && matches.length >= 2) {
|
if (matches && matches.length >= 2) {
|
||||||
|
Loading…
Reference in New Issue
Block a user