|
|
|
@ -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') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.setState({ seedPhrase, seedPhraseError }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (warning) { |
|
|
|
|
displayWarning(warning) |
|
|
|
|
} else { |
|
|
|
|
hideWarning() |
|
|
|
|
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') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
seedPhrase && this.setState({ seedPhrase }) |
|
|
|
|
password && this.setState({ password }) |
|
|
|
|
confirmPassword && this.setState({ confirmPassword }) |
|
|
|
|
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 }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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" |
|
|
|
|
<TextField |
|
|
|
|
id="password" |
|
|
|
|
label={t('newPassword')} |
|
|
|
|
type="password" |
|
|
|
|
placeholder="New Password (min 8 characters)" |
|
|
|
|
onChange={e => this.onChange({password: e.target.value})} |
|
|
|
|
className="first-time-flow__input" |
|
|
|
|
value={this.state.password} |
|
|
|
|
onChange={event => this.handlePasswordChange(event.target.value)} |
|
|
|
|
error={passwordError} |
|
|
|
|
autoComplete="new-password" |
|
|
|
|
margin="normal" |
|
|
|
|
/> |
|
|
|
|
</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, |
|
|
|
|
})} |
|
|
|
|
<TextField |
|
|
|
|
id="confirm-password" |
|
|
|
|
label={t('confirmPassword')} |
|
|
|
|
type="password" |
|
|
|
|
placeholder="Confirm Password" |
|
|
|
|
onChange={e => this.onChange({confirmPassword: e.target.value})} |
|
|
|
|
disabled={password.length < 8} |
|
|
|
|
className="first-time-flow__input" |
|
|
|
|
value={this.state.confirmPassword} |
|
|
|
|
onChange={event => this.handleConfirmPasswordChange(event.target.value)} |
|
|
|
|
error={confirmPasswordError} |
|
|
|
|
autoComplete="confirm-password" |
|
|
|
|
margin="normal" |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
<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) |
|
|
|
|