diff --git a/src/App.js b/src/App.js index 121d999305c4e270db41c851f60d47b1fc25614b..f886510a4afdec518e4f809640e239d3d4d418ce 100644 --- a/src/App.js +++ b/src/App.js @@ -8,6 +8,7 @@ import HeatDistribution from './HeatDistribution'; import SeparateBoiler from './SeparateBoiler'; import HeatingSystemAge from './HeatingSystemAge'; import HeatingSystemPlan from './HeatingSystemPlan'; +import UnitBreakdown from './UnitBreakdown' import BuildingTypes from './BuildingTypes'; import UtilityBills from './UtilityBills'; import ComfortIssues from './ComfortIssues'; @@ -26,7 +27,7 @@ import BuildingPastImprovement from './BuildingPastImprovement'; import BuildingFutureImprovement from './BuildingFutureImprovement'; import { questionTree } from './constants'; import { connect } from 'react-redux'; -import { submitContact, submitAnswer, submitBuilding, submitQuestionnaire } from './actions'; +import { submitContact, submitAnswer, submitBuilding, submitQuestionnaire, submitUserAnswer } from './actions'; import './App.css'; import ReactGA from 'react-ga'; @@ -125,6 +126,13 @@ class App extends React.Component { value: 0, answerIds: [17, 18, 19, 12], prev: 'heatingSystemAge', + next: 'unitBreakdown', + }, + unitBreakdown: { + title: 'Tell us about your building.', + questionIds: [52, 53, 54, 55, 56, 57], + answers: [0, 0, 0, 0, 0, 0], + prev: 'heatingSystemPlan', next: 'buildingTypes', }, buildingTypes: { @@ -134,7 +142,7 @@ class App extends React.Component { value: '', answerIds: [20, 21, 22, 23, 32, 33], answers: { 20: 'singleFamily', 21: 'multiFamily', 22: 'mixedUse', 23: 'coop', 32: 'church', 33: 'other' }, - prev: 'heatingSystemPlan', + prev: 'unitBreakdown', next: '', }, utilityBills: { @@ -626,6 +634,8 @@ class App extends React.Component { questions[question]['questions'][i]['value'] = value[i]; questionAnswers[questions[question]['questions'][i].id] = value[i]; }); + } else if (Array.isArray(answer) === true && Array.isArray(questions[question]['questionIds']) === true) { + questions[question]['answers'] = value; } else { questions[question].answer = answer; questions[question].value = value; @@ -638,6 +648,15 @@ class App extends React.Component { this.props.onSubmitBuilding({ address: this.state.questions[question].value, }); + } else if (question === 'unitBreakdown'){ + this.setQuestion(this.state.questions[question].next); + this.props.onSubmitUserAnswer({ + questionId: questions[question]['questionIds'], + answers: questions[question]['answers'], + surveyId: this.props.building.data.surveyId, + buildingId: this.props.building.data.buildingId, + userId: this.props.building.data.userId, + }); } else { this.setQuestion(this.state.questions[question].next); this.props.onSubmitAnswer({ @@ -979,6 +998,12 @@ class App extends React.Component { answer={this.state.questions['heatingSystemPlan'].value} answerIds={this.state.questions['heatingSystemPlan'].answerIds} />, + unitBreakdown: , buildingTypes: { return { onSubmitBuilding: (data) => dispatch(submitBuilding(data)), onSubmitAnswer: (data) => dispatch(submitAnswer(data)), + onSubmitUserAnswer: (data) => dispatch(submitUserAnswer(data)), onSubmitContact: (data) => dispatch(submitContact(data)), onSubmitQuestionnaire: (data) => dispatch(submitQuestionnaire(data)), } diff --git a/src/UnitBreakdown.js b/src/UnitBreakdown.js new file mode 100644 index 0000000000000000000000000000000000000000..c8506919c4d5a1e7b09ac4ad286c5c970dcd1413 --- /dev/null +++ b/src/UnitBreakdown.js @@ -0,0 +1,159 @@ +import React from "react"; +import { Row, Col, Button } from 'reactstrap'; +import './index.css'; +import ReactGA from 'react-ga'; + +export default class UnitBreakDown extends React.Component { + constructor(props) { + super(props); + this.state = { + studio: this.props.answers[0], + oneBedroom: this.props.answers[1], + twoBedroom: this.props.answers[2], + threeBedroom: this.props.answers[3], + fourBedroom: this.props.answers[4], + other: this.props.answers[5], + }; + this.names = { + 52: 'Studio', + 53: '1 Bedroom', + 54: '2 Bedroom', + 55: '3 Bedroom', + 56: '4 Bedroom', + 57: 'Other', + } + this.ids = [ + 'studio', + 'oneBedroom', + 'twoBedroom', + 'threeBedroom', + 'fourBedroom', + 'other' + ] + } + + handleInputChange = (event) => { + const val = event.target.value; + const name = event.target.name; + this.setState({ + ...this.state, + [name]: val, + }); + } + + prevQuestion = () => { + this.props.prevQuestion('unitBreakDown'); + } + + nextQuestion = () => { + if(this.validateEmptyInputs()) { + this.props.nextQuestion( + 'unitBreakdown', + [], + [this.state.studio, + this.state.oneBedroom, + this.state.twoBedroom, + this.state.threeBedroom, + this.state.fourBedroom, + this.state.other], + ); + } + } + + validateEmptyInputs() { + const invalidFields = []; + const errorMessage = []; + const validNumber = /^[0-9]/; + const unitTypes = ['studio', 'oneBedroom', 'twoBedroom', 'threeBedroom', 'fourBedroom', 'other']; + const displayName = ['Studio', 'One Bedroom', 'Two Bedroom', 'Three Bedroom', 'Four Bedroom', 'Other']; + unitTypes.map((unit, index) => { + if (!(validNumber.test(this.state[unit]))) { + invalidFields.push(displayName[index]); + } + }); + if (invalidFields.length > 0) { + errorMessage.push(`\nInvalid input in:\n${invalidFields.join('\n')}`); + alert(errorMessage); + return false; + } + return true; + } + + handleFocus = (event) => event.target.select(); + + render() { + const content = ( + + + Please tell us about your building units. + + + + + { + this.props.questions.map((questionId, index) => { + const answer = this.props.answers[index]; + return ( + + + + {this.names[questionId]} : + + this.handleInputChange(e)}> + + + ); + }) + } + + + + + + + + {'<'} Back + + + + {/* Button will be disabled only if all inputs are 0 or any of the input is empty. */} + + Continue > + + + + + ); + + return ( + + {content} + + ); + } +} diff --git a/src/actions.js b/src/actions.js index 18ecb9b22ddc77cbf1962fce55e9e60fe4f4859d..6156dfbe2cdc05a5899fef8784ccabfd990f1fb0 100644 --- a/src/actions.js +++ b/src/actions.js @@ -52,6 +52,23 @@ export const submitAnswer = (data) => { } } +// asynchronous action creator +export const submitUserAnswer = (data) => { + const blocLinkUrl = process.env.REACT_APP_BLOCLINK_URL; + return (dispatch) => { + dispatch({ type: "UserAnswerRequested" }); + return axios.put( + `${blocLinkUrl}/buildings/bis/submit-user-answer/`, + data, + { headers : { 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8' } }, + ) + .then(res => dispatch( + { type: "UserAnswerSucceeded", data: res })) + .catch(err => dispatch( + { type: "UserAnswerFailed", msg: err.response.data })); + } +} + // asynchronous action creator export const submitContact = (contact) => { const blocLinkUrl = process.env.REACT_APP_BLOCLINK_URL; diff --git a/src/index.css b/src/index.css index 611f192ade6aa47c1d07c4cd1ccbf607e2ac69d4..e882c2f7d455793dfab2bc6085187e14d3ebe57d 100644 --- a/src/index.css +++ b/src/index.css @@ -235,6 +235,9 @@ code { padding: 0 0 0 0; } + .unitTitle { + text-align-last: end; + } .HSName { margin-top: 20%; @@ -327,6 +330,37 @@ code { color: #002F43; } +.unitSection { + font-size: 16px; + font-weight: bold; + width: 100%; + color: #002F43; + text-align-last: center; + text-align: left; + margin-top: 30px; +} + +.unitTitle { + font-size: 16px; + font-weight: bold; + width: 40%; + color: #002F43; + text-align: left; + margin-top: 30px; + float: left; +} + +.unitText { + font-size: 16px; + font-weight: bold; + width: 40%; + color: #002F43; + text-align: center; + margin-top: 25px; + max-width: 150px; + border: #002F43 solid 2px; +} + .image { width: 30%; } diff --git a/src/reducers/reducer.js b/src/reducers/reducer.js index 459b690805a7e806dbf8d1cc2ee7d7726c299be0..cb27e487ed3f2834b75dcded006b5920eb887e42 100644 --- a/src/reducers/reducer.js +++ b/src/reducers/reducer.js @@ -105,6 +105,33 @@ const reducer = (state = intialState, action) => { error: true, }, }; + case "UserAnswerRequested": + return { + ...state, + questions: { + ...state.questions, + loading: true, + error: false, + }, + }; + case "UserAnswerSucceeded": + return { + ...state, + questions: { + data: action.data.data, + loading: false, + error: false, + }, + }; + case "UserAnswerFailed": + return { + ...state, + questions: { + data: action.msg, + loading: false, + error: true, + }, + }; case "QuestionRequested": return { ...state,