diff --git a/app/src/frontend/building/building-edit.tsx b/app/src/frontend/building/building-edit.tsx
index 5af6c1fd..2c4f7ab5 100644
--- a/app/src/frontend/building/building-edit.tsx
+++ b/app/src/frontend/building/building-edit.tsx
@@ -1,367 +1,8 @@
import React, { Component, Fragment } from 'react';
-import { Link, NavLink, Redirect } from 'react-router-dom';
+import { NavLink } from 'react-router-dom';
import PropTypes from 'prop-types';
-import Sidebar from './sidebar';
-import BuildingNotFound from './building-not-found';
-import ErrorBox from '../components/error-box';
-import InfoBox from '../components/info-box';
import Tooltip from '../components/tooltip';
-import { BackIcon, SaveIcon } from '../components/icons';
-
-import CONFIG from './fields-config.json';
-
-const BuildingEdit = (props) => {
- if (!props.user){
- return
- }
- const cat = props.match.params.cat;
- const sections = CONFIG.filter((d) => d.slug === cat)
-
- if (!props.building_id || sections.length !== 1){
- return ();
- }
-
- const section = sections[0];
- return (
-
-
-
- );
-}
-
-BuildingEdit.propTypes = {
- user: PropTypes.object,
- match: PropTypes.object,
- building_id: PropTypes.number
-}
-
-class EditForm extends Component { // TODO: add proper types
- static propTypes = { // TODO: generate propTypes from TS
- 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,
- building_id: PropTypes.number,
- inactive: PropTypes.bool,
- fields: PropTypes.array
- };
-
- 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
- }
-
- this.handleChange = this.handleChange.bind(this);
- this.handleCheck = this.handleCheck.bind(this);
- this.handleLike = this.handleLike.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- this.handleUpdate = this.handleUpdate.bind(this);
-
- 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
- })
- }
-
- /**
- * Handle changes on typical inputs
- * - e.g. input[type=text], radio, select, textare
- *
- * @param {DocumentEvent} event
- */
- handleChange(event) {
- const target = event.target;
- let value = (target.value === '')? null : target.value;
- const name = target.name;
-
- // special transform - consider something data driven before adding 'else if's
- if (name === 'location_postcode' && value !== null) {
- value = value.toUpperCase();
- }
- 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;
-
- this.setState({
- [name]: value
- });
- }
-
- /**
- * 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
- */
- handleLike(event) {
- event.preventDefault();
- const like = event.target.checked;
-
- fetch(`/api/buildings/${this.props.building_id}/like.json`, {
- method: 'POST',
- headers:{
- 'Content-Type': 'application/json'
- },
- credentials: 'same-origin',
- body: JSON.stringify({like: like})
- }).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})
- );
- }
-
- handleSubmit(event) {
- event.preventDefault();
- this.setState({error: undefined})
-
- fetch(`/api/buildings/${this.props.building_id}.json`, {
- method: 'POST',
- body: JSON.stringify(this.state),
- headers:{
- 'Content-Type': 'application/json'
- },
- credentials: 'same-origin'
- }).then(
- res => res.json()
- ).then(function(res){
- if (res.error) {
- this.setState({error: res.error})
- } else {
- this.props.selectBuilding(res);
- }
- }.bind(this)).catch(
- (err) => this.setState({error: err})
- );
- }
-
- render() {
- const match = this.props.cat === this.props.slug;
- const cat = this.props.cat;
- const buildingLike = this.props.building_like;
-
- 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);
-
- return (
-
-
-
-
-
- {this.props.title}
-
-
- {
- match? (
- !this.props.inactive?
-
- :
- ) : null
- }
-
- )
- }
-}
const TextInput = (props) => (
@@ -598,9 +239,12 @@ class YearEstimator extends Component { // TODO: add proper types
// TODO handle changes internally, reporting out date_year, date_upper, date_lower
render() {
return (
-
+ value={this.props.value}
+ key={this.props.slug}
+ />
)
}
}
diff --git a/app/src/frontend/building/data-container.tsx b/app/src/frontend/building/data-container.tsx
index ec0c5026..407c1a58 100644
--- a/app/src/frontend/building/data-container.tsx
+++ b/app/src/frontend/building/data-container.tsx
@@ -1,9 +1,12 @@
-import React from 'react';
+import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
+import { Redirect } from 'react-router-dom';
import BuildingNotFound from './building-not-found';
import ContainerHeader from './container-header';
import Sidebar from './sidebar';
+import ErrorBox from '../components/error-box';
+import InfoBox from '../components/info-box';
/**
* Shared functionality for view/edit forms
@@ -27,10 +30,27 @@ 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,
- values_to_copy: {}
+ keys_to_copy: {},
+ ...fieldsObj
};
+
+ this.handleChange = this.handleChange.bind(this);
+ this.handleCheck = this.handleCheck.bind(this);
+ this.handleLike = this.handleLike.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleUpdate = this.handleUpdate.bind(this);
+
this.toggleCopying = this.toggleCopying.bind(this);
this.toggleCopyAttribute = this.toggleCopyAttribute.bind(this);
}
@@ -49,21 +69,134 @@ const withCopyEdit = (WrappedComponent) => {
*
* @param {string} key
*/
- toggleCopyAttribute(key) {
- const value = this.props.building[key];
- const values = this.state.values_to_copy;
- if(Object.keys(this.state.values_to_copy).includes(key)){
- delete values[key];
+ toggleCopyAttribute(key: string) {
+ const keys = this.state.keys_to_copy;
+ if(this.state.keys_to_copy[key]){
+ delete keys[key];
} else {
- values[key] = value;
+ keys[key] = true;
}
this.setState({
- values_to_copy: values
+ keys_to_copy: keys
})
}
+ /**
+ * Handle changes on typical inputs
+ * - e.g. input[type=text], radio, select, textare
+ *
+ * @param {DocumentEvent} event
+ */
+ handleChange(event) {
+ const target = event.target;
+ let value = (target.value === '')? null : target.value;
+ const name = target.name;
+
+ // special transform - consider something data driven before adding 'else if's
+ if (name === 'location_postcode' && value !== null) {
+ value = value.toUpperCase();
+ }
+ 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;
+
+ this.setState({
+ [name]: value
+ });
+ }
+
+ /**
+ * 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
+ */
+ handleLike(event) {
+ event.preventDefault();
+ const like = event.target.checked;
+
+ fetch(`/building/${this.props.building_id}/like.json`, {
+ method: 'POST',
+ headers:{
+ 'Content-Type': 'application/json'
+ },
+ credentials: 'same-origin',
+ body: JSON.stringify({like: like})
+ }).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})
+ );
+ }
+
+ handleSubmit(event) {
+ event.preventDefault();
+ this.setState({error: undefined})
+
+ fetch(`/building/${this.props.building_id}.json`, {
+ method: 'POST',
+ body: JSON.stringify(this.state),
+ headers:{
+ 'Content-Type': 'application/json'
+ },
+ credentials: 'same-origin'
+ }).then(
+ res => res.json()
+ ).then(function(res){
+ if (res.error) {
+ this.setState({error: res.error})
+ } else {
+ this.props.selectBuilding(res);
+ }
+ }.bind(this)).catch(
+ (err) => this.setState({error: err})
+ );
+ }
+
render() {
- const data_string = JSON.stringify(this.state.values_to_copy);
+ if (this.state.mode === 'edit' && !this.props.user){
+ return
+ }
+
+ 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);
const copy = {
copying: this.state.copying,
toggleCopying: this.toggleCopying,
@@ -72,14 +205,55 @@ const withCopyEdit = (WrappedComponent) => {
}
return this.props.building?
-
+
:
}
diff --git a/app/src/frontend/building/data-containers/location.tsx b/app/src/frontend/building/data-containers/location.tsx
index 4638d596..60a6c3b4 100644
--- a/app/src/frontend/building/data-containers/location.tsx
+++ b/app/src/frontend/building/data-containers/location.tsx
@@ -1,10 +1,13 @@
-import React from 'react';
+import React, { Fragment } from 'react';
import withCopyEdit from '../data-container';
import DataEntry from '../data-components/data-entry';
import UPRNsDataEntry from '../data-components/uprns-data-entry';
+import InfoBox from '../../components/info-box';
const LocationView = (props) => (
+
+
(
// "placeholder": 0
}
+
)
const LocationContainer = withCopyEdit(LocationView);