2018-10-01 07:45:33 -04:00
|
|
|
import React, { Component, Fragment } from 'react';
|
|
|
|
import { Link, NavLink, Redirect } from 'react-router-dom';
|
2019-05-27 13:26:29 -04:00
|
|
|
import PropTypes from 'prop-types';
|
2018-09-13 12:13:03 -04:00
|
|
|
|
|
|
|
import ErrorBox from './error-box';
|
2018-09-13 15:41:42 -04:00
|
|
|
import InfoBox from './info-box';
|
2018-09-11 15:59:59 -04:00
|
|
|
import Sidebar from './sidebar';
|
2018-10-05 13:41:12 -04:00
|
|
|
import Tooltip from './tooltip';
|
2018-11-30 04:44:19 -05:00
|
|
|
import { SaveIcon } from './icons';
|
2018-09-09 17:22:44 -04:00
|
|
|
|
2018-10-03 16:47:49 -04:00
|
|
|
import CONFIG from './fields-config.json';
|
|
|
|
|
2018-10-04 17:50:33 -04:00
|
|
|
const BuildingEdit = (props) => {
|
|
|
|
if (!props.user){
|
|
|
|
return <Redirect to="/sign-up.html" />
|
|
|
|
}
|
2019-05-10 09:00:20 -04:00
|
|
|
const cat = props.match.params.cat;
|
2018-10-04 17:50:33 -04:00
|
|
|
if (!props.building_id){
|
2018-10-01 07:45:33 -04:00
|
|
|
return (
|
2018-11-30 04:44:19 -05:00
|
|
|
<Sidebar title="Building Not Found" back={`/edit/${cat}.html`}>
|
2018-10-04 17:50:33 -04:00
|
|
|
<InfoBox msg="We can't find that one anywhere - try the map again?" />
|
2019-05-10 11:10:16 -04:00
|
|
|
<div className="buttons-container ml-3 mr-3">
|
2018-11-30 04:44:19 -05:00
|
|
|
<Link to={`/edit/${cat}.html`} className="btn btn-secondary">Back to maps</Link>
|
2018-10-04 17:50:33 -04:00
|
|
|
</div>
|
2018-10-01 07:45:33 -04:00
|
|
|
</Sidebar>
|
|
|
|
);
|
|
|
|
}
|
2018-10-04 17:50:33 -04:00
|
|
|
return (
|
2018-11-29 17:00:53 -05:00
|
|
|
<Sidebar
|
|
|
|
key={props.building_id}
|
2019-05-27 11:31:48 -04:00
|
|
|
title={'You are editing'}
|
2018-11-29 17:00:53 -05:00
|
|
|
back={`/edit/${cat}.html`}>
|
2018-10-04 17:50:33 -04:00
|
|
|
{
|
2019-05-27 13:26:29 -04:00
|
|
|
CONFIG.map((section) => {
|
2018-10-04 17:50:33 -04:00
|
|
|
return <EditForm
|
2019-05-27 13:26:29 -04:00
|
|
|
{...section} {...props}
|
|
|
|
cat={cat} key={section.slug} />
|
2018-10-04 17:50:33 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
</Sidebar>
|
|
|
|
);
|
2018-10-01 07:45:33 -04:00
|
|
|
}
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
BuildingEdit.propTypes = {
|
|
|
|
user: PropTypes.object,
|
|
|
|
match: PropTypes.object,
|
2019-05-27 15:28:28 -04:00
|
|
|
building_id: PropTypes.number
|
2019-05-27 13:26:29 -04:00
|
|
|
}
|
|
|
|
|
2018-10-01 07:45:33 -04:00
|
|
|
class EditForm extends Component {
|
2018-09-11 15:59:59 -04:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2019-08-01 07:16:08 -04:00
|
|
|
this.state = {
|
|
|
|
error: this.props.error || undefined,
|
|
|
|
like: this.props.like || undefined,
|
|
|
|
copying: false,
|
|
|
|
keys_to_copy: {}
|
|
|
|
}
|
2019-05-27 13:35:12 -04:00
|
|
|
for (const field of props.fields) {
|
2018-10-20 10:35:52 -04:00
|
|
|
this.state[field.slug] = props[field.slug]
|
|
|
|
}
|
2018-09-11 15:59:59 -04:00
|
|
|
|
|
|
|
this.handleChange = this.handleChange.bind(this);
|
2019-01-19 11:54:20 -05:00
|
|
|
this.handleCheck = this.handleCheck.bind(this);
|
2018-09-11 15:59:59 -04:00
|
|
|
this.handleLike = this.handleLike.bind(this);
|
|
|
|
this.handleSubmit = this.handleSubmit.bind(this);
|
2018-11-30 10:53:55 -05:00
|
|
|
this.handleUpdate = this.handleUpdate.bind(this);
|
2019-08-01 07:16:08 -04:00
|
|
|
|
|
|
|
this.toggleCopying = this.toggleCopying.bind(this);
|
|
|
|
this.toggleCopyAttribute = this.toggleCopyAttribute.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter or exit "copying" state - allow user to select attributes to copy
|
|
|
|
*/
|
|
|
|
toggleCopying() {
|
|
|
|
this.setState({
|
|
|
|
copying: !this.state.copying
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Keep track of data to copy (accumulate while in "copying" state)
|
|
|
|
*
|
|
|
|
* Note that we track keys only - values are already held in state
|
|
|
|
*
|
|
|
|
* @param {string} key
|
|
|
|
*/
|
|
|
|
toggleCopyAttribute(key) {
|
|
|
|
const keys = this.state.keys_to_copy;
|
|
|
|
if(this.state.keys_to_copy[key]){
|
|
|
|
delete keys[key];
|
|
|
|
} else {
|
|
|
|
keys[key] = true;
|
|
|
|
}
|
|
|
|
this.setState({
|
|
|
|
keys_to_copy: keys
|
|
|
|
})
|
2018-09-11 15:59:59 -04:00
|
|
|
}
|
|
|
|
|
2018-11-30 10:53:55 -05:00
|
|
|
/**
|
|
|
|
* Handle changes on typical inputs
|
|
|
|
* - e.g. input[type=text], radio, select, textare
|
|
|
|
*
|
|
|
|
* @param {DocumentEvent} event
|
|
|
|
*/
|
2018-09-11 15:59:59 -04:00
|
|
|
handleChange(event) {
|
|
|
|
const target = event.target;
|
2018-10-25 06:57:58 -04:00
|
|
|
let value = (target.value === '')? null : target.value;
|
2018-09-11 15:59:59 -04:00
|
|
|
const name = target.name;
|
|
|
|
|
2018-10-25 06:57:58 -04:00
|
|
|
// special transform - consider something data driven before adding 'else if's
|
|
|
|
if (name === 'location_postcode' && value !== null) {
|
|
|
|
value = value.toUpperCase();
|
|
|
|
}
|
2019-01-19 11:54:20 -05:00
|
|
|
this.setState({
|
|
|
|
[name]: value
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle changes on checkboxes
|
|
|
|
* - e.g. input[type=checkbox]
|
|
|
|
*
|
|
|
|
* @param {DocumentEvent} event
|
|
|
|
*/
|
|
|
|
handleCheck(event) {
|
|
|
|
const target = event.target;
|
|
|
|
const value = target.checked;
|
|
|
|
const name = target.name;
|
2018-10-25 06:57:58 -04:00
|
|
|
|
2018-09-11 15:59:59 -04:00
|
|
|
this.setState({
|
|
|
|
[name]: value
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-30 10:53:55 -05:00
|
|
|
/**
|
|
|
|
* Handle update directly
|
|
|
|
* - e.g. as callback from MultiTextInput where we set a list of strings
|
|
|
|
*
|
|
|
|
* @param {String} key
|
|
|
|
* @param {*} value
|
|
|
|
*/
|
|
|
|
handleUpdate(key, value) {
|
|
|
|
this.setState({
|
|
|
|
[key]: value
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle likes separately
|
|
|
|
* - like/love reaction is limited to set/unset per user
|
|
|
|
*
|
|
|
|
* @param {DocumentEvent} event
|
|
|
|
*/
|
2018-09-11 15:59:59 -04:00
|
|
|
handleLike(event) {
|
2018-10-25 08:34:54 -04:00
|
|
|
event.preventDefault();
|
2019-01-22 12:52:32 -05:00
|
|
|
const like = event.target.checked;
|
2018-10-25 08:34:54 -04:00
|
|
|
|
2019-01-22 12:34:46 -05:00
|
|
|
fetch(`/building/${this.props.building_id}/like.json`, {
|
2018-10-25 08:34:54 -04:00
|
|
|
method: 'POST',
|
|
|
|
headers:{
|
2019-05-27 11:39:16 -04:00
|
|
|
'Content-Type': 'application/json'
|
2018-10-25 08:34:54 -04:00
|
|
|
},
|
2019-01-22 12:52:32 -05:00
|
|
|
credentials: 'same-origin',
|
|
|
|
body: JSON.stringify({like: like})
|
2018-10-25 08:34:54 -04:00
|
|
|
}).then(
|
|
|
|
res => res.json()
|
|
|
|
).then(function(res){
|
|
|
|
if (res.error) {
|
|
|
|
this.setState({error: res.error})
|
|
|
|
} else {
|
|
|
|
this.props.selectBuilding(res);
|
|
|
|
this.setState({
|
|
|
|
likes_total: res.likes_total
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}.bind(this)).catch(
|
|
|
|
(err) => this.setState({error: err})
|
|
|
|
);
|
2018-09-11 15:59:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
handleSubmit(event) {
|
|
|
|
event.preventDefault();
|
2018-09-13 12:13:03 -04:00
|
|
|
this.setState({error: undefined})
|
|
|
|
|
2018-09-30 16:54:47 -04:00
|
|
|
fetch(`/building/${this.props.building_id}.json`, {
|
2018-09-11 15:59:59 -04:00
|
|
|
method: 'POST',
|
|
|
|
body: JSON.stringify(this.state),
|
|
|
|
headers:{
|
2019-05-27 11:39:16 -04:00
|
|
|
'Content-Type': 'application/json'
|
2018-09-30 15:29:46 -04:00
|
|
|
},
|
|
|
|
credentials: 'same-origin'
|
2018-09-11 15:59:59 -04:00
|
|
|
}).then(
|
|
|
|
res => res.json()
|
|
|
|
).then(function(res){
|
|
|
|
if (res.error) {
|
2018-09-13 12:13:03 -04:00
|
|
|
this.setState({error: res.error})
|
2018-09-11 15:59:59 -04:00
|
|
|
} else {
|
2018-10-01 07:45:33 -04:00
|
|
|
this.props.selectBuilding(res);
|
2018-09-11 15:59:59 -04:00
|
|
|
}
|
2018-09-13 12:13:03 -04:00
|
|
|
}.bind(this)).catch(
|
|
|
|
(err) => this.setState({error: err})
|
2018-09-11 15:59:59 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2018-11-29 17:00:53 -05:00
|
|
|
const match = this.props.cat === this.props.slug;
|
2019-05-10 11:10:16 -04:00
|
|
|
const cat = this.props.cat;
|
2019-05-27 13:26:29 -04:00
|
|
|
const buildingLike = this.props.building_like;
|
2019-05-10 11:10:16 -04:00
|
|
|
|
2019-08-01 07:16:08 -04:00
|
|
|
const values_to_copy = {}
|
|
|
|
for (const key of Object.keys(this.state.keys_to_copy)) {
|
|
|
|
values_to_copy[key] = this.state[key]
|
|
|
|
}
|
|
|
|
const data_string = JSON.stringify(values_to_copy);
|
|
|
|
|
2018-09-11 15:59:59 -04:00
|
|
|
return (
|
2019-05-27 11:31:48 -04:00
|
|
|
<section className={(this.props.inactive)? 'data-section inactive': 'data-section'}>
|
|
|
|
<header className={`section-header edit ${this.props.slug} ${(match? 'active' : '')}`}>
|
2018-11-29 17:00:53 -05:00
|
|
|
<NavLink
|
|
|
|
to={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}
|
|
|
|
title={(this.props.inactive)? 'Coming soon… Click the ? for more info.' :
|
|
|
|
(match)? 'Hide details' : 'Show details'}
|
|
|
|
isActive={() => match}>
|
|
|
|
<h3 className="h3">{this.props.title}</h3>
|
|
|
|
</NavLink>
|
2018-10-05 04:10:20 -04:00
|
|
|
<nav className="icon-buttons">
|
2019-05-27 11:39:16 -04:00
|
|
|
{
|
2019-08-01 07:16:08 -04:00
|
|
|
(match && !this.props.inactive && this.props.slug !== 'like')?
|
|
|
|
this.state.copying?
|
|
|
|
<Fragment>
|
|
|
|
<NavLink
|
|
|
|
to={`/multi-edit/${this.props.cat}.html?data=${data_string}`}
|
|
|
|
className="icon-button copy">
|
|
|
|
Copy selected
|
|
|
|
</NavLink>
|
|
|
|
<a className="icon-button copy" onClick={this.toggleCopying}>Cancel</a>
|
|
|
|
</Fragment>
|
|
|
|
:
|
|
|
|
<a className="icon-button copy" onClick={this.toggleCopying}>Copy</a>
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
{
|
|
|
|
(match && this.props.slug === 'like')?
|
|
|
|
<NavLink
|
|
|
|
to={`/multi-edit/${this.props.cat}.html`}
|
|
|
|
className="icon-button copy">
|
|
|
|
Copy
|
|
|
|
</NavLink>
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
{
|
|
|
|
this.props.help && !this.state.copying?
|
2019-05-27 11:39:16 -04:00
|
|
|
<a className="icon-button help" title="Find out more" href={this.props.help}>
|
2019-01-22 14:39:16 -05:00
|
|
|
Info
|
2019-05-27 11:39:16 -04:00
|
|
|
</a>
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
{
|
2019-08-01 07:16:08 -04:00
|
|
|
(match && !this.state.copying && !this.props.inactive && this.props.slug !== 'like')? // special-case for likes
|
2019-05-27 11:39:16 -04:00
|
|
|
<NavLink className="icon-button save" title="Save Changes"
|
|
|
|
onClick={this.handleSubmit}
|
|
|
|
to={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}>
|
2018-10-25 06:48:25 -04:00
|
|
|
Save
|
2019-05-27 11:39:16 -04:00
|
|
|
<SaveIcon />
|
|
|
|
</NavLink>
|
|
|
|
: null
|
|
|
|
}
|
2018-10-05 04:10:20 -04:00
|
|
|
</nav>
|
2018-10-04 17:50:33 -04:00
|
|
|
</header>
|
2018-11-29 17:00:53 -05:00
|
|
|
{
|
2019-05-27 15:13:43 -04:00
|
|
|
match? (
|
|
|
|
!this.props.inactive?
|
|
|
|
<form action={`/edit/${this.props.slug}/building/${this.props.building_id}.html`}
|
|
|
|
method="GET" onSubmit={this.handleSubmit}>
|
|
|
|
{
|
|
|
|
this.props.slug === 'location'?
|
|
|
|
<InfoBox msg="Text-based address fields are disabled at the moment. We're looking into how best to collect this data." />
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
<ErrorBox msg={this.state.error} />
|
|
|
|
{
|
|
|
|
this.props.fields.map((props) => {
|
|
|
|
switch (props.type) {
|
|
|
|
case 'text':
|
|
|
|
return <TextInput {...props} handleChange={this.handleChange}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={this.state.copying}
|
|
|
|
toggleCopyAttribute={this.toggleCopyAttribute}
|
|
|
|
copy={this.state.keys_to_copy[props.slug]}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
case 'text_list':
|
|
|
|
return <TextListInput {...props} handleChange={this.handleChange}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={this.state.copying}
|
|
|
|
toggleCopyAttribute={this.toggleCopyAttribute}
|
|
|
|
copy={this.state.keys_to_copy[props.slug]}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
case 'text_long':
|
|
|
|
return <LongTextInput {...props} handleChange={this.handleChange}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={this.state.copying}
|
|
|
|
toggleCopyAttribute={this.toggleCopyAttribute}
|
|
|
|
copy={this.state.keys_to_copy[props.slug]}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
case 'number':
|
|
|
|
return <NumberInput {...props} handleChange={this.handleChange}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={this.state.copying}
|
|
|
|
toggleCopyAttribute={this.toggleCopyAttribute}
|
|
|
|
copy={this.state.keys_to_copy[props.slug]}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
case 'year_estimator':
|
|
|
|
return <YearEstimator {...props} handleChange={this.handleChange}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={this.state.copying}
|
|
|
|
toggleCopyAttribute={this.toggleCopyAttribute}
|
|
|
|
copy={this.state.keys_to_copy[props.slug]}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
case 'text_multi':
|
|
|
|
return <MultiTextInput {...props} handleChange={this.handleUpdate}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={this.state.copying}
|
|
|
|
toggleCopyAttribute={this.toggleCopyAttribute}
|
|
|
|
copy={this.state.keys_to_copy[props.slug]}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
case 'checkbox':
|
|
|
|
return <CheckboxInput {...props} handleChange={this.handleCheck}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={this.state.copying}
|
|
|
|
toggleCopyAttribute={this.toggleCopyAttribute}
|
|
|
|
copy={this.state.keys_to_copy[props.slug]}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
case 'like':
|
|
|
|
return <LikeButton {...props} handleLike={this.handleLike}
|
2019-05-27 13:26:29 -04:00
|
|
|
building_like={buildingLike}
|
2019-05-10 11:10:16 -04:00
|
|
|
value={this.state[props.slug]} key={props.slug} cat={cat} />
|
2019-05-27 15:13:43 -04:00
|
|
|
default:
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
})
|
2019-05-27 11:39:16 -04:00
|
|
|
}
|
2019-05-27 15:13:43 -04:00
|
|
|
<InfoBox msg="Colouring may take a few seconds - try zooming the map or hitting refresh after saving (we're working on making this smoother)." />
|
|
|
|
{
|
|
|
|
(this.props.slug === 'like')? // special-case for likes
|
|
|
|
null :
|
|
|
|
<div className="buttons-container">
|
|
|
|
<button type="submit" className="btn btn-primary">Save</button>
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
</form>
|
|
|
|
: <form>
|
2019-07-07 14:20:28 -04:00
|
|
|
<InfoBox msg={`We're not collecting data on ${this.props.title.toLowerCase()} yet - check back soon.`} />
|
2019-05-27 15:13:43 -04:00
|
|
|
</form>
|
|
|
|
) : null
|
2019-05-27 11:39:16 -04:00
|
|
|
}
|
2018-10-01 07:45:33 -04:00
|
|
|
</section>
|
|
|
|
)
|
2018-09-11 15:59:59 -04:00
|
|
|
}
|
|
|
|
}
|
2018-09-09 17:22:44 -04:00
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
EditForm.propTypes = {
|
|
|
|
title: PropTypes.string,
|
|
|
|
slug: PropTypes.string,
|
|
|
|
cat: PropTypes.string,
|
|
|
|
help: PropTypes.string,
|
|
|
|
error: PropTypes.object,
|
|
|
|
like: PropTypes.bool,
|
|
|
|
building_like: PropTypes.bool,
|
|
|
|
selectBuilding: PropTypes.func,
|
2019-05-27 15:28:28 -04:00
|
|
|
building_id: PropTypes.number,
|
2019-05-27 13:26:29 -04:00
|
|
|
inactive: PropTypes.bool,
|
|
|
|
fields: PropTypes.array
|
|
|
|
}
|
|
|
|
|
2018-10-01 07:45:33 -04:00
|
|
|
const TextInput = (props) => (
|
|
|
|
<Fragment>
|
2019-05-10 11:10:16 -04:00
|
|
|
<Label slug={props.slug} title={props.title} tooltip={props.tooltip}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={props.copying}
|
|
|
|
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
|
|
copy={props.copy}
|
|
|
|
cat={props.cat}
|
|
|
|
disabled={props.disabled} />
|
2018-10-01 07:45:33 -04:00
|
|
|
<input className="form-control" type="text"
|
|
|
|
id={props.slug} name={props.slug}
|
2019-05-27 11:31:48 -04:00
|
|
|
value={props.value || ''}
|
2019-01-19 11:54:20 -05:00
|
|
|
maxLength={props.max_length}
|
2018-10-05 17:19:26 -04:00
|
|
|
disabled={props.disabled}
|
2018-10-05 17:47:37 -04:00
|
|
|
placeholder={props.placeholder}
|
2018-10-01 07:45:33 -04:00
|
|
|
onChange={props.handleChange}
|
2019-05-27 11:39:16 -04:00
|
|
|
/>
|
2018-10-01 07:45:33 -04:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
TextInput.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
2019-05-27 15:13:43 -04:00
|
|
|
cat: PropTypes.string,
|
2019-05-27 13:26:29 -04:00
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.string,
|
|
|
|
max_length: PropTypes.number,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
placeholder: PropTypes.string,
|
|
|
|
handleChange: PropTypes.func
|
|
|
|
}
|
|
|
|
|
2018-11-30 10:53:55 -05:00
|
|
|
const LongTextInput = (props) => (
|
|
|
|
<Fragment>
|
2019-05-27 15:54:43 -04:00
|
|
|
<Label slug={props.slug} title={props.title} cat={props.cat}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={props.copying}
|
|
|
|
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
|
|
copy={props.copy}
|
2019-05-27 15:54:43 -04:00
|
|
|
disabled={props.disabled} tooltip={props.tooltip} />
|
2018-11-30 10:53:55 -05:00
|
|
|
<textarea className="form-control"
|
|
|
|
id={props.slug} name={props.slug}
|
|
|
|
disabled={props.disabled}
|
|
|
|
placeholder={props.placeholder}
|
|
|
|
onChange={props.handleChange}
|
2019-05-27 11:31:48 -04:00
|
|
|
value={props.value || ''}></textarea>
|
2018-11-30 10:53:55 -05:00
|
|
|
</Fragment>
|
|
|
|
)
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
LongTextInput.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.string,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
placeholder: PropTypes.string,
|
|
|
|
handleChange: PropTypes.func
|
|
|
|
}
|
2018-11-30 10:53:55 -05:00
|
|
|
|
|
|
|
class MultiTextInput extends Component {
|
|
|
|
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) {
|
2019-05-27 13:26:29 -04:00
|
|
|
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;
|
2018-11-30 10:53:55 -05:00
|
|
|
});
|
|
|
|
this.props.handleChange(this.props.slug, values);
|
|
|
|
}
|
|
|
|
|
|
|
|
add(event) {
|
|
|
|
event.preventDefault();
|
2019-05-27 11:31:48 -04:00
|
|
|
const values = this.getValues().concat('');
|
2018-11-30 10:53:55 -05:00
|
|
|
this.props.handleChange(this.props.slug, values);
|
|
|
|
}
|
|
|
|
|
|
|
|
remove(event){
|
2019-05-27 13:26:29 -04:00
|
|
|
const removeIndex = +event.target.dataset.index;
|
2018-11-30 10:53:55 -05:00
|
|
|
const values = this.getValues().filter((_, i) => {
|
2019-05-27 13:26:29 -04:00
|
|
|
return i !== removeIndex;
|
2018-11-30 10:53:55 -05:00
|
|
|
});
|
|
|
|
this.props.handleChange(this.props.slug, values);
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const values = this.getValues();
|
|
|
|
return (
|
2019-05-27 11:39:16 -04:00
|
|
|
<Fragment>
|
2019-08-01 07:16:08 -04:00
|
|
|
<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} />
|
2019-05-27 11:39:16 -04:00
|
|
|
{
|
|
|
|
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}
|
2019-04-18 12:07:13 -04:00
|
|
|
className="btn btn-outline-dark">+</button>
|
2019-05-27 11:39:16 -04:00
|
|
|
</Fragment>
|
2018-11-30 10:53:55 -05:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
MultiTextInput.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.arrayOf(PropTypes.string),
|
|
|
|
placeholder: PropTypes.string,
|
|
|
|
disabled: PropTypes.bool,
|
2019-08-01 07:16:08 -04:00
|
|
|
handleChange: PropTypes.func,
|
|
|
|
copy: PropTypes.bool,
|
|
|
|
toggleCopyAttribute: PropTypes.func,
|
|
|
|
copying: PropTypes.bool
|
2019-05-27 13:26:29 -04:00
|
|
|
}
|
|
|
|
|
2018-10-05 13:41:12 -04:00
|
|
|
const TextListInput = (props) => (
|
|
|
|
<Fragment>
|
2019-05-10 11:10:16 -04:00
|
|
|
<Label slug={props.slug} title={props.title} tooltip={props.tooltip}
|
2019-05-27 15:54:43 -04:00
|
|
|
cat={props.cat} disabled={props.disabled}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={props.copying}
|
|
|
|
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
|
|
copy={props.copy} />
|
2018-10-05 13:41:12 -04:00
|
|
|
<select className="form-control"
|
|
|
|
id={props.slug} name={props.slug}
|
2019-05-27 11:31:48 -04:00
|
|
|
value={props.value || ''}
|
2018-10-05 17:19:26 -04:00
|
|
|
disabled={props.disabled}
|
2018-10-05 13:41:12 -04:00
|
|
|
list={`${props.slug}_suggestions`}
|
|
|
|
onChange={props.handleChange}>
|
|
|
|
<option value="">Select a source</option>
|
|
|
|
{
|
|
|
|
props.options.map(option => (
|
2018-10-05 17:19:26 -04:00
|
|
|
<option key={option} value={option}>{option}</option>
|
2018-10-05 13:41:12 -04:00
|
|
|
))
|
|
|
|
}
|
|
|
|
</select>
|
|
|
|
</Fragment>
|
|
|
|
)
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
TextListInput.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
2019-05-27 15:13:43 -04:00
|
|
|
cat: PropTypes.string,
|
2019-05-27 13:26:29 -04:00
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
options: PropTypes.arrayOf(PropTypes.string),
|
|
|
|
value: PropTypes.string,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
handleChange: PropTypes.func
|
|
|
|
}
|
|
|
|
|
2018-10-01 07:45:33 -04:00
|
|
|
const NumberInput = (props) => (
|
|
|
|
<Fragment>
|
2019-05-10 11:10:16 -04:00
|
|
|
<Label slug={props.slug} title={props.title} tooltip={props.tooltip}
|
2019-05-27 15:54:43 -04:00
|
|
|
cat={props.cat} disabled={props.disabled}
|
2019-08-01 07:16:08 -04:00
|
|
|
copying={props.copying}
|
|
|
|
toggleCopyAttribute={props.toggleCopyAttribute}
|
|
|
|
copy={props.copy} />
|
2018-10-01 07:45:33 -04:00
|
|
|
<input className="form-control" type="number" step={props.step}
|
|
|
|
id={props.slug} name={props.slug}
|
2019-05-27 11:31:48 -04:00
|
|
|
value={props.value || ''}
|
2018-10-05 17:19:26 -04:00
|
|
|
disabled={props.disabled}
|
2018-10-01 07:45:33 -04:00
|
|
|
onChange={props.handleChange}
|
2019-05-27 11:39:16 -04:00
|
|
|
/>
|
2018-10-01 07:45:33 -04:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
NumberInput.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
2019-05-27 15:13:43 -04:00
|
|
|
cat: PropTypes.string,
|
2019-05-27 13:26:29 -04:00
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
step: PropTypes.number,
|
|
|
|
value: PropTypes.number,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
handleChange: PropTypes.func
|
|
|
|
}
|
|
|
|
|
2019-04-04 08:05:58 -04:00
|
|
|
class YearEstimator extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2019-04-18 12:07:13 -04:00
|
|
|
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
|
|
|
|
}
|
2019-04-04 08:05:58 -04:00
|
|
|
}
|
|
|
|
// 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}
|
2019-08-01 07:16:08 -04:00
|
|
|
|
2019-05-27 11:39:16 -04:00
|
|
|
value={this.props.value} key={this.props.slug} />
|
2019-04-04 08:05:58 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
YearEstimator.propTypes = {
|
|
|
|
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,
|
2019-08-01 07:16:08 -04:00
|
|
|
handleChange: PropTypes.func,
|
|
|
|
copy: PropTypes.bool,
|
|
|
|
toggleCopyAttribute: PropTypes.func,
|
|
|
|
copying: PropTypes.bool
|
2019-05-27 13:26:29 -04:00
|
|
|
}
|
|
|
|
|
2019-01-19 11:54:20 -05:00
|
|
|
const CheckboxInput = (props) => (
|
2019-08-01 07:16:08 -04:00
|
|
|
<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>
|
2019-01-19 11:54:20 -05:00
|
|
|
)
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
CheckboxInput.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.bool,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
handleChange: PropTypes.func
|
|
|
|
}
|
|
|
|
|
2018-10-01 07:45:33 -04:00
|
|
|
const LikeButton = (props) => (
|
|
|
|
<Fragment>
|
2018-10-25 08:49:02 -04:00
|
|
|
<p className="likes">{(props.value)? props.value : 0} likes</p>
|
2019-01-22 12:52:32 -05:00
|
|
|
<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}
|
2019-05-27 11:39:16 -04:00
|
|
|
/>
|
2019-01-22 12:52:32 -05:00
|
|
|
<label htmlFor={props.slug} className="form-check-label">
|
2019-04-04 08:57:45 -04:00
|
|
|
I like this building and think it contributes to the city!
|
2019-01-22 12:52:32 -05:00
|
|
|
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
|
|
|
</label>
|
|
|
|
</div>
|
2019-05-28 16:18:36 -04:00
|
|
|
<p>
|
|
|
|
<NavLink
|
2019-08-01 07:16:08 -04:00
|
|
|
to={`/multi-edit/${props.cat}.html`}>
|
2019-05-28 16:18:36 -04:00
|
|
|
Like more buildings
|
|
|
|
</NavLink>
|
|
|
|
</p>
|
2018-10-01 07:45:33 -04:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
|
2019-05-27 13:26:29 -04:00
|
|
|
LikeButton.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
2019-05-27 15:13:43 -04:00
|
|
|
cat: PropTypes.string,
|
2019-05-27 13:26:29 -04:00
|
|
|
title: PropTypes.string,
|
|
|
|
tooltip: PropTypes.string,
|
|
|
|
value: PropTypes.number,
|
|
|
|
building_like: PropTypes.bool,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
handleLike: PropTypes.func
|
|
|
|
}
|
|
|
|
|
2019-08-01 05:29:32 -04:00
|
|
|
const Label = (props) => {
|
|
|
|
return (
|
|
|
|
<label htmlFor={props.slug}>
|
|
|
|
{props.title}
|
2019-08-01 07:16:08 -04:00
|
|
|
{ (props.copying && props.cat && props.slug && !props.disabled)?
|
2019-08-01 05:29:32 -04:00
|
|
|
<div className="icon-buttons">
|
2019-08-01 07:16:08 -04:00
|
|
|
<label className="icon-button copy">
|
2019-08-01 05:29:32 -04:00
|
|
|
Copy
|
2019-08-01 07:16:08 -04:00
|
|
|
<input type="checkbox" checked={props.copy}
|
|
|
|
onChange={() => props.toggleCopyAttribute(props.slug)}/>
|
|
|
|
</label>
|
2019-08-01 05:29:32 -04:00
|
|
|
</div> : null
|
|
|
|
}
|
2019-08-01 07:16:08 -04:00
|
|
|
{ props.tooltip? <Tooltip text={ props.tooltip } /> : null }
|
2019-08-01 05:29:32 -04:00
|
|
|
</label>
|
|
|
|
);
|
|
|
|
}
|
2019-05-27 13:26:29 -04:00
|
|
|
|
|
|
|
Label.propTypes = {
|
|
|
|
slug: PropTypes.string,
|
2019-05-27 15:13:43 -04:00
|
|
|
cat: PropTypes.string,
|
2019-05-27 13:26:29 -04:00
|
|
|
title: PropTypes.string,
|
2019-05-27 15:54:43 -04:00
|
|
|
disabled: PropTypes.bool,
|
2019-05-27 13:26:29 -04:00
|
|
|
tooltip: PropTypes.string
|
|
|
|
}
|
2018-10-05 13:41:12 -04:00
|
|
|
|
2018-09-09 17:22:44 -04:00
|
|
|
export default BuildingEdit;
|