diff options
author | Tayane Fernandes <tayane.rmf@gmail.com> | 2017-03-13 14:04:59 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-13 14:04:59 -0300 |
commit | ed15fdb62afb97af406fe35cc17da5d3790b7bd4 (patch) | |
tree | 34dad5108dce0b96d940792a98cb572646e5db35 /web-ui | |
parent | 67d7d84fea07d64800a2b04a379aaa2a103b4a39 (diff) | |
parent | 471b58e945613956db951b3a7b87c9c528b152a4 (diff) |
Merge pull request #1006 from pixelated/validate-email
Email validation on the backup account page
Diffstat (limited to 'web-ui')
-rw-r--r-- | web-ui/app/locales/en_US/translation.json | 5 | ||||
-rw-r--r-- | web-ui/app/locales/pt_BR/translation.json | 5 | ||||
-rw-r--r-- | web-ui/package.json | 1 | ||||
-rw-r--r-- | web-ui/src/backup_account/page.js | 81 | ||||
-rw-r--r-- | web-ui/src/backup_account/page.scss | 5 | ||||
-rw-r--r-- | web-ui/src/backup_account/page.spec.js | 55 | ||||
-rw-r--r-- | web-ui/src/common/input_field/input_field.js | 1 | ||||
-rw-r--r-- | web-ui/src/common/submit_button/submit_button.js | 33 | ||||
-rw-r--r-- | web-ui/src/common/submit_button/submit_button.scss | 8 | ||||
-rw-r--r-- | web-ui/src/common/submit_button/submit_button.spec.js | 6 | ||||
-rw-r--r-- | web-ui/test/integration/backup_account.spec.js | 59 |
11 files changed, 216 insertions, 43 deletions
diff --git a/web-ui/app/locales/en_US/translation.json b/web-ui/app/locales/en_US/translation.json index 3f050e67..9df1867e 100644 --- a/web-ui/app/locales/en_US/translation.json +++ b/web-ui/app/locales/en_US/translation.json @@ -86,7 +86,10 @@ "paragraph1": "You will need a backup account. Choose an alternative email address you use regularly.", "paragraph2": "Instructions to recover your password will be sent to this email address, save it.", "input-label": "Type your backup account", - "button": "Add Account" + "button": "Add Account", + "error": { + "invalid-email": "Please enter a valid email address" + } }, "back-to-inbox": "Back to my inbox", "footer-text": "Product in development. Feedback and issues to", diff --git a/web-ui/app/locales/pt_BR/translation.json b/web-ui/app/locales/pt_BR/translation.json index 431b8f82..ac4fe10d 100644 --- a/web-ui/app/locales/pt_BR/translation.json +++ b/web-ui/app/locales/pt_BR/translation.json @@ -86,7 +86,10 @@ "paragraph1": "Informe outro e-mail que você usa regularmente. Esse será o seu e-mail de recuperação.", "paragraph2": "Instruções para recuperar sua senha serão enviadas para esse e-mail, guarde com carinho.", "input-label": "Digite seu e-mail de recuperação", - "button": "Adicionar e-mail" + "button": "Adicionar e-mail", + "error": { + "invalid-email": "Por favor informe um e-mail válido" + } }, "back-to-inbox": "Voltar", "footer-text": "Produto em desenvolvimento. Reporte problemas através do", diff --git a/web-ui/package.json b/web-ui/package.json index 613613c4..81901c55 100644 --- a/web-ui/package.json +++ b/web-ui/package.json @@ -75,6 +75,7 @@ "typeahead.js": "^0.11.1", "url-loader": "^0.5.7", "utf8": "^2.1.2", + "validator": "^7.0.0", "watch": "0.19.1", "webpack": "^1.14.0" }, diff --git a/web-ui/src/backup_account/page.js b/web-ui/src/backup_account/page.js index cc93a560..c7554cfb 100644 --- a/web-ui/src/backup_account/page.js +++ b/web-ui/src/backup_account/page.js @@ -22,40 +22,65 @@ import SubmitButton from 'src/common/submit_button/submit_button'; import InputField from 'src/common/input_field/input_field'; import Footer from 'src/common/footer/footer'; import Header from 'src/common/header/header'; +import validator from 'validator'; import 'font-awesome/scss/font-awesome.scss'; import './page.scss'; -export const Page = ({ t }) => ( - <DocumentTitle title={t('backup-account.page-title')}> - <div className='page'> - <Header /> - <section> - <div className='container'> - <img - className='backup-account-image' - src='/public/images/forgot-my-password.svg' - alt={t('backup-account.image-description')} - /> - <form> - <h1>{t('backup-account.title')}</h1> - <p>{t('backup-account.paragraph1')}</p> - <p>{t('backup-account.paragraph2')}</p> - <InputField name='email' label={t('backup-account.input-label')} /> - <SubmitButton buttonText={t('backup-account.button')} /> - <div> - <a href='/' className='link'> - <i className='fa fa-angle-left' aria-hidden='true' /> - <span>{t('back-to-inbox')}</span> - </a> + +export class Page extends React.Component { + + constructor(props) { + super(props); + this.state = { error: '', submitButtonDisabled: true }; + this.validateEmail = this.validateEmail.bind(this); + } + + validateEmail(event) { + const validEmail = validator.isEmail(event.target.value); + const emptyEmail = validator.isEmpty(event.target.value); + const t = this.props.t; + this.setState({ + error: !emptyEmail && !validEmail ? t('backup-account.error.invalid-email') : '', + submitButtonDisabled: !validEmail || emptyEmail + }); + } + + render() { + const t = this.props.t; + return ( + <DocumentTitle title={t('backup-account.page-title')}> + <div className='page'> + <Header /> + <section> + <div className='container'> + <img + className='backup-account-image' + src='/public/images/forgot-my-password.svg' + alt={t('backup-account.image-description')} + /> + <form> + <h1>{t('backup-account.title')}</h1> + <p>{t('backup-account.paragraph1')}</p> + <p>{t('backup-account.paragraph2')}</p> + <InputField name='email' label={t('backup-account.input-label')} errorText={this.state.error} onChange={this.validateEmail} /> + <SubmitButton buttonText={t('backup-account.button')} disabled={this.state.submitButtonDisabled} /> + <div className='link-content'> + <a href='/' className='link'> + <i className='fa fa-angle-left' aria-hidden='true' /> + <span>{t('back-to-inbox')}</span> + </a> + </div> + </form> </div> - </form> + </section> + <Footer /> </div> - </section> - <Footer /> - </div> - </DocumentTitle> -); + </DocumentTitle> + ); + } +} + Page.propTypes = { t: React.PropTypes.func.isRequired diff --git a/web-ui/src/backup_account/page.scss b/web-ui/src/backup_account/page.scss index 9d94c156..aa973fcd 100644 --- a/web-ui/src/backup_account/page.scss +++ b/web-ui/src/backup_account/page.scss @@ -101,7 +101,7 @@ p { display: flex; flex-direction: column; - div { + .input-field-group, .submit-button, .link-content { width: 70%; align-self: center; } @@ -119,8 +119,9 @@ p { form { margin-left: 2.5em; + min-height: 492px; - div { + .input-field-group, .submit-button, .link-content { width: 300px; align-self: flex-start; } diff --git a/web-ui/src/backup_account/page.spec.js b/web-ui/src/backup_account/page.spec.js index ece61336..334d3ba8 100644 --- a/web-ui/src/backup_account/page.spec.js +++ b/web-ui/src/backup_account/page.spec.js @@ -22,4 +22,59 @@ describe('BackupAccount', () => { it('renders backup account submit button', () => { expect(page.find('SubmitButton').props().buttonText).toEqual('backup-account.button'); }); + + describe('Email validation', () => { + let pageInstance; + + beforeEach(() => { + pageInstance = page.instance(); + }); + + it('verify initial state', () => { + expect(pageInstance.state.error).toEqual(''); + expect(page.find('SubmitButton').props().disabled).toEqual(true); + }); + + context('with invalid email', () => { + beforeEach(() => { + pageInstance.validateEmail({ target: { value: 'test' } }); + }); + + it('sets error in state', () => { + expect(pageInstance.state.error).toEqual('backup-account.error.invalid-email'); + }); + + it('disables submit button', () => { + expect(page.find('SubmitButton').props().disabled).toEqual(true); + }); + }); + + context('with valid email', () => { + beforeEach(() => { + pageInstance.validateEmail({ target: { value: 'test@test.com' } }); + }); + + it('does not set error in state', () => { + expect(pageInstance.state.error).toEqual(''); + }); + + it('submit button is enabled', () => { + expect(page.find('SubmitButton').props().disabled).toEqual(false); + }); + }); + + context('with empty email', () => { + beforeEach(() => { + pageInstance.validateEmail({ target: { value: '' } }); + }); + + it('not set error in state', () => { + expect(pageInstance.state.error).toEqual(''); + }); + + it('disables submit button', () => { + expect(page.find('SubmitButton').props().disabled).toEqual(true); + }); + }); + }); }); diff --git a/web-ui/src/common/input_field/input_field.js b/web-ui/src/common/input_field/input_field.js index 438241e1..f50fc2b1 100644 --- a/web-ui/src/common/input_field/input_field.js +++ b/web-ui/src/common/input_field/input_field.js @@ -28,6 +28,7 @@ const InputField = ({ label, name, type = 'text', ...other }) => ( name={name} type={type} fullWidth + floatingLabelFocusStyle={{ color: '#178ca6' }} {...other} /> </div> diff --git a/web-ui/src/common/submit_button/submit_button.js b/web-ui/src/common/submit_button/submit_button.js index 4754e042..1224c7bd 100644 --- a/web-ui/src/common/submit_button/submit_button.js +++ b/web-ui/src/common/submit_button/submit_button.js @@ -16,15 +16,42 @@ */ import React from 'react'; +import RaisedButton from 'material-ui/RaisedButton'; import './submit_button.scss'; -const SubmitButton = ({ buttonText }) => ( - <input type='submit' className='submit-button' value={buttonText} /> +const labelStyle = { + textTransform: 'none', + fontSize: '1em', + lineHeight: '48px' +}; + +const buttonStyle = { + height: '48px' +}; + +const SubmitButton = ({ buttonText, disabled = false }) => ( + <div className='submit-button'> + <RaisedButton + type='submit' + label={buttonText} + disabled={disabled} + labelStyle={labelStyle} + buttonStyle={buttonStyle} + overlayStyle={buttonStyle} + fullWidth + primary + /> + </div> ); SubmitButton.propTypes = { - buttonText: React.PropTypes.string.isRequired + buttonText: React.PropTypes.string.isRequired, + disabled: React.PropTypes.bool +}; + +SubmitButton.defaultProps = { + disabled: false }; export default SubmitButton; diff --git a/web-ui/src/common/submit_button/submit_button.scss b/web-ui/src/common/submit_button/submit_button.scss index 13cb7607..851899f7 100644 --- a/web-ui/src/common/submit_button/submit_button.scss +++ b/web-ui/src/common/submit_button/submit_button.scss @@ -18,15 +18,9 @@ @import "~scss/base/colors"; .submit-button { - background: $dark_blue; - padding: 0.8em; - color: $white; - text-align: center; - border: none; - border-radius: 2px; - font-weight: 300; width: 100%; margin-bottom: 1em; + font-size: 1em; } @media only screen and (min-width : 500px) { diff --git a/web-ui/src/common/submit_button/submit_button.spec.js b/web-ui/src/common/submit_button/submit_button.spec.js index 8279547c..0ba8137c 100644 --- a/web-ui/src/common/submit_button/submit_button.spec.js +++ b/web-ui/src/common/submit_button/submit_button.spec.js @@ -11,6 +11,10 @@ describe('SubmitButton', () => { }); it('renders an input of type submit for add email', () => { - expect(submitButton.find('input[type="submit"]').props().value).toEqual('Add Email'); + expect(submitButton.find('RaisedButton').props().label).toEqual('Add Email'); + }); + + it('renders button in enabled state', () => { + expect(submitButton.find('RaisedButton').props().disabled).toEqual(false); }); }); diff --git a/web-ui/test/integration/backup_account.spec.js b/web-ui/test/integration/backup_account.spec.js new file mode 100644 index 00000000..b44c3b2c --- /dev/null +++ b/web-ui/test/integration/backup_account.spec.js @@ -0,0 +1,59 @@ +import { mount } from 'enzyme'; +import expect from 'expect'; +import React from 'react'; +import App from 'src/common/app'; +import BackupAccountPage from 'src/backup_account/page'; +import testI18n from './i18n'; + +describe('Backup account email validation', () => { + context('Backup Account Page', () => { + let app, backupAccountPage; + + beforeEach(() => { + app = mount(<App i18n={testI18n} child={<BackupAccountPage />} />); + backupAccountPage = app.find('Page'); + }); + + context('with valid email', () => { + beforeEach(() => { + backupAccountPage.find('input').simulate('change', {target: {value: 'test@test.com'}}); + }); + + it('shows no validation error', () => { + expect(backupAccountPage.find('InputField').props().errorText).toEqual(''); + }); + + it('submit button is enabled', () => { + expect(backupAccountPage.find('SubmitButton').props().disabled).toEqual(false); + }); + }); + + context('with invalid email', () => { + beforeEach(() => { + backupAccountPage.find('input').simulate('change', {target: {value: 'test'}}); + }); + + it('shows validation error', () => { + expect(backupAccountPage.find('InputField').props().errorText).toEqual('Please enter a valid email address'); + }); + + it('disables submit button', () => { + expect(backupAccountPage.find('SubmitButton').props().disabled).toEqual(true); + }); + }); + + context('with empty email', () => { + beforeEach(() => { + backupAccountPage.find('input').simulate('change', {target: {value: ''}}); + }); + + it('shows no validation error', () => { + expect(backupAccountPage.find('InputField').props().errorText).toEqual(''); + }); + + it('disables submit button', () => { + expect(backupAccountPage.find('SubmitButton').props().disabled).toEqual(true); + }); + }); + }); +}); |