diff options
author | Alexander Tseung <alextsg@gmail.com> | 2018-05-13 11:53:40 +0800 |
---|---|---|
committer | Alexander Tseung <alextsg@gmail.com> | 2018-05-14 12:46:12 +0800 |
commit | 0bcfbc15446b01b3b87233715cd3ead42d2730e4 (patch) | |
tree | 8b39abffed694538464ff00c2471fdc0df25ecd8 /mascara | |
parent | 6bd1b21d3b8f74c44214f814c3fe1c8770ab9e2d (diff) | |
download | tangerine-wallet-browser-0bcfbc15446b01b3b87233715cd3ead42d2730e4.tar tangerine-wallet-browser-0bcfbc15446b01b3b87233715cd3ead42d2730e4.tar.gz tangerine-wallet-browser-0bcfbc15446b01b3b87233715cd3ead42d2730e4.tar.bz2 tangerine-wallet-browser-0bcfbc15446b01b3b87233715cd3ead42d2730e4.tar.lz tangerine-wallet-browser-0bcfbc15446b01b3b87233715cd3ead42d2730e4.tar.xz tangerine-wallet-browser-0bcfbc15446b01b3b87233715cd3ead42d2730e4.tar.zst tangerine-wallet-browser-0bcfbc15446b01b3b87233715cd3ead42d2730e4.zip |
Add error message when passwords don't match in first time flow. Change input field styling in first time flow
Diffstat (limited to 'mascara')
-rw-r--r-- | mascara/src/app/first-time/create-password-screen.js | 133 | ||||
-rw-r--r-- | mascara/src/app/first-time/import-seed-phrase-screen.js | 146 | ||||
-rw-r--r-- | mascara/src/app/first-time/index.css | 33 |
3 files changed, 145 insertions, 167 deletions
diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js index 6ec05e11d..99d210ed1 100644 --- a/mascara/src/app/first-time/create-password-screen.js +++ b/mascara/src/app/first-time/create-password-screen.js @@ -13,8 +13,13 @@ import { INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE, INITIALIZE_NOTICE_ROUTE, } from '../../../../ui/app/routes' +import TextField from '../../../../ui/app/components/text-field' class CreatePasswordScreen extends Component { + static contextTypes = { + t: PropTypes.func, + } + static propTypes = { isLoading: PropTypes.bool.isRequired, createAccount: PropTypes.func.isRequired, @@ -27,6 +32,8 @@ class CreatePasswordScreen extends Component { state = { password: '', confirmPassword: '', + passwordError: null, + confirmPasswordError: null, } constructor (props) { @@ -69,82 +76,37 @@ class CreatePasswordScreen extends Component { .then(() => history.push(INITIALIZE_UNIQUE_IMAGE_ROUTE)) } - renderFields () { - const { isMascara, history } = this.props + handlePasswordChange (password) { + const { confirmPassword } = this.state + let confirmPasswordError = null + let passwordError = null - return ( - <div className={classnames({ 'first-view-main-wrapper': !isMascara })}> - <div className={classnames({ - 'first-view-main': !isMascara, - 'first-view-main__mascara': isMascara, - })}> - {isMascara && <div className="mascara-info first-view-phone-invisible"> - <Mascot - animationEventEmitter={this.animationEventEmitter} - width="225" - height="225" - /> - <div className="info"> - MetaMask is a secure identity vault for Ethereum. - </div> - <div className="info"> - It allows you to hold ether & tokens, and interact with decentralized applications. - </div> - </div>} - <div className="create-password"> - <div className="create-password__title"> - Create Password - </div> - <input - className="first-time-flow__input" - type="password" - placeholder="New Password (min 8 characters)" - onChange={e => this.setState({password: e.target.value})} - /> - <input - className="first-time-flow__input create-password__confirm-input" - type="password" - placeholder="Confirm Password" - onChange={e => this.setState({confirmPassword: e.target.value})} - /> - <button - className="first-time-flow__button" - disabled={!this.isValid()} - onClick={this.createAccount} - > - Create - </button> - <a - href="" - className="first-time-flow__link create-password__import-link" - onClick={e => { - e.preventDefault() - history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE) - }} - > - Import with seed phrase - </a> - { /* } - <a - href="" - className="first-time-flow__link create-password__import-link" - onClick={e => { - e.preventDefault() - history.push(INITIALIZE_IMPORT_ACCOUNT_ROUTE) - }} - > - Import an account - </a> - { */ } - <Breadcrumbs total={3} currentIndex={0} /> - </div> - </div> - </div> - ) + if (password && password.length < 8) { + passwordError = this.context.t('passwordNotLongEnough') + } + + if (confirmPassword && password !== confirmPassword) { + confirmPasswordError = this.context.t('passwordsDontMatch') + } + + this.setState({ password, passwordError, confirmPasswordError }) + } + + handleConfirmPasswordChange (confirmPassword) { + const { password } = this.state + let confirmPasswordError = null + + if (password !== confirmPassword) { + confirmPasswordError = this.context.t('passwordsDontMatch') + } + + this.setState({ confirmPassword, confirmPasswordError }) } render () { const { history, isMascara } = this.props + const { passwordError, confirmPasswordError } = this.state + const { t } = this.context return ( <div className={classnames({ 'first-view-main-wrapper': !isMascara })}> @@ -169,17 +131,30 @@ class CreatePasswordScreen extends Component { <div className="create-password__title"> Create Password </div> - <input - className="first-time-flow__input" + <TextField + id="create-password" + label={t('newPassword')} type="password" - placeholder="New Password (min 8 characters)" - onChange={e => this.setState({password: e.target.value})} + className="first-time-flow__input" + value={this.state.password} + onChange={event => this.handlePasswordChange(event.target.value)} + error={passwordError} + autoFocus + autoComplete="new-password" + margin="normal" + fullWidth /> - <input - className="first-time-flow__input create-password__confirm-input" + <TextField + id="confirm-password" + label={t('confirmPassword')} type="password" - placeholder="Confirm Password" - onChange={e => this.setState({confirmPassword: e.target.value})} + className="first-time-flow__input" + value={this.state.confirmPassword} + onChange={event => this.handleConfirmPasswordChange(event.target.value)} + error={confirmPasswordError} + autoComplete="confirm-password" + margin="normal" + fullWidth /> <button className="first-time-flow__button" diff --git a/mascara/src/app/first-time/import-seed-phrase-screen.js b/mascara/src/app/first-time/import-seed-phrase-screen.js index 5834919de..4fda2bbc1 100644 --- a/mascara/src/app/first-time/import-seed-phrase-screen.js +++ b/mascara/src/app/first-time/import-seed-phrase-screen.js @@ -1,29 +1,33 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' -import classnames from 'classnames' import { createNewVaultAndRestore, - hideWarning, - displayWarning, unMarkPasswordForgotten, } from '../../../../ui/app/actions' -import { DEFAULT_ROUTE, INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes' +import { INITIALIZE_NOTICE_ROUTE } from '../../../../ui/app/routes' +import TextField from '../../../../ui/app/components/text-field' class ImportSeedPhraseScreen extends Component { + static contextTypes = { + t: PropTypes.func, + } + static propTypes = { warning: PropTypes.string, createNewVaultAndRestore: PropTypes.func.isRequired, - hideWarning: PropTypes.func.isRequired, - displayWarning: PropTypes.func, leaveImportSeedScreenState: PropTypes.func, history: PropTypes.object, + isLoading: PropTypes.bool, }; state = { seedPhrase: '', password: '', confirmPassword: '', + seedPhraseError: null, + passwordError: null, + confirmPasswordError: null, } parseSeedPhrase = (seedPhrase) => { @@ -32,39 +36,47 @@ class ImportSeedPhraseScreen extends Component { .join(' ') } - onChange = ({ seedPhrase, password, confirmPassword }) => { - const { - password: prevPassword, - confirmPassword: prevConfirmPassword, - } = this.state - const { displayWarning, hideWarning } = this.props - - let warning = null + handleSeedPhraseChange (seedPhrase) { + let seedPhraseError = null if (seedPhrase && this.parseSeedPhrase(seedPhrase).split(' ').length !== 12) { - warning = 'Seed Phrases are 12 words long' - } else if (password && password.length < 8) { - warning = 'Passwords require a mimimum length of 8' - } else if ((password || prevPassword) !== (confirmPassword || prevConfirmPassword)) { - warning = 'Confirmed password does not match' + seedPhraseError = this.context.t('seedPhraseReq') } - if (warning) { - displayWarning(warning) - } else { - hideWarning() + this.setState({ seedPhrase, seedPhraseError }) + } + + handlePasswordChange (password) { + const { confirmPassword } = this.state + let confirmPasswordError = null + let passwordError = null + + if (password && password.length < 8) { + passwordError = this.context.t('passwordNotLongEnough') + } + + if (confirmPassword && password !== confirmPassword) { + confirmPasswordError = this.context.t('passwordsDontMatch') + } + + this.setState({ password, passwordError, confirmPasswordError }) + } + + handleConfirmPasswordChange (confirmPassword) { + const { password } = this.state + let confirmPasswordError = null + + if (password !== confirmPassword) { + confirmPasswordError = this.context.t('passwordsDontMatch') } - seedPhrase && this.setState({ seedPhrase }) - password && this.setState({ password }) - confirmPassword && this.setState({ confirmPassword }) + this.setState({ confirmPassword, confirmPasswordError }) } onClick = () => { const { password, seedPhrase } = this.state const { createNewVaultAndRestore, - displayWarning, leaveImportSeedScreenState, history, } = this.props @@ -74,10 +86,23 @@ class ImportSeedPhraseScreen extends Component { .then(() => history.push(INITIALIZE_NOTICE_ROUTE)) } + hasError () { + const { passwordError, confirmPasswordError, seedPhraseError } = this.state + return passwordError || confirmPasswordError || seedPhraseError + } + render () { - const { seedPhrase, password, confirmPassword } = this.state - const { warning, isLoading } = this.props - const importDisabled = warning || !seedPhrase || !password || !confirmPassword || isLoading + const { + seedPhrase, + password, + confirmPassword, + seedPhraseError, + passwordError, + confirmPasswordError, + } = this.state + const { t } = this.context + const { isLoading } = this.props + const disabled = !seedPhrase || !password || !confirmPassword || isLoading || this.hasError() return ( <div className="first-view-main-wrapper"> @@ -103,45 +128,40 @@ class ImportSeedPhraseScreen extends Component { <label className="import-account__input-label">Wallet Seed</label> <textarea className="import-account__secret-phrase" - onChange={e => this.onChange({seedPhrase: e.target.value})} + onChange={e => this.handleSeedPhraseChange(e.target.value)} value={this.state.seedPhrase} placeholder="Separate each word with a single space" /> </div> - <span - className="error" - > - {this.props.warning} + <span className="error"> + { seedPhraseError } </span> - <div className="import-account__input-wrapper"> - <label className="import-account__input-label">New Password</label> - <input - className="first-time-flow__input" - type="password" - placeholder="New Password (min 8 characters)" - onChange={e => this.onChange({password: e.target.value})} - /> - </div> - <div className="import-account__input-wrapper"> - <label - className={classnames('import-account__input-label', { - 'import-account__input-label__disabled': password.length < 8, - })} - >Confirm Password</label> - <input - className={classnames('first-time-flow__input', { - 'first-time-flow__input__disabled': password.length < 8, - })} - type="password" - placeholder="Confirm Password" - onChange={e => this.onChange({confirmPassword: e.target.value})} - disabled={password.length < 8} - /> - </div> + <TextField + id="password" + label={t('newPassword')} + type="password" + className="first-time-flow__input" + value={this.state.password} + onChange={event => this.handlePasswordChange(event.target.value)} + error={passwordError} + autoComplete="new-password" + margin="normal" + /> + <TextField + id="confirm-password" + label={t('confirmPassword')} + type="password" + className="first-time-flow__input" + value={this.state.confirmPassword} + onChange={event => this.handleConfirmPasswordChange(event.target.value)} + error={confirmPasswordError} + autoComplete="confirm-password" + margin="normal" + /> <button className="first-time-flow__button" - onClick={() => !importDisabled && this.onClick()} - disabled={importDisabled} + onClick={() => !disabled && this.onClick()} + disabled={disabled} > Import </button> @@ -159,7 +179,5 @@ export default connect( dispatch(unMarkPasswordForgotten()) }, createNewVaultAndRestore: (pw, seed) => dispatch(createNewVaultAndRestore(pw, seed)), - displayWarning: (warning) => dispatch(displayWarning(warning)), - hideWarning: () => dispatch(hideWarning()), }) )(ImportSeedPhraseScreen) diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index dffc21017..25e60b84a 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -174,10 +174,7 @@ } .first-time-flow__input { - width: initial !important; - font-size: 14px !important; - line-height: 18px !important; - padding: 12px !important; + width: 100%; } .tou__body { @@ -248,7 +245,7 @@ } .create-password__confirm-input { - margin-top: 15px; + margin-top: 16px; } .create-password__import-link { @@ -520,10 +517,6 @@ button.backup-phrase__confirm-seed-option:hover { margin-top: 30px; } -.first-time-flow__input--error { - border: 1px solid #FF001F !important; -} - .import-account__input-error-message { margin-top: 10px; width: 422px; @@ -544,7 +537,13 @@ button.backup-phrase__confirm-seed-option:hover { } .import-account__input { - width: 325px !important; + width: 350px; +} + +@media only screen and (max-width: 575px) { + .import-account__input { + width: 100%; + } } .import-account__file-input { @@ -681,20 +680,6 @@ button.backup-phrase__confirm-seed-option:hover { .first-time-flow__input { width: 350px; - font-size: 18px; - line-height: 24px; - padding: 15px; - border: 1px solid #CDCDCD; - background-color: #FFFFFF; -} - -.first-time-flow__input__disabled { - opacity: 0.5; -} - -.first-time-flow__input::placeholder { - color: #9B9B9B; - font-weight: 200; } .first-time-flow__button { |