From 26e21748a320f2235801886cfcb4390710782262 Mon Sep 17 00:00:00 2001 From: Michael Villis Date: Sun, 13 Mar 2016 19:54:57 +1000 Subject: [PATCH] refactored assessment form to use separate components not tabs --- client/js/components/assessment/attribute.js | 112 +++++++++++++ .../js/components/assessment/attributeList.js | 158 +++++------------- client/js/components/assessment/intro.js | 38 +++++ client/js/components/assessment/rating.js | 7 - client/js/components/assessment/ratingList.js | 46 ----- client/js/components/assessment/summary.js | 82 +++++++++ client/js/main.js | 11 +- 7 files changed, 284 insertions(+), 170 deletions(-) create mode 100644 client/js/components/assessment/attribute.js create mode 100644 client/js/components/assessment/intro.js delete mode 100644 client/js/components/assessment/ratingList.js create mode 100644 client/js/components/assessment/summary.js diff --git a/client/js/components/assessment/attribute.js b/client/js/components/assessment/attribute.js new file mode 100644 index 000000000..668e8d1ba --- /dev/null +++ b/client/js/components/assessment/attribute.js @@ -0,0 +1,112 @@ +'use strict' + +var React = require('react') +var ReactBootstrap = require('react-bootstrap') +var Rating = require('./rating') +var ObserveInput = require('./observeInput') +var Loader = require('react-loader') +var _ = require('lodash') +var Panel = ReactBootstrap.Panel +var Alert = ReactBootstrap.Alert +var ListGroup = ReactBootstrap.ListGroup +var $ = require('jquery') + +var Attribute = React.createClass({ + propTypes: { + key: React.PropTypes.number, + eventKey: React.PropTypes.number, + activeTab: React.PropTypes.number, + attribute: React.PropTypes.object, + params: React.PropTypes.object + }, + getInitialState: function () { + return { + attribute: null, + measurement: null, + measureSyncActivity: false, + dirtyObservation: false, + loaded: false + } + }, + componentDidMount: function () { + this.getData(this.props.params.id, this.props.params.attribute) + }, + componentWillReceiveProps: function (nextProps) { + this.getData(nextProps.params.id, nextProps.params.attribute) + }, + getData: function (id, attribute) { + var setAttribute = function (data) { this.setState({attribute: data}) }.bind(this) + var setMeasurement = function (data) { this.setState({measurement: _.head(data), loaded: true}) }.bind(this) + this.dataSource('/api/attributes/' + attribute, setAttribute) + this.dataSource('/api/measurements/' + '?assessment__id=' + id + '&rating__attribute=' + attribute, setMeasurement) + }, + dataSource: function (url, callback) { + $.ajax({ + type: 'get', + dataType: 'json', + url: url, + success: callback, + error: this.handleSubmitFailure + }) + }, + handleSubmitFailure: function (xhr, ajaxOptions, thrownError) { + console.error('There was a failure') + }, + saveMeasurement: function (ratingType, value) { + var existingMeasurement = this.state.measurement + var postData = { + observations: (this.state.measurement.observations) ? this.state.measurement.observations : '', + id: (this.state.measurement) ? this.state.measurement.id : '', + assessment: this.props.params.id, + rating: (ratingType === 'rating') ? value : this.state.measurement.rating, + target_rating: (ratingType === 'target') ? value : ((existingMeasurement && this.state.measurement.target_rating) ? this.state.measurement.target_rating : '') // eslint-disable-line camelcase + } + this.syncMeasurement(postData) + }, + measurementUpdateCallback: function (data) { + this.setState({ + measurement: data, + measureSyncActivity: false, + dirtyObservation: false + }) + }, + syncMeasurement: function (postData) { + var createNewMeasure = !postData.id + this.setState({ measureSyncActivity: true }) + console.log('Should a new measurement be created? ' + createNewMeasure) + $.ajax({ + type: ((createNewMeasure) ? 'POST' : 'PUT'), + contentType: 'application/json; charset=utf-8', + url: ((createNewMeasure) ? '/api/measurements/' : ('/api/measurements/' + postData.id + '/')), + data: JSON.stringify(postData), + dataType: 'json', + success: this.measurementUpdateCallback, + error: this.handleSubmitFailure + }) + }, + render: function () { + if (this.state.attribute !== null) { + var ratingList = this.state.attribute.ratings.map(function (rating) { + return ( + + ) + }.bind(this)) + } + + return ( + + + + {this.state.attribute && this.state.attribute.desc ? this.state.attribute.desc : ''} + + + + {ratingList} + + + + ) + } +}) + +module.exports = Attribute diff --git a/client/js/components/assessment/attributeList.js b/client/js/components/assessment/attributeList.js index c56c8534e..f791f645f 100644 --- a/client/js/components/assessment/attributeList.js +++ b/client/js/components/assessment/attributeList.js @@ -2,29 +2,29 @@ var React = require('react') var ReactBootstrap = require('react-bootstrap') -var _ = require('lodash') +var ReactRouterBootstrap = require('react-router-bootstrap') var PageHeader = ReactBootstrap.PageHeader -var Tabs = ReactBootstrap.Tabs -var Tab = ReactBootstrap.Tab -var Panel = ReactBootstrap.Panel -var Alert = ReactBootstrap.Alert -var ListGroup = ReactBootstrap.ListGroup +var Nav = ReactBootstrap.Nav +var NavItem = ReactBootstrap.NavItem +var Grid = ReactBootstrap.Grid +var Row = ReactBootstrap.Row +var Col = ReactBootstrap.Col var Pager = ReactBootstrap.Pager var PageItem = ReactBootstrap.PageItem var Glyphicon = ReactBootstrap.Glyphicon +var LinkContainer = ReactRouterBootstrap.LinkContainer var Loader = require('react-loader') -var RatingList = require('./ratingList') -var ObserveInput = require('./observeInput') -var AssessmentReport = require('./assessmentReport') var $ = require('jquery') var AttributeList = React.createClass({ propTypes: { - params: React.PropTypes.object + params: React.PropTypes.object, + location: React.PropTypes.object, + children: React.PropTypes.object }, getInitialState: function () { return { - activeTab: 1, + activeTab: parseInt(this.props.location.query.tab, 10) || 1, activeAttribute: null, measurements: null, template: null, @@ -40,18 +40,11 @@ var AttributeList = React.createClass({ componentWillMount: function () { this.dataSource('/api/assessments/' + this.props.params.id + '/', this.assessmentCallback) }, - measurementCallback: function (data) { + templateCallback: function (data) { this.setState({ - measurements: data, + template: data, initialLoad: true }) - this.handleSelect(1) - }, - templateCallback: function (data) { - this.setState({ - template: data - }, this.dataSource('/api/measurements/' + '?assessment__id=' + this.props.params.id, this.measurementCallback) - ) }, assessmentCallback: function (data) { this.setState({ @@ -71,58 +64,6 @@ var AttributeList = React.createClass({ error: this.handleSubmitFailure }) }, - measurementUpdateCallback: function (data) { - var existingMeasurementIndex = _.findIndex(this.state.measurements, function (measurement) { - return measurement.id === data.id - }) - var updatedDirtyObservation = this.state.dirtyObservation - updatedDirtyObservation[this.state.activeTab] = false - if (existingMeasurementIndex !== -1) { - var updatedMeasurements = this.state.measurements.slice() - updatedMeasurements[existingMeasurementIndex] = data - this.setState({ - measurements: updatedMeasurements, - measureSyncActivity: false, - dirtyObservation: updatedDirtyObservation - }) - } else { - var newMeasurements = this.state.measurements.concat([data]) - this.setState({ - measurements: newMeasurements, - measureSyncActivity: false, - dirtyObservation: updatedDirtyObservation - }) - } - }, - syncMeasurement: function (postData) { - var createNewMeasure = !postData.id - if (this.state.observations[this.state.activeTab]) { - postData['observations'] = this.state.observations[this.state.activeTab] - } else { - var matchMeasure = _.find(this.state.measurements, function (measurement) { - return measurement.id === postData.id - }) - matchMeasure ? postData['observations'] = matchMeasure.observations : postData['observations'] = '' - } - this.setState({ measureSyncActivity: true }) - console.log('Should a new measurement be created? ' + createNewMeasure) - $.ajax({ - type: ((createNewMeasure) ? 'POST' : 'PUT'), - contentType: 'application/json; charset=utf-8', - url: ((createNewMeasure) ? '/api/measurements/' : ('/api/measurements/' + postData.id + '/')), - data: JSON.stringify(postData), - dataType: 'json', - success: this.measurementUpdateCallback, - error: this.handleSubmitFailure - }) - }, - onObservationChange: function (text, activeTab) { - var observations = this.state.observations - observations[activeTab] = text - var updatedDirtyObservation = this.state.dirtyObservation - updatedDirtyObservation[this.state.activeTab] = true - this.setState({observations: observations, dirtyObservation: updatedDirtyObservation}) - }, handleNext: function () { if (this.state.activeTab < this.state.template.attributes.length + 1 && !this.state.nextHide) { var newTab = this.state.activeTab + 1 @@ -195,40 +136,18 @@ var AttributeList = React.createClass({ var completeMeasurement = measurement && measurement.rating && measurement.target_rating var tabIcon = (completeMeasurement) ? : return ( - {tabIcon} {attribute.name}}> - - - {attribute.desc} - - - - - - - - + + {attribute.name} + ) }.bind(this)) - var summaryTab = function () { + var summaryNode = function () { + if (!this.state.template) return (undefined) return ( - Summary}> - - - How did you go? Where are you strengths and weaknesses? What are some improvements you could make? - - - - + + Summary + ) }.bind(this)() } @@ -238,19 +157,28 @@ var AttributeList = React.createClass({ {!!this.state.assessment === true ? this.state.assessment.template.name : ''} {this.state.assessment ? this.state.assessment.template.short_desc : ''} - - {attributeNodes} - {summaryTab} - - - {' '} Previous - - {' '} - - Next {' '} - - - + + + + {React.cloneElement(this.props.children, {attributes: this.state.attributes})} + + + {' '} Previous + + {' '} + + Next {' '} + + + + + + + + ) diff --git a/client/js/components/assessment/intro.js b/client/js/components/assessment/intro.js new file mode 100644 index 000000000..9ce02d514 --- /dev/null +++ b/client/js/components/assessment/intro.js @@ -0,0 +1,38 @@ +'use strict' + +var React = require('react') +var ReactBootstrap = require('react-bootstrap') +var ReactRouterBootstrap = require('react-router-bootstrap') +var LinkContainer = ReactRouterBootstrap.LinkContainer +var Jumbotron = ReactBootstrap.Jumbotron +var Button = ReactBootstrap.Button + +var Intro = React.createClass({ + propTypes: { + attributes: React.PropTypes.array, + params: React.PropTypes.object + }, + getInitialState: function () { + return { + attribute: undefined, + measureSyncActivity: false, + dirtyObservation: false + } + }, + render: function () { + return ( + +

Let's get started!

+

Look to your right. There you will find a list of the areas we are going to measure. Start by selecting the top one.

+ + + + +   + +
+ ) + } +}) + +module.exports = Intro diff --git a/client/js/components/assessment/rating.js b/client/js/components/assessment/rating.js index 4c790ea15..0aec2d985 100644 --- a/client/js/components/assessment/rating.js +++ b/client/js/components/assessment/rating.js @@ -13,19 +13,12 @@ var Rating = React.createClass({ propTypes: { key: React.PropTypes.number, eventKey: React.PropTypes.number, - activeTab: React.PropTypes.number, measurement: React.PropTypes.object, assessId: React.PropTypes.string.isRequired, attribute: React.PropTypes.object, saveMeasurement: React.PropTypes.func.isRequired, rating: React.PropTypes.object }, - shouldComponentUpdate: function (nextProps, nextState) { - if (nextProps.activeTab === this.props.eventKey) { - return true - } - return false - }, render: function () { var ratingActive = (this.props.measurement && this.props.measurement.rating) ? (this.props.measurement.rating === this.props.rating.id) : false var targetActive = (this.props.measurement && this.props.measurement.target_rating) ? (this.props.measurement.target_rating === this.props.rating.id) : false diff --git a/client/js/components/assessment/ratingList.js b/client/js/components/assessment/ratingList.js deleted file mode 100644 index c9f98e0f7..000000000 --- a/client/js/components/assessment/ratingList.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict' - -var React = require('react') -var Rating = require('./rating') - -var RatingList = React.createClass({ - propTypes: { - key: React.PropTypes.number, - eventKey: React.PropTypes.number, - activeTab: React.PropTypes.number, - measurement: React.PropTypes.object, - assessId: React.PropTypes.string.isRequired, - syncMeasurement: React.PropTypes.func.isRequired, - attribute: React.PropTypes.object - }, - shouldComponentUpdate: function (nextProps, nextState) { - if (nextProps.activeTab === this.props.eventKey) { - return true - } - return false - }, - saveMeasurement: function (ratingType, value) { - var existingMeasurement = this.props.measurement - var postData = { - id: (this.props.measurement) ? this.props.measurement.id : '', - assessment: this.props.assessId, - rating: (ratingType === 'rating') ? value : this.props.measurement.rating, - target_rating: (ratingType === 'target') ? value : ((existingMeasurement && this.props.measurement.target_rating) ? this.props.measurement.target_rating : '') // eslint-disable-line camelcase - } - this.props.syncMeasurement(postData) - }, - render: function () { - var ratingNodes = this.props.attribute.ratings.map(function (rating) { - return ( - - ) - }.bind(this)) - return ( -
- {ratingNodes} -
- ) - } -}) - -module.exports = RatingList diff --git a/client/js/components/assessment/summary.js b/client/js/components/assessment/summary.js new file mode 100644 index 000000000..02dc5e5a2 --- /dev/null +++ b/client/js/components/assessment/summary.js @@ -0,0 +1,82 @@ +'use strict' + +var React = require('react') +var ReactBootstrap = require('react-bootstrap') +var AssessmentReport = require('./assessmentReport') +var Loader = require('react-loader') +var Panel = ReactBootstrap.Panel +var Alert = ReactBootstrap.Alert +var $ = require('jquery') + +var Summary = React.createClass({ + propTypes: { + key: React.PropTypes.number, + eventKey: React.PropTypes.number, + activeTab: React.PropTypes.number, + attribute: React.PropTypes.object, + params: React.PropTypes.object + }, + getInitialState: function () { + return { + attribute: undefined, + loaded: false, + dirtyObservation: false + } + }, + componentWillMount: function () { + this.dataSource('/api/assessments/' + this.props.params.id + '/', this.assessmentCallback) + }, + measurementCallback: function (data) { + this.setState({ + measurements: data, + loaded: true + }) + }, + templateCallback: function (data) { + this.setState({ + template: data + }, this.dataSource('/api/measurements/' + '?assessment__id=' + this.props.params.id, this.measurementCallback) + ) + }, + assessmentCallback: function (data) { + this.setState({ + assessment: data + }, this.dataSource('/api/templates/' + data.template.id + '/', this.templateCallback) + ) + }, + handleSubmitFailure: function (xhr, ajaxOptions, thrownError) { + console.error('There was a failure') + }, + dataSource: function (url, callback) { + $.ajax({ + type: 'get', + dataType: 'json', + url: url, + success: callback, + error: this.handleSubmitFailure + }) + }, + render: function () { + return ( + + + + How did you go? Where are you strengths and weaknesses? What are some improvements you could make? + + + + + ) + } +}) + +module.exports = Summary diff --git a/client/js/main.js b/client/js/main.js index 852cd1d0c..51c666d13 100755 --- a/client/js/main.js +++ b/client/js/main.js @@ -6,9 +6,13 @@ var ReactRouter = require('react-router') var hashHistory = ReactRouter.hashHistory var Router = ReactRouter.Router var Route = ReactRouter.Route +var IndexRoute = ReactRouter.IndexRoute var Header = require('./components/common/header') var Home = require('./components/home/home') var AttributeList = require('./components/assessment/attributeList') +var Attribute = require('./components/assessment/attribute') +var Summary = require('./components/assessment/summary') +var Intro = require('./components/assessment/intro') var AssessmentTable = require('./components/assessment/assessmentTable') var Team = require('./components/team/team') var TeamTable = require('./components/team/teamTable') @@ -19,7 +23,11 @@ ReactDOM.render( - + + + + + @@ -27,4 +35,3 @@ ReactDOM.render( , document.getElementById('app') ) -