From e122df8f1aebb8a86c27878b4fb2e450defb99c2 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 31 Jan 2018 15:13:40 -0500 Subject: [PATCH 01/52] Add DisaggregationForm --- .../UtilityLine/DisaggregationForm.js | 38 +++++++++++++++++++ .../UtilityLine/UtilityDisaggregation.js | 36 +++++++++++++----- 2 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 src/components/UtilityLine/DisaggregationForm.js diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js new file mode 100644 index 00000000..335500c3 --- /dev/null +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -0,0 +1,38 @@ +import React, { Component } from 'react'; +import { Input } from 'reactstrap'; +import { Icon } from 'react-fa'; + + +class DisaggregationForm extends Component { + state = { } + + usageTypes = { + DHW: 4, + Lighting: 5, + Cooking: 6, + 'Plug load': 7, + } + + render() { + return ( + + + + {Object.keys(this.usageTypes).map((key) => ( + ) + )} + + + + + + + + { }} /> + + + ); + } +} + +export default DisaggregationForm; diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index a01fe1a5..2672b4b5 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -1,7 +1,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Icon } from 'react-fa'; +import { Table } from 'reactstrap'; import { generateBillDownload } from './dataInteraction'; +import DisaggregationForm from './DisaggregationForm'; class UtilityDisaggregation extends Component { @@ -51,15 +53,30 @@ class UtilityDisaggregation extends Component { return (
- - {this.renderDownloadBtn()} -
+

Non-weather related usage

+ + + + + + + + + + + +
End UsageValue% +
+ +
+ + {this.renderDownloadBtn()} {this.props.renderUploadButton('Disaggregated Bill')}
@@ -67,6 +84,7 @@ class UtilityDisaggregation extends Component { } } + UtilityDisaggregation.propTypes = { street_address: PropTypes.string, disaggregateData: PropTypes.array, // eslint-disable-line -- GitLab From de29ebbbb5b02ccf6fc5dc8f7ed67c80fe1ffd64 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 31 Jan 2018 15:32:32 -0500 Subject: [PATCH 02/52] Add default state to disaggregationForm --- .../UtilityLine/DisaggregationForm.js | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 335500c3..ee628d30 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -1,10 +1,16 @@ import React, { Component } from 'react'; import { Input } from 'reactstrap'; import { Icon } from 'react-fa'; +import PropTypes from 'prop-types'; class DisaggregationForm extends Component { - state = { } + state = { + usage_type: 'DHW', + value: null, + is_percentage: false, + showDelete: false, + } usageTypes = { DHW: 4, @@ -17,22 +23,45 @@ class DisaggregationForm extends Component { return ( - + {Object.keys(this.usageTypes).map((key) => ( ) )} - + + + + + - + { }} + style={{ marginLeft: 0 }} + type="checkbox" + /> + - { }} /> + {!this.props.showDelete ? + { }} /> : + { }} /> + } ); } } +DisaggregationForm.propTypes = { + showDelete: PropTypes.boolean, +}; + export default DisaggregationForm; -- GitLab From 4631f34ef941a27289c89fc021818b95c9969184 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 31 Jan 2018 18:26:14 -0500 Subject: [PATCH 03/52] handle input changes for bill disaggregation form --- .../UtilityLine/DisaggregationForm.js | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index ee628d30..c36d6d85 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -6,10 +6,11 @@ import PropTypes from 'prop-types'; class DisaggregationForm extends Component { state = { - usage_type: 'DHW', - value: null, - is_percentage: false, - showDelete: false, + form: { + usage_type: 'DHW', + value: 0, + is_percentage: false, + }, } usageTypes = { @@ -19,6 +20,24 @@ class DisaggregationForm extends Component { 'Plug load': 7, } + handleInputChange = (event) => { + const target = event.target; + const name = target.name; + + let val = target.type === 'checkbox' ? target.checked : target.value; + + if (target.type === 'number') { + val = Number(val); + } + + this.setState({ + form: { + ...this.state.form, + [name]: val, + }, + }); + } + render() { return ( @@ -26,6 +45,8 @@ class DisaggregationForm extends Component { this.handleInputChange(e)} + value={this.state.form.usage_type} > {Object.keys(this.usageTypes).map((key) => ( ) @@ -37,15 +58,18 @@ class DisaggregationForm extends Component { this.handleInputChange(e)} + value={this.state.form.value} /> { }} + onChange={e => this.handleInputChange(e)} style={{ marginLeft: 0 }} type="checkbox" + checked={this.state.form.is_percentage} /> @@ -61,7 +85,11 @@ class DisaggregationForm extends Component { } DisaggregationForm.propTypes = { - showDelete: PropTypes.boolean, + showDelete: PropTypes.bool, +}; + +DisaggregationForm.defaultProps = { + showDelete: false, }; export default DisaggregationForm; -- GitLab From 27d568980e24131c152c5d72779e874e311a2420 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Thu, 1 Feb 2018 09:41:10 -0500 Subject: [PATCH 04/52] Remove padding from disagg form --- .../UtilityLine/UtilityDisaggregation.js | 11 ++++---- src/components/UtilityLine/UtilityLine.js | 26 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 2672b4b5..b958144e 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -40,7 +40,8 @@ class UtilityDisaggregation extends Component { color: (this.props.rSquared < LOW_RSQUARED) ? 'red' : 'black', }} > - {this.props.rSquared ? this.props.rSquared.toFixed(3).replace(/^0+/, '') : ''} + {this.props.rSquared && this.props.rSquared.toFixed(3).replace(/^0+/, '')} + ); @@ -57,10 +58,10 @@ class UtilityDisaggregation extends Component { - - - - + + + diff --git a/src/components/UtilityLine/UtilityLine.js b/src/components/UtilityLine/UtilityLine.js index 6336a8cc..ac629f6d 100644 --- a/src/components/UtilityLine/UtilityLine.js +++ b/src/components/UtilityLine/UtilityLine.js @@ -811,20 +811,18 @@ class UtilityLine extends Component {
{this.state.accountCreated && 'Disaggregation'}
-
- -
+
{this.state.accountCreated ? 'View Data' : ''}
-- GitLab From 51ac0e8fee68d174fed608e0301e3d8f2e4bc05d Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Fri, 2 Feb 2018 13:10:36 -0500 Subject: [PATCH 05/52] Implement add and delete methods for dissaggregation form --- .../UtilityLine/DisaggregationForm.js | 33 +++++++++---- .../UtilityLine/UtilityDisaggregation.js | 46 ++++++++++++++++++- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index c36d6d85..0e1b104a 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -5,12 +5,17 @@ import PropTypes from 'prop-types'; class DisaggregationForm extends Component { - state = { - form: { - usage_type: 'DHW', - value: 0, - is_percentage: false, - }, + constructor(props) { + super(props); + if (this.props.form) { + this.state = { + form: { ...this.props.form }, + }; + } + } + + componentWillReceiveProps(nextProps) { + console.log('component will receive props ', nextProps.form); } usageTypes = { @@ -75,8 +80,8 @@ class DisaggregationForm extends Component {
@@ -85,11 +90,23 @@ class DisaggregationForm extends Component { } DisaggregationForm.propTypes = { + addEndUsage: PropTypes.func, + deleteEndUsage: PropTypes.func, + form: PropTypes.shape({ + usage_type: PropTypes.string, + value: PropTypes.number, + is_percentage: PropTypes.bool, + }), showDelete: PropTypes.bool, }; DisaggregationForm.defaultProps = { showDelete: false, + form: { + usage_type: 'DHW', + value: 0, + is_percentage: false, + }, }; export default DisaggregationForm; diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index b958144e..3b80e2a9 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -7,7 +7,39 @@ import DisaggregationForm from './DisaggregationForm'; class UtilityDisaggregation extends Component { - state = { } + state = { + endUsages: [], + } + + componentWillMount() { + this.setState({ + endUsages: [ + { + usage_type: 'DHW', + value: 5, + is_percentage: false, + }, + ], + }); + } + + + addNewEndUsage = (disaggregationForm) => { + this.setState({ + endUsages: [ + ...this.state.endUsages, + disaggregationForm, + ], + }); + } + + deleteEndUsage = (index) => { + const endUsageCopy = [...this.state.endUsages]; + endUsageCopy.splice(index, 1); + this.setState({ + endUsages: endUsageCopy, + }); + } renderDownloadBtn = () => { const { disaggregateData } = this.props; @@ -65,7 +97,17 @@ class UtilityDisaggregation extends Component { - + {this.state.endUsages.map((disaggregationForm, index) => ( + this.deleteEndUsage(index)} + showDelete + /> + ))} +
End UsageValue% + End UsageValue%
{!this.props.showDelete ? - { }} /> : - { }} /> + this.props.addEndUsage(this.state.form)} /> : + this.props.deleteEndUsage()} /> }
-- GitLab From c5d09377785bbdb08215d9e4c4e938b3bd4d0dae Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Fri, 2 Feb 2018 13:40:05 -0500 Subject: [PATCH 06/52] Clear form after hitting enter --- src/components/UtilityLine/DisaggregationForm.js | 9 ++++++++- src/components/UtilityLine/UtilityDisaggregation.js | 3 +-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 0e1b104a..f1917946 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -80,7 +80,14 @@ class DisaggregationForm extends Component { {!this.props.showDelete ? - this.props.addEndUsage(this.state.form)} /> : + { + this.props.addEndUsage(this.state.form); + // Clear form after selecting plus icon + this.setState({ form: { ...this.props.form } }); + }} + /> : this.props.deleteEndUsage()} /> } diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 3b80e2a9..336e9bb6 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -23,7 +23,6 @@ class UtilityDisaggregation extends Component { }); } - addNewEndUsage = (disaggregationForm) => { this.setState({ endUsages: [ @@ -117,7 +116,7 @@ class UtilityDisaggregation extends Component { disabled={this.props.disableDisaggregateBtn()} onClick={this.props.handleDisaggregateUtilityBill} > - {this.props.loadingDisaggregate ? 'Disaggregating...' : 'Disaggregate'} + {this.props.loadingDisaggregate ? 'Disaggregating...' : 'Save'} {this.renderDownloadBtn()} {this.props.renderUploadButton('Disaggregated Bill')} -- GitLab From d8050264f63b2c27e7623437d2c17873bb5f9072 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Fri, 2 Feb 2018 13:46:47 -0500 Subject: [PATCH 07/52] Add id to default props --- src/components/UtilityLine/DisaggregationForm.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index f1917946..5e38437e 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -110,6 +110,7 @@ DisaggregationForm.propTypes = { DisaggregationForm.defaultProps = { showDelete: false, form: { + id: null, usage_type: 'DHW', value: 0, is_percentage: false, -- GitLab From 21a63a8f5168998a78eff09604bd344d2087b676 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 5 Feb 2018 17:44:51 -0500 Subject: [PATCH 08/52] Add Fade component --- package-lock.json | 26 +++----------------------- package.json | 1 + src/components/Fade.js | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 src/components/Fade.js diff --git a/package-lock.json b/package-lock.json index 5b104203..c2684e74 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1771,6 +1771,7 @@ "version": "4.0.0-alpha.6", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-alpha.6.tgz", "integrity": "sha1-T1TdM6wN6sOyhAe8LffsYIhpycg=", + "dev": true, "requires": { "jquery": "3.2.1", "tether": "1.4.0" @@ -1829,15 +1830,6 @@ } } }, - "bpl": { - "version": "git+https://7f8bbb4b0a383ad905fee5b0f7cbc0c22533b556:x-oauth-basic@github.com/Blocp/bpl.git#044aab932460e8c5d2cc3f993538a3910d42e660", - "requires": { - "bootstrap": "4.0.0-alpha.6", - "copy-dir": "0.3.0", - "jquery": "3.2.1", - "tether": "1.4.0" - } - }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", @@ -2522,14 +2514,6 @@ "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=" }, - "copy-dir": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-0.3.0.tgz", - "integrity": "sha1-3rLcL6nJKQ7UfIQVWpmabUX1o1g=", - "requires": { - "mkdir-p": "0.0.7" - } - }, "copy-to-clipboard": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz", @@ -7032,7 +7016,8 @@ "jquery": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", - "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" + "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=", + "dev": true }, "js-base64": { "version": "2.3.2", @@ -7793,11 +7778,6 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, - "mkdir-p": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mkdir-p/-/mkdir-p-0.0.7.tgz", - "integrity": "sha1-JMXb4m2jqZ7xWKHu+aXC3Z3laDw=" - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", diff --git a/package.json b/package.json index a5c9f8c4..176d1262 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "react-table": "^6.7.4", "react-timeseries-charts": "^0.12.8", "react-tooltip": "^3.3.0", + "react-transition-group": "^2.2.1", "reactstrap": "^4.8.0", "recharts": "^0.21.2", "redux": "^3.6.0", diff --git a/src/components/Fade.js b/src/components/Fade.js new file mode 100644 index 00000000..93fb2e41 --- /dev/null +++ b/src/components/Fade.js @@ -0,0 +1,38 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Transition from 'react-transition-group/Transition'; + +const DURATION = 300; + +const Fade = ({ in: inProp, children }) => ( + + {(state) => ( +
+ {children} +
+ )} +
+); + +const styles = { + defaultStyle: { + transition: `opacity ${DURATION}ms ease-in-out`, + opacity: 0, + display: 'inline-block', + }, + transitionStyles: { + entering: { opacity: 0 }, + entered: { opacity: 1 }, + }, +}; + +Fade.propTypes = { + in: PropTypes.bool, + children: PropTypes.element, +}; + +export default Fade; -- GitLab From eb05aad0bbea15c179b6aa069d1af1bf4a3932df Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 5 Feb 2018 18:05:55 -0500 Subject: [PATCH 09/52] Save disaggregate meta info --- src/components/Utilities/index.js | 101 ++++++++++++------ .../UtilityLine/DisaggregationForm.js | 16 +-- .../UtilityLine/UtilityDisaggregation.js | 18 +++- src/components/UtilityLine/UtilityLine.js | 12 ++- src/utils/restServices.js | 1 + 5 files changed, 104 insertions(+), 44 deletions(-) diff --git a/src/components/Utilities/index.js b/src/components/Utilities/index.js index ee93bfb3..d02c9105 100644 --- a/src/components/Utilities/index.js +++ b/src/components/Utilities/index.js @@ -5,7 +5,7 @@ import buildingDetailPropTypes from '../../containers/Building/propTypes'; import request from '../../utils/request'; import ErrorAlert from '../../components/ErrorAlert'; -import { getHeaders, scrapeURL, accountURL, disaggregateURL } from '../../utils/restServices'; +import { getHeaders, scrapeURL, accountURL, disaggregateURL, disaggregateMetaURL } from '../../utils/restServices'; import LinkBarDetail from '../../components/LinkBarDetail'; import UtilityLine from '../UtilityLine/UtilityLine'; import Loading from '../../components/Loading'; @@ -72,50 +72,87 @@ class Utilities extends Component { }); } + + saveDisaggregateMeta = (accountId, disaggregateMeta, updateSavingDisaggregateMeta) => { + return new Promise((resolve, reject) => { + request(disaggregateMetaURL, { + method: 'PUT', + headers: getHeaders(), + body: JSON.stringify({ + account_id: accountId, + disaggregateMeta, + }), + }).then(res => { + if (res.err) { + this.setState({ error: res.err }); + reject(); + } else { + console.log('success post', res); + } + + setTimeout(() => { + updateSavingDisaggregateMeta(false); + resolve(); + }, 1000); + }); + }); + } + + disaggregateUtilityBill = ( form, accountId, updateLoadingDisaggregateState, setDisaggregateData, setRSquared, + disaggregateMeta, + updateSavingDisaggregateMeta, ) => { ReactGA.event({ category: 'Utilities', action: 'Dissagregate Bill Request', label: `Utility: ${form.utility}, Account: ${form.account_number}`, }); - request(disaggregateURL, { - method: 'POST', - headers: getHeaders(), - body: JSON.stringify({ - ...form, - account_id: accountId, - building_id: this.props.buildingId, - }), - }).then((res) => { - if (res.err) { - ReactGA.event({ - category: 'Utilities', - action: 'Disaggregate Bill Error', - label: `Utility: ${form.utility}, - Account: ${form.account_number}, - Error: ${res.err}`, - }); - this.setState({ error: res.err }); - } else { - ReactGA.event({ - category: 'Utilities', - action: 'Disaggregate Bill Success', - label: `Utility: ${form.utility}, Account: ${form.account_number}`, - }); - const data = res.data; - const disaggregateData = this.parseDisaggregateData(data.disaggregate_database_output); - setDisaggregateData(disaggregateData); - setRSquared(data.r_squared); - this.resetErrorMessage(); - } - updateLoadingDisaggregateState(false); + this.saveDisaggregateMeta( + accountId, disaggregateMeta, updateSavingDisaggregateMeta + ).then(() => { + request(disaggregateURL, { + method: 'POST', + headers: getHeaders(), + body: JSON.stringify({ + ...form, + account_id: accountId, + building_id: this.props.buildingId, + }), + }).then((disaggregateRes) => { + if (disaggregateRes.err) { + ReactGA.event({ + category: 'Utilities', + action: 'Disaggregate Bill Error', + label: `Utility: ${form.utility}, + Account: ${form.account_number}, + Error: ${disaggregateRes.err}`, + }); + this.setState({ error: disaggregateRes.err }); + } else { + ReactGA.event({ + category: 'Utilities', + action: 'Disaggregate Bill Success', + label: `Utility: ${form.utility}, Account: ${form.account_number}`, + }); + const data = disaggregateRes.data; + const disaggregateData = this.parseDisaggregateData(data.disaggregate_database_output); + setDisaggregateData(disaggregateData); + setRSquared(data.r_squared); + + this.resetErrorMessage(); + } + + setTimeout(() => { + updateLoadingDisaggregateState(false); + }, 1000); + }); }); } diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 5e38437e..883c1cb0 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -19,10 +19,10 @@ class DisaggregationForm extends Component { } usageTypes = { - DHW: 4, - Lighting: 5, - Cooking: 6, - 'Plug load': 7, + 5: 'DHW', + 6: 'Lighting', + 7: 'Cooking', + 8: 'Plug load', } handleInputChange = (event) => { @@ -48,13 +48,13 @@ class DisaggregationForm extends Component { this.handleInputChange(e)} value={this.state.form.usage_type} > {Object.keys(this.usageTypes).map((key) => ( - ) + ) )} @@ -100,7 +100,7 @@ DisaggregationForm.propTypes = { addEndUsage: PropTypes.func, deleteEndUsage: PropTypes.func, form: PropTypes.shape({ - usage_type: PropTypes.string, + usage_type: PropTypes.number, value: PropTypes.number, is_percentage: PropTypes.bool, }), @@ -111,7 +111,7 @@ DisaggregationForm.defaultProps = { showDelete: false, form: { id: null, - usage_type: 'DHW', + usage_type_id: 5, value: 0, is_percentage: false, }, diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 336e9bb6..7a78916d 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -4,6 +4,7 @@ import { Icon } from 'react-fa'; import { Table } from 'reactstrap'; import { generateBillDownload } from './dataInteraction'; import DisaggregationForm from './DisaggregationForm'; +import Fade from '../Fade'; class UtilityDisaggregation extends Component { @@ -15,7 +16,8 @@ class UtilityDisaggregation extends Component { this.setState({ endUsages: [ { - usage_type: 'DHW', + id: null, + usage_type_id: 5, // DHW value: 5, is_percentage: false, }, @@ -114,11 +116,20 @@ class UtilityDisaggregation extends Component { {this.renderDownloadBtn()} +
+ + + Saving + + + Disaggregating + +
{this.props.renderUploadButton('Disaggregated Bill')}
@@ -138,6 +149,7 @@ UtilityDisaggregation.propTypes = { disableDisaggregateBtn: PropTypes.func, handleDisaggregateUtilityBill: PropTypes.func, loadingDisaggregate: PropTypes.bool, + savingDisaggregateMeta: PropTypes.bool, }; export default UtilityDisaggregation; diff --git a/src/components/UtilityLine/UtilityLine.js b/src/components/UtilityLine/UtilityLine.js index ac629f6d..b60c9352 100644 --- a/src/components/UtilityLine/UtilityLine.js +++ b/src/components/UtilityLine/UtilityLine.js @@ -43,6 +43,7 @@ class UtilityLine extends Component { loadingUpload: false, editing: false, saving: false, + savingDisaggregateMeta: false, prevForm: { account_number: '', username: '', @@ -86,6 +87,10 @@ class UtilityLine extends Component { this.setState({ loadingFetch: isLoading }) ) + updateSavingDisaggregateMeta = isSaving => ( + this.setState({ savingDisaggregateMeta: isSaving }) + ) + updateLoadingDisaggregateState = isLoading => ( this.setState({ loadingDisaggregate: isLoading }) ) @@ -133,15 +138,19 @@ class UtilityLine extends Component { ); } - handleDisaggregateUtilityBill = (event) => { + handleDisaggregateUtilityBill = (event, disaggregateMeta) => { event.preventDefault(); + this.updateSavingDisaggregateMeta(true); this.updateLoadingDisaggregateState(true); + this.props.disaggregateUtilityBill( this.state.form, this.state.account_id, this.updateLoadingDisaggregateState, this.setDisaggregateData, this.setRSquared, + disaggregateMeta, + this.updateSavingDisaggregateMeta, ); } @@ -822,6 +831,7 @@ class UtilityLine extends Component { disableDisaggregateBtn={this.disableDisaggregateBtn} handleDisaggregateUtilityBill={this.handleDisaggregateUtilityBill} loadingDisaggregate={this.state.loadingDisaggregate} + savingDisaggregateMeta={this.state.savingDisaggregateMeta} />
diff --git a/src/utils/restServices.js b/src/utils/restServices.js index 3c913b67..a292d8a7 100644 --- a/src/utils/restServices.js +++ b/src/utils/restServices.js @@ -31,6 +31,7 @@ export const boxAccessTokenURL = `${documentService}/boxusertoken/`; export const accountURL = `${utilityService}/account/`; export const scrapeURL = `${utilityService}/scrape/`; export const disaggregateURL = `${utilityService}/disaggregate/`; +export const disaggregateMetaURL = `${utilityService}/disaggregatemeta/`; export const projectURL = `${projectService}/project/`; export const contactsURL = `${projectService}/contact/`; -- GitLab From b5539dd61f5a061c98961d600c414a8f31d7a11c Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 5 Feb 2018 18:16:23 -0500 Subject: [PATCH 10/52] Fix Disaggregation usage_id in form --- .../UtilityLine/DisaggregationForm.js | 17 +++++++++++++---- .../UtilityLine/UtilityDisaggregation.js | 1 - 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 883c1cb0..23c2b3fd 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -28,11 +28,20 @@ class DisaggregationForm extends Component { handleInputChange = (event) => { const target = event.target; const name = target.name; + let val = null; - let val = target.type === 'checkbox' ? target.checked : target.value; + switch (target.type) { + case 'checkbox': + val = target.checked; + break; - if (target.type === 'number') { - val = Number(val); + case 'number': + case 'select-one': + val = Number(target.value); + break; + + default: + val = target.value; } this.setState({ @@ -51,7 +60,7 @@ class DisaggregationForm extends Component { name="usage_type_id" type="select" onChange={e => this.handleInputChange(e)} - value={this.state.form.usage_type} + value={this.state.form.usage_type_id} > {Object.keys(this.usageTypes).map((key) => ( ) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 7a78916d..d5cf6e0b 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -123,7 +123,6 @@ class UtilityDisaggregation extends Component { {this.renderDownloadBtn()}
- Saving -- GitLab From cd5f6fe607cb51a6e815cb9b35a1fde1dc4b892a Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 5 Feb 2018 18:43:33 -0500 Subject: [PATCH 11/52] Load existing disaggregate data --- src/components/Utilities/index.js | 3 +++ .../UtilityLine/UtilityDisaggregation.js | 22 +++++++++++++++++-- src/components/UtilityLine/UtilityLine.js | 3 +-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/components/Utilities/index.js b/src/components/Utilities/index.js index d02c9105..63992d35 100644 --- a/src/components/Utilities/index.js +++ b/src/components/Utilities/index.js @@ -114,9 +114,12 @@ class Utilities extends Component { label: `Utility: ${form.utility}, Account: ${form.account_number}`, }); + updateSavingDisaggregateMeta(true); this.saveDisaggregateMeta( accountId, disaggregateMeta, updateSavingDisaggregateMeta ).then(() => { + updateLoadingDisaggregateState(true); + request(disaggregateURL, { method: 'POST', headers: getHeaders(), diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index d5cf6e0b..4385196e 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -5,6 +5,8 @@ import { Table } from 'reactstrap'; import { generateBillDownload } from './dataInteraction'; import DisaggregationForm from './DisaggregationForm'; import Fade from '../Fade'; +import request from '../../utils/request'; +import { getHeaders, disaggregateMetaURL } from '../../utils/restServices'; class UtilityDisaggregation extends Component { @@ -25,6 +27,21 @@ class UtilityDisaggregation extends Component { }); } + componentDidMount() { + if (this.props.accountId === null) { + return; + } + + request(`${disaggregateMetaURL}?account_id=${this.props.accountId}`, { + method: 'GET', + headers: getHeaders(), + }).then((res) => { + if (!res.err) { + this.setState({ endUsages: res.data }); + } + }); + } + addNewEndUsage = (disaggregationForm) => { this.setState({ endUsages: [ @@ -118,14 +135,14 @@ class UtilityDisaggregation extends Component { disabled={this.props.disableDisaggregateBtn()} onClick={(e) => this.props.handleDisaggregateUtilityBill(e, this.state.endUsages)} > - Disaggregate + Save {this.renderDownloadBtn()}
Saving - + Disaggregating
@@ -149,6 +166,7 @@ UtilityDisaggregation.propTypes = { handleDisaggregateUtilityBill: PropTypes.func, loadingDisaggregate: PropTypes.bool, savingDisaggregateMeta: PropTypes.bool, + accountId: PropTypes.number, }; export default UtilityDisaggregation; diff --git a/src/components/UtilityLine/UtilityLine.js b/src/components/UtilityLine/UtilityLine.js index b60c9352..3297895f 100644 --- a/src/components/UtilityLine/UtilityLine.js +++ b/src/components/UtilityLine/UtilityLine.js @@ -140,8 +140,6 @@ class UtilityLine extends Component { handleDisaggregateUtilityBill = (event, disaggregateMeta) => { event.preventDefault(); - this.updateSavingDisaggregateMeta(true); - this.updateLoadingDisaggregateState(true); this.props.disaggregateUtilityBill( this.state.form, @@ -832,6 +830,7 @@ class UtilityLine extends Component { handleDisaggregateUtilityBill={this.handleDisaggregateUtilityBill} loadingDisaggregate={this.state.loadingDisaggregate} savingDisaggregateMeta={this.state.savingDisaggregateMeta} + accountId={this.state.account_id} />
-- GitLab From 68ca067e87cccb5768f7c86454da10dea89f1670 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 5 Feb 2018 18:49:22 -0500 Subject: [PATCH 12/52] Remove initial end usage --- src/components/UtilityLine/UtilityDisaggregation.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 4385196e..b1cb3913 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -14,19 +14,6 @@ class UtilityDisaggregation extends Component { endUsages: [], } - componentWillMount() { - this.setState({ - endUsages: [ - { - id: null, - usage_type_id: 5, // DHW - value: 5, - is_percentage: false, - }, - ], - }); - } - componentDidMount() { if (this.props.accountId === null) { return; -- GitLab From 6460a9cd0318fc72905914657ccf4dc00ebd7dc8 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 5 Feb 2018 18:58:58 -0500 Subject: [PATCH 13/52] Add delete function --- .../UtilityLine/UtilityDisaggregation.js | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index b1cb3913..7fb19138 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -40,7 +40,27 @@ class UtilityDisaggregation extends Component { deleteEndUsage = (index) => { const endUsageCopy = [...this.state.endUsages]; - endUsageCopy.splice(index, 1); + const toBeDeleted = endUsageCopy.splice(index, 1); + + const confirmAns = confirm('Are you sure you want to delete this? This action cannot be undone.'); + if (!confirmAns) { + return; + } + + if (toBeDeleted.id !== null) { + request(`${disaggregateMetaURL}${toBeDeleted.pop().id}`, { + method: 'DELETE', + headers: getHeaders(), + }).then((res) => { + if (!res.err) { + this.setState({ + endUsages: endUsageCopy, + }); + } + }); + return; + } + this.setState({ endUsages: endUsageCopy, }); -- GitLab From da73d1c5beca34ec68fed6dbfd0564427b67e720 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 5 Feb 2018 19:09:53 -0500 Subject: [PATCH 14/52] Update props names in utility line --- .../UtilityLine/UtilityDisaggregation.js | 14 +++++++++++--- src/components/UtilityLine/UtilityLine.js | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 7fb19138..8d17a5b3 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -83,7 +83,7 @@ class UtilityDisaggregation extends Component { { this.props.handleBillGAEvent('Download Disaggregated Bill'); }} > @@ -163,8 +163,16 @@ class UtilityDisaggregation extends Component { UtilityDisaggregation.propTypes = { street_address: PropTypes.string, - disaggregateData: PropTypes.array, // eslint-disable-line - form: PropTypes.object, // eslint-disable-line + disaggregateData: PropTypes.arrayOf( + PropTypes.shape({ + bill_from_date: PropTypes.string, + bill_to_date: PropTypes.string, + heating: PropTypes.number, + cooling: PropTypes.number, + other: PropTypes.number, + }) + ), + utility_type: PropTypes.string, handleBillGAEvent: PropTypes.func, rSquared: PropTypes.number, renderUploadButton: PropTypes.func, diff --git a/src/components/UtilityLine/UtilityLine.js b/src/components/UtilityLine/UtilityLine.js index 3297895f..421f948c 100644 --- a/src/components/UtilityLine/UtilityLine.js +++ b/src/components/UtilityLine/UtilityLine.js @@ -820,7 +820,7 @@ class UtilityLine extends Component {
{this.state.accountCreated && 'Disaggregation'}
Date: Tue, 6 Feb 2018 13:12:07 -0500 Subject: [PATCH 15/52] Set state back to default form --- src/components/UtilityLine/DisaggregationForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 23c2b3fd..a9114140 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -94,7 +94,7 @@ class DisaggregationForm extends Component { onClick={() => { this.props.addEndUsage(this.state.form); // Clear form after selecting plus icon - this.setState({ form: { ...this.props.form } }); + this.setState({ form: { ...this.defaultProps.form } }); }} /> : this.props.deleteEndUsage()} /> -- GitLab From 49c388465719466e710df77e282b18b7d61bcbc9 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 6 Feb 2018 14:46:05 -0500 Subject: [PATCH 16/52] Add disaggregation form test --- package-lock.json | 263 ++++++++++++++++++ package.json | 3 + .../UtilityLine/DisaggregationForm.js | 2 +- .../UtilityLine/DisaggregationForm.test.js | 82 ++++++ .../DisaggregationForm.test.js.snap | 165 +++++++++++ 5 files changed, 514 insertions(+), 1 deletion(-) create mode 100644 src/components/UtilityLine/DisaggregationForm.test.js create mode 100644 src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap diff --git a/package-lock.json b/package-lock.json index c2684e74..eef4367f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2151,6 +2151,61 @@ } } }, + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-serializer": "0.1.0", + "entities": "1.1.1", + "htmlparser2": "3.9.2", + "lodash.assignin": "4.2.0", + "lodash.bind": "4.2.1", + "lodash.defaults": "4.2.0", + "lodash.filter": "4.6.0", + "lodash.flatten": "4.4.0", + "lodash.foreach": "4.5.0", + "lodash.map": "4.6.0", + "lodash.merge": "4.6.1", + "lodash.pick": "4.4.0", + "lodash.reduce": "4.6.0", + "lodash.reject": "4.6.0", + "lodash.some": "4.6.0" + }, + "dependencies": { + "domhandler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.4.1", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + } + } + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -3503,6 +3558,56 @@ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", "dev": true }, + "enzyme": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-2.8.2.tgz", + "integrity": "sha1-bIvLBQEqvEqkvDIT+yN4C5tbFxQ=", + "dev": true, + "requires": { + "cheerio": "0.22.0", + "function.prototype.name": "1.1.0", + "is-subset": "0.1.1", + "lodash": "4.17.4", + "object-is": "1.0.1", + "object.assign": "4.1.0", + "object.entries": "1.0.4", + "object.values": "1.0.4", + "prop-types": "15.6.0", + "uuid": "2.0.3" + }, + "dependencies": { + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + } + } + }, + "enzyme-adapter-react-15": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-15/-/enzyme-adapter-react-15-1.0.5.tgz", + "integrity": "sha512-GxQ+ZYbo6YFwwpaLc9LLyAwsx+F1au628/+hwTx3XV2OiuvHGyWgC/r1AAK1HlDRjujzfwwMNZTc/JxkjIuYVg==", + "dev": true, + "requires": { + "enzyme-adapter-utils": "1.3.0", + "lodash": "4.17.4", + "object.assign": "4.1.0", + "object.values": "1.0.4", + "prop-types": "15.6.0" + } + }, + "enzyme-adapter-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz", + "integrity": "sha512-vVXSt6uDv230DIv+ebCG66T1Pm36Kv+m74L1TrF4kaE7e1V7Q/LcxO0QRkajk5cA6R3uu9wJf5h13wOTezTbjA==", + "dev": true, + "requires": { + "lodash": "4.17.4", + "object.assign": "4.1.0", + "prop-types": "15.6.0" + } + }, "errno": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", @@ -5393,6 +5498,17 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "function.prototype.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.0.tgz", + "integrity": "sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg==", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "is-callable": "1.1.3" + } + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -5714,6 +5830,12 @@ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -6536,6 +6658,12 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-subset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", + "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", + "dev": true + }, "is-svg": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", @@ -7388,6 +7516,18 @@ "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", "dev": true }, + "lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=", + "dev": true + }, + "lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", + "dev": true + }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -7438,11 +7578,29 @@ } } }, + "lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, "lodash.flow": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=", + "dev": true + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -7476,12 +7634,24 @@ "lodash.isarray": "3.0.4" } }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "dev": true + }, "lodash.mergewith": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", @@ -7498,12 +7668,36 @@ "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=" }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", + "dev": true + }, + "lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=", + "dev": true + }, + "lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=", + "dev": true + }, "lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", "dev": true }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "dev": true + }, "lodash.template": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", @@ -8119,12 +8313,42 @@ "integrity": "sha512-smRWXzkvxw72VquyZ0wggySl7PFUtoDhvhpdwgESXxUrH7vVhhp9asfup1+rVLrhsl7L45Ee1Q/l5R2Ul4MwUg==", "dev": true }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, "object-keys": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", "dev": true }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "object-keys": "1.0.11" + } + }, + "object.entries": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", + "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.10.0", + "function-bind": "1.1.1", + "has": "1.0.1" + } + }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", @@ -8135,6 +8359,18 @@ "is-extendable": "0.1.1" } }, + "object.values": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", + "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.10.0", + "function-bind": "1.1.1", + "has": "1.0.1" + } + }, "obuf": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz", @@ -10770,6 +11006,33 @@ "classnames": "2.2.5" } }, + "react-test-renderer": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-15.6.1.tgz", + "integrity": "sha1-Am9KW7VVJmH9LMS7zQ1LyKNev34=", + "dev": true, + "requires": { + "fbjs": "0.8.16", + "object-assign": "4.1.1" + }, + "dependencies": { + "fbjs": { + "version": "0.8.16", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", + "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", + "dev": true, + "requires": { + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.1.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.17" + } + } + } + }, "react-tether": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/react-tether/-/react-tether-0.5.7.tgz", diff --git a/package.json b/package.json index 176d1262..a4fcff73 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "css-loader": "0.28.1", "detect-port": "1.0.1", "dotenv": "4.0.0", + "enzyme": "^2.8.2", + "enzyme-adapter-react-15": "^1.0.5", "eslint": "^4.3.0", "eslint-config-airbnb": "^15.1.0", "eslint-config-react-app": "^2.0.1", @@ -49,6 +51,7 @@ "promise": "7.1.1", "react-dev-utils": "^1.0.0", "react-error-overlay": "^1.0.0", + "react-test-renderer": "^15.6.1", "recursive-readdir": "2.1.0", "resolve-url-loader": "1.6.1", "rimraf": "2.5.4", diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index a9114140..6577127d 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -109,7 +109,7 @@ DisaggregationForm.propTypes = { addEndUsage: PropTypes.func, deleteEndUsage: PropTypes.func, form: PropTypes.shape({ - usage_type: PropTypes.number, + usage_type_id: PropTypes.number, value: PropTypes.number, is_percentage: PropTypes.bool, }), diff --git a/src/components/UtilityLine/DisaggregationForm.test.js b/src/components/UtilityLine/DisaggregationForm.test.js new file mode 100644 index 00000000..4be6b465 --- /dev/null +++ b/src/components/UtilityLine/DisaggregationForm.test.js @@ -0,0 +1,82 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Table } from 'reactstrap'; +import renderer from 'react-test-renderer'; +import { shallow } from 'enzyme'; +import DisaggregationForm from './DisaggregationForm'; + +const form = { + usage_type_id: 6, + value: 99, + is_percentage: false, +}; + +const SimpleTable = (props) => ( + + + { + // eslint-disable-next-line + }{props.children} + +
+); + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render( + + {}} + deleteEndUsage={() => {}} + /> + , + div); +}); + +test('DisaggregationForm renders form passed in', () => { + const shallowDisaggregationForm = shallow( + {}} + deleteEndUsage={() => {}} + form={form} + /> + ); + + // Make sure state is initialized by props + const componentForm = shallowDisaggregationForm.state().form; + expect(componentForm.usage_type_id).toEqual(form.usage_type_id); + expect(componentForm.value).toEqual(form.value); + expect(componentForm.is_percentage).toEqual(form.is_percentage); + + // Make sure form is rendered to DOM + expect(shallowDisaggregationForm.find('[name="usage_type_id"]').props().value).toEqual(form.usage_type_id); + expect(shallowDisaggregationForm.find('[name="value"]').props().value).toEqual(form.value); + expect(shallowDisaggregationForm.find('[name="is_percentage"]').props().checked).toEqual(form.is_percentage); +}); + +test('DisaggregationForm snapshot with default form', () => { + const component = renderer.create( + + {}} + deleteEndUsage={() => {}} + /> + , + ); + let tree = component.toJSON(); + expect(tree).toMatchSnapshot(); +}); + +test('DisaggregationForm snapshot passing in form', () => { + const component = renderer.create( + + {}} + deleteEndUsage={() => {}} + form={form} + /> + , + ); + let tree = component.toJSON(); + expect(tree).toMatchSnapshot(); +}); diff --git a/src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap b/src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap new file mode 100644 index 00000000..20768cd6 --- /dev/null +++ b/src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap @@ -0,0 +1,165 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DisaggregationForm snapshot passing in form 1`] = ` + + + + + + + + + + +
+ + + + + + + +
+`; + +exports[`DisaggregationForm snapshot with default form 1`] = ` + + + + + + + + + + +
+ + + + + + + +
+`; -- GitLab From b057ef013e912fa67d7348be067d3dc075b635ce Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Fri, 9 Feb 2018 12:30:26 -0500 Subject: [PATCH 17/52] Switch default props --- src/components/UtilityLine/DisaggregationForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 6577127d..787410d8 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -94,7 +94,7 @@ class DisaggregationForm extends Component { onClick={() => { this.props.addEndUsage(this.state.form); // Clear form after selecting plus icon - this.setState({ form: { ...this.defaultProps.form } }); + this.setState({ form: { ...this.props.form } }); }} /> : this.props.deleteEndUsage()} /> -- GitLab From 72648f9d28db6775a4d0b1fea4b55a2f059766a4 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 12 Feb 2018 15:19:51 -0500 Subject: [PATCH 18/52] Update upload disaggregation button --- src/components/Utilities/index.js | 5 ++ .../UtilityLine/UtilityDisaggregation.js | 63 +++++++++++++++++-- src/components/UtilityLine/dataInteraction.js | 19 +----- 3 files changed, 66 insertions(+), 21 deletions(-) diff --git a/src/components/Utilities/index.js b/src/components/Utilities/index.js index 63992d35..136ee234 100644 --- a/src/components/Utilities/index.js +++ b/src/components/Utilities/index.js @@ -285,6 +285,11 @@ class Utilities extends Component { heating: val.heating_usage, cooling: val.cooling_usage, other: val.other_usage, + dhw: val.dhw, + cooking: val.cooking, + lighting: val.lighting, + plug_load: val.plug_load, + miscellaneous: val.miscellaneous, })); return disaggregateData; } diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 8d17a5b3..00cca31b 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -2,11 +2,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Icon } from 'react-fa'; import { Table } from 'reactstrap'; -import { generateBillDownload } from './dataInteraction'; import DisaggregationForm from './DisaggregationForm'; import Fade from '../Fade'; import request from '../../utils/request'; import { getHeaders, disaggregateMetaURL } from '../../utils/restServices'; +import { getDateDiff } from './dataInteraction'; class UtilityDisaggregation extends Component { @@ -29,6 +29,21 @@ class UtilityDisaggregation extends Component { }); } + disaggregateDataMapping = { + 'Bill From Date': 'bill_from_date', + 'Bill To Date': 'bill_to_date', + 'Days In Bill': 'days_in_bill', + Usage: 'usage', + 'Heating Usage': 'heating', + 'Cooling Usage': 'cooling', + 'Other Usage': 'other', + DHW: 'dhw', + Lighting: 'lighting', + Cooking: 'cooking', + 'Plug Load': 'plug_load', + Miscellaneous: 'miscellaneous', + } + addNewEndUsage = (disaggregationForm) => { this.setState({ endUsages: [ @@ -66,6 +81,46 @@ class UtilityDisaggregation extends Component { }); } + generateBillDownload = (data) => { + if (data.length === 0) { + return null; + } + + // headings + let csvString = Object.keys(this.disaggregateDataMapping).join(','); + + csvString += '\n'; + csvString += data.reduce((acc, val) => { + let line = ''; + const daysInBill = getDateDiff(val.bill_from_date, val.bill_to_date); + + Object.values(this.disaggregateDataMapping).map(columnName => { + if (columnName === 'usage') { + line += `${val.heating + val.cooling + val.other},`; + return val.heating + val.cooling + val.other; + + } else if (columnName === 'days_in_bill') { + line += `${daysInBill},`; + return daysInBill; + } + + line += `${val[columnName]},`; + return val[columnName]; + }); + + // Remove whitespace created by the template formatting + line = line.replace(' ', ''); + return `${acc}${line}\n`; + }, ''); + + const mimeType = 'text/csv;encoding:utf-8'; + const href = URL.createObjectURL(new Blob([csvString], { + type: mimeType, + })); + + return href; + }; + renderDownloadBtn = () => { const { disaggregateData } = this.props; @@ -84,7 +139,7 @@ class UtilityDisaggregation extends Component { className="btn m-1" style={{ disaggregateVisibility }} download={`${this.props.street_address}_${this.props.utility_type}_disaggregated_utility_bill.csv`} - href={generateBillDownload(disaggregateData)} + href={this.generateBillDownload(disaggregateData)} onClick={() => { this.props.handleBillGAEvent('Download Disaggregated Bill'); }} > @@ -115,8 +170,8 @@ class UtilityDisaggregation extends Component { - - + + diff --git a/src/components/UtilityLine/dataInteraction.js b/src/components/UtilityLine/dataInteraction.js index e73728e3..10bba30c 100644 --- a/src/components/UtilityLine/dataInteraction.js +++ b/src/components/UtilityLine/dataInteraction.js @@ -4,7 +4,7 @@ import React from 'react'; * */ -const getDateDiff = (date1String, date2String) => { +export const getDateDiff = (date1String, date2String) => { const d1 = new Date(date1String); const d2 = new Date(date2String); const timeDiff = Math.abs(d2.getTime() - d1.getTime()); @@ -33,13 +33,6 @@ export const generateBillDownload = (data) => { 'ESCO Charge,' + 'Total Charge,' + ''; - } else { - // Disaggregated Bill - csvString += '' + - 'Heating Usage,' + - 'Cooling Usage,' + - 'Other Usage,' + - ''; } csvString += '\n'; @@ -57,16 +50,8 @@ export const generateBillDownload = (data) => { line += `${val.supply_charge},`; line += `${val.esco_charge},`; line += `${val.total_charge_bill},`; - } else { - const totalUsage = ( - val.heating + val.cooling + val.other - ); - // Disaggregated Bill - line += `${totalUsage},`; - line += `${val.heating},`; - line += `${val.cooling},`; - line += `${val.other},`; } + // Remove whitespace created by the template formatting line = line.replace(' ', ''); return `${acc}${line}\n`; -- GitLab From b214d0789eaed59e71f0d98be7796f934afa0e4d Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 12 Feb 2018 15:26:24 -0500 Subject: [PATCH 19/52] Remove else statement --- src/components/Utilities/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/Utilities/index.js b/src/components/Utilities/index.js index 136ee234..65665212 100644 --- a/src/components/Utilities/index.js +++ b/src/components/Utilities/index.js @@ -86,8 +86,6 @@ class Utilities extends Component { if (res.err) { this.setState({ error: res.err }); reject(); - } else { - console.log('success post', res); } setTimeout(() => { -- GitLab From 2748c2ef66fa5e062e63f0bedb85615b0b0ea4a9 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 12 Feb 2018 17:41:37 -0500 Subject: [PATCH 20/52] Make mapping static variable --- .../UtilityLine/UtilityDisaggregation.js | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 00cca31b..377435a4 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -10,6 +10,21 @@ import { getDateDiff } from './dataInteraction'; class UtilityDisaggregation extends Component { + static disaggregateDataMapping = { + 'Bill From Date': 'bill_from_date', + 'Bill To Date': 'bill_to_date', + 'Days In Bill': 'days_in_bill', + Usage: 'usage', + 'Heating Usage': 'heating', + 'Cooling Usage': 'cooling', + 'Other Usage': 'other', + DHW: 'dhw', + Lighting: 'lighting', + Cooking: 'cooking', + 'Plug Load': 'plug_load', + Miscellaneous: 'miscellaneous', + } + state = { endUsages: [], } @@ -29,21 +44,6 @@ class UtilityDisaggregation extends Component { }); } - disaggregateDataMapping = { - 'Bill From Date': 'bill_from_date', - 'Bill To Date': 'bill_to_date', - 'Days In Bill': 'days_in_bill', - Usage: 'usage', - 'Heating Usage': 'heating', - 'Cooling Usage': 'cooling', - 'Other Usage': 'other', - DHW: 'dhw', - Lighting: 'lighting', - Cooking: 'cooking', - 'Plug Load': 'plug_load', - Miscellaneous: 'miscellaneous', - } - addNewEndUsage = (disaggregationForm) => { this.setState({ endUsages: [ @@ -82,19 +82,19 @@ class UtilityDisaggregation extends Component { } generateBillDownload = (data) => { - if (data.length === 0) { + if (data == null || data.length === 0) { return null; } // headings - let csvString = Object.keys(this.disaggregateDataMapping).join(','); + let csvString = Object.keys(UtilityDisaggregation.disaggregateDataMapping).join(','); csvString += '\n'; csvString += data.reduce((acc, val) => { let line = ''; const daysInBill = getDateDiff(val.bill_from_date, val.bill_to_date); - Object.values(this.disaggregateDataMapping).map(columnName => { + Object.values(UtilityDisaggregation.disaggregateDataMapping).map(columnName => { if (columnName === 'usage') { line += `${val.heating + val.cooling + val.other},`; return val.heating + val.cooling + val.other; -- GitLab From 4edcbd6966436d72ff71d00233e12cf5d478bf36 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 12 Feb 2018 18:30:15 -0500 Subject: [PATCH 21/52] Remove percentage checkbox --- src/components/UtilityLine/DisaggregationForm.js | 12 ------------ src/components/UtilityLine/UtilityDisaggregation.js | 3 +-- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 787410d8..382bd490 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -77,16 +77,6 @@ class DisaggregationForm extends Component { /> - - - - + -- GitLab From ce53a846b8d9b72161295fc5f2dede32a6e59943 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 12 Feb 2018 18:53:34 -0500 Subject: [PATCH 22/52] Fix delete method when item has not been saved yet --- src/components/UtilityLine/UtilityDisaggregation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index bf30f93c..9e4272da 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -62,7 +62,7 @@ class UtilityDisaggregation extends Component { return; } - if (toBeDeleted.id !== null) { + if (toBeDeleted.id != null) { request(`${disaggregateMetaURL}${toBeDeleted.pop().id}`, { method: 'DELETE', headers: getHeaders(), -- GitLab From 28a4c72d5c6f7fa2fc516d9fa97e6bded39e204f Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 12 Feb 2018 19:15:41 -0500 Subject: [PATCH 23/52] Add edit mode to non weather related usage --- .../UtilityLine/UtilityDisaggregation.js | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 9e4272da..e4cd3546 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -27,6 +27,7 @@ class UtilityDisaggregation extends Component { state = { endUsages: [], + editMode: false, } componentDidMount() { @@ -44,6 +45,10 @@ class UtilityDisaggregation extends Component { }); } + calculateTotalEndUsage = () => { + return this.state.endUsages.reduce((acc, i) => acc + i.value, 0); + } + addNewEndUsage = (disaggregationForm) => { this.setState({ endUsages: [ @@ -172,18 +177,38 @@ class UtilityDisaggregation extends Component { - - {this.state.endUsages.map((disaggregationForm, index) => ( - this.deleteEndUsage(index)} - showDelete - /> - ))} + {this.state.endUsages.map((disaggregationForm, index) => { + return this.state.editMode ? + this.deleteEndUsage(index)} + showDelete + /> : + + + + ; + })} + + + + + -- GitLab From f865c2e3443af4ca6c0e41bbcfe8c457581e3908 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Mon, 12 Feb 2018 19:48:15 -0500 Subject: [PATCH 24/52] Add edit mode to UtilityDisaggregation component --- .../UtilityLine/DisaggregationForm.js | 1 + .../UtilityLine/UtilityDisaggregation.js | 82 ++++++++++++------- src/components/UtilityLine/styles.css | 9 ++ 3 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 382bd490..494f0101 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -72,6 +72,7 @@ class DisaggregationForm extends Component { this.handleInputChange(e)} value={this.state.form.value} /> diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index e4cd3546..a390c061 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -7,6 +7,7 @@ import Fade from '../Fade'; import request from '../../utils/request'; import { getHeaders, disaggregateMetaURL } from '../../utils/restServices'; import { getDateDiff } from './dataInteraction'; +import './styles.css'; class UtilityDisaggregation extends Component { @@ -45,8 +46,17 @@ class UtilityDisaggregation extends Component { }); } + toggleEditMode = (event) => { + if (this.state.editMode) { + this.props.handleDisaggregateUtilityBill(event, this.state.endUsages); + } + + this.setState({ editMode: !this.state.editMode }); + } + calculateTotalEndUsage = () => { - return this.state.endUsages.reduce((acc, i) => acc + i.value, 0); + const total = this.state.endUsages.reduce((acc, i) => acc + i.value, 0); + return { total, overLimit: total > 100 }; } addNewEndUsage = (disaggregationForm) => { @@ -126,6 +136,10 @@ class UtilityDisaggregation extends Component { return href; }; + disableBtns = () => { + return this.props.disableDisaggregateBtn() || this.props.savingDisaggregateMeta; + } + renderDownloadBtn = () => { const { disaggregateData } = this.props; @@ -158,6 +172,7 @@ class UtilityDisaggregation extends Component { }} > {this.props.rSquared && this.props.rSquared.toFixed(3).replace(/^0+/, '')} + {' '} @@ -175,15 +190,15 @@ class UtilityDisaggregation extends Component {
End UsageValueEnd UsageValue %
- this.handleInputChange(e)} - style={{ marginLeft: 0 }} - type="checkbox" - checked={this.state.form.is_percentage} - /> - {!this.props.showDelete ?
End UsageValue%Percentage
End Usage Percentage + + +
{disaggregationForm.usage_type_id}{disaggregationForm.value} +
Total{this.calculateTotalEndUsage()} +
- - + + @@ -203,35 +218,37 @@ class UtilityDisaggregation extends Component { ; })} + + {this.state.editMode && + + } + - + {/* eslint-disable no-use-before-define */} + - -
End UsagePercentageEnd UsagePercentage
Total{this.calculateTotalEndUsage()} + {this.calculateTotalEndUsage().total} +
-
- +
+ + Saving + + + Disaggregating + +
+ +
{this.renderDownloadBtn()} -
- - Saving - - - Disaggregating - -
{this.props.renderUploadButton('Disaggregated Bill')}
@@ -239,6 +256,15 @@ class UtilityDisaggregation extends Component { } } +const styles = { + redText: { + color: 'red', + textAlign: 'right', + }, + alignRight: { + textAlign: 'right', + }, +}; UtilityDisaggregation.propTypes = { street_address: PropTypes.string, diff --git a/src/components/UtilityLine/styles.css b/src/components/UtilityLine/styles.css index 40c1fc1f..ed697fb5 100644 --- a/src/components/UtilityLine/styles.css +++ b/src/components/UtilityLine/styles.css @@ -1,3 +1,12 @@ .add { margin-bottom: 0 !important; } + +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; +} + +input[type=number] { + -moz-appearance: textfield; +} -- GitLab From 38252af1c01036ef46c5bed7d00d937465c36fb8 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 13 Feb 2018 09:29:37 -0500 Subject: [PATCH 25/52] Display usage types --- src/components/UtilityLine/UtilityDisaggregation.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index a390c061..0515fdf4 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -26,6 +26,13 @@ class UtilityDisaggregation extends Component { Miscellaneous: 'miscellaneous', } + static usageTypes = { + 5: 'DHW', + 6: 'Lighting', + 7: 'Cooking', + 8: 'Plug load', + } + state = { endUsages: [], editMode: false, @@ -213,7 +220,7 @@ class UtilityDisaggregation extends Component { showDelete /> : - {disaggregationForm.usage_type_id} + {UtilityDisaggregation.usageTypes[disaggregationForm.usage_type_id]} {disaggregationForm.value} ; -- GitLab From d41d36e9dd97ca909ae6508d39803f31953f7f7f Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 13 Feb 2018 10:17:41 -0500 Subject: [PATCH 26/52] Rename Total to Miscellaneous --- src/components/UtilityLine/UtilityDisaggregation.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 0515fdf4..95bce5e4 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -221,7 +221,7 @@ class UtilityDisaggregation extends Component { /> : {UtilityDisaggregation.usageTypes[disaggregationForm.usage_type_id]} - {disaggregationForm.value} + {disaggregationForm.value} % ; })} @@ -233,12 +233,12 @@ class UtilityDisaggregation extends Component { } - Total + Miscellaneous {/* eslint-disable no-use-before-define */} - {this.calculateTotalEndUsage().total} + {100 - this.calculateTotalEndUsage().total} % -- GitLab From 814211a87f32637d1da6eceedc96184e2ef56efb Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 13 Feb 2018 14:35:38 -0500 Subject: [PATCH 27/52] Hide usages already selected --- src/components/UtilityLine/DisaggregationForm.js | 11 ++++++++++- src/components/UtilityLine/UtilityDisaggregation.js | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 494f0101..a9cb0676 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -62,7 +62,15 @@ class DisaggregationForm extends Component { onChange={e => this.handleInputChange(e)} value={this.state.form.usage_type_id} > - {Object.keys(this.usageTypes).map((key) => ( + {this.props.showDelete && + + } + {Object.keys(this.props.availableUsageTypes).map((key) => ( ) )} @@ -104,6 +112,7 @@ DisaggregationForm.propTypes = { value: PropTypes.number, }), showDelete: PropTypes.bool, + availableUsageTypes: PropTypes.object, // eslint-disable-line }; DisaggregationForm.defaultProps = { diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 95bce5e4..1c640c03 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -103,6 +103,16 @@ class UtilityDisaggregation extends Component { }); } + availableUsageTypes = () => { + const usageTypeAvailable = { ...UtilityDisaggregation.usageTypes }; + + this.state.endUsages.forEach(i => ( + delete usageTypeAvailable[i.usage_type_id] + )); + + return usageTypeAvailable; + } + generateBillDownload = (data) => { if (data == null || data.length === 0) { return null; @@ -217,6 +227,7 @@ class UtilityDisaggregation extends Component { key={index} form={disaggregationForm} deleteEndUsage={() => this.deleteEndUsage(index)} + availableUsageTypes={this.availableUsageTypes()} showDelete /> : @@ -229,6 +240,7 @@ class UtilityDisaggregation extends Component { {this.state.editMode && } -- GitLab From e5583cfa0866624a05ec0ef1258d52811212eb11 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 13 Feb 2018 14:39:53 -0500 Subject: [PATCH 28/52] Hide adding form if there are no more available usages types --- src/components/UtilityLine/UtilityDisaggregation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 1c640c03..e59575e7 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -237,7 +237,7 @@ class UtilityDisaggregation extends Component { ; })} - {this.state.editMode && + {this.state.editMode && Object.keys(this.availableUsageTypes()).length > 0 && Date: Tue, 13 Feb 2018 15:28:34 -0500 Subject: [PATCH 29/52] Fix delete method --- src/components/UtilityLine/UtilityDisaggregation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index e59575e7..cbc342e6 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -77,7 +77,7 @@ class UtilityDisaggregation extends Component { deleteEndUsage = (index) => { const endUsageCopy = [...this.state.endUsages]; - const toBeDeleted = endUsageCopy.splice(index, 1); + const toBeDeleted = endUsageCopy.splice(index, 1).pop(); const confirmAns = confirm('Are you sure you want to delete this? This action cannot be undone.'); if (!confirmAns) { @@ -85,7 +85,7 @@ class UtilityDisaggregation extends Component { } if (toBeDeleted.id != null) { - request(`${disaggregateMetaURL}${toBeDeleted.pop().id}`, { + request(`${disaggregateMetaURL}${toBeDeleted.id}`, { method: 'DELETE', headers: getHeaders(), }).then((res) => { -- GitLab From bb62693aad0f02fb546dc0dddf68a74433e1a01d Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 13 Feb 2018 15:29:17 -0500 Subject: [PATCH 30/52] Update form method --- .../UtilityLine/DisaggregationForm.js | 24 ++++++++++++++----- .../UtilityLine/UtilityDisaggregation.js | 13 ++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index a9cb0676..f185b8b9 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -15,7 +15,11 @@ class DisaggregationForm extends Component { } componentWillReceiveProps(nextProps) { - console.log('component will receive props ', nextProps.form); + Object.keys(this.props.form).forEach(key => { + if (this.props.form[key] !== nextProps.form[key]) { + this.setState({ form: { ...nextProps.form } }); + } + }); } usageTypes = { @@ -44,12 +48,19 @@ class DisaggregationForm extends Component { val = target.value; } - this.setState({ - form: { - ...this.state.form, + if (this.props.showDelete) { + this.props.updateEndUsage({ + ...this.props.form, [name]: val, - }, - }); + }); + } else { + this.setState({ + form: { + ...this.state.form, + [name]: val, + }, + }); + } } render() { @@ -106,6 +117,7 @@ class DisaggregationForm extends Component { DisaggregationForm.propTypes = { addEndUsage: PropTypes.func, + updateEndUsage: PropTypes.func, deleteEndUsage: PropTypes.func, form: PropTypes.shape({ usage_type_id: PropTypes.number, diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index cbc342e6..27f4f8b3 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -75,6 +75,18 @@ class UtilityDisaggregation extends Component { }); } + updateEndUsage = (form) => { + const updatedEndUsage = this.state.endUsages.map(endUsage => { + if (endUsage.id === form.id) { + return form; + } + + return endUsage; + }); + + this.setState({ endUsages: updatedEndUsage }); + } + deleteEndUsage = (index) => { const endUsageCopy = [...this.state.endUsages]; const toBeDeleted = endUsageCopy.splice(index, 1).pop(); @@ -226,6 +238,7 @@ class UtilityDisaggregation extends Component { this.updateEndUsage(form)} deleteEndUsage={() => this.deleteEndUsage(index)} availableUsageTypes={this.availableUsageTypes()} showDelete -- GitLab From 7544bf9495da6f80a53f645fb4708eff11e79151 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 13 Feb 2018 15:33:39 -0500 Subject: [PATCH 31/52] Make variable static --- .../UtilityLine/DisaggregationForm.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index f185b8b9..19597ddb 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -5,6 +5,13 @@ import PropTypes from 'prop-types'; class DisaggregationForm extends Component { + static usageTypes = { + 5: 'DHW', + 6: 'Lighting', + 7: 'Cooking', + 8: 'Plug load', + } + constructor(props) { super(props); if (this.props.form) { @@ -22,13 +29,6 @@ class DisaggregationForm extends Component { }); } - usageTypes = { - 5: 'DHW', - 6: 'Lighting', - 7: 'Cooking', - 8: 'Plug load', - } - handleInputChange = (event) => { const target = event.target; const name = target.name; @@ -78,11 +78,11 @@ class DisaggregationForm extends Component { key={this.state.form.usage_type_id} value={this.state.form.usage_type_id} > - {this.usageTypes[this.state.form.usage_type_id]} + {DisaggregationForm.usageTypes[this.state.form.usage_type_id]} } {Object.keys(this.props.availableUsageTypes).map((key) => ( - ) + ) )} -- GitLab From 6a9c87cbf61af7ed09b3823a8eaa8850c0e03f43 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 13 Feb 2018 15:49:43 -0500 Subject: [PATCH 32/52] Fix adding new form --- src/components/UtilityLine/DisaggregationForm.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 19597ddb..e293b915 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -14,7 +14,15 @@ class DisaggregationForm extends Component { constructor(props) { super(props); - if (this.props.form) { + + if (this.props.form.usage_type_id == null) { + this.state = { + form: { + ...this.props.form, + usage_type_id: Object.keys(this.props.availableUsageTypes).pop(), + }, + }; + } else if (this.props.form) { this.state = { form: { ...this.props.form }, }; @@ -54,6 +62,7 @@ class DisaggregationForm extends Component { [name]: val, }); } else { + console.log('inside form ', { ...this.state.form, [name]: val }); this.setState({ form: { ...this.state.form, @@ -131,7 +140,7 @@ DisaggregationForm.defaultProps = { showDelete: false, form: { id: null, - usage_type_id: 5, + usage_type_id: null, value: 0, }, }; -- GitLab From 0edc8276051f7a0d851ca96679804a983e705d40 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 08:27:55 -0500 Subject: [PATCH 33/52] Move state out of DisaggregationForm --- .../UtilityLine/DisaggregationForm.js | 91 ++----------- .../UtilityLine/UtilityDisaggregation.js | 123 ++++++++++++++---- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index e293b915..1ad8b4a9 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -12,66 +12,6 @@ class DisaggregationForm extends Component { 8: 'Plug load', } - constructor(props) { - super(props); - - if (this.props.form.usage_type_id == null) { - this.state = { - form: { - ...this.props.form, - usage_type_id: Object.keys(this.props.availableUsageTypes).pop(), - }, - }; - } else if (this.props.form) { - this.state = { - form: { ...this.props.form }, - }; - } - } - - componentWillReceiveProps(nextProps) { - Object.keys(this.props.form).forEach(key => { - if (this.props.form[key] !== nextProps.form[key]) { - this.setState({ form: { ...nextProps.form } }); - } - }); - } - - handleInputChange = (event) => { - const target = event.target; - const name = target.name; - let val = null; - - switch (target.type) { - case 'checkbox': - val = target.checked; - break; - - case 'number': - case 'select-one': - val = Number(target.value); - break; - - default: - val = target.value; - } - - if (this.props.showDelete) { - this.props.updateEndUsage({ - ...this.props.form, - [name]: val, - }); - } else { - console.log('inside form ', { ...this.state.form, [name]: val }); - this.setState({ - form: { - ...this.state.form, - [name]: val, - }, - }); - } - } - render() { return ( @@ -79,15 +19,15 @@ class DisaggregationForm extends Component { this.handleInputChange(e)} - value={this.state.form.usage_type_id} + onChange={e => this.props.handleInputChange(e)} + value={this.props.form.usage_type_id} > {this.props.showDelete && } {Object.keys(this.props.availableUsageTypes).map((key) => ( @@ -101,21 +41,14 @@ class DisaggregationForm extends Component { name="value" type="number" style={{ textAlign: 'right' }} - onChange={e => this.handleInputChange(e)} - value={this.state.form.value} + onChange={e => this.props.handleInputChange(e)} + value={this.props.form.value} /> {!this.props.showDelete ? - { - this.props.addEndUsage(this.state.form); - // Clear form after selecting plus icon - this.setState({ form: { ...this.props.form } }); - }} - /> : + this.props.addEndUsage()} /> : this.props.deleteEndUsage()} /> } @@ -126,9 +59,10 @@ class DisaggregationForm extends Component { DisaggregationForm.propTypes = { addEndUsage: PropTypes.func, - updateEndUsage: PropTypes.func, deleteEndUsage: PropTypes.func, + handleInputChange: PropTypes.func, form: PropTypes.shape({ + id: PropTypes.number, usage_type_id: PropTypes.number, value: PropTypes.number, }), @@ -138,11 +72,6 @@ DisaggregationForm.propTypes = { DisaggregationForm.defaultProps = { showDelete: false, - form: { - id: null, - usage_type_id: null, - value: 0, - }, }; export default DisaggregationForm; diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 27f4f8b3..320f6773 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -33,9 +33,15 @@ class UtilityDisaggregation extends Component { 8: 'Plug load', } - state = { - endUsages: [], - editMode: false, + constructor(props) { + super(props); + + this.state = { + availableUsageTypes: { ...UtilityDisaggregation.usageTypes }, + endUsages: [], + editMode: false, + pendingEndUsage: this.resetPendingEndUsage({ ...UtilityDisaggregation.usageTypes }), + }; } componentDidMount() { @@ -48,7 +54,10 @@ class UtilityDisaggregation extends Component { headers: getHeaders(), }).then((res) => { if (!res.err) { - this.setState({ endUsages: res.data }); + this.setState({ + endUsages: res.data, + availableUsageTypes: this.updateAvailableUsageTypes(res.data), + }); } }); } @@ -61,28 +70,54 @@ class UtilityDisaggregation extends Component { this.setState({ editMode: !this.state.editMode }); } + resetPendingEndUsage = (availableUsageTypes) => { + return { + id: null, + usage_type_id: Number(Object.keys(availableUsageTypes)[0]), + value: 0, + }; + } + calculateTotalEndUsage = () => { const total = this.state.endUsages.reduce((acc, i) => acc + i.value, 0); return { total, overLimit: total > 100 }; } - addNewEndUsage = (disaggregationForm) => { + addNewEndUsage = () => { + const updateEndUsages = [ + ...this.state.endUsages, + this.state.pendingEndUsage, + ]; + + const updateUsageTypes = this.updateAvailableUsageTypes(updateEndUsages); + this.setState({ - endUsages: [ - ...this.state.endUsages, - disaggregationForm, - ], + endUsages: updateEndUsages, + availableUsageTypes: updateUsageTypes, + pendingEndUsage: this.resetPendingEndUsage(updateUsageTypes), }); } updateEndUsage = (form) => { - const updatedEndUsage = this.state.endUsages.map(endUsage => { - if (endUsage.id === form.id) { - return form; - } + let updatedEndUsage = []; - return endUsage; - }); + if (form.id == null) { + updatedEndUsage = this.state.endUsages.map(endUsage => { + if (endUsage.usage_type_id === form.usage_type_id) { + return form; + } + + return endUsage; + }); + } else { + updatedEndUsage = this.state.endUsages.map(endUsage => { + if (endUsage.id === form.id) { + return form; + } + + return endUsage; + }); + } this.setState({ endUsages: updatedEndUsage }); } @@ -115,14 +150,48 @@ class UtilityDisaggregation extends Component { }); } - availableUsageTypes = () => { - const usageTypeAvailable = { ...UtilityDisaggregation.usageTypes }; + updateAvailableUsageTypes = (endUsages) => { + const newUsageTypeAvailable = { ...this.state.availableUsageTypes }; - this.state.endUsages.forEach(i => ( - delete usageTypeAvailable[i.usage_type_id] + endUsages.forEach(i => ( + delete newUsageTypeAvailable[i.usage_type_id] )); - return usageTypeAvailable; + return newUsageTypeAvailable; + } + + handleInputChange = (event, newEndUsageForm = false) => { + const target = event.target; + const name = target.name; + let val = null; + + switch (target.type) { + case 'checkbox': + val = target.checked; + break; + + case 'number': + case 'select-one': + val = Number(target.value); + break; + + default: + val = target.value; + } + + if (!newEndUsageForm) { + this.updateEndUsage({ + ...this.state.form, + [name]: val, + }); + } else { + this.setState({ + pendingEndUsage: { + ...this.state.pendingEndUsage, + [name]: val, + }, + }); + } } generateBillDownload = (data) => { @@ -236,11 +305,11 @@ class UtilityDisaggregation extends Component { {this.state.endUsages.map((disaggregationForm, index) => { return this.state.editMode ? this.updateEndUsage(form)} + availableUsageTypes={this.state.availableUsageTypes} deleteEndUsage={() => this.deleteEndUsage(index)} - availableUsageTypes={this.availableUsageTypes()} + form={disaggregationForm} + key={index} + handleInputChange={this.handleInputChange} showDelete /> : @@ -250,10 +319,12 @@ class UtilityDisaggregation extends Component { ; })} - {this.state.editMode && Object.keys(this.availableUsageTypes()).length > 0 && + {this.state.editMode && Object.keys(this.state.availableUsageTypes).length > 0 && this.handleInputChange(event, true)} /> } -- GitLab From ccfbc2e5129b2b6f86aa1bd4c1ad6a6605a1cbf2 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 08:43:06 -0500 Subject: [PATCH 34/52] Fix update end usage --- .../UtilityLine/UtilityDisaggregation.js | 40 ++++--------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 320f6773..d877db20 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -98,30 +98,6 @@ class UtilityDisaggregation extends Component { }); } - updateEndUsage = (form) => { - let updatedEndUsage = []; - - if (form.id == null) { - updatedEndUsage = this.state.endUsages.map(endUsage => { - if (endUsage.usage_type_id === form.usage_type_id) { - return form; - } - - return endUsage; - }); - } else { - updatedEndUsage = this.state.endUsages.map(endUsage => { - if (endUsage.id === form.id) { - return form; - } - - return endUsage; - }); - } - - this.setState({ endUsages: updatedEndUsage }); - } - deleteEndUsage = (index) => { const endUsageCopy = [...this.state.endUsages]; const toBeDeleted = endUsageCopy.splice(index, 1).pop(); @@ -160,7 +136,7 @@ class UtilityDisaggregation extends Component { return newUsageTypeAvailable; } - handleInputChange = (event, newEndUsageForm = false) => { + handleInputChange = (event, index = null) => { const target = event.target; const name = target.name; let val = null; @@ -179,11 +155,11 @@ class UtilityDisaggregation extends Component { val = target.value; } - if (!newEndUsageForm) { - this.updateEndUsage({ - ...this.state.form, - [name]: val, - }); + if (index != null) { + const updatedEndUsage = [...this.state.endUsages]; + updatedEndUsage[index][name] = val; + this.setState({ endUsages: updatedEndUsage }); + } else { this.setState({ pendingEndUsage: { @@ -309,7 +285,7 @@ class UtilityDisaggregation extends Component { deleteEndUsage={() => this.deleteEndUsage(index)} form={disaggregationForm} key={index} - handleInputChange={this.handleInputChange} + handleInputChange={(form) => this.handleInputChange(form, index)} showDelete /> : @@ -324,7 +300,7 @@ class UtilityDisaggregation extends Component { addEndUsage={this.addNewEndUsage} availableUsageTypes={this.state.availableUsageTypes} form={this.state.pendingEndUsage} - handleInputChange={(event) => this.handleInputChange(event, true)} + handleInputChange={(event) => this.handleInputChange(event)} /> } -- GitLab From f3539d956df3561def25302c43766b721b0ffd32 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 08:52:08 -0500 Subject: [PATCH 35/52] Update pendingEndUsage --- .../UtilityLine/UtilityDisaggregation.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index d877db20..f682d082 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -54,9 +54,12 @@ class UtilityDisaggregation extends Component { headers: getHeaders(), }).then((res) => { if (!res.err) { + const newAvailableUsageTypes = this.updateAvailableUsageTypes(res.data); + this.setState({ endUsages: res.data, - availableUsageTypes: this.updateAvailableUsageTypes(res.data), + availableUsageTypes: newAvailableUsageTypes, + pendingEndUsage: this.resetPendingEndUsage(newAvailableUsageTypes), }); } }); @@ -91,6 +94,9 @@ class UtilityDisaggregation extends Component { const updateUsageTypes = this.updateAvailableUsageTypes(updateEndUsages); + console.log('adding new usage, endusage updating to: ', updateEndUsages); + console.log('available usages are now', updateUsageTypes); + this.setState({ endUsages: updateEndUsages, availableUsageTypes: updateUsageTypes, @@ -133,6 +139,10 @@ class UtilityDisaggregation extends Component { delete newUsageTypeAvailable[i.usage_type_id] )); + console.log('inside updateAvailendUsage, all endusages', endUsages); + console.log('original available usage types', this.state.availableUsageTypes); + console.log('updated usage types', newUsageTypeAvailable); + return newUsageTypeAvailable; } @@ -258,6 +268,8 @@ class UtilityDisaggregation extends Component { return
; } + console.log('pending usage: ', this.state.pendingEndUsage); + return (

Non-weather related usage

-- GitLab From d8fe5e2d2710b3ba3679167750a61ce07e54abf7 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 08:55:45 -0500 Subject: [PATCH 36/52] Remove logs --- .../UtilityLine/UtilityDisaggregation.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index f682d082..35b6aa2b 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -54,7 +54,7 @@ class UtilityDisaggregation extends Component { headers: getHeaders(), }).then((res) => { if (!res.err) { - const newAvailableUsageTypes = this.updateAvailableUsageTypes(res.data); + const newAvailableUsageTypes = this.determineAvailableUsageTypesLeft(res.data); this.setState({ endUsages: res.data, @@ -92,10 +92,7 @@ class UtilityDisaggregation extends Component { this.state.pendingEndUsage, ]; - const updateUsageTypes = this.updateAvailableUsageTypes(updateEndUsages); - - console.log('adding new usage, endusage updating to: ', updateEndUsages); - console.log('available usages are now', updateUsageTypes); + const updateUsageTypes = this.determineAvailableUsageTypesLeft(updateEndUsages); this.setState({ endUsages: updateEndUsages, @@ -132,17 +129,13 @@ class UtilityDisaggregation extends Component { }); } - updateAvailableUsageTypes = (endUsages) => { + determineAvailableUsageTypesLeft = (endUsages) => { const newUsageTypeAvailable = { ...this.state.availableUsageTypes }; endUsages.forEach(i => ( delete newUsageTypeAvailable[i.usage_type_id] )); - console.log('inside updateAvailendUsage, all endusages', endUsages); - console.log('original available usage types', this.state.availableUsageTypes); - console.log('updated usage types', newUsageTypeAvailable); - return newUsageTypeAvailable; } @@ -268,8 +261,6 @@ class UtilityDisaggregation extends Component { return
; } - console.log('pending usage: ', this.state.pendingEndUsage); - return (

Non-weather related usage

-- GitLab From 692530d58837c80d4b6999c999d03322977ba972 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 09:01:08 -0500 Subject: [PATCH 37/52] Update calculatemiscendusage method --- .../UtilityLine/UtilityDisaggregation.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 35b6aa2b..2b4be7c5 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -81,9 +81,9 @@ class UtilityDisaggregation extends Component { }; } - calculateTotalEndUsage = () => { - const total = this.state.endUsages.reduce((acc, i) => acc + i.value, 0); - return { total, overLimit: total > 100 }; + calculateMiscEndUsage = () => { + const total = 100 - this.state.endUsages.reduce((acc, i) => acc + i.value, 0); + return { total, overLimit: total < 0 }; } addNewEndUsage = () => { @@ -214,7 +214,9 @@ class UtilityDisaggregation extends Component { }; disableBtns = () => { - return this.props.disableDisaggregateBtn() || this.props.savingDisaggregateMeta; + return this.props.disableDisaggregateBtn() || + this.props.savingDisaggregateMeta || + this.calculateMiscEndUsage().overLimit; } renderDownloadBtn = () => { @@ -311,9 +313,9 @@ class UtilityDisaggregation extends Component { Miscellaneous {/* eslint-disable no-use-before-define */} - {100 - this.calculateTotalEndUsage().total} % + {this.calculateMiscEndUsage().total} % -- GitLab From cd1c4937bbcbebf1d5baa8d14f377b6bcf7465c5 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 09:11:08 -0500 Subject: [PATCH 38/52] Update test for DisaggregationForm --- .../UtilityLine/DisaggregationForm.test.js | 34 ++--- .../DisaggregationForm.test.js.snap | 120 +----------------- 2 files changed, 17 insertions(+), 137 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.test.js b/src/components/UtilityLine/DisaggregationForm.test.js index 4be6b465..cfaaaedb 100644 --- a/src/components/UtilityLine/DisaggregationForm.test.js +++ b/src/components/UtilityLine/DisaggregationForm.test.js @@ -6,9 +6,8 @@ import { shallow } from 'enzyme'; import DisaggregationForm from './DisaggregationForm'; const form = { - usage_type_id: 6, + usage_type_id: 5, value: 99, - is_percentage: false, }; const SimpleTable = (props) => ( @@ -28,6 +27,9 @@ it('renders without crashing', () => { {}} deleteEndUsage={() => {}} + handleInputChange={() => {}} + form={form} + availableUsageTypes={{ 5: 'DHW' }} /> , div); @@ -38,42 +40,32 @@ test('DisaggregationForm renders form passed in', () => { {}} deleteEndUsage={() => {}} + handleInputChange={() => {}} form={form} + availableUsageTypes={{ 5: 'DHW' }} /> ); // Make sure state is initialized by props - const componentForm = shallowDisaggregationForm.state().form; - expect(componentForm.usage_type_id).toEqual(form.usage_type_id); - expect(componentForm.value).toEqual(form.value); - expect(componentForm.is_percentage).toEqual(form.is_percentage); + // const componentForm = shallowDisaggregationForm.state().form; + // expect(componentForm.usage_type_id).toEqual(form.usage_type_id); + // expect(componentForm.value).toEqual(form.value); + // expect(componentForm.is_percentage).toEqual(form.is_percentage); // Make sure form is rendered to DOM expect(shallowDisaggregationForm.find('[name="usage_type_id"]').props().value).toEqual(form.usage_type_id); expect(shallowDisaggregationForm.find('[name="value"]').props().value).toEqual(form.value); - expect(shallowDisaggregationForm.find('[name="is_percentage"]').props().checked).toEqual(form.is_percentage); -}); - -test('DisaggregationForm snapshot with default form', () => { - const component = renderer.create( - - {}} - deleteEndUsage={() => {}} - /> - , - ); - let tree = component.toJSON(); - expect(tree).toMatchSnapshot(); }); -test('DisaggregationForm snapshot passing in form', () => { +test('DisaggregationForm snapshot with form', () => { const component = renderer.create( {}} deleteEndUsage={() => {}} + handleInputChange={() => {}} form={form} + availableUsageTypes={{ 5: 'DHW' }} /> , ); diff --git a/src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap b/src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap index 20768cd6..4245836d 100644 --- a/src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap +++ b/src/components/UtilityLine/__snapshots__/DisaggregationForm.test.js.snap @@ -1,88 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`DisaggregationForm snapshot passing in form 1`] = ` - - - - - - - - - - -
- - - - - - - -
-`; - -exports[`DisaggregationForm snapshot with default form 1`] = ` +exports[`DisaggregationForm snapshot with form 1`] = ` @@ -101,21 +19,6 @@ exports[`DisaggregationForm snapshot with default form 1`] = ` > DHW - - - -
@@ -123,28 +26,13 @@ exports[`DisaggregationForm snapshot with default form 1`] = ` className="form-control" name="value" onChange={[Function]} - type="number" - value={0} - /> - - Date: Wed, 14 Feb 2018 09:43:08 -0500 Subject: [PATCH 39/52] Rename scrape to fetch --- src/components/UtilityLine/UtilityLine.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/UtilityLine/UtilityLine.js b/src/components/UtilityLine/UtilityLine.js index 421f948c..594e5d8b 100644 --- a/src/components/UtilityLine/UtilityLine.js +++ b/src/components/UtilityLine/UtilityLine.js @@ -734,9 +734,9 @@ class UtilityLine extends Component { ); let scrapeDaysString = ''; if (scrapeDaysElapsed > 0) { - scrapeDaysString = `Last scraped ${scrapeDaysElapsed} day${scrapeDaysElapsed > 1 ? 's' : ''} ago`; + scrapeDaysString = `Last fetched ${scrapeDaysElapsed} day${scrapeDaysElapsed > 1 ? 's' : ''} ago`; } else { - scrapeDaysString = 'Last scraped today'; + scrapeDaysString = 'Last fetched today'; } const color = scrapeDaysElapsed >= 30 ? 'red' : null; scrapeDays = ( -- GitLab From e771c17ae590bb8a87a5bc71f6435cd9be057dc5 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 09:59:15 -0500 Subject: [PATCH 40/52] Add disaggreaget button --- src/components/UtilityLine/UtilityDisaggregation.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 2b4be7c5..82420ba5 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -332,6 +332,13 @@ class UtilityDisaggregation extends Component {
+ {this.renderDownloadBtn()} {this.props.renderUploadButton('Disaggregated Bill')}
-- GitLab From 480bcabe6d1fdacee555935c8c2e4166f02d8ae6 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 10:09:31 -0500 Subject: [PATCH 41/52] Disable quote props --- src/components/UtilityLine/UtilityDisaggregation.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 82420ba5..6a5b5758 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -11,19 +11,20 @@ import './styles.css'; class UtilityDisaggregation extends Component { + /* eslint-disable quote-props */ static disaggregateDataMapping = { 'Bill From Date': 'bill_from_date', 'Bill To Date': 'bill_to_date', 'Days In Bill': 'days_in_bill', - Usage: 'usage', + 'Usage': 'usage', 'Heating Usage': 'heating', 'Cooling Usage': 'cooling', 'Other Usage': 'other', - DHW: 'dhw', - Lighting: 'lighting', - Cooking: 'cooking', + 'DHW': 'dhw', + 'Lighting': 'lighting', + 'Cooking': 'cooking', 'Plug Load': 'plug_load', - Miscellaneous: 'miscellaneous', + 'Miscellaneous': 'miscellaneous', } static usageTypes = { -- GitLab From 2db3b5248da94693247470829de3040b7587bd52 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 10:10:25 -0500 Subject: [PATCH 42/52] Enable quote props --- src/components/UtilityLine/UtilityDisaggregation.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 6a5b5758..75bfc6b8 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -26,6 +26,7 @@ class UtilityDisaggregation extends Component { 'Plug Load': 'plug_load', 'Miscellaneous': 'miscellaneous', } + /* eslint-enable quote-props */ static usageTypes = { 5: 'DHW', -- GitLab From 2e20497efb25881cde14d7aeca99a871edb4c522 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 14:04:59 -0500 Subject: [PATCH 43/52] Add bulk to endpoint --- src/components/Utilities/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Utilities/index.js b/src/components/Utilities/index.js index 65665212..d9aaf8e9 100644 --- a/src/components/Utilities/index.js +++ b/src/components/Utilities/index.js @@ -75,7 +75,7 @@ class Utilities extends Component { saveDisaggregateMeta = (accountId, disaggregateMeta, updateSavingDisaggregateMeta) => { return new Promise((resolve, reject) => { - request(disaggregateMetaURL, { + request(`${disaggregateMetaURL}bulk/`, { method: 'PUT', headers: getHeaders(), body: JSON.stringify({ -- GitLab From 7184be2feeb46ac8aa00835f33e5299167353e7c Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 14:48:20 -0500 Subject: [PATCH 44/52] Move saveDisaggregatemeta out o f Utilities component --- src/components/Utilities/index.js | 30 ++----------------- .../UtilityLine/UtilityDisaggregation.js | 27 ++++++++++++++++- src/components/UtilityLine/UtilityLine.js | 3 +- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/components/Utilities/index.js b/src/components/Utilities/index.js index d9aaf8e9..11c909c1 100644 --- a/src/components/Utilities/index.js +++ b/src/components/Utilities/index.js @@ -5,7 +5,7 @@ import buildingDetailPropTypes from '../../containers/Building/propTypes'; import request from '../../utils/request'; import ErrorAlert from '../../components/ErrorAlert'; -import { getHeaders, scrapeURL, accountURL, disaggregateURL, disaggregateMetaURL } from '../../utils/restServices'; +import { getHeaders, scrapeURL, accountURL, disaggregateURL } from '../../utils/restServices'; import LinkBarDetail from '../../components/LinkBarDetail'; import UtilityLine from '../UtilityLine/UtilityLine'; import Loading from '../../components/Loading'; @@ -72,31 +72,6 @@ class Utilities extends Component { }); } - - saveDisaggregateMeta = (accountId, disaggregateMeta, updateSavingDisaggregateMeta) => { - return new Promise((resolve, reject) => { - request(`${disaggregateMetaURL}bulk/`, { - method: 'PUT', - headers: getHeaders(), - body: JSON.stringify({ - account_id: accountId, - disaggregateMeta, - }), - }).then(res => { - if (res.err) { - this.setState({ error: res.err }); - reject(); - } - - setTimeout(() => { - updateSavingDisaggregateMeta(false); - resolve(); - }, 1000); - }); - }); - } - - disaggregateUtilityBill = ( form, accountId, @@ -105,6 +80,7 @@ class Utilities extends Component { setRSquared, disaggregateMeta, updateSavingDisaggregateMeta, + saveDisaggregateMetaCallback, ) => { ReactGA.event({ category: 'Utilities', @@ -113,7 +89,7 @@ class Utilities extends Component { }); updateSavingDisaggregateMeta(true); - this.saveDisaggregateMeta( + saveDisaggregateMetaCallback( accountId, disaggregateMeta, updateSavingDisaggregateMeta ).then(() => { updateLoadingDisaggregateState(true); diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 75bfc6b8..17f4d89c 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -69,7 +69,9 @@ class UtilityDisaggregation extends Component { toggleEditMode = (event) => { if (this.state.editMode) { - this.props.handleDisaggregateUtilityBill(event, this.state.endUsages); + this.props.handleDisaggregateUtilityBill( + event, this.state.endUsages, this.saveDisaggregateMeta + ); } this.setState({ editMode: !this.state.editMode }); @@ -131,6 +133,29 @@ class UtilityDisaggregation extends Component { }); } + saveDisaggregateMeta = (accountId, disaggregateMeta, updateSavingDisaggregateMeta) => { + return new Promise((resolve, reject) => { + request(`${disaggregateMetaURL}bulk/`, { + method: 'PUT', + headers: getHeaders(), + body: JSON.stringify({ + account_id: accountId, + disaggregateMeta, + }), + }).then(res => { + if (res.err) { + this.setState({ error: res.err }); + reject(); + } + + setTimeout(() => { + updateSavingDisaggregateMeta(false); + resolve(); + }, 1000); + }); + }); + } + determineAvailableUsageTypesLeft = (endUsages) => { const newUsageTypeAvailable = { ...this.state.availableUsageTypes }; diff --git a/src/components/UtilityLine/UtilityLine.js b/src/components/UtilityLine/UtilityLine.js index 594e5d8b..82297655 100644 --- a/src/components/UtilityLine/UtilityLine.js +++ b/src/components/UtilityLine/UtilityLine.js @@ -138,7 +138,7 @@ class UtilityLine extends Component { ); } - handleDisaggregateUtilityBill = (event, disaggregateMeta) => { + handleDisaggregateUtilityBill = (event, disaggregateMeta, saveDisaggregateMetaCallback) => { event.preventDefault(); this.props.disaggregateUtilityBill( @@ -149,6 +149,7 @@ class UtilityLine extends Component { this.setRSquared, disaggregateMeta, this.updateSavingDisaggregateMeta, + saveDisaggregateMetaCallback ); } -- GitLab From 34b875f17763b08795d5fa8e77642f2be68e1556 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 15:19:32 -0500 Subject: [PATCH 45/52] Add deleted end usages to a list called to be deleted --- .../UtilityLine/DisaggregationForm.js | 1 + .../UtilityLine/UtilityDisaggregation.js | 23 ++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index 1ad8b4a9..dd586402 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -19,6 +19,7 @@ class DisaggregationForm extends Component { this.props.handleInputChange(e)} value={this.props.form.usage_type_id} > diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 17f4d89c..2115569a 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -39,8 +39,9 @@ class UtilityDisaggregation extends Component { super(props); this.state = { - availableUsageTypes: { ...UtilityDisaggregation.usageTypes }, + availableUsageTypes: this.determineAvailableUsageTypesLeft([]), endUsages: [], + endUsagesToDelete: [], editMode: false, pendingEndUsage: this.resetPendingEndUsage({ ...UtilityDisaggregation.usageTypes }), }; @@ -109,27 +110,23 @@ class UtilityDisaggregation extends Component { const endUsageCopy = [...this.state.endUsages]; const toBeDeleted = endUsageCopy.splice(index, 1).pop(); - const confirmAns = confirm('Are you sure you want to delete this? This action cannot be undone.'); + const confirmAns = confirm('Are you sure you want to delete this?'); if (!confirmAns) { return; } if (toBeDeleted.id != null) { - request(`${disaggregateMetaURL}${toBeDeleted.id}`, { - method: 'DELETE', - headers: getHeaders(), - }).then((res) => { - if (!res.err) { - this.setState({ - endUsages: endUsageCopy, - }); - } + this.setState({ + endUsagesToDelete: [...this.state.endUsagesToDelete, toBeDeleted], }); - return; } + const newAvailableUsageTypes = this.determineAvailableUsageTypesLeft(endUsageCopy); + this.setState({ endUsages: endUsageCopy, + availableUsageTypes: newAvailableUsageTypes, + pendingEndUsage: this.resetPendingEndUsage(newAvailableUsageTypes), }); } @@ -157,7 +154,7 @@ class UtilityDisaggregation extends Component { } determineAvailableUsageTypesLeft = (endUsages) => { - const newUsageTypeAvailable = { ...this.state.availableUsageTypes }; + const newUsageTypeAvailable = { ...UtilityDisaggregation.usageTypes }; endUsages.forEach(i => ( delete newUsageTypeAvailable[i.usage_type_id] -- GitLab From a337b1cba9975acb30f7e8c24d3d378a6a2ce4e4 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 16:09:56 -0500 Subject: [PATCH 46/52] Remove saveDisaggregation from parent component --- src/components/Utilities/index.js | 76 +++++++++---------- .../UtilityLine/UtilityDisaggregation.js | 67 +++++++++------- src/components/UtilityLine/UtilityLine.js | 15 +--- 3 files changed, 75 insertions(+), 83 deletions(-) diff --git a/src/components/Utilities/index.js b/src/components/Utilities/index.js index 11c909c1..06c0b18e 100644 --- a/src/components/Utilities/index.js +++ b/src/components/Utilities/index.js @@ -78,9 +78,6 @@ class Utilities extends Component { updateLoadingDisaggregateState, setDisaggregateData, setRSquared, - disaggregateMeta, - updateSavingDisaggregateMeta, - saveDisaggregateMetaCallback, ) => { ReactGA.event({ category: 'Utilities', @@ -88,48 +85,43 @@ class Utilities extends Component { label: `Utility: ${form.utility}, Account: ${form.account_number}`, }); - updateSavingDisaggregateMeta(true); - saveDisaggregateMetaCallback( - accountId, disaggregateMeta, updateSavingDisaggregateMeta - ).then(() => { - updateLoadingDisaggregateState(true); + updateLoadingDisaggregateState(true); - request(disaggregateURL, { - method: 'POST', - headers: getHeaders(), - body: JSON.stringify({ - ...form, - account_id: accountId, - building_id: this.props.buildingId, - }), - }).then((disaggregateRes) => { - if (disaggregateRes.err) { - ReactGA.event({ - category: 'Utilities', - action: 'Disaggregate Bill Error', - label: `Utility: ${form.utility}, - Account: ${form.account_number}, - Error: ${disaggregateRes.err}`, - }); - this.setState({ error: disaggregateRes.err }); - } else { - ReactGA.event({ - category: 'Utilities', - action: 'Disaggregate Bill Success', - label: `Utility: ${form.utility}, Account: ${form.account_number}`, - }); - const data = disaggregateRes.data; - const disaggregateData = this.parseDisaggregateData(data.disaggregate_database_output); - setDisaggregateData(disaggregateData); - setRSquared(data.r_squared); + request(disaggregateURL, { + method: 'POST', + headers: getHeaders(), + body: JSON.stringify({ + ...form, + account_id: accountId, + building_id: this.props.buildingId, + }), + }).then((disaggregateRes) => { + if (disaggregateRes.err) { + ReactGA.event({ + category: 'Utilities', + action: 'Disaggregate Bill Error', + label: `Utility: ${form.utility}, + Account: ${form.account_number}, + Error: ${disaggregateRes.err}`, + }); + this.setState({ error: disaggregateRes.err }); + } else { + ReactGA.event({ + category: 'Utilities', + action: 'Disaggregate Bill Success', + label: `Utility: ${form.utility}, Account: ${form.account_number}`, + }); + const data = disaggregateRes.data; + const disaggregateData = this.parseDisaggregateData(data.disaggregate_database_output); + setDisaggregateData(disaggregateData); + setRSquared(data.r_squared); - this.resetErrorMessage(); - } + this.resetErrorMessage(); + } - setTimeout(() => { - updateLoadingDisaggregateState(false); - }, 1000); - }); + setTimeout(() => { + updateLoadingDisaggregateState(false); + }, 1000); }); } diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 2115569a..74e8823c 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -43,6 +43,7 @@ class UtilityDisaggregation extends Component { endUsages: [], endUsagesToDelete: [], editMode: false, + savingDisaggregateMeta: false, pendingEndUsage: this.resetPendingEndUsage({ ...UtilityDisaggregation.usageTypes }), }; } @@ -68,11 +69,9 @@ class UtilityDisaggregation extends Component { }); } - toggleEditMode = (event) => { + toggleEditMode = () => { if (this.state.editMode) { - this.props.handleDisaggregateUtilityBill( - event, this.state.endUsages, this.saveDisaggregateMeta - ); + this.saveDisaggregateMeta(event); } this.setState({ editMode: !this.state.editMode }); @@ -130,26 +129,39 @@ class UtilityDisaggregation extends Component { }); } - saveDisaggregateMeta = (accountId, disaggregateMeta, updateSavingDisaggregateMeta) => { - return new Promise((resolve, reject) => { - request(`${disaggregateMetaURL}bulk/`, { - method: 'PUT', - headers: getHeaders(), - body: JSON.stringify({ - account_id: accountId, - disaggregateMeta, - }), - }).then(res => { - if (res.err) { - this.setState({ error: res.err }); - reject(); - } + saveDisaggregateMeta = () => { + this.setState({ savingDisaggregateMeta: true }); - setTimeout(() => { - updateSavingDisaggregateMeta(false); - resolve(); - }, 1000); - }); + const putDisaggregate = request(`${disaggregateMetaURL}bulk/`, { + method: 'PUT', + headers: getHeaders(), + body: JSON.stringify({ + account_id: this.props.accountId, + disaggregateMeta: this.state.endUsages, + }), + }); + + const deleteDisaggregate = request(`${disaggregateMetaURL}bulk/`, { + method: 'DELETE', + headers: getHeaders(), + body: JSON.stringify({ + ids: this.state.endUsagesToDelete.map(i => i.id), + }), + }); + + Promise.all([putDisaggregate, deleteDisaggregate]).then((values) => { + if (values[0].err) { + this.setState({ error: values[0].err }); + } + + if (values[1].err) { + this.setState({ error: values[1].err }); + } + + setTimeout(() => { + this.setState({ savingDisaggregateMeta: false }); + this.props.handleDisaggregateUtilityBill(); + }, 1000); }); } @@ -239,7 +251,7 @@ class UtilityDisaggregation extends Component { disableBtns = () => { return this.props.disableDisaggregateBtn() || - this.props.savingDisaggregateMeta || + this.state.savingDisaggregateMeta || this.calculateMiscEndUsage().overLimit; } @@ -297,7 +309,7 @@ class UtilityDisaggregation extends Component {
Percentage
- + Saving @@ -359,7 +371,7 @@ class UtilityDisaggregation extends Component { @@ -400,7 +412,6 @@ UtilityDisaggregation.propTypes = { disableDisaggregateBtn: PropTypes.func, handleDisaggregateUtilityBill: PropTypes.func, loadingDisaggregate: PropTypes.bool, - savingDisaggregateMeta: PropTypes.bool, accountId: PropTypes.number, }; diff --git a/src/components/UtilityLine/UtilityLine.js b/src/components/UtilityLine/UtilityLine.js index 82297655..01b3fa9b 100644 --- a/src/components/UtilityLine/UtilityLine.js +++ b/src/components/UtilityLine/UtilityLine.js @@ -43,7 +43,6 @@ class UtilityLine extends Component { loadingUpload: false, editing: false, saving: false, - savingDisaggregateMeta: false, prevForm: { account_number: '', username: '', @@ -87,10 +86,6 @@ class UtilityLine extends Component { this.setState({ loadingFetch: isLoading }) ) - updateSavingDisaggregateMeta = isSaving => ( - this.setState({ savingDisaggregateMeta: isSaving }) - ) - updateLoadingDisaggregateState = isLoading => ( this.setState({ loadingDisaggregate: isLoading }) ) @@ -125,8 +120,7 @@ class UtilityLine extends Component { } - handleFetchingUtilityBill = (event) => { - event.preventDefault(); + handleFetchingUtilityBill = () => { this.updateLoadingFetchState(true); this.props.fetchUtilityBill( this.state.form, @@ -138,8 +132,7 @@ class UtilityLine extends Component { ); } - handleDisaggregateUtilityBill = (event, disaggregateMeta, saveDisaggregateMetaCallback) => { - event.preventDefault(); + handleDisaggregateUtilityBill = () => { this.props.disaggregateUtilityBill( this.state.form, @@ -147,9 +140,6 @@ class UtilityLine extends Component { this.updateLoadingDisaggregateState, this.setDisaggregateData, this.setRSquared, - disaggregateMeta, - this.updateSavingDisaggregateMeta, - saveDisaggregateMetaCallback ); } @@ -830,7 +820,6 @@ class UtilityLine extends Component { disableDisaggregateBtn={this.disableDisaggregateBtn} handleDisaggregateUtilityBill={this.handleDisaggregateUtilityBill} loadingDisaggregate={this.state.loadingDisaggregate} - savingDisaggregateMeta={this.state.savingDisaggregateMeta} accountId={this.state.account_id} />
-- GitLab From 6ea407f3d990219b942d5262f1378c5347064445 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 17:20:05 -0500 Subject: [PATCH 47/52] Add min 0 to input form --- src/components/UtilityLine/DisaggregationForm.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/UtilityLine/DisaggregationForm.js b/src/components/UtilityLine/DisaggregationForm.js index dd586402..c49f5edb 100644 --- a/src/components/UtilityLine/DisaggregationForm.js +++ b/src/components/UtilityLine/DisaggregationForm.js @@ -41,6 +41,7 @@ class DisaggregationForm extends Component { this.props.handleInputChange(e)} value={this.props.form.value} -- GitLab From e024f517135c5a6e288316303340f85209ada8bb Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Wed, 14 Feb 2018 17:41:10 -0500 Subject: [PATCH 48/52] Reset state after saving data --- .../UtilityLine/UtilityDisaggregation.js | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 74e8823c..10190b86 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -39,7 +39,7 @@ class UtilityDisaggregation extends Component { super(props); this.state = { - availableUsageTypes: this.determineAvailableUsageTypesLeft([]), + availableUsageTypes: this.determineAvailableUsageTypes([]), endUsages: [], endUsagesToDelete: [], editMode: false, @@ -58,7 +58,7 @@ class UtilityDisaggregation extends Component { headers: getHeaders(), }).then((res) => { if (!res.err) { - const newAvailableUsageTypes = this.determineAvailableUsageTypesLeft(res.data); + const newAvailableUsageTypes = this.determineAvailableUsageTypes(res.data); this.setState({ endUsages: res.data, @@ -96,7 +96,7 @@ class UtilityDisaggregation extends Component { this.state.pendingEndUsage, ]; - const updateUsageTypes = this.determineAvailableUsageTypesLeft(updateEndUsages); + const updateUsageTypes = this.determineAvailableUsageTypes(updateEndUsages); this.setState({ endUsages: updateEndUsages, @@ -120,7 +120,7 @@ class UtilityDisaggregation extends Component { }); } - const newAvailableUsageTypes = this.determineAvailableUsageTypesLeft(endUsageCopy); + const newAvailableUsageTypes = this.determineAvailableUsageTypes(endUsageCopy); this.setState({ endUsages: endUsageCopy, @@ -150,8 +150,18 @@ class UtilityDisaggregation extends Component { }); Promise.all([putDisaggregate, deleteDisaggregate]).then((values) => { - if (values[0].err) { - this.setState({ error: values[0].err }); + const putDisaggregateRes = values[0]; + + if (putDisaggregateRes.err) { + this.setState({ error: putDisaggregateRes.err }); + } else { + const newAvailableUsageTypes = this.determineAvailableUsageTypes(putDisaggregateRes.data); + + this.setState({ + endUsages: putDisaggregateRes.data, + availableUsageTypes: newAvailableUsageTypes, + pendingEndUsage: this.resetPendingEndUsage(newAvailableUsageTypes), + }); } if (values[1].err) { @@ -165,7 +175,7 @@ class UtilityDisaggregation extends Component { }); } - determineAvailableUsageTypesLeft = (endUsages) => { + determineAvailableUsageTypes = (endUsages) => { const newUsageTypeAvailable = { ...UtilityDisaggregation.usageTypes }; endUsages.forEach(i => ( -- GitLab From cbade42651770b630df7c42617eec08017984abb Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Thu, 15 Feb 2018 10:13:03 -0500 Subject: [PATCH 49/52] Add loading icon on initial load --- src/components/UtilityLine/UtilityDisaggregation.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 10190b86..d24da0cf 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -7,6 +7,7 @@ import Fade from '../Fade'; import request from '../../utils/request'; import { getHeaders, disaggregateMetaURL } from '../../utils/restServices'; import { getDateDiff } from './dataInteraction'; +import Loading from '../Loading'; import './styles.css'; @@ -43,6 +44,7 @@ class UtilityDisaggregation extends Component { endUsages: [], endUsagesToDelete: [], editMode: false, + loadingDisaggregateMeta: false, savingDisaggregateMeta: false, pendingEndUsage: this.resetPendingEndUsage({ ...UtilityDisaggregation.usageTypes }), }; @@ -53,6 +55,9 @@ class UtilityDisaggregation extends Component { return; } + // eslint-disable-next-line + this.setState({ loadingDisaggregateMeta: true }); + request(`${disaggregateMetaURL}?account_id=${this.props.accountId}`, { method: 'GET', headers: getHeaders(), @@ -63,6 +68,7 @@ class UtilityDisaggregation extends Component { this.setState({ endUsages: res.data, availableUsageTypes: newAvailableUsageTypes, + loadingDisaggregateMeta: false, pendingEndUsage: this.resetPendingEndUsage(newAvailableUsageTypes), }); } @@ -307,6 +313,8 @@ class UtilityDisaggregation extends Component { render() { if (!this.props.accountCreated) { return
; + } else if (this.state.loadingDisaggregateMeta) { + return ; } return ( -- GitLab From 57e6baa480fb979bfbc4f48d44ed8d547dbb578c Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Thu, 15 Feb 2018 10:23:53 -0500 Subject: [PATCH 50/52] Add error when fetching --- .../UtilityLine/UtilityDisaggregation.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index d24da0cf..8287d226 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -7,6 +7,7 @@ import Fade from '../Fade'; import request from '../../utils/request'; import { getHeaders, disaggregateMetaURL } from '../../utils/restServices'; import { getDateDiff } from './dataInteraction'; +import ErrorAlert from '../ErrorAlert'; import Loading from '../Loading'; import './styles.css'; @@ -44,6 +45,7 @@ class UtilityDisaggregation extends Component { endUsages: [], endUsagesToDelete: [], editMode: false, + error: null, loadingDisaggregateMeta: false, savingDisaggregateMeta: false, pendingEndUsage: this.resetPendingEndUsage({ ...UtilityDisaggregation.usageTypes }), @@ -71,6 +73,11 @@ class UtilityDisaggregation extends Component { loadingDisaggregateMeta: false, pendingEndUsage: this.resetPendingEndUsage(newAvailableUsageTypes), }); + } else { + this.setState({ + error: res.err, + loadingDisaggregateMeta: false, + }); } }); } @@ -313,6 +320,13 @@ class UtilityDisaggregation extends Component { render() { if (!this.props.accountCreated) { return
; + } else if (this.state.error != null) { + return ( + + ); } else if (this.state.loadingDisaggregateMeta) { return ; } -- GitLab From d0eafafb93ec414f41b2139c6f97ca8a58568a63 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Thu, 15 Feb 2018 10:32:09 -0500 Subject: [PATCH 51/52] Add error to saving --- .../UtilityLine/UtilityDisaggregation.js | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 8287d226..382c1f01 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -45,8 +45,9 @@ class UtilityDisaggregation extends Component { endUsages: [], endUsagesToDelete: [], editMode: false, - error: null, + fetchError: null, loadingDisaggregateMeta: false, + saveError: null, savingDisaggregateMeta: false, pendingEndUsage: this.resetPendingEndUsage({ ...UtilityDisaggregation.usageTypes }), }; @@ -75,7 +76,7 @@ class UtilityDisaggregation extends Component { }); } else { this.setState({ - error: res.err, + fetchError: res.err, loadingDisaggregateMeta: false, }); } @@ -164,23 +165,26 @@ class UtilityDisaggregation extends Component { Promise.all([putDisaggregate, deleteDisaggregate]).then((values) => { const putDisaggregateRes = values[0]; + const deleteDisaggregateRes = values[1]; if (putDisaggregateRes.err) { - this.setState({ error: putDisaggregateRes.err }); - } else { - const newAvailableUsageTypes = this.determineAvailableUsageTypes(putDisaggregateRes.data); - - this.setState({ - endUsages: putDisaggregateRes.data, - availableUsageTypes: newAvailableUsageTypes, - pendingEndUsage: this.resetPendingEndUsage(newAvailableUsageTypes), - }); + this.setState({ saveError: putDisaggregateRes.err }); + return; } - if (values[1].err) { - this.setState({ error: values[1].err }); + if (deleteDisaggregateRes.err) { + this.setState({ saveError: deleteDisaggregateRes.err }); + return; } + const newAvailableUsageTypes = this.determineAvailableUsageTypes(putDisaggregateRes.data); + + this.setState({ + endUsages: putDisaggregateRes.data, + availableUsageTypes: newAvailableUsageTypes, + pendingEndUsage: this.resetPendingEndUsage(newAvailableUsageTypes), + }); + setTimeout(() => { this.setState({ savingDisaggregateMeta: false }); this.props.handleDisaggregateUtilityBill(); @@ -320,13 +324,20 @@ class UtilityDisaggregation extends Component { render() { if (!this.props.accountCreated) { return
; - } else if (this.state.error != null) { + } else if (this.state.fetchError != null) { return ( ); + } else if (this.state.saveError != null) { + return ( + + ); } else if (this.state.loadingDisaggregateMeta) { return ; } -- GitLab From e117076954167add39107939e294362c4e7ef8a8 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Thu, 15 Feb 2018 11:00:35 -0500 Subject: [PATCH 52/52] Remove event variable --- src/components/UtilityLine/UtilityDisaggregation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UtilityLine/UtilityDisaggregation.js b/src/components/UtilityLine/UtilityDisaggregation.js index 382c1f01..ce59f31c 100644 --- a/src/components/UtilityLine/UtilityDisaggregation.js +++ b/src/components/UtilityLine/UtilityDisaggregation.js @@ -85,7 +85,7 @@ class UtilityDisaggregation extends Component { toggleEditMode = () => { if (this.state.editMode) { - this.saveDisaggregateMeta(event); + this.saveDisaggregateMeta(); } this.setState({ editMode: !this.state.editMode }); -- GitLab