diff --git a/client/src/app/main/main-home/main-home-page-login-widget.scss b/client/src/app/main/main-home/main-home-page-login-widget.scss index 248ae7f2..117fc2e2 100644 --- a/client/src/app/main/main-home/main-home-page-login-widget.scss +++ b/client/src/app/main/main-home/main-home-page-login-widget.scss @@ -4,10 +4,6 @@ height: 361px; } - &__input { - margin: 10px 0; - } - &__inputs { display: inline-block; margin: 0 auto 20px; diff --git a/client/src/app/main/main-recover-password/main-recover-password-page.scss b/client/src/app/main/main-recover-password/main-recover-password-page.scss index 59cae9b5..d492e74a 100644 --- a/client/src/app/main/main-recover-password/main-recover-password-page.scss +++ b/client/src/app/main/main-recover-password/main-recover-password-page.scss @@ -1,14 +1,10 @@ .recover-password { &__inputs { display: inline-block; - margin: 0 auto 20px; + margin: 0 auto 10px; text-align: left; } - &__input { - margin: 10px 0 0 0; - } - &__submit-button { margin-bottom: 40px; } diff --git a/client/src/app/main/main-signup/main-signup-page.js b/client/src/app/main/main-signup/main-signup-page.js index 23b2e76e..a4b9eb57 100644 --- a/client/src/app/main/main-signup/main-signup-page.js +++ b/client/src/app/main/main-signup/main-signup-page.js @@ -24,17 +24,17 @@ let MainSignUpPageWidget = React.createClass({ render() { return (
- + -
-
- - - - + +
+ + + +
-
- +
+
@@ -47,7 +47,7 @@ let MainSignUpPageWidget = React.createClass({ getInputProps() { return { inputType: 'secondary', - className: 'signup-widget-input' + className: 'signup-widget__input' } }, diff --git a/client/src/app/main/main-signup/main-signup-page.scss b/client/src/app/main/main-signup/main-signup-page.scss index a4d0fe5a..d2018cb5 100644 --- a/client/src/app/main/main-signup/main-signup-page.scss +++ b/client/src/app/main/main-signup/main-signup-page.scss @@ -1,26 +1,17 @@ .main-signup-page { - - &--widget-container { - height: 525px; - width: 364px; - } + height: 629px; .signup-widget { padding: 30px; text-align: center; - &--inputs { + &__inputs { display: inline-block; margin: 0 auto; } - &--input { - margin-bottom: 5px; - } - - &--captcha { - margin-top: 30px; - margin-bottom: 20px; + &__captcha { + margin: 20px 0; height: 78px; width: 304px; } diff --git a/client/src/core-components/__tests__/form-test.js b/client/src/core-components/__tests__/form-test.js index ea1e1f7a..46136923 100644 --- a/client/src/core-components/__tests__/form-test.js +++ b/client/src/core-components/__tests__/form-test.js @@ -25,8 +25,8 @@ describe('Form component', function () { } function resetStubs() { - ValidationFactoryMock.validators.defaultValidatorMock.validate = stub(); - ValidationFactoryMock.validators.customValidatorMock.validate = stub(); + ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub(); + ValidationFactoryMock.validators.customValidatorMock.performValidation = stub(); ValidationFactoryMock.getValidator.reset(); onSubmit.reset(); } @@ -84,8 +84,8 @@ describe('Form component', function () { }); it('should validate required fields when blurring', function () { - ValidationFactoryMock.validators.defaultValidatorMock.validate = stub().returns('MOCK_ERROR'); - ValidationFactoryMock.validators.customValidatorMock.validate = stub().returns('MOCK_ERROR_2'); + ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub().returns('MOCK_ERROR'); + ValidationFactoryMock.validators.customValidatorMock.performValidation = stub().returns('MOCK_ERROR_2'); expect(fields[0].props.error).to.equal(undefined); expect(fields[0].props.error).to.equal(undefined); expect(fields[0].props.error).to.equal(undefined); @@ -107,8 +107,8 @@ describe('Form component', function () { beforeEach(function () { onValidateErrors = stub(); - ValidationFactoryMock.validators.defaultValidatorMock.validate = stub().returns('MOCK_ERROR'); - ValidationFactoryMock.validators.customValidatorMock.validate = stub().returns('MOCK_ERROR_2'); + ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub().returns('MOCK_ERROR'); + ValidationFactoryMock.validators.customValidatorMock.performValidation = stub().returns('MOCK_ERROR_2'); renderForm({ errors: {first: 'MOCK_ERROR_CONTROLLED'}, @@ -172,8 +172,8 @@ describe('Form component', function () { }); it('should validate all fields and not call onSubmit if there are errors', function () { - ValidationFactoryMock.validators.defaultValidatorMock.validate = stub().returns('MOCK_ERROR'); - ValidationFactoryMock.validators.customValidatorMock.validate = stub().returns('MOCK_ERROR_2'); + ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub().returns('MOCK_ERROR'); + ValidationFactoryMock.validators.customValidatorMock.performValidation = stub().returns('MOCK_ERROR_2'); fields[0].focus = spy(fields[0].focus); fields[1].focus = spy(fields[1].focus); @@ -186,15 +186,15 @@ describe('Form component', function () { }); it('should focus the first field with error', function () { - ValidationFactoryMock.validators.defaultValidatorMock.validate = stub().returns('MOCK_ERROR'); - ValidationFactoryMock.validators.customValidatorMock.validate = stub().returns('MOCK_ERROR_2'); + ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub().returns('MOCK_ERROR'); + ValidationFactoryMock.validators.customValidatorMock.performValidation = stub().returns('MOCK_ERROR_2'); fields[0].focus = spy(fields[0].focus); fields[1].focus = spy(fields[1].focus); TestUtils.Simulate.submit(ReactDOM.findDOMNode(form)); expect(fields[0].focus).to.have.been.called; - ValidationFactoryMock.validators.defaultValidatorMock.validate = stub(); + ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub(); fields[0].focus.reset(); fields[1].focus.reset(); diff --git a/client/src/core-components/form.js b/client/src/core-components/form.js index 91409714..36922806 100644 --- a/client/src/core-components/form.js +++ b/client/src/core-components/form.js @@ -1,5 +1,6 @@ const React = require('react'); const _ = require('lodash'); +const classNames = require('classnames'); const {reactDFS, renderChildrenWithProps} = require('lib-core/react-dfs'); const ValidationFactory = require('lib-app/validations/validations-factory'); @@ -49,8 +50,9 @@ const Form = React.createClass({ getProps() { let props = _.clone(this.props); + props.className = this.getClass(); props.onSubmit = this.handleSubmit; - + delete props.errors; delete props.loading; delete props.onValidateErrors; @@ -58,6 +60,16 @@ const Form = React.createClass({ return props; }, + getClass() { + let classes = { + 'form': true + }; + + classes[this.props.className] = (this.props.className); + + return classNames(classes); + }, + getFieldProps({props, type}) { let additionalProps = {}; @@ -112,7 +124,7 @@ const Form = React.createClass({ let newErrors = _.clone(errors); if (this.state.validations[fieldName]) { - newErrors[fieldName] = this.state.validations[fieldName].validate(form[fieldName], form); + newErrors[fieldName] = this.state.validations[fieldName].performValidation(form[fieldName], form); } return newErrors; diff --git a/client/src/core-components/form.scss b/client/src/core-components/form.scss new file mode 100644 index 00000000..cc2c9aac --- /dev/null +++ b/client/src/core-components/form.scss @@ -0,0 +1,5 @@ +.form { + .input { + margin-bottom: 20px; + } +} \ No newline at end of file diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 41d85727..1a24eea4 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -15,6 +15,7 @@ export default { //ERRORS 'ERROR_EMPTY': 'Invalid value', 'ERROR_PASSWORD': 'Invalid password', + 'ERROR_NAME': 'Invalid name', 'ERROR_EMAIL': 'Invalid email', 'PASSWORD_NOT_MATCH': 'Password does not match' }; \ No newline at end of file diff --git a/client/src/lib-app/__mocks__/validations/validation-factory-mock.js b/client/src/lib-app/__mocks__/validations/validation-factory-mock.js index 0724ac1a..e5b0d761 100644 --- a/client/src/lib-app/__mocks__/validations/validation-factory-mock.js +++ b/client/src/lib-app/__mocks__/validations/validation-factory-mock.js @@ -1,5 +1,5 @@ -let customValidatorMock = {validate: stub()}; -let defaultValidatorMock = {validate: stub()}; +let customValidatorMock = {performValidation: stub(), validate: stub()}; +let defaultValidatorMock = {performValidation: stub(), validate: stub()}; export default { getValidator: spy(function (validation) { diff --git a/client/src/lib-app/validations/alphanumeric-validator.js b/client/src/lib-app/validations/alphanumeric-validator.js new file mode 100644 index 00000000..3336491e --- /dev/null +++ b/client/src/lib-app/validations/alphanumeric-validator.js @@ -0,0 +1,17 @@ +import Validator from 'lib-app/validations/validator'; + +class AlphaNumericValidator extends Validator { + constructor(errorKey = 'INVALID_VALUE', validator = null) { + super(validator); + + this.errorKey = errorKey; + } + + validate(value, form) { + let alphaMatch = /^[-\sa-zA-Z.]+$/; + + if (!alphaMatch.test(value)) return this.getError(this.errorKey); + } +} + +export default AlphaNumericValidator; \ No newline at end of file diff --git a/client/src/lib-app/validations/email-validator.js b/client/src/lib-app/validations/email-validator.js index 9cba77b8..56f02852 100644 --- a/client/src/lib-app/validations/email-validator.js +++ b/client/src/lib-app/validations/email-validator.js @@ -3,8 +3,9 @@ import Validator from 'lib-app/validations/validator'; class EmailValidator extends Validator { validate(value, form) { - if (value.length < 6) return this.getError('ERROR_EMAIL'); - if (value.indexOf('@') === -1) return this.getError('ERROR_EMAIL'); + let emailMatch = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + + if (!emailMatch.test(value)) return this.getError('ERROR_EMAIL'); } } diff --git a/client/src/lib-app/validations/length-validator.js b/client/src/lib-app/validations/length-validator.js index 2d68dae5..b91e3e16 100644 --- a/client/src/lib-app/validations/length-validator.js +++ b/client/src/lib-app/validations/length-validator.js @@ -1,8 +1,8 @@ import Validator from 'lib-app/validations/validator'; class LengthValidator extends Validator { - constructor(length, errorKey = 'INVALID_VALUE') { - super(); + constructor(length, errorKey = 'INVALID_VALUE', validator = null) { + super(validator); this.minlength = length; this.errorKey = errorKey; diff --git a/client/src/lib-app/validations/validations-factory.js b/client/src/lib-app/validations/validations-factory.js index 355077c9..00e443f9 100644 --- a/client/src/lib-app/validations/validations-factory.js +++ b/client/src/lib-app/validations/validations-factory.js @@ -1,10 +1,12 @@ import Validator from 'lib-app/validations/validator'; +import AlphaNumericValidator from 'lib-app/validations/alphanumeric-validator'; import EmailValidator from 'lib-app/validations/email-validator'; import RepeatPasswordValidator from 'lib-app/validations/repeat-password-validator'; import LengthValidator from 'lib-app/validations/length-validator'; let validators = { 'DEFAULT': new Validator(), + 'NAME': new AlphaNumericValidator('ERROR_NAME', new LengthValidator(2, 'ERROR_NAME')), 'EMAIL': new EmailValidator(), 'PASSWORD': new LengthValidator(6, 'ERROR_PASSWORD'), 'REPEAT_PASSWORD': new RepeatPasswordValidator() diff --git a/client/src/lib-app/validations/validator.js b/client/src/lib-app/validations/validator.js index 62659891..5eeb7e35 100644 --- a/client/src/lib-app/validations/validator.js +++ b/client/src/lib-app/validations/validator.js @@ -1,6 +1,22 @@ const i18n = require('lib-app/i18n'); class Validator { + constructor(validator = null) { + this.previousValidator = validator; + } + + performValidation(value, form) { + let error; + + error = this.validate(value, form); + + if (this.previousValidator && !error) { + error = this.previousValidator.validate(value, form); + } + + return error; + } + validate(value, form) { if (!value.length) return this.getError('ERROR_EMPTY'); }