Skip to content
This repository has been archived by the owner on Jul 4, 2019. It is now read-only.

Commit

Permalink
Merge pull request #12 from Financial-Times/feature/validate-feedback
Browse files Browse the repository at this point in the history
Validating the feedback form
  • Loading branch information
ciprianlujeru authored Mar 2, 2017
2 parents 32c3190 + 1097469 commit 27bad07
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 45 deletions.
10 changes: 10 additions & 0 deletions src/actions/feedback-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ export function togglePanel() {
};
}

/**
* Toggles feedback form valid state
* @returns {{type: String}}
*/
export function toggleFeedbackValid() {
return {
type: "F_TOGGLE_VALID"
};
}

/**
* Submit the user feedback
* @param {String} theUrl
Expand Down
101 changes: 62 additions & 39 deletions src/components/feedback-form/index.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,74 @@
import React, { Component, PropTypes } from 'react';
import { submitFeedback } from "../../actions/feedback-form";
import { submitFeedback, toggleFeedbackValid } from "../../actions/feedback-form";

class FeedbackForm extends Component {
constructor(props) {
super(props);

this.submit = this.submit.bind(this);
this.getData = this.getData.bind(this);
this.toggleValidState = this.toggleValidState.bind(this);
}

shouldComponentUpdate(nextProps, nextState) {
// only render if the props (state) have changed
return JSON.stringify(nextProps) !== JSON.stringify(this.props);
}

toggleValidState() {
const theData = this.getData();
const isValid = Object.keys(theData).some((key) => theData[key] !== undefined && theData[key].trim().length > 0);
if (this.props.isValid !== isValid) {
this.props.dispatch(toggleFeedbackValid());
}
}

getData() {
const theData = {
npsscore: undefined,
positivefeedback: undefined,
negativefeedback: undefined
};
Object.keys(this.refs).forEach((key) => {
if (key.indexOf("nps") === 0) {
if (this.refs[key].checked) {
theData["npsscore"] = this.refs[key].value;
}
} else {
theData[key] = this.refs[key].value;
}
});

return theData;
}

submit(e) {
e.preventDefault();
const theForm = e.target;
// TODO: fix this (temporary use)
if (theForm) {
const theUrl = theForm.getAttribute("action");
const data = {};

const npsscore = document.getElementsByName("npsscore");
const positivefeedback = document.getElementsByName("positivefeedback");
const negativefeedback = document.getElementsByName("negativefeedback");
if (npsscore) {
for (let item of npsscore) {
if (item.checked) {
data.npsscore = item.value;
break;
}
}
}
if (positivefeedback && positivefeedback[0]) {
data.positivefeedback = positivefeedback[0].value;
}
if (negativefeedback && negativefeedback[0]) {
data.negativefeedback = negativefeedback[0].value;
}

this.props.dispatch(submitFeedback(theUrl, data));
this.props.dispatch(submitFeedback(theUrl, this.getData()));
}
}

render() {
const formAttr = {
action: "#"
};
const submitAttr = {
disabled: true,
type: "button"
};
if (this.props.isValid === true) {
formAttr.action = window.FEEDBACK_ROUTE;
formAttr.onSubmit = this.submit;
submitAttr.type = "submit";
delete submitAttr.disabled;
}

return (
<div>
<form method="POST" className="kat-feedback" action={window.FEEDBACK_ROUTE} onSubmit={this.submit}>
<form method="POST" className="kat-feedback" {...formAttr}>
<div className="kat-feedback__row">
<div>We'd love to hear your feedback about our Knowledge & Administration Tools, aka KAT. Please tell us your thoughts below. If you would like a reply, please leave your name and email address with your comments.</div>
</div>
Expand All @@ -57,42 +79,42 @@ class FeedbackForm extends Component {
<small className="o-forms__additional-info kat-feedback__less">Less Likely</small>
<small className="o-forms__additional-info kat-feedback__more">Extremely Likely</small>
<div className="kat-feedback__score">
<input type="radio" name="npsscore" value="0" className="o-forms__radio o-forms__radio--small" id="nps0" />
<input type="radio" name="npsscore" value="0" className="o-forms__radio o-forms__radio--small" id="nps0" ref="nps0" onChange={this.toggleValidState} />
<label htmlFor="nps0" className="o-forms__label nps-label">0</label>
<input type="radio" name="npsscore" value="1" className="o-forms__radio o-forms__radio--small" id="nps1"/>
<input type="radio" name="npsscore" value="1" className="o-forms__radio o-forms__radio--small" id="nps1" ref="nps1" onChange={this.toggleValidState} />
<label htmlFor="nps1" className="o-forms__label nps-label">1</label>
<input type="radio" name="npsscore" value="2" className="o-forms__radio o-forms__radio--small" id="nps2"/>
<input type="radio" name="npsscore" value="2" className="o-forms__radio o-forms__radio--small" id="nps2" ref="nps2" onChange={this.toggleValidState} />
<label htmlFor="nps2" className="o-forms__label nps-label">2</label>
<input type="radio" name="npsscore" value="3" className="o-forms__radio o-forms__radio--small" id="nps3"/>
<input type="radio" name="npsscore" value="3" className="o-forms__radio o-forms__radio--small" id="nps3" ref="nps3" onChange={this.toggleValidState} />
<label htmlFor="nps3" className="o-forms__label nps-label">3</label>
<input type="radio" name="npsscore" value="4" className="o-forms__radio o-forms__radio--small" id="nps4"/>
<input type="radio" name="npsscore" value="4" className="o-forms__radio o-forms__radio--small" id="nps4" ref="nps4" onChange={this.toggleValidState} />
<label htmlFor="nps4" className="o-forms__label nps-label">4</label>
<input type="radio" name="npsscore" value="5" className="o-forms__radio o-forms__radio--small" id="nps5"/>
<input type="radio" name="npsscore" value="5" className="o-forms__radio o-forms__radio--small" id="nps5" ref="nps5" onChange={this.toggleValidState} />
<label htmlFor="nps5" className="o-forms__label nps-label">5</label>
<input type="radio" name="npsscore" value="6" className="o-forms__radio o-forms__radio--small" id="nps6"/>
<input type="radio" name="npsscore" value="6" className="o-forms__radio o-forms__radio--small" id="nps6" ref="nps6" onChange={this.toggleValidState} />
<label htmlFor="nps6" className="o-forms__label nps-label">6</label>
<input type="radio" name="npsscore" value="7" className="o-forms__radio o-forms__radio--small" id="nps7"/>
<input type="radio" name="npsscore" value="7" className="o-forms__radio o-forms__radio--small" id="nps7" ref="nps7" onChange={this.toggleValidState} />
<label htmlFor="nps7" className="o-forms__label nps-label">7</label>
<input type="radio" name="npsscore" value="8" className="o-forms__radio o-forms__radio--small" id="nps8"/>
<input type="radio" name="npsscore" value="8" className="o-forms__radio o-forms__radio--small" id="nps8" ref="nps8" onChange={this.toggleValidState} />
<label htmlFor="nps8" className="o-forms__label nps-label">8</label>
<input type="radio" name="npsscore" value="9" className="o-forms__radio o-forms__radio--small" id="nps9"/>
<input type="radio" name="npsscore" value="9" className="o-forms__radio o-forms__radio--small" id="nps9" ref="nps9" onChange={this.toggleValidState} />
<label htmlFor="nps9" className="o-forms__label nps-label">9</label>
<input type="radio" name="npsscore" value="10" className="o-forms__radio o-forms__radio--small" id="nps10"/>
<input type="radio" name="npsscore" value="10" className="o-forms__radio o-forms__radio--small" id="nps10" ref="nps10" onChange={this.toggleValidState} />
<label htmlFor="nps10" className="o-forms__label nps-label">10</label>
</div>
</div>
<div className="kat-feedback__row">
<label className="o-forms__label">Would you like to...</label>
<label className="o-forms__label">Leave a comment?</label>
<textarea className="o-forms__textarea kat-feedback__textarea" name="positivefeedback"></textarea>
<textarea className="o-forms__textarea kat-feedback__textarea" name="positivefeedback" ref="positivefeedback" onChange={this.toggleValidState}></textarea>
</div>

<div className="kat-feedback__row">
<label className="o-forms__label">Report something is missing or not working?</label>
<textarea className="o-forms__textarea kat-feedback__textarea" name="negativefeedback"></textarea>
<textarea className="o-forms__textarea kat-feedback__textarea" name="negativefeedback" ref="negativefeedback" onChange={this.toggleValidState}></textarea>
</div>
<div className="kat-feedback__row">
<button className="kat-feedback__submit" type="submit">Submit</button>
<button className="kat-feedback__submit" {...submitAttr}>Submit</button>
</div>
</form>
</div>
Expand All @@ -101,7 +123,8 @@ class FeedbackForm extends Component {
};

FeedbackForm.propTypes = {
dispatch: PropTypes.func.isRequired
dispatch: PropTypes.func.isRequired,
isValid: PropTypes.bool.isRequired
};

export default FeedbackForm;
5 changes: 4 additions & 1 deletion src/components/overlay/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ class Overlay extends Component {
}

shouldComponentUpdate(nextProps, nextState) {
// children will be a React object that can't be stringified
const replacer = (k, v) => k === "children" ? v.props || null : v;

// only render if the props (state) have changed
return JSON.stringify(nextProps) !== JSON.stringify(this.props);
return JSON.stringify(nextProps, replacer) !== JSON.stringify(this.props, replacer);
}

componentDidMount() {
Expand Down
8 changes: 5 additions & 3 deletions src/containers/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class HeaderContainer extends Component {
<HeaderNav menu={this.props.menu} />
{this.props.feedbackIsExpanded === true
? <Overlay {...overlayProps}>
<FeedbackForm dispatch={this.props.dispatch} />
<FeedbackForm dispatch={this.props.dispatch} isValid={this.props.feedbackIsValid} />
</Overlay>
: null
}
Expand All @@ -73,15 +73,17 @@ HeaderContainer.propTypes = {
menu: PropTypes.shape(menuTypes).isRequired,
headerTitle: PropTypes.shape(headerTitleTypes).isRequired,
extraActions: PropTypes.shape(extraActionsTypes).isRequired,
feedbackIsExpanded: PropTypes.bool.isRequired
feedbackIsExpanded: PropTypes.bool.isRequired,
feedbackIsValid: PropTypes.bool.isRequired
};

const mapStateToProps = (store) => {
return {
menu: store.KmtHeaderNs.mainMenu,
headerTitle: store.KmtHeaderNs.headerTitle,
extraActions: store.KmtHeaderNs.extraActions,
feedbackIsExpanded: store.KmtHeaderNs.feedbackForm.isExpanded
feedbackIsExpanded: store.KmtHeaderNs.feedbackForm.isExpanded,
feedbackIsValid: store.KmtHeaderNs.feedbackForm.isValid
};
};

Expand Down
7 changes: 5 additions & 2 deletions src/reducers/feedback-form.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
const defaultState = {
isExpanded: false,
submitFn: () => {}
isValid: false
};
const feedbackForm = (state = defaultState, action = {}) => {

switch (action.type) {
case "F_TOGGLE":
state = Object.assign({}, state, {isExpanded: !state.isExpanded});
state = Object.assign({}, state, {isValid: false, isExpanded: !state.isExpanded});
break;
case "F_TOGGLE_VALID":
state = Object.assign({}, state, {isValid: !state.isValid});
break;
}
return state;
Expand Down

0 comments on commit 27bad07

Please sign in to comment.