mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-22 15:17:53 -05:00
Add international phone validation
This commit is contained in:
parent
bcda082014
commit
fe74208f32
15 changed files with 127 additions and 49 deletions
|
@ -47,6 +47,7 @@
|
||||||
"formsy-react-components": "0.7.1",
|
"formsy-react-components": "0.7.1",
|
||||||
"git-bundle-sha": "0.0.2",
|
"git-bundle-sha": "0.0.2",
|
||||||
"glob": "5.0.15",
|
"glob": "5.0.15",
|
||||||
|
"google-libphonenumber": "1.0.21",
|
||||||
"json-loader": "0.5.2",
|
"json-loader": "0.5.2",
|
||||||
"json2po-stream": "1.0.3",
|
"json2po-stream": "1.0.3",
|
||||||
"jsx-loader": "0.13.2",
|
"jsx-loader": "0.13.2",
|
||||||
|
@ -69,6 +70,7 @@
|
||||||
"react-onclickoutside": "4.1.1",
|
"react-onclickoutside": "4.1.1",
|
||||||
"react-redux": "4.4.5",
|
"react-redux": "4.4.5",
|
||||||
"react-slick": "0.12.2",
|
"react-slick": "0.12.2",
|
||||||
|
"react-telephone-input": "3.4.5",
|
||||||
"redux": "3.5.2",
|
"redux": "3.5.2",
|
||||||
"redux-thunk": "2.0.1",
|
"redux-thunk": "2.0.1",
|
||||||
"sass-lint": "1.5.1",
|
"sass-lint": "1.5.1",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var FRCCheckboxGroup = require('formsy-react-components').CheckboxGroup;
|
var FRCCheckboxGroup = require('formsy-react-components').CheckboxGroup;
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var validateMixin = require('./validateMixin.jsx');
|
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||||
|
|
||||||
var CheckboxGroup = React.createClass({
|
var CheckboxGroup = React.createClass({
|
||||||
type: 'CheckboxGroup',
|
type: 'CheckboxGroup',
|
||||||
|
@ -16,4 +16,4 @@ var CheckboxGroup = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = validateMixin(CheckboxGroup);
|
module.exports = defaultValidationHOC(CheckboxGroup);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var FRCCheckbox = require('formsy-react-components').Checkbox;
|
var FRCCheckbox = require('formsy-react-components').Checkbox;
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var validateMixin = require('./validateMixin.jsx');
|
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||||
|
|
||||||
var Checkbox = React.createClass({
|
var Checkbox = React.createClass({
|
||||||
type: 'Checkbox',
|
type: 'Checkbox',
|
||||||
|
@ -16,4 +16,4 @@ var Checkbox = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = validateMixin(Checkbox);
|
module.exports = defaultValidationHOC(Checkbox);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var Formsy = require('formsy-react');
|
var Formsy = require('formsy-react');
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var validations = require('./validations');
|
var validations = require('./validations.jsx').validations;
|
||||||
|
|
||||||
for (var validation in validations) {
|
for (var validation in validations) {
|
||||||
Formsy.addValidationRule(validation, validations[validation]);
|
Formsy.addValidationRule(validation, validations[validation]);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var FRCInput = require('formsy-react-components').Input;
|
var FRCInput = require('formsy-react-components').Input;
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var validateMixin = require('./validateMixin.jsx');
|
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||||
|
|
||||||
require('./input.scss');
|
require('./input.scss');
|
||||||
|
|
||||||
|
@ -22,4 +22,4 @@ var Input = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = validateMixin(Input);
|
module.exports = defaultValidationHOC(Input);
|
||||||
|
|
55
src/components/forms/phone-input.jsx
Normal file
55
src/components/forms/phone-input.jsx
Normal file
|
@ -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 (
|
||||||
|
<Row {... this.getRowProperties()}
|
||||||
|
htmlFor={this.getId()}
|
||||||
|
className={classNames('phone-input', this.props.className)}
|
||||||
|
>
|
||||||
|
<div className="input-group">
|
||||||
|
<ReactPhoneInput className="form-control"
|
||||||
|
{... this.props}
|
||||||
|
onChange={this.onChangeInput}
|
||||||
|
id={this.getId()}
|
||||||
|
label={null}
|
||||||
|
disabled={this.isFormDisabled() || this.props.disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{this.renderHelp()}
|
||||||
|
{this.renderErrorMessage()}
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var phoneValidationHOC = validationHOCFactory({
|
||||||
|
isPhone: 'Please enter a valid phone number'
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = defaultValidationHOC(phoneValidationHOC(PhoneInput));
|
|
@ -1,7 +1,7 @@
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var FRCRadioGroup = require('formsy-react-components').RadioGroup;
|
var FRCRadioGroup = require('formsy-react-components').RadioGroup;
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var validateMixin = require('./validateMixin.jsx');
|
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||||
|
|
||||||
var RadioGroup = React.createClass({
|
var RadioGroup = React.createClass({
|
||||||
type: 'RadioGroup',
|
type: 'RadioGroup',
|
||||||
|
@ -16,4 +16,4 @@ var RadioGroup = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = validateMixin(RadioGroup);
|
module.exports = defaultValidationHOC(RadioGroup);
|
||||||
|
|
|
@ -2,7 +2,7 @@ var classNames = require('classnames');
|
||||||
var defaults = require('lodash.defaultsdeep');
|
var defaults = require('lodash.defaultsdeep');
|
||||||
var FRCSelect = require('formsy-react-components').Select;
|
var FRCSelect = require('formsy-react-components').Select;
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var validateMixin = require('./validateMixin.jsx');
|
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||||
|
|
||||||
require('./select.scss');
|
require('./select.scss');
|
||||||
|
|
||||||
|
@ -26,4 +26,4 @@ var Select = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = validateMixin(Select);
|
module.exports = defaultValidationHOC(Select);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var FRCTextarea = require('formsy-react-components').Textarea;
|
var FRCTextarea = require('formsy-react-components').Textarea;
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var validateMixin = require('./validateMixin.jsx');
|
var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC;
|
||||||
|
|
||||||
require('./textarea.scss');
|
require('./textarea.scss');
|
||||||
|
|
||||||
|
@ -18,4 +18,4 @@ var TextArea = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = validateMixin(TextArea);
|
module.exports = defaultValidationHOC(TextArea);
|
||||||
|
|
|
@ -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 (
|
|
||||||
<Component {...this.props} validationErrors={validationErrors} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ValidatedComponent;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = validateMixin;
|
|
|
@ -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;
|
|
46
src/components/forms/validations.jsx
Normal file
46
src/components/forms/validations.jsx
Normal file
|
@ -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 (
|
||||||
|
<Component {...this.props} validationErrors={validationErrors} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ValidatedComponent;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.defaultValidationHOC = module.exports.validationHOCFactory({
|
||||||
|
isDefaultRequiredValue: 'This field is required'
|
||||||
|
});
|
|
@ -13,6 +13,7 @@ var FormSet = formset.FormSet;
|
||||||
var FormStep = formset.FormStep;
|
var FormStep = formset.FormStep;
|
||||||
var Input = require('../../components/forms/input.jsx');
|
var Input = require('../../components/forms/input.jsx');
|
||||||
var Page = require('../../components/page/www/page.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 RadioGroup = require('../../components/forms/radio-group.jsx');
|
||||||
var Select = require('../../components/forms/select.jsx');
|
var Select = require('../../components/forms/select.jsx');
|
||||||
var TextArea = require('../../components/forms/textarea.jsx');
|
var TextArea = require('../../components/forms/textarea.jsx');
|
||||||
|
@ -152,7 +153,10 @@ var PhoneNumberStep = React.createClass({
|
||||||
Why do we ask for this information <a onClick={this.handle}>?</a>
|
Why do we ask for this information <a onClick={this.handle}>?</a>
|
||||||
</p>}>
|
</p>}>
|
||||||
<Form onValidSubmit={this.props.onNextStep}>
|
<Form onValidSubmit={this.props.onNextStep}>
|
||||||
<Input label="Phone Number" type="tel" name="phone" required />
|
<PhoneInput label="Phone Number"
|
||||||
|
name="phone"
|
||||||
|
defaultCountry="us"
|
||||||
|
required />
|
||||||
<Checkbox label={
|
<Checkbox label={
|
||||||
'Yes, I consent to lorem ipsum dolor sit amet, consectetur' +
|
'Yes, I consent to lorem ipsum dolor sit amet, consectetur' +
|
||||||
'adipiscing elit.'
|
'adipiscing elit.'
|
||||||
|
|
BIN
static/images/flags.png
Normal file
BIN
static/images/flags.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
|
@ -79,11 +79,16 @@ module.exports = {
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
loader: 'style!css!postcss-loader!sass'
|
loader: 'style!css!postcss-loader!sass'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
loader: 'style!css!postcss-loader'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|jpg|gif|eot|svg|ttf|woff)$/,
|
test: /\.(png|jpg|gif|eot|svg|ttf|woff)$/,
|
||||||
loader: 'url-loader'
|
loader: 'url-loader'
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
noParse: /node_modules\/google-libphonenumber\/dist/
|
||||||
},
|
},
|
||||||
postcss: function () {
|
postcss: function () {
|
||||||
return [autoprefixer({browsers: ['last 3 versions']})];
|
return [autoprefixer({browsers: ['last 3 versions']})];
|
||||||
|
|
Loading…
Reference in a new issue