From 00687dbaed19f108aa68ac5b232eafe1922a7f15 Mon Sep 17 00:00:00 2001 From: Tom Russell Date: Thu, 1 Aug 2019 10:29:32 +0100 Subject: [PATCH 1/8] Switch to JSON in URL for copy In preparation for multi-attribute copy. --- app/src/frontend/app.js | 14 ++-- app/src/frontend/building-edit.js | 35 +++++----- app/src/frontend/building-view.js | 106 ++++++++++++++++-------------- app/src/frontend/multi-edit.js | 11 +++- 4 files changed, 96 insertions(+), 70 deletions(-) diff --git a/app/src/frontend/app.js b/app/src/frontend/app.js index 857ef73f..f23ffc3f 100644 --- a/app/src/frontend/app.js +++ b/app/src/frontend/app.js @@ -118,16 +118,22 @@ class App extends React.Component { }); } + /** + * Colour building + * + * Used in multi-edit mode to colour buildings on map click + * + * Pulls data from URL to form update + * + * @param {object} building + */ colourBuilding(building) { const cat = parseCategoryURL(window.location.pathname); const q = parse(window.location.search); - let data; + const data = (cat === 'like')? {like: true}: JSON.parse(q.data); if (cat === 'like'){ - data = {like: true} this.likeBuilding(building.building_id) } else { - data = {} - data[q.k] = q.v; this.updateBuilding(building.building_id, data) } } diff --git a/app/src/frontend/building-edit.js b/app/src/frontend/building-edit.js index a7925cba..37f7ce71 100644 --- a/app/src/frontend/building-edit.js +++ b/app/src/frontend/building-edit.js @@ -564,21 +564,26 @@ LikeButton.propTypes = { handleLike: PropTypes.func } -const Label = (props) => ( - -); +const Label = (props) => { + const data = {}; + data[props.slug] = props.value; + const data_string = JSON.stringify(data); + return ( + + ); +} Label.propTypes = { slug: PropTypes.string, diff --git a/app/src/frontend/building-view.js b/app/src/frontend/building-view.js index bd770195..5d7dd97c 100644 --- a/app/src/frontend/building-view.js +++ b/app/src/frontend/building-view.js @@ -135,30 +135,35 @@ DataSection.propTypes = { children: PropTypes.node } -const DataEntry = (props) => ( - -
- { props.title } - { props.tooltip? : null } - { (props.cat && props.slug && !props.disabled)? -
- - Copy - -
- : null - } -
-
{ - (props.value != null && props.value !== '')? - (typeof(props.value) === 'boolean')? - (props.value)? 'Yes' : 'No' - : props.value - : '\u00A0'}
-
-); +const DataEntry = (props) => { + const data = {}; + data[props.slug] = props.value; + const data_string = JSON.stringify(data); + return ( + +
+ { props.title } + { props.tooltip? : null } + { (props.cat && props.slug && !props.disabled)? +
+ + Copy + +
+ : null + } +
+
{ + (props.value != null && props.value !== '')? + (typeof(props.value) === 'boolean')? + (props.value)? 'Yes' : 'No' + : props.value + : '\u00A0'}
+
+ ); +} DataEntry.propTypes = { title: PropTypes.string, @@ -169,33 +174,36 @@ DataEntry.propTypes = { value: PropTypes.any } -const LikeDataEntry = (props) => ( - -
- { props.title } - { props.tooltip? : null } -
- - Copy - -
-
-
+const LikeDataEntry = (props) => { + const data_string = JSON.stringify({like: true}); + ( + +
+ { props.title } + { props.tooltip? : null } +
+ + Copy + +
+
+
+ { + (props.value != null)? + (props.value === 1)? + `${props.value} person likes this building` + : `${props.value} people like this building` + : '\u00A0' + } +
{ - (props.value != null)? - (props.value === 1)? - `${props.value} person likes this building` - : `${props.value} people like this building` - : '\u00A0' + (props.user_building_like)?
…including you!
: null } - - { - (props.user_building_like)?
…including you!
: null - } -
-); + + ); +} LikeDataEntry.propTypes = { title: PropTypes.string, diff --git a/app/src/frontend/multi-edit.js b/app/src/frontend/multi-edit.js index ab592533..231dfa7a 100644 --- a/app/src/frontend/multi-edit.js +++ b/app/src/frontend/multi-edit.js @@ -34,7 +34,7 @@ const MultiEdit = (props) => { } const q = parse(props.location.search); - const label = fieldTitleFromSlug(q.k); + const data = JSON.parse(q.data) const title = sectionTitleFromCat(cat); return ( {

{title}

-

Set {label} to {q.v}

+ { + Object.keys(data).map((key => { + const label = fieldTitleFromSlug(key); + return (

+ Set {label} to {data[key]} +

) + })) + }
From 4a185b372e971253836098e493165f223e553290 Mon Sep 17 00:00:00 2001 From: Tom Russell Date: Thu, 1 Aug 2019 11:19:04 +0100 Subject: [PATCH 2/8] Enable multi-copy from building view --- app/src/frontend/building-view.js | 225 +++++++++++++++++++----------- app/src/frontend/sidebar.css | 7 +- 2 files changed, 148 insertions(+), 84 deletions(-) diff --git a/app/src/frontend/building-view.js b/app/src/frontend/building-view.js index 5d7dd97c..bcc95f4d 100644 --- a/app/src/frontend/building-view.js +++ b/app/src/frontend/building-view.js @@ -29,43 +29,7 @@ const BuildingView = (props) => { - { - section.fields.map(field => { - - switch (field.type) { - case 'uprn_list': - return - case 'text_multi': - return - case 'like': - return - default: - return - } - }) - } - + {...section} {...props} /> )) } @@ -82,46 +46,144 @@ BuildingView.propTypes = { building_like: PropTypes.bool } -const DataSection = (props) => { - const match = props.cat === props.slug; - return ( -
-
- match}> -

{props.title}

-
- -
- { - match? - !props.inactive? -
{props.children}
- :

{props.intro}

- : null - } -
- ); +
+ { + props.fields.map(field => { + + switch (field.type) { + case 'uprn_list': + return + case 'text_multi': + return + case 'like': + return + default: + return + } + }) + } + +
+ :

{props.intro}

+ : null + } + + ); + } } DataSection.propTypes = { @@ -136,21 +198,18 @@ DataSection.propTypes = { } const DataEntry = (props) => { - const data = {}; - data[props.slug] = props.value; - const data_string = JSON.stringify(data); return (
{ props.title } { props.tooltip? : null } - { (props.cat && props.slug && !props.disabled)? + { (props.copying && props.cat && props.slug && !props.disabled)?
- + + props.toggleCopyAttribute(props.slug)}/> +
: null } diff --git a/app/src/frontend/sidebar.css b/app/src/frontend/sidebar.css index 61589b11..b275de11 100644 --- a/app/src/frontend/sidebar.css +++ b/app/src/frontend/sidebar.css @@ -288,9 +288,14 @@ color: rgb(11, 225, 225); } .icon-button.help, -.section-header .icon-button.help { +.section-header .icon-button.help, +.section-header .icon-button.copy { margin-top: 2px; } +.section-header .icon-button.copy { + cursor: pointer; + margin-left: 5px; +} .icon-button.copy:hover, .icon-button.help:hover { color: rgb(0, 81, 255) From ce10a2adc477c46dafd9ab21ad550cf2bc5b84d3 Mon Sep 17 00:00:00 2001 From: Tom Russell Date: Thu, 1 Aug 2019 12:16:08 +0100 Subject: [PATCH 3/8] Enable multi-copy for edit --- app/src/frontend/building-edit.js | 183 +++++++++++++++++++++++------- app/src/frontend/sidebar.css | 3 + 2 files changed, 148 insertions(+), 38 deletions(-) diff --git a/app/src/frontend/building-edit.js b/app/src/frontend/building-edit.js index 37f7ce71..8f61a79e 100644 --- a/app/src/frontend/building-edit.js +++ b/app/src/frontend/building-edit.js @@ -50,18 +50,52 @@ BuildingEdit.propTypes = { class EditForm extends Component { constructor(props) { super(props); - this.state = {} + this.state = { + error: this.props.error || undefined, + like: this.props.like || undefined, + copying: false, + keys_to_copy: {} + } for (const field of props.fields) { this.state[field.slug] = props[field.slug] } - this.state.error = this.props.error || undefined; - this.state.like = this.props.like || undefined; 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 + }) } /** @@ -175,6 +209,12 @@ class EditForm extends Component { 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 (
@@ -187,14 +227,38 @@ class EditForm extends Component {