Unpack building edit to data-components with mode
This commit is contained in:
parent
b44b43bc31
commit
541a307b99
@ -1,344 +0,0 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
|
||||||
import { NavLink } from 'react-router-dom';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import Tooltip from '../components/tooltip';
|
|
||||||
|
|
||||||
const TextInput = (props) => (
|
|
||||||
<Fragment>
|
|
||||||
<Label slug={props.slug} title={props.title} tooltip={props.tooltip}
|
|
||||||
copying={props.copying}
|
|
||||||
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
||||||
copy={props.copy}
|
|
||||||
cat={props.cat}
|
|
||||||
disabled={props.disabled} />
|
|
||||||
<input className="form-control" type="text"
|
|
||||||
id={props.slug} name={props.slug}
|
|
||||||
value={props.value || ''}
|
|
||||||
maxLength={props.max_length}
|
|
||||||
disabled={props.disabled}
|
|
||||||
placeholder={props.placeholder}
|
|
||||||
onChange={props.handleChange}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
TextInput.propTypes = {
|
|
||||||
slug: PropTypes.string,
|
|
||||||
cat: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
value: PropTypes.string,
|
|
||||||
max_length: PropTypes.number,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
handleChange: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
const LongTextInput = (props) => (
|
|
||||||
<Fragment>
|
|
||||||
<Label slug={props.slug} title={props.title} cat={props.cat}
|
|
||||||
copying={props.copying}
|
|
||||||
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
||||||
copy={props.copy}
|
|
||||||
disabled={props.disabled} tooltip={props.tooltip} />
|
|
||||||
<textarea className="form-control"
|
|
||||||
id={props.slug} name={props.slug}
|
|
||||||
disabled={props.disabled}
|
|
||||||
placeholder={props.placeholder}
|
|
||||||
onChange={props.handleChange}
|
|
||||||
value={props.value || ''}></textarea>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
|
|
||||||
LongTextInput.propTypes = {
|
|
||||||
slug: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
value: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
handleChange: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
class MultiTextInput extends Component<any, any> { // TODO: add proper types
|
|
||||||
static propTypes = { // TODO: generate propTypes from TS
|
|
||||||
slug: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
value: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
handleChange: PropTypes.func,
|
|
||||||
copy: PropTypes.bool,
|
|
||||||
toggleCopyAttribute: PropTypes.func,
|
|
||||||
copying: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.edit = this.edit.bind(this);
|
|
||||||
this.add = this.add.bind(this);
|
|
||||||
this.remove = this.remove.bind(this);
|
|
||||||
this.getValues = this.getValues.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
getValues() {
|
|
||||||
return (this.props.value && this.props.value.length)? this.props.value : [null];
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(event) {
|
|
||||||
const editIndex = +event.target.dataset.index;
|
|
||||||
const editItem = event.target.value;
|
|
||||||
const oldValues = this.getValues();
|
|
||||||
const values = oldValues.map((item, i) => {
|
|
||||||
return i === editIndex ? editItem : item;
|
|
||||||
});
|
|
||||||
this.props.handleChange(this.props.slug, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
add(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const values = this.getValues().concat('');
|
|
||||||
this.props.handleChange(this.props.slug, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(event){
|
|
||||||
const removeIndex = +event.target.dataset.index;
|
|
||||||
const values = this.getValues().filter((_, i) => {
|
|
||||||
return i !== removeIndex;
|
|
||||||
});
|
|
||||||
this.props.handleChange(this.props.slug, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const values = this.getValues();
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<Label slug={this.props.slug} title={this.props.title} tooltip={this.props.tooltip}
|
|
||||||
cat={this.props.cat}
|
|
||||||
copying={this.props.copying}
|
|
||||||
disabled={this.props.disabled}
|
|
||||||
toggleCopyAttribute={this.props.toggleCopyAttribute}
|
|
||||||
copy={this.props.copy} />
|
|
||||||
{
|
|
||||||
values.map((item, i) => (
|
|
||||||
<div className="input-group" key={i}>
|
|
||||||
<input className="form-control" type="text"
|
|
||||||
key={`${this.props.slug}-${i}`} name={`${this.props.slug}-${i}`}
|
|
||||||
data-index={i}
|
|
||||||
value={item || ''}
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
disabled={this.props.disabled}
|
|
||||||
onChange={this.edit}
|
|
||||||
/>
|
|
||||||
<div className="input-group-append">
|
|
||||||
<button type="button" onClick={this.remove}
|
|
||||||
title="Remove"
|
|
||||||
data-index={i} className="btn btn-outline-dark">✕</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
<button type="button" title="Add" onClick={this.add}
|
|
||||||
className="btn btn-outline-dark">+</button>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const TextListInput = (props) => (
|
|
||||||
<Fragment>
|
|
||||||
<Label slug={props.slug} title={props.title} tooltip={props.tooltip}
|
|
||||||
cat={props.cat} disabled={props.disabled}
|
|
||||||
copying={props.copying}
|
|
||||||
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
||||||
copy={props.copy} />
|
|
||||||
<select className="form-control"
|
|
||||||
id={props.slug} name={props.slug}
|
|
||||||
value={props.value || ''}
|
|
||||||
disabled={props.disabled}
|
|
||||||
// list={`${props.slug}_suggestions`} TODO: investigate whether this was needed
|
|
||||||
onChange={props.handleChange}>
|
|
||||||
<option value="">Select a source</option>
|
|
||||||
{
|
|
||||||
props.options.map(option => (
|
|
||||||
<option key={option} value={option}>{option}</option>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
|
|
||||||
TextListInput.propTypes = {
|
|
||||||
slug: PropTypes.string,
|
|
||||||
cat: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
options: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
value: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
handleChange: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
const NumberInput = (props) => (
|
|
||||||
<Fragment>
|
|
||||||
<Label slug={props.slug} title={props.title} tooltip={props.tooltip}
|
|
||||||
cat={props.cat} disabled={props.disabled}
|
|
||||||
copying={props.copying}
|
|
||||||
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
||||||
copy={props.copy} />
|
|
||||||
<input className="form-control" type="number" step={props.step}
|
|
||||||
id={props.slug} name={props.slug}
|
|
||||||
value={props.value || ''}
|
|
||||||
disabled={props.disabled}
|
|
||||||
onChange={props.handleChange}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
NumberInput.propTypes = {
|
|
||||||
slug: PropTypes.string,
|
|
||||||
cat: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
step: PropTypes.number,
|
|
||||||
value: PropTypes.number,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
handleChange: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
class YearEstimator extends Component<any, any> { // TODO: add proper types
|
|
||||||
static propTypes = { // TODO: generate propTypes from TS
|
|
||||||
slug: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
date_year: PropTypes.number,
|
|
||||||
date_upper: PropTypes.number,
|
|
||||||
date_lower: PropTypes.number,
|
|
||||||
value: PropTypes.number,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
handleChange: PropTypes.func,
|
|
||||||
copy: PropTypes.bool,
|
|
||||||
toggleCopyAttribute: PropTypes.func,
|
|
||||||
copying: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
year: props.date_year,
|
|
||||||
upper: props.date_upper,
|
|
||||||
lower: props.date_lower,
|
|
||||||
decade: Math.floor(props.date_year / 10) * 10,
|
|
||||||
century: Math.floor(props.date_year / 100) * 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO add dropdown for decade, century
|
|
||||||
// TODO roll in first/last year estimate
|
|
||||||
// TODO handle changes internally, reporting out date_year, date_upper, date_lower
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<NumberInput {...this.props}
|
|
||||||
handleChange={this.props.handleChange}
|
|
||||||
|
|
||||||
value={this.props.value}
|
|
||||||
key={this.props.slug}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const CheckboxInput = (props) => (
|
|
||||||
<Fragment>
|
|
||||||
<Label slug={props.slug} title={props.title} tooltip={props.tooltip}
|
|
||||||
cat={props.cat} disabled={props.disabled}
|
|
||||||
copying={props.copying}
|
|
||||||
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
||||||
copy={props.copy} />
|
|
||||||
<div className="form-check">
|
|
||||||
<input className="form-check-input" type="checkbox"
|
|
||||||
id={props.slug} name={props.slug}
|
|
||||||
checked={!!props.value}
|
|
||||||
disabled={props.disabled}
|
|
||||||
onChange={props.handleChange}
|
|
||||||
/>
|
|
||||||
<label htmlFor={props.slug} className="form-check-label">
|
|
||||||
{props.title}
|
|
||||||
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
|
|
||||||
CheckboxInput.propTypes = {
|
|
||||||
slug: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
value: PropTypes.bool,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
handleChange: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
const LikeButton = (props) => (
|
|
||||||
<Fragment>
|
|
||||||
<p className="likes">{(props.value)? props.value : 0} likes</p>
|
|
||||||
<div className="form-check">
|
|
||||||
<input className="form-check-input" type="checkbox"
|
|
||||||
id={props.slug} name={props.slug}
|
|
||||||
checked={!!props.building_like}
|
|
||||||
disabled={props.disabled}
|
|
||||||
onChange={props.handleLike}
|
|
||||||
/>
|
|
||||||
<label htmlFor={props.slug} className="form-check-label">
|
|
||||||
I like this building and think it contributes to the city!
|
|
||||||
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<NavLink
|
|
||||||
to={`/multi-edit/${props.cat}.html`}>
|
|
||||||
Like more buildings
|
|
||||||
</NavLink>
|
|
||||||
</p>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
LikeButton.propTypes = {
|
|
||||||
slug: PropTypes.string,
|
|
||||||
cat: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
tooltip: PropTypes.string,
|
|
||||||
value: PropTypes.number,
|
|
||||||
building_like: PropTypes.bool,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
handleLike: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
const Label: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
|
||||||
return (
|
|
||||||
<label htmlFor={props.slug}>
|
|
||||||
{props.title}
|
|
||||||
{ (props.copying && props.cat && props.slug && !props.disabled)?
|
|
||||||
<div className="icon-buttons">
|
|
||||||
<label className="icon-button copy">
|
|
||||||
Copy
|
|
||||||
<input type="checkbox" checked={props.copy}
|
|
||||||
onChange={() => props.toggleCopyAttribute(props.slug)}/>
|
|
||||||
</label>
|
|
||||||
</div> : null
|
|
||||||
}
|
|
||||||
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Label.propTypes = {
|
|
||||||
slug: PropTypes.string,
|
|
||||||
cat: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
tooltip: PropTypes.string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BuildingEdit;
|
|
@ -21,10 +21,15 @@ import LikeContainer from './data-containers/like';
|
|||||||
* @param props
|
* @param props
|
||||||
*/
|
*/
|
||||||
const BuildingView = (props) => {
|
const BuildingView = (props) => {
|
||||||
|
if (typeof(props.building) === "undefined"){
|
||||||
|
return <BuildingNotFound mode="view" />
|
||||||
|
}
|
||||||
|
|
||||||
switch (props.cat) {
|
switch (props.cat) {
|
||||||
case 'location':
|
case 'location':
|
||||||
return <LocationContainer
|
return <LocationContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Location"
|
title="Location"
|
||||||
help="https://pages.colouring.london/location"
|
help="https://pages.colouring.london/location"
|
||||||
intro="Where are the buildings? Address, location and cross-references."
|
intro="Where are the buildings? Address, location and cross-references."
|
||||||
@ -32,6 +37,7 @@ const BuildingView = (props) => {
|
|||||||
case 'use':
|
case 'use':
|
||||||
return <UseContainer
|
return <UseContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
inactive={true}
|
inactive={true}
|
||||||
title="Land Use"
|
title="Land Use"
|
||||||
intro="How are buildings used, and how does use change over time? Coming soon…"
|
intro="How are buildings used, and how does use change over time? Coming soon…"
|
||||||
@ -40,6 +46,7 @@ const BuildingView = (props) => {
|
|||||||
case 'type':
|
case 'type':
|
||||||
return <TypeContainer
|
return <TypeContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
inactive={true}
|
inactive={true}
|
||||||
title="Type"
|
title="Type"
|
||||||
intro="How were buildings previously used? Coming soon…"
|
intro="How were buildings previously used? Coming soon…"
|
||||||
@ -48,6 +55,7 @@ const BuildingView = (props) => {
|
|||||||
case 'age':
|
case 'age':
|
||||||
return <AgeContainer
|
return <AgeContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Age"
|
title="Age"
|
||||||
help="https://pages.colouring.london/age"
|
help="https://pages.colouring.london/age"
|
||||||
intro="Building age data can support energy analysis and help predict long-term change."
|
intro="Building age data can support energy analysis and help predict long-term change."
|
||||||
@ -55,6 +63,7 @@ const BuildingView = (props) => {
|
|||||||
case 'size':
|
case 'size':
|
||||||
return <SizeContainer
|
return <SizeContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Size & Shape"
|
title="Size & Shape"
|
||||||
intro="How big are buildings?"
|
intro="How big are buildings?"
|
||||||
help="https://pages.colouring.london/shapeandsize"
|
help="https://pages.colouring.london/shapeandsize"
|
||||||
@ -62,6 +71,7 @@ const BuildingView = (props) => {
|
|||||||
case 'construction':
|
case 'construction':
|
||||||
return <ConstructionContainer
|
return <ConstructionContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Construction"
|
title="Construction"
|
||||||
intro="How are buildings built? Coming soon…"
|
intro="How are buildings built? Coming soon…"
|
||||||
help="https://pages.colouring.london/construction"
|
help="https://pages.colouring.london/construction"
|
||||||
@ -70,6 +80,7 @@ const BuildingView = (props) => {
|
|||||||
case 'team':
|
case 'team':
|
||||||
return <TeamContainer
|
return <TeamContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Team"
|
title="Team"
|
||||||
intro="Who built the buildings? Coming soon…"
|
intro="Who built the buildings? Coming soon…"
|
||||||
help="https://pages.colouring.london/team"
|
help="https://pages.colouring.london/team"
|
||||||
@ -78,6 +89,7 @@ const BuildingView = (props) => {
|
|||||||
case 'sustainability':
|
case 'sustainability':
|
||||||
return <SustainabilityContainer
|
return <SustainabilityContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Sustainability"
|
title="Sustainability"
|
||||||
intro="Are buildings energy efficient? Coming soon…"
|
intro="Are buildings energy efficient? Coming soon…"
|
||||||
help="https://pages.colouring.london/sustainability"
|
help="https://pages.colouring.london/sustainability"
|
||||||
@ -86,6 +98,7 @@ const BuildingView = (props) => {
|
|||||||
case 'greenery':
|
case 'greenery':
|
||||||
return <GreeneryContainer
|
return <GreeneryContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Greenery"
|
title="Greenery"
|
||||||
intro="Is there greenery nearby? Coming soon…"
|
intro="Is there greenery nearby? Coming soon…"
|
||||||
help="https://pages.colouring.london/greenery"
|
help="https://pages.colouring.london/greenery"
|
||||||
@ -94,6 +107,7 @@ const BuildingView = (props) => {
|
|||||||
case 'community':
|
case 'community':
|
||||||
return <CommunityContainer
|
return <CommunityContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Community"
|
title="Community"
|
||||||
intro="How does this building work for the local community?"
|
intro="How does this building work for the local community?"
|
||||||
help="https://pages.colouring.london/community"
|
help="https://pages.colouring.london/community"
|
||||||
@ -102,6 +116,7 @@ const BuildingView = (props) => {
|
|||||||
case 'planning':
|
case 'planning':
|
||||||
return <PlanningContainer
|
return <PlanningContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Planning"
|
title="Planning"
|
||||||
intro="Planning controls relating to protection and reuse."
|
intro="Planning controls relating to protection and reuse."
|
||||||
help="https://pages.colouring.london/planning"
|
help="https://pages.colouring.london/planning"
|
||||||
@ -109,6 +124,7 @@ const BuildingView = (props) => {
|
|||||||
case 'like':
|
case 'like':
|
||||||
return <LikeContainer
|
return <LikeContainer
|
||||||
{...props}
|
{...props}
|
||||||
|
key={props.building.building_id}
|
||||||
title="Like Me!"
|
title="Like Me!"
|
||||||
intro="Do you like the building and think it contributes to the city?"
|
intro="Do you like the building and think it contributes to the city?"
|
||||||
help="https://pages.colouring.london/likeme"
|
help="https://pages.colouring.london/likeme"
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { DataTitleCopyable } from './data-title';
|
||||||
|
|
||||||
|
const DataEntry: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<DataTitleCopyable
|
||||||
|
slug={props.slug}
|
||||||
|
title={props.title}
|
||||||
|
tooltip={props.tooltip}
|
||||||
|
disabled={props.disabled}
|
||||||
|
copy={props.copy}
|
||||||
|
/>
|
||||||
|
<div className="form-check">
|
||||||
|
<input className="form-check-input" type="checkbox"
|
||||||
|
id={props.slug}
|
||||||
|
name={props.slug}
|
||||||
|
checked={!!props.value}
|
||||||
|
disabled={props.mode === 'view' || props.disabled}
|
||||||
|
onChange={props.onChange}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor={props.slug}
|
||||||
|
className="form-check-label">
|
||||||
|
{props.title}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataEntry.propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
slug: PropTypes.string,
|
||||||
|
tooltip: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
value: PropTypes.any,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
maxLength: PropTypes.number,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
copy: PropTypes.shape({
|
||||||
|
copying: PropTypes.bool,
|
||||||
|
copyingKey: PropTypes.func,
|
||||||
|
toggleCopyAttribute: PropTypes.func
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DataEntry;
|
@ -13,15 +13,15 @@ const DataEntry: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
|||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
/>
|
/>
|
||||||
<dd>
|
<input className="form-control" type="text"
|
||||||
{
|
id={props.slug}
|
||||||
(props.value != null && props.value !== '')?
|
name={props.slug}
|
||||||
(typeof(props.value) === 'boolean')?
|
value={props.value || ''}
|
||||||
(props.value)? 'Yes' : 'No'
|
maxLength={props.maxLength}
|
||||||
: props.value
|
disabled={props.mode === 'view' || props.disabled}
|
||||||
: '\u00A0'
|
placeholder={props.placeholder}
|
||||||
}
|
onChange={props.onChange}
|
||||||
</dd>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -32,6 +32,9 @@ DataEntry.propTypes = {
|
|||||||
tooltip: PropTypes.string,
|
tooltip: PropTypes.string,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
value: PropTypes.any,
|
value: PropTypes.any,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
maxLength: PropTypes.number,
|
||||||
|
onChange: PropTypes.func,
|
||||||
copy: PropTypes.shape({
|
copy: PropTypes.shape({
|
||||||
copying: PropTypes.bool,
|
copying: PropTypes.bool,
|
||||||
copyingKey: PropTypes.func,
|
copyingKey: PropTypes.func,
|
||||||
|
@ -19,10 +19,9 @@ DataTitle.propTypes = {
|
|||||||
|
|
||||||
const DataTitleCopyable: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
const DataTitleCopyable: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
||||||
return (
|
return (
|
||||||
<dt>
|
<div className="data-title">
|
||||||
{ props.title }
|
|
||||||
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
||||||
{ (props.copy.copying && props.slug && !props.disabled)?
|
{ (props.copy && props.copy.copying && props.slug && !props.disabled)?
|
||||||
<div className="icon-buttons">
|
<div className="icon-buttons">
|
||||||
<label className="icon-button copy">
|
<label className="icon-button copy">
|
||||||
Copy
|
Copy
|
||||||
@ -34,7 +33,10 @@ const DataTitleCopyable: React.FunctionComponent<any> = (props) => { // TODO: re
|
|||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
</dt>
|
<label htmlFor={props.slug}>
|
||||||
|
{ props.title }
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,29 +8,35 @@ const LikeDataEntry: React.FunctionComponent<any> = (props) => { // TODO: remove
|
|||||||
const data_string = JSON.stringify({like: true});
|
const data_string = JSON.stringify({like: true});
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<dt>
|
<div className="data-title">
|
||||||
Number of likes
|
|
||||||
<Tooltip text="People who like the building and think it contributes to the city." />
|
<Tooltip text="People who like the building and think it contributes to the city." />
|
||||||
<div className="icon-buttons">
|
<div className="icon-buttons">
|
||||||
<NavLink
|
<NavLink
|
||||||
to={`/multi-edit/like.html?data=${data_string}`}
|
to={`/multi-edit/like.html?data=${data_string}`}
|
||||||
className="icon-button copy">
|
className="icon-button like">
|
||||||
Copy
|
Like more
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</dt>
|
<label>Number of likes</label>
|
||||||
<dd>
|
</div>
|
||||||
|
<p>
|
||||||
{
|
{
|
||||||
(props.value != null)?
|
(props.value != null)?
|
||||||
(props.value === 1)?
|
(props.value === 1)?
|
||||||
`${props.value} person likes this building`
|
`${props.value} person likes this building`
|
||||||
: `${props.value} people like this building`
|
: `${props.value} people like this building`
|
||||||
: '\u00A0'
|
: "0 people like this building so far - you could be the first!"
|
||||||
}
|
}
|
||||||
</dd>
|
</p>
|
||||||
{
|
<input className="form-check-input" type="checkbox"
|
||||||
(props.user_building_like)? <dd>…including you!</dd> : ''
|
id="like" name="like"
|
||||||
}
|
checked={!!props.building_like}
|
||||||
|
disabled={props.mode === 'view'}
|
||||||
|
onChange={props.handleLike}
|
||||||
|
/>
|
||||||
|
<label htmlFor="like" className="form-check-label">
|
||||||
|
I like this building and think it contributes to the city!
|
||||||
|
</label>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,111 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { sanitiseURL } from '../../helpers';
|
import { sanitiseURL } from '../../helpers';
|
||||||
import { DataTitleCopyable } from './data-title';
|
import { DataTitleCopyable } from './data-title';
|
||||||
|
|
||||||
|
|
||||||
const MultiDataEntry: React.FunctionComponent<any> = (props) => ( // TODO: remove any
|
class MultiDataEntry extends Component<any, any> { // TODO: add proper types
|
||||||
<Fragment>
|
static propTypes = { // TODO: generate propTypes from TS
|
||||||
<DataTitleCopyable
|
slug: PropTypes.string,
|
||||||
slug={props.slug}
|
title: PropTypes.string,
|
||||||
title={props.title}
|
tooltip: PropTypes.string,
|
||||||
tooltip={props.tooltip}
|
value: PropTypes.arrayOf(PropTypes.string),
|
||||||
disabled={props.disabled}
|
placeholder: PropTypes.string,
|
||||||
/>
|
disabled: PropTypes.bool,
|
||||||
<dd>
|
handleChange: PropTypes.func,
|
||||||
{
|
copy: PropTypes.bool,
|
||||||
(props.value && props.value.length)?
|
toggleCopyAttribute: PropTypes.func,
|
||||||
<ul>
|
copying: PropTypes.bool
|
||||||
{
|
};
|
||||||
props.value.map((item, index) => {
|
|
||||||
return <li key={index}><a href={sanitiseURL(item)}>{item}</a></li>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
:'\u00A0'
|
|
||||||
}
|
|
||||||
</dd>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
|
|
||||||
MultiDataEntry.propTypes = {
|
constructor(props) {
|
||||||
title: PropTypes.string,
|
super(props);
|
||||||
tooltip: PropTypes.string,
|
this.edit = this.edit.bind(this);
|
||||||
value: PropTypes.arrayOf(PropTypes.string)
|
this.add = this.add.bind(this);
|
||||||
|
this.remove = this.remove.bind(this);
|
||||||
|
this.getValues = this.getValues.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValues() {
|
||||||
|
return (this.props.value && this.props.value.length)? this.props.value : [null];
|
||||||
|
}
|
||||||
|
|
||||||
|
edit(event) {
|
||||||
|
const editIndex = +event.target.dataset.index;
|
||||||
|
const editItem = event.target.value;
|
||||||
|
const oldValues = this.getValues();
|
||||||
|
const values = oldValues.map((item, i) => {
|
||||||
|
return i === editIndex ? editItem : item;
|
||||||
|
});
|
||||||
|
this.props.onChange(this.props.slug, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const values = this.getValues().concat('');
|
||||||
|
this.props.onChange(this.props.slug, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(event){
|
||||||
|
const removeIndex = +event.target.dataset.index;
|
||||||
|
const values = this.getValues().filter((_, i) => {
|
||||||
|
return i !== removeIndex;
|
||||||
|
});
|
||||||
|
this.props.onChange(this.props.slug, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const values = this.getValues();
|
||||||
|
const props = this.props;
|
||||||
|
return <Fragment>
|
||||||
|
<DataTitleCopyable
|
||||||
|
slug={props.slug}
|
||||||
|
title={props.title}
|
||||||
|
tooltip={props.tooltip}
|
||||||
|
disabled={props.disabled}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
(props.mode === 'view')?
|
||||||
|
(props.value && props.value.length)?
|
||||||
|
<ul className="data-link-list">
|
||||||
|
{
|
||||||
|
props.value.map((item, index) => {
|
||||||
|
return <li
|
||||||
|
key={index}
|
||||||
|
className="form-control">
|
||||||
|
<a href={sanitiseURL(item)}>{item}</a>
|
||||||
|
</li>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
:'\u00A0'
|
||||||
|
: values.map((item, i) => (
|
||||||
|
<div className="input-group" key={i}>
|
||||||
|
<input className="form-control" type="text"
|
||||||
|
key={`${props.slug}-${i}`} name={`${props.slug}-${i}`}
|
||||||
|
data-index={i}
|
||||||
|
value={item || ''}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
disabled={props.disabled}
|
||||||
|
onChange={this.edit}
|
||||||
|
/>
|
||||||
|
<div className="input-group-append">
|
||||||
|
<button type="button" onClick={this.remove}
|
||||||
|
title="Remove"
|
||||||
|
data-index={i} className="btn btn-outline-dark">✕</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
title="Add"
|
||||||
|
onClick={this.add}
|
||||||
|
disabled={props.mode === 'view'}
|
||||||
|
className="btn btn-outline-dark">+</button>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MultiDataEntry;
|
export default MultiDataEntry;
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { DataTitleCopyable } from './data-title';
|
||||||
|
|
||||||
|
const NumericDataEntry: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<DataTitleCopyable
|
||||||
|
slug={props.slug}
|
||||||
|
title={props.title}
|
||||||
|
tooltip={props.tooltip}
|
||||||
|
disabled={props.disabled}
|
||||||
|
copy={props.copy}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
className="form-control"
|
||||||
|
type="number"
|
||||||
|
id={props.slug}
|
||||||
|
name={props.slug}
|
||||||
|
value={props.value || ''}
|
||||||
|
step={props.step || 1}
|
||||||
|
max={props.max}
|
||||||
|
min={props.min || 0}
|
||||||
|
disabled={props.mode === 'view' || props.disabled}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
onChange={props.onChange}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumericDataEntry.propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
slug: PropTypes.string,
|
||||||
|
tooltip: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
value: PropTypes.any,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
max: PropTypes.number,
|
||||||
|
min: PropTypes.number,
|
||||||
|
step: PropTypes.number,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
copy: PropTypes.shape({
|
||||||
|
copying: PropTypes.bool,
|
||||||
|
copyingKey: PropTypes.func,
|
||||||
|
toggleCopyAttribute: PropTypes.func
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NumericDataEntry;
|
@ -0,0 +1,48 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { DataTitleCopyable } from './data-title';
|
||||||
|
|
||||||
|
const SelectDataEntry: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<DataTitleCopyable
|
||||||
|
slug={props.slug}
|
||||||
|
title={props.title}
|
||||||
|
tooltip={props.tooltip}
|
||||||
|
disabled={props.disabled}
|
||||||
|
copy={props.copy}
|
||||||
|
/>
|
||||||
|
<select className="form-control"
|
||||||
|
id={props.slug} name={props.slug}
|
||||||
|
value={props.value || ''}
|
||||||
|
disabled={props.mode === 'view' || props.disabled}
|
||||||
|
onChange={props.handleChange}>
|
||||||
|
<option value="">{props.placeholder}</option>
|
||||||
|
{
|
||||||
|
props.options.map(option => (
|
||||||
|
<option key={option} value={option}>{option}</option>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectDataEntry.propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
slug: PropTypes.string,
|
||||||
|
tooltip: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
value: PropTypes.any,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
options: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
copy: PropTypes.shape({
|
||||||
|
copying: PropTypes.bool,
|
||||||
|
copyingKey: PropTypes.func,
|
||||||
|
toggleCopyAttribute: PropTypes.func
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectDataEntry;
|
@ -0,0 +1,47 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { DataTitleCopyable } from './data-title';
|
||||||
|
|
||||||
|
const TextboxDataEntry: React.FunctionComponent<any> = (props) => { // TODO: remove any
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<DataTitleCopyable
|
||||||
|
slug={props.slug}
|
||||||
|
title={props.title}
|
||||||
|
tooltip={props.tooltip}
|
||||||
|
disabled={props.disabled}
|
||||||
|
copy={props.copy}
|
||||||
|
/>
|
||||||
|
<textarea
|
||||||
|
className="form-control"
|
||||||
|
id={props.slug}
|
||||||
|
name={props.slug}
|
||||||
|
value={props.value || ''}
|
||||||
|
maxLength={props.max_length}
|
||||||
|
rows={5}
|
||||||
|
disabled={props.mode === 'view' || props.disabled}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
onChange={props.onChange}
|
||||||
|
></textarea>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextboxDataEntry.propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
slug: PropTypes.string,
|
||||||
|
tooltip: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
value: PropTypes.any,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
maxLength: PropTypes.number,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
copy: PropTypes.shape({
|
||||||
|
copying: PropTypes.bool,
|
||||||
|
copyingKey: PropTypes.func,
|
||||||
|
toggleCopyAttribute: PropTypes.func
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TextboxDataEntry;
|
@ -0,0 +1,71 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import NumericDataEntry from './numeric-data-entry';
|
||||||
|
|
||||||
|
class YearDataEntry extends Component<any, any> { // TODO: add proper types
|
||||||
|
static propTypes = { // TODO: generate propTypes from TS
|
||||||
|
year: PropTypes.number,
|
||||||
|
upper: PropTypes.number,
|
||||||
|
lower: PropTypes.number,
|
||||||
|
mode: PropTypes.string,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
copy: PropTypes.shape({
|
||||||
|
copying: PropTypes.bool,
|
||||||
|
copyingKey: PropTypes.func,
|
||||||
|
toggleCopyAttribute: PropTypes.func
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
year: props.year,
|
||||||
|
upper: props.upper,
|
||||||
|
lower: props.lower,
|
||||||
|
decade: Math.floor(props.year / 10) * 10,
|
||||||
|
century: Math.floor(props.year / 100) * 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO add dropdown for decade, century
|
||||||
|
// TODO roll in first/last year estimate
|
||||||
|
// TODO handle changes internally, reporting out date_year, date_upper, date_lower
|
||||||
|
render() {
|
||||||
|
const props = this.props;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<NumericDataEntry
|
||||||
|
title="Year built (best estimate)"
|
||||||
|
slug="date_year"
|
||||||
|
value={props.year}
|
||||||
|
mode={props.mode}
|
||||||
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
// "type": "year_estimator"
|
||||||
|
/>
|
||||||
|
<NumericDataEntry
|
||||||
|
title="Latest possible start year"
|
||||||
|
slug="date_upper"
|
||||||
|
value={props.upper}
|
||||||
|
mode={props.mode}
|
||||||
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={1}
|
||||||
|
tooltip="This should be the latest year in which building could have started."
|
||||||
|
/>
|
||||||
|
<NumericDataEntry
|
||||||
|
title="Earliest possible start date"
|
||||||
|
slug="date_lower"
|
||||||
|
value={props.lower}
|
||||||
|
mode={props.mode}
|
||||||
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={1}
|
||||||
|
tooltip="This should be the earliest year in which building could have started."
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default YearDataEntry;
|
@ -31,18 +31,12 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// create object and spread into state to avoid TS complaining about modifying readonly state
|
|
||||||
let fieldsObj = {};
|
|
||||||
for (const field of props.fields) {
|
|
||||||
fieldsObj[field.slug] = props[field.slug];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
error: this.props.error || undefined,
|
error: this.props.error || undefined,
|
||||||
like: this.props.like || undefined,
|
like: this.props.like || undefined,
|
||||||
copying: false,
|
copying: false,
|
||||||
keys_to_copy: {},
|
keys_to_copy: {},
|
||||||
...fieldsObj
|
building: this.props.building
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
this.handleChange = this.handleChange.bind(this);
|
||||||
@ -81,11 +75,20 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateBuildingState(key, value) {
|
||||||
|
const building = {...this.state.building};
|
||||||
|
building[key] = value;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
building: building
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle changes on typical inputs
|
* Handle changes on typical inputs
|
||||||
* - e.g. input[type=text], radio, select, textare
|
* - e.g. input[type=text], radio, select, textare
|
||||||
*
|
*
|
||||||
* @param {DocumentEvent} event
|
* @param {*} event
|
||||||
*/
|
*/
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
@ -96,25 +99,21 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
if (name === 'location_postcode' && value !== null) {
|
if (name === 'location_postcode' && value !== null) {
|
||||||
value = value.toUpperCase();
|
value = value.toUpperCase();
|
||||||
}
|
}
|
||||||
this.setState({
|
this.updateBuildingState(name, value);
|
||||||
[name]: value
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle changes on checkboxes
|
* Handle changes on checkboxes
|
||||||
* - e.g. input[type=checkbox]
|
* - e.g. input[type=checkbox]
|
||||||
*
|
*
|
||||||
* @param {DocumentEvent} event
|
* @param {*} event
|
||||||
*/
|
*/
|
||||||
handleCheck(event) {
|
handleCheck(event) {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
const value = target.checked;
|
const value = target.checked;
|
||||||
const name = target.name;
|
const name = target.name;
|
||||||
|
|
||||||
this.setState({
|
this.updateBuildingState(name, value);
|
||||||
[name]: value
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,23 +123,21 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
* @param {String} key
|
* @param {String} key
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
*/
|
*/
|
||||||
handleUpdate(key, value) {
|
handleUpdate(key: string, value: any) {
|
||||||
this.setState({
|
this.updateBuildingState(name, value);
|
||||||
[key]: value
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle likes separately
|
* Handle likes separately
|
||||||
* - like/love reaction is limited to set/unset per user
|
* - like/love reaction is limited to set/unset per user
|
||||||
*
|
*
|
||||||
* @param {DocumentEvent} event
|
* @param {*} event
|
||||||
*/
|
*/
|
||||||
handleLike(event) {
|
handleLike(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const like = event.target.checked;
|
const like = event.target.checked;
|
||||||
|
|
||||||
fetch(`/building/${this.props.building_id}/like.json`, {
|
fetch(`/api/buildings/${this.props.building.building_id}/like.json`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers:{
|
headers:{
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@ -154,9 +151,7 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
this.setState({error: res.error})
|
this.setState({error: res.error})
|
||||||
} else {
|
} else {
|
||||||
this.props.selectBuilding(res);
|
this.props.selectBuilding(res);
|
||||||
this.setState({
|
this.updateBuildingState('likes_total', res.likes_total);
|
||||||
likes_total: res.likes_total
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}.bind(this)).catch(
|
}.bind(this)).catch(
|
||||||
(err) => this.setState({error: err})
|
(err) => this.setState({error: err})
|
||||||
@ -167,9 +162,9 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.setState({error: undefined})
|
this.setState({error: undefined})
|
||||||
|
|
||||||
fetch(`/building/${this.props.building_id}.json`, {
|
fetch(`/api/buildings/${this.props.building.building_id}.json`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(this.state),
|
body: JSON.stringify(this.state.building),
|
||||||
headers:{
|
headers:{
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
@ -194,29 +189,29 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
|
|
||||||
const values_to_copy = {}
|
const values_to_copy = {}
|
||||||
for (const key of Object.keys(this.state.keys_to_copy)) {
|
for (const key of Object.keys(this.state.keys_to_copy)) {
|
||||||
values_to_copy[key] = this.state[key]
|
values_to_copy[key] = this.state.building[key]
|
||||||
}
|
}
|
||||||
const data_string = JSON.stringify(values_to_copy);
|
const data_string = JSON.stringify(values_to_copy);
|
||||||
const copy = {
|
const copy = {
|
||||||
copying: this.state.copying,
|
copying: this.state.copying,
|
||||||
toggleCopying: this.toggleCopying,
|
toggleCopying: this.toggleCopying,
|
||||||
toggleCopyAttribute: this.toggleCopyAttribute,
|
toggleCopyAttribute: this.toggleCopyAttribute,
|
||||||
copyingKey: (key) => Object.keys(this.state.values_to_copy).includes(key)
|
copyingKey: (key) => this.state.keys_to_copy[key]
|
||||||
}
|
}
|
||||||
return this.props.building?
|
return this.props.building?
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<section
|
<section
|
||||||
id={this.props.slug}
|
id={this.props.slug}
|
||||||
className="data-section">
|
className="data-section">
|
||||||
|
<ContainerHeader
|
||||||
|
{...this.props}
|
||||||
|
data_string={data_string}
|
||||||
|
copy={copy}
|
||||||
|
/>
|
||||||
<form
|
<form
|
||||||
action={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}
|
action={`/edit/${this.props.slug}/building/${this.props.building.building_id}.html`}
|
||||||
method="POST"
|
method="POST"
|
||||||
onSubmit={this.handleSubmit}>
|
onSubmit={this.handleSubmit}>
|
||||||
<ContainerHeader
|
|
||||||
{...this.props}
|
|
||||||
data_string={data_string}
|
|
||||||
copy={copy}
|
|
||||||
/>
|
|
||||||
<ErrorBox msg={this.state.error} />
|
<ErrorBox msg={this.state.error} />
|
||||||
{
|
{
|
||||||
(this.props.mode === 'edit' && this.props.inactive)?
|
(this.props.mode === 'edit' && this.props.inactive)?
|
||||||
@ -226,12 +221,13 @@ const withCopyEdit = (WrappedComponent) => {
|
|||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
<WrappedComponent
|
<WrappedComponent
|
||||||
{...this.props}
|
building={this.state.building}
|
||||||
|
mode={this.props.mode}
|
||||||
copy={copy}
|
copy={copy}
|
||||||
handleChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
handleCheck={this.handleCheck}
|
onCheck={this.handleCheck}
|
||||||
handleLike={this.handleLike}
|
onLike={this.handleLike}
|
||||||
handleUpdate={this.handleUpdate}
|
onUpdate={this.handleUpdate}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
(this.props.mode === 'edit' && !this.props.inactive)?
|
(this.props.mode === 'edit' && !this.props.inactive)?
|
||||||
|
@ -1,80 +1,74 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
|
||||||
import withCopyEdit from '../data-container';
|
import withCopyEdit from '../data-container';
|
||||||
import DataEntry from '../data-components/data-entry';
|
import MultiDataEntry from '../data-components/multi-data-entry';
|
||||||
|
import NumericDataEntry from '../data-components/numeric-data-entry';
|
||||||
|
import SelectDataEntry from '../data-components/select-data-entry';
|
||||||
|
import TextboxDataEntry from '../data-components/textbox-data-entry';
|
||||||
|
import YearDataEntry from '../data-components/year-data-entry';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Age view/edit section
|
* Age view/edit section
|
||||||
*/
|
*/
|
||||||
const AgeView = (props) => (
|
const AgeView = (props) => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<DataEntry
|
<YearDataEntry
|
||||||
title="Year built (best estimate)"
|
year={props.building.date_year}
|
||||||
slug="date_year"
|
upper={props.building.date_upper}
|
||||||
value={props.building.date_year}
|
lower={props.building.date_lower}
|
||||||
copy={props.copy}
|
mode={props.mode}
|
||||||
// "type": "year_estimator"
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
<DataEntry
|
<NumericDataEntry
|
||||||
title="Latest possible start year"
|
|
||||||
slug="date_upper"
|
|
||||||
value={props.building.date_upper}
|
|
||||||
copy={props.copy}
|
|
||||||
// "type": "number", "step": 1,
|
|
||||||
tooltip="This should be the latest year in which building could have started."
|
|
||||||
/>
|
|
||||||
<DataEntry
|
|
||||||
title="Earliest possible start date"
|
|
||||||
slug="date_lower"
|
|
||||||
value={props.building.date_lower}
|
|
||||||
copy={props.copy}
|
|
||||||
// "type": "number", "step": 1,
|
|
||||||
tooltip="This should be the earliest year in which building could have started."
|
|
||||||
/>
|
|
||||||
<DataEntry
|
|
||||||
title="Facade year"
|
title="Facade year"
|
||||||
slug="facade_year"
|
slug="facade_year"
|
||||||
value={props.building.facade_year}
|
value={props.building.facade_year}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
// "type": "number", "step": 1,
|
onChange={props.onChange}
|
||||||
|
step={1}
|
||||||
tooltip="Best estimate"
|
tooltip="Best estimate"
|
||||||
/>
|
/>
|
||||||
<DataEntry
|
<SelectDataEntry
|
||||||
title="Source of information"
|
title="Source of information"
|
||||||
slug="date_source"
|
slug="date_source"
|
||||||
value={props.building.date_source}
|
value={props.building.date_source}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
// "type": "text_list",
|
onChange={props.onChange}
|
||||||
tooltip="Source for the main start date"
|
tooltip="Source for the main start date"
|
||||||
// "options": [
|
placeholder=""
|
||||||
// "Survey of London",
|
options={[
|
||||||
// "Pevsner Guides",
|
"Survey of London",
|
||||||
// "Local history publication",
|
"Pevsner Guides",
|
||||||
// "National Heritage List for England",
|
"Local history publication",
|
||||||
// "Historical map",
|
"National Heritage List for England",
|
||||||
// "Archive research",
|
"Historical map",
|
||||||
// "Expert knowledge of building",
|
"Archive research",
|
||||||
// "Other book",
|
"Expert knowledge of building",
|
||||||
// "Other website",
|
"Other book",
|
||||||
// "Other"
|
"Other website",
|
||||||
// ]
|
"Other"
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
<DataEntry
|
<TextboxDataEntry
|
||||||
title="Source details"
|
title="Source details"
|
||||||
slug="date_source_detail"
|
slug="date_source_detail"
|
||||||
value={props.building.date_source_detail}
|
value={props.building.date_source_detail}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
// "type": "text_long",
|
onChange={props.onChange}
|
||||||
tooltip="References for date source (max 500 characters)"
|
tooltip="References for date source (max 500 characters)"
|
||||||
/>
|
/>
|
||||||
<DataEntry
|
<MultiDataEntry
|
||||||
title="Text and Image Links"
|
title="Text and Image Links"
|
||||||
slug="date_link"
|
slug="date_link"
|
||||||
value={props.building.date_link}
|
value={props.building.date_link}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
// "type": "text_multi",
|
onChange={props.onChange}
|
||||||
tooltip="URL for age and date reference"
|
tooltip="URL for age and date reference"
|
||||||
// "placeholder": "https://..."
|
placeholder="https://..."
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,8 @@ const LikeView = (props) => (
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<LikeDataEntry
|
<LikeDataEntry
|
||||||
value={props.building.likes_total}
|
value={props.building.likes_total}
|
||||||
|
mode={props.mode}
|
||||||
|
onLike={props.onLike}
|
||||||
user_building_like={props.building_like}
|
user_building_like={props.building_like}
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
@ -2,127 +2,113 @@ import React, { Fragment } from 'react';
|
|||||||
|
|
||||||
import withCopyEdit from '../data-container';
|
import withCopyEdit from '../data-container';
|
||||||
import DataEntry from '../data-components/data-entry';
|
import DataEntry from '../data-components/data-entry';
|
||||||
|
import NumericDataEntry from '../data-components/numeric-data-entry';
|
||||||
import UPRNsDataEntry from '../data-components/uprns-data-entry';
|
import UPRNsDataEntry from '../data-components/uprns-data-entry';
|
||||||
import InfoBox from '../../components/info-box';
|
import InfoBox from '../../components/info-box';
|
||||||
|
|
||||||
const LocationView = (props) => (
|
const LocationView = (props) => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<InfoBox msg="Text-based address fields are disabled at the moment. We're looking into how best to collect this data." />
|
<InfoBox msg="Text-based address fields are disabled at the moment. We're looking into how best to collect this data." />
|
||||||
<Fragment>
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Building Name"
|
title="Building Name"
|
||||||
slug="location_name"
|
slug="location_name"
|
||||||
value={props.building.location_name}
|
value={props.building.location_name}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
tooltip="May not be needed for many buildings."
|
tooltip="May not be needed for many buildings."
|
||||||
|
placeholder="Building name (if any)"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "text",
|
|
||||||
// "placeholder": "Building name (if any)",
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Building number"
|
title="Building number"
|
||||||
slug="location_number"
|
slug="location_number"
|
||||||
value={props.building.location_number}
|
value={props.building.location_number}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={1}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "number",
|
|
||||||
// "step": 1
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Street"
|
title="Street"
|
||||||
slug="location_street"
|
slug="location_street"
|
||||||
value={props.building.location_street}
|
value={props.building.location_street}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text",
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Address line 2"
|
title="Address line 2"
|
||||||
slug="location_line_two"
|
slug="location_line_two"
|
||||||
value={props.building.location_line_two}
|
value={props.building.location_line_two}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text",
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Town"
|
title="Town"
|
||||||
slug="location_town"
|
slug="location_town"
|
||||||
value={props.building.location_town}
|
value={props.building.location_town}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Postcode"
|
title="Postcode"
|
||||||
slug="location_postcode"
|
slug="location_postcode"
|
||||||
value={props.building.location_postcode}
|
value={props.building.location_postcode}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
maxLength={8}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text",
|
|
||||||
// "max_length": 8
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="TOID"
|
title="TOID"
|
||||||
slug="ref_toid"
|
slug="ref_toid"
|
||||||
value={props.building.ref_toid}
|
value={props.building.ref_toid}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
tooltip="Ordnance Survey Topography Layer ID (to be filled automatically)"
|
tooltip="Ordnance Survey Topography Layer ID (to be filled automatically)"
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text",
|
|
||||||
}
|
|
||||||
<UPRNsDataEntry
|
<UPRNsDataEntry
|
||||||
title="UPRNs"
|
title="UPRNs"
|
||||||
value={props.building.uprns}
|
value={props.building.uprns}
|
||||||
tooltip="Unique Property Reference Numbers (to be filled automatically)"
|
tooltip="Unique Property Reference Numbers (to be filled automatically)"
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "uprn_list",
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="OSM ID"
|
title="OSM ID"
|
||||||
slug="ref_osm_id"
|
slug="ref_osm_id"
|
||||||
value={props.building.ref_osm_id}
|
value={props.building.ref_osm_id}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
tooltip="OpenStreetMap feature ID"
|
tooltip="OpenStreetMap feature ID"
|
||||||
|
maxLength={20}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "text",
|
|
||||||
// "max_length": 20
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Latitude"
|
title="Latitude"
|
||||||
slug="location_latitude"
|
slug="location_latitude"
|
||||||
value={props.building.location_latitude}
|
value={props.building.location_latitude}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
step={0.0001}
|
||||||
|
placeholder={51}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.0001,
|
|
||||||
// "placeholder": 51
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Longitude"
|
title="Longitude"
|
||||||
slug="location_longitude"
|
slug="location_longitude"
|
||||||
value={props.building.location_longitude}
|
value={props.building.location_longitude}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
step={0.0001}
|
||||||
|
placeholder={0}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.0001,
|
|
||||||
// "placeholder": 0
|
|
||||||
}
|
|
||||||
</Fragment>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
const LocationContainer = withCopyEdit(LocationView);
|
const LocationContainer = withCopyEdit(LocationView);
|
||||||
|
@ -2,6 +2,8 @@ import React, { Fragment } from 'react';
|
|||||||
|
|
||||||
import withCopyEdit from '../data-container';
|
import withCopyEdit from '../data-container';
|
||||||
import DataEntry from '../data-components/data-entry';
|
import DataEntry from '../data-components/data-entry';
|
||||||
|
import CheckboxDataEntry from '../data-components/checkbox-data-entry';
|
||||||
|
import SelectDataEntry from '../data-components/select-data-entry';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Planning view/edit section
|
* Planning view/edit section
|
||||||
@ -12,207 +14,186 @@ const PlanningView = (props) => (
|
|||||||
title="Planning portal link"
|
title="Planning portal link"
|
||||||
slug="planning_portal_link"
|
slug="planning_portal_link"
|
||||||
value={props.building.planning_portal_link}
|
value={props.building.planning_portal_link}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="In a conservation area?"
|
title="In a conservation area?"
|
||||||
slug="planning_in_conservation_area"
|
slug="planning_in_conservation_area"
|
||||||
value={props.building.planning_in_conservation_area}
|
value={props.building.planning_in_conservation_area}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Conservation area name"
|
title="Conservation area name"
|
||||||
slug="planning_conservation_area_name"
|
slug="planning_conservation_area_name"
|
||||||
value={props.building.planning_conservation_area_name}
|
value={props.building.planning_conservation_area_name}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Is listed on the National Heritage List for England?"
|
title="Is listed on the National Heritage List for England?"
|
||||||
slug="planning_in_list"
|
slug="planning_in_list"
|
||||||
value={props.building.planning_in_list}
|
value={props.building.planning_in_list}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="National Heritage List for England list id"
|
title="National Heritage List for England list id"
|
||||||
slug="planning_list_id"
|
slug="planning_list_id"
|
||||||
value={props.building.planning_list_id}
|
value={props.building.planning_list_id}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<SelectDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="National Heritage List for England list type"
|
title="National Heritage List for England list type"
|
||||||
slug="planning_list_cat"
|
slug="planning_list_cat"
|
||||||
value={props.building.planning_list_cat}
|
value={props.building.planning_list_cat}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
options={[
|
||||||
|
"Listed Building",
|
||||||
|
"Scheduled Monument",
|
||||||
|
"World Heritage Site",
|
||||||
|
"Building Preservation Notice",
|
||||||
|
"None"
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
{
|
<SelectDataEntry
|
||||||
// "type": "text_list",
|
|
||||||
// "options": [
|
|
||||||
// "Listed Building"
|
|
||||||
// "Scheduled Monument"
|
|
||||||
// "World Heritage Site"
|
|
||||||
// "Building Preservation Notice"
|
|
||||||
// "None"
|
|
||||||
// ]
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Listing grade"
|
title="Listing grade"
|
||||||
slug="planning_list_grade"
|
slug="planning_list_grade"
|
||||||
value={props.building.planning_list_grade}
|
value={props.building.planning_list_grade}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
options={[
|
||||||
|
"I",
|
||||||
|
"II*",
|
||||||
|
"II",
|
||||||
|
"None"
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text_list",
|
|
||||||
// "options": [
|
|
||||||
// "I"
|
|
||||||
// "II*"
|
|
||||||
// "II"
|
|
||||||
// "None"
|
|
||||||
// ]
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Heritage at risk list id"
|
title="Heritage at risk list id"
|
||||||
slug="planning_heritage_at_risk_id"
|
slug="planning_heritage_at_risk_id"
|
||||||
value={props.building.planning_heritage_at_risk_id}
|
value={props.building.planning_heritage_at_risk_id}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="World heritage list id"
|
title="World heritage list id"
|
||||||
slug="planning_world_list_id"
|
slug="planning_world_list_id"
|
||||||
value={props.building.planning_world_list_id}
|
value={props.building.planning_world_list_id}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="In the Greater London Historic Environment Record?"
|
title="In the Greater London Historic Environment Record?"
|
||||||
slug="planning_in_glher"
|
slug="planning_in_glher"
|
||||||
value={props.building.planning_in_glher}
|
value={props.building.planning_in_glher}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Greater London Historic Environment Record link"
|
title="Greater London Historic Environment Record link"
|
||||||
slug="planning_glher_url"
|
slug="planning_glher_url"
|
||||||
value={props.building.planning_glher_url}
|
value={props.building.planning_glher_url}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="In an Architectural Priority Area?"
|
title="In an Architectural Priority Area?"
|
||||||
slug="planning_in_apa"
|
slug="planning_in_apa"
|
||||||
value={props.building.planning_in_apa}
|
value={props.building.planning_in_apa}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Architectural Priority Area name"
|
title="Architectural Priority Area name"
|
||||||
slug="planning_apa_name"
|
slug="planning_apa_name"
|
||||||
value={props.building.planning_apa_name}
|
value={props.building.planning_apa_name}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Architectural Priority Area tier"
|
title="Architectural Priority Area tier"
|
||||||
slug="planning_apa_tier"
|
slug="planning_apa_tier"
|
||||||
value={props.building.planning_apa_tier}
|
value={props.building.planning_apa_tier}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Is locally listed?"
|
title="Is locally listed?"
|
||||||
slug="planning_in_local_list"
|
slug="planning_in_local_list"
|
||||||
value={props.building.planning_in_local_list}
|
value={props.building.planning_in_local_list}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Local list link"
|
title="Local list link"
|
||||||
slug="planning_local_list_url"
|
slug="planning_local_list_url"
|
||||||
value={props.building.planning_local_list_url}
|
value={props.building.planning_local_list_url}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Within a historic area assessment?"
|
title="Within a historic area assessment?"
|
||||||
slug="planning_in_historic_area_assessment"
|
slug="planning_in_historic_area_assessment"
|
||||||
value={props.building.planning_in_historic_area_assessment}
|
value={props.building.planning_in_historic_area_assessment}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Historic area assessment link"
|
title="Historic area assessment link"
|
||||||
slug="planning_historic_area_assessment_url"
|
slug="planning_historic_area_assessment_url"
|
||||||
value={props.building.planning_historic_area_assessment_url}
|
value={props.building.planning_historic_area_assessment_url}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Is the building proposed for demolition?"
|
title="Is the building proposed for demolition?"
|
||||||
slug="planning_demolition_proposed"
|
slug="planning_demolition_proposed"
|
||||||
value={props.building.planning_demolition_proposed}
|
value={props.building.planning_demolition_proposed}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
<CheckboxDataEntry
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Has the building been demolished?"
|
title="Has the building been demolished?"
|
||||||
slug="planning_demolition_complete"
|
slug="planning_demolition_complete"
|
||||||
value={props.building.planning_demolition_complete}
|
value={props.building.planning_demolition_complete}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "checkbox"
|
|
||||||
}
|
|
||||||
<DataEntry
|
<DataEntry
|
||||||
title="Dates of construction and demolition of previous buildings on site"
|
title="Dates of construction and demolition of previous buildings on site"
|
||||||
slug="planning_demolition_history"
|
slug="planning_demolition_history"
|
||||||
value={props.building.planning_demolition_history}
|
value={props.building.planning_demolition_history}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text"
|
|
||||||
}
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
const PlanningContainer = withCopyEdit(PlanningView);
|
const PlanningContainer = withCopyEdit(PlanningView);
|
||||||
|
@ -1,150 +1,139 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
|
||||||
import withCopyEdit from '../data-container';
|
import withCopyEdit from '../data-container';
|
||||||
import DataEntry from '../data-components/data-entry';
|
import NumericDataEntry from '../data-components/numeric-data-entry';
|
||||||
|
import SelectDataEntry from '../data-components/select-data-entry';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size view/edit section
|
* Size view/edit section
|
||||||
*/
|
*/
|
||||||
const SizeView = (props) => (
|
const SizeView = (props) => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<DataEntry
|
<NumericDataEntry
|
||||||
title="Core storeys"
|
title="Core storeys"
|
||||||
slug="size_storeys_core"
|
slug="size_storeys_core"
|
||||||
value={props.building.size_storeys_core}
|
value={props.building.size_storeys_core}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
tooltip="How many storeys between the pavement and start of roof?"
|
tooltip="How many storeys between the pavement and start of roof?"
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 1,
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Attic storeys"
|
title="Attic storeys"
|
||||||
slug="size_storeys_attic"
|
slug="size_storeys_attic"
|
||||||
value={props.building.size_storeys_attic}
|
value={props.building.size_storeys_attic}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
tooltip="How many storeys above start of roof?"
|
tooltip="How many storeys above start of roof?"
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 1,
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Basement storeys"
|
title="Basement storeys"
|
||||||
slug="size_storeys_basement"
|
slug="size_storeys_basement"
|
||||||
value={props.building.size_storeys_basement}
|
value={props.building.size_storeys_basement}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
tooltip="How many storeys below pavement level?"
|
tooltip="How many storeys below pavement level?"
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 1,
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Height to apex (m)"
|
title="Height to apex (m)"
|
||||||
slug="size_height_apex"
|
slug="size_height_apex"
|
||||||
value={props.building.size_height_apex}
|
value={props.building.size_height_apex}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={0.1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.1
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Height to eaves (m)"
|
title="Height to eaves (m)"
|
||||||
slug="size_height_eaves"
|
slug="size_height_eaves"
|
||||||
value={props.building.size_height_eaves}
|
value={props.building.size_height_eaves}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={0.1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.1
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Ground floor area (m²)"
|
title="Ground floor area (m²)"
|
||||||
slug="size_floor_area_ground"
|
slug="size_floor_area_ground"
|
||||||
value={props.building.size_floor_area_ground}
|
value={props.building.size_floor_area_ground}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={0.1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.1
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Total floor area (m²)"
|
title="Total floor area (m²)"
|
||||||
slug="size_floor_area_total"
|
slug="size_floor_area_total"
|
||||||
value={props.building.size_floor_area_total}
|
value={props.building.size_floor_area_total}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={0.1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.1
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Frontage Width (m)"
|
title="Frontage Width (m)"
|
||||||
slug="size_width_frontage"
|
slug="size_width_frontage"
|
||||||
value={props.building.size_width_frontage}
|
value={props.building.size_width_frontage}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={0.1}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.1
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Total area of plot (m²)"
|
title="Total area of plot (m²)"
|
||||||
slug="size_plot_area_total"
|
slug="size_plot_area_total"
|
||||||
value={props.building.size_plot_area_total}
|
value={props.building.size_plot_area_total}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={0.1}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
<NumericDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.1
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="FAR ratio (percentage of plot covered by building)"
|
title="FAR ratio (percentage of plot covered by building)"
|
||||||
slug="size_far_ratio"
|
slug="size_far_ratio"
|
||||||
value={props.building.size_far_ratio}
|
value={props.building.size_far_ratio}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
|
step={0.1}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
{
|
<SelectDataEntry
|
||||||
// "type": "number",
|
|
||||||
// "step": 0.1
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Configuration (semi/detached, end/terrace)"
|
title="Configuration (semi/detached, end/terrace)"
|
||||||
slug="size_configuration"
|
slug="size_configuration"
|
||||||
value={props.building.size_configuration}
|
value={props.building.size_configuration}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
|
options={[
|
||||||
|
"Detached",
|
||||||
|
"Semi-detached",
|
||||||
|
"Terrace",
|
||||||
|
"End terrace",
|
||||||
|
"Block"
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
{
|
<SelectDataEntry
|
||||||
// "type": "text_list",
|
|
||||||
// "options": [
|
|
||||||
// "Detached",
|
|
||||||
// "Semi-detached",
|
|
||||||
// "Terrace",
|
|
||||||
// "End terrace",
|
|
||||||
// "Block"
|
|
||||||
// ]
|
|
||||||
}
|
|
||||||
<DataEntry
|
|
||||||
title="Roof shape"
|
title="Roof shape"
|
||||||
slug="size_roof_shape"
|
slug="size_roof_shape"
|
||||||
value={props.building.size_roof_shape}
|
value={props.building.size_roof_shape}
|
||||||
|
mode={props.mode}
|
||||||
copy={props.copy}
|
copy={props.copy}
|
||||||
|
onChange={props.onChange}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
|
options={[
|
||||||
|
"Flat",
|
||||||
|
"Pitched",
|
||||||
|
"Other"
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
{
|
|
||||||
// "type": "text_list",
|
|
||||||
// "options": [
|
|
||||||
// "Flat",
|
|
||||||
// "Pitched",
|
|
||||||
// "Other"
|
|
||||||
// ]
|
|
||||||
}
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
const SizeContainer = withCopyEdit(SizeView);
|
const SizeContainer = withCopyEdit(SizeView);
|
||||||
|
@ -148,8 +148,7 @@
|
|||||||
.icon-button.save:hover svg {
|
.icon-button.save:hover svg {
|
||||||
color: rgb(11, 225, 72);
|
color: rgb(11, 225, 72);
|
||||||
}
|
}
|
||||||
label .icon-buttons,
|
.data-title .icon-buttons {
|
||||||
.data-list dt .icon-buttons {
|
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,3 +224,13 @@ label .icon-buttons,
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
.data-section .data-link-list {
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
.data-link-list li {
|
||||||
|
border-color: #6c757d;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user