diff --git a/package.json b/package.json index 08f47b80a..a816d3ed9 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "formsy-react-components": "0.7.1", "git-bundle-sha": "0.0.2", "glob": "5.0.15", + "google-libphonenumber": "1.0.21", "json-loader": "0.5.2", "json2po-stream": "1.0.3", "jsx-loader": "0.13.2", @@ -69,6 +70,7 @@ "react-onclickoutside": "4.1.1", "react-redux": "4.4.5", "react-slick": "0.12.2", + "react-telephone-input": "3.4.5", "redux": "3.5.2", "redux-thunk": "2.0.1", "sass-lint": "1.5.1", diff --git a/src/components/forms/checkbox-group.jsx b/src/components/forms/checkbox-group.jsx index 87b08d41e..30fd85c7a 100644 --- a/src/components/forms/checkbox-group.jsx +++ b/src/components/forms/checkbox-group.jsx @@ -1,7 +1,7 @@ var classNames = require('classnames'); var FRCCheckboxGroup = require('formsy-react-components').CheckboxGroup; var React = require('react'); -var validateMixin = require('./validateMixin.jsx'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; var CheckboxGroup = React.createClass({ type: 'CheckboxGroup', @@ -16,4 +16,4 @@ var CheckboxGroup = React.createClass({ } }); -module.exports = validateMixin(CheckboxGroup); +module.exports = defaultValidationHOC(CheckboxGroup); diff --git a/src/components/forms/checkbox.jsx b/src/components/forms/checkbox.jsx index 38abfdd45..4363b24fe 100644 --- a/src/components/forms/checkbox.jsx +++ b/src/components/forms/checkbox.jsx @@ -1,7 +1,7 @@ var classNames = require('classnames'); var FRCCheckbox = require('formsy-react-components').Checkbox; var React = require('react'); -var validateMixin = require('./validateMixin.jsx'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; var Checkbox = React.createClass({ type: 'Checkbox', @@ -16,4 +16,4 @@ var Checkbox = React.createClass({ } }); -module.exports = validateMixin(Checkbox); +module.exports = defaultValidationHOC(Checkbox); diff --git a/src/components/forms/form.jsx b/src/components/forms/form.jsx index 319c559f4..b9811b075 100644 --- a/src/components/forms/form.jsx +++ b/src/components/forms/form.jsx @@ -1,7 +1,7 @@ var classNames = require('classnames'); var Formsy = require('formsy-react'); var React = require('react'); -var validations = require('./validations'); +var validations = require('./validations.jsx').validations; for (var validation in validations) { Formsy.addValidationRule(validation, validations[validation]); diff --git a/src/components/forms/input.jsx b/src/components/forms/input.jsx index 0b06c5438..23bea730e 100644 --- a/src/components/forms/input.jsx +++ b/src/components/forms/input.jsx @@ -1,7 +1,7 @@ var classNames = require('classnames'); var FRCInput = require('formsy-react-components').Input; var React = require('react'); -var validateMixin = require('./validateMixin.jsx'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; require('./input.scss'); @@ -22,4 +22,4 @@ var Input = React.createClass({ } }); -module.exports = validateMixin(Input); +module.exports = defaultValidationHOC(Input); diff --git a/src/components/forms/phone-input.jsx b/src/components/forms/phone-input.jsx new file mode 100644 index 000000000..16c11bdba --- /dev/null +++ b/src/components/forms/phone-input.jsx @@ -0,0 +1,55 @@ +var classNames = require('classnames'); +var React = require('react'); +var FormsyMixin = require('formsy-react').Mixin; +var ReactPhoneInput = require('react-telephone-input/lib/withStyles'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var validationHOCFactory = require('./validations.jsx').validationHOCFactory; +var Row = require('formsy-react-components').Row; +var ComponentMixin = require('formsy-react-components').ComponentMixin; + +var PhoneInput = React.createClass({ + displayName: 'PhoneInput', + mixins: [ + FormsyMixin, + ComponentMixin + ], + getDefaultProps: function () { + return { + validations: { + isPhone: true + }, + flagsImagePath: '/images/flags.png' + }; + }, + onChangeInput: function (number, country) { + var value = {national_number: number, country_code: country}; + this.setValue(value); + this.props.onChange(this.props.name, value); + }, + render: function () { + return ( + +
+ +
+ {this.renderHelp()} + {this.renderErrorMessage()} +
+ ); + } +}); + +var phoneValidationHOC = validationHOCFactory({ + isPhone: 'Please enter a valid phone number' +}); + +module.exports = defaultValidationHOC(phoneValidationHOC(PhoneInput)); diff --git a/src/components/forms/radio-group.jsx b/src/components/forms/radio-group.jsx index 430b27e59..8f2a99033 100644 --- a/src/components/forms/radio-group.jsx +++ b/src/components/forms/radio-group.jsx @@ -1,7 +1,7 @@ var classNames = require('classnames'); var FRCRadioGroup = require('formsy-react-components').RadioGroup; var React = require('react'); -var validateMixin = require('./validateMixin.jsx'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; var RadioGroup = React.createClass({ type: 'RadioGroup', @@ -16,4 +16,4 @@ var RadioGroup = React.createClass({ } }); -module.exports = validateMixin(RadioGroup); +module.exports = defaultValidationHOC(RadioGroup); diff --git a/src/components/forms/select.jsx b/src/components/forms/select.jsx index d87e76c14..9ddab75dd 100644 --- a/src/components/forms/select.jsx +++ b/src/components/forms/select.jsx @@ -2,7 +2,7 @@ var classNames = require('classnames'); var defaults = require('lodash.defaultsdeep'); var FRCSelect = require('formsy-react-components').Select; var React = require('react'); -var validateMixin = require('./validateMixin.jsx'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; require('./select.scss'); @@ -26,4 +26,4 @@ var Select = React.createClass({ } }); -module.exports = validateMixin(Select); +module.exports = defaultValidationHOC(Select); diff --git a/src/components/forms/textarea.jsx b/src/components/forms/textarea.jsx index 56c1a8c25..f317e220e 100644 --- a/src/components/forms/textarea.jsx +++ b/src/components/forms/textarea.jsx @@ -1,7 +1,7 @@ var classNames = require('classnames'); var FRCTextarea = require('formsy-react-components').Textarea; var React = require('react'); -var validateMixin = require('./validateMixin.jsx'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; require('./textarea.scss'); @@ -18,4 +18,4 @@ var TextArea = React.createClass({ } }); -module.exports = validateMixin(TextArea); +module.exports = defaultValidationHOC(TextArea); diff --git a/src/components/forms/validateMixin.jsx b/src/components/forms/validateMixin.jsx deleted file mode 100644 index 72bcdc557..000000000 --- a/src/components/forms/validateMixin.jsx +++ /dev/null @@ -1,24 +0,0 @@ -var defaults = require('lodash.defaultsdeep'); -var React = require('react'); - -var validateMixin = function (Component) { - var ValidatedComponent = React.createClass({ - getDefaultValidationErrors: function () { - return { - isDefaultRequiredValue: 'This field is required' - }; - }, - render: function () { - var validationErrors = defaults( - this.getDefaultValidationErrors(), - this.props.validationErrors - ); - return ( - - ); - } - }); - return ValidatedComponent; -}; - -module.exports = validateMixin; diff --git a/src/components/forms/validations.js b/src/components/forms/validations.js deleted file mode 100644 index 38985788c..000000000 --- a/src/components/forms/validations.js +++ /dev/null @@ -1,10 +0,0 @@ -var Validations = { - notEquals: function (values, value, neq) { - return value !== neq; - }, - notEqualsField: function (values, value, field) { - return value !== values[field]; - } -}; - -module.exports = Validations; diff --git a/src/components/forms/validations.jsx b/src/components/forms/validations.jsx new file mode 100644 index 000000000..db0b71632 --- /dev/null +++ b/src/components/forms/validations.jsx @@ -0,0 +1,46 @@ +var defaults = require('lodash.defaultsdeep'); +var libphonenumber = require('google-libphonenumber'); +var phoneNumberUtil = libphonenumber.PhoneNumberUtil.getInstance(); +var React = require('react'); + +module.exports = {}; + +module.exports.validations = { + notEquals: function (values, value, neq) { + return value !== neq; + }, + notEqualsField: function (values, value, field) { + return value !== values[field]; + }, + isPhone: function (values, value) { + if (typeof value === 'undefined') return true; + if (value && value.national_number === '+') return true; + try { + var parsed = phoneNumberUtil.parse(value.national_number, value.country_code.iso2); + } catch (err) { + return false; + } + return phoneNumberUtil.isValidNumber(parsed); + } +}; + +module.exports.validationHOCFactory = function (defaultValidationErrors) { + return function (Component) { + var ValidatedComponent = React.createClass({ + render: function () { + var validationErrors = defaults( + defaultValidationErrors, + this.props.validationErrors + ); + return ( + + ); + } + }); + return ValidatedComponent; + }; +}; + +module.exports.defaultValidationHOC = module.exports.validationHOCFactory({ + isDefaultRequiredValue: 'This field is required' +}); diff --git a/src/views/teacherregistration/teacherregistration.jsx b/src/views/teacherregistration/teacherregistration.jsx index 75091356e..74933704c 100644 --- a/src/views/teacherregistration/teacherregistration.jsx +++ b/src/views/teacherregistration/teacherregistration.jsx @@ -13,6 +13,7 @@ var FormSet = formset.FormSet; var FormStep = formset.FormStep; var Input = require('../../components/forms/input.jsx'); var Page = require('../../components/page/www/page.jsx'); +var PhoneInput = require('../../components/forms/phone-input.jsx'); var RadioGroup = require('../../components/forms/radio-group.jsx'); var Select = require('../../components/forms/select.jsx'); var TextArea = require('../../components/forms/textarea.jsx'); @@ -152,7 +153,10 @@ var PhoneNumberStep = React.createClass({ Why do we ask for this information ?

}>
- +