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",
|
||||
"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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
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 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 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 <a onClick={this.handle}>?</a>
|
||||
</p>}>
|
||||
<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={
|
||||
'Yes, I consent to lorem ipsum dolor sit amet, consectetur' +
|
||||
'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$/,
|
||||
loader: 'style!css!postcss-loader!sass'
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: 'style!css!postcss-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif|eot|svg|ttf|woff)$/,
|
||||
loader: 'url-loader'
|
||||
}
|
||||
]
|
||||
],
|
||||
noParse: /node_modules\/google-libphonenumber\/dist/
|
||||
},
|
||||
postcss: function () {
|
||||
return [autoprefixer({browsers: ['last 3 versions']})];
|
||||
|
|
Loading…
Reference in a new issue