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