Merge pull request #4648 from MetaMask/update-import-from-seed-screen
Update import from seed screen on new ui.feature/default_network_editable
commit
6595f84d07
@ -1,178 +1,189 @@ |
|||||||
const { withRouter } = require('react-router-dom') |
import React, { Component } from 'react' |
||||||
const PropTypes = require('prop-types') |
import PropTypes from 'prop-types' |
||||||
const { compose } = require('recompose') |
import {connect} from 'react-redux' |
||||||
const PersistentForm = require('../../../../lib/persistent-form') |
import { |
||||||
const connect = require('../../../metamask-connect') |
createNewVaultAndRestore, |
||||||
const h = require('react-hyperscript') |
unMarkPasswordForgotten, |
||||||
const { createNewVaultAndRestore, unMarkPasswordForgotten } = require('../../../actions') |
} from '../../../actions' |
||||||
const { DEFAULT_ROUTE } = require('../../../routes') |
import { DEFAULT_ROUTE } from '../../../routes' |
||||||
const log = require('loglevel') |
import TextField from '../../text-field' |
||||||
|
|
||||||
class RestoreVaultPage extends PersistentForm { |
class RestoreVaultPage extends Component { |
||||||
constructor (props) { |
static contextTypes = { |
||||||
super(props) |
t: PropTypes.func, |
||||||
|
} |
||||||
this.state = { |
|
||||||
error: null, |
static propTypes = { |
||||||
} |
warning: PropTypes.string, |
||||||
} |
createNewVaultAndRestore: PropTypes.func.isRequired, |
||||||
|
leaveImportSeedScreenState: PropTypes.func, |
||||||
|
history: PropTypes.object, |
||||||
|
isLoading: PropTypes.bool, |
||||||
|
}; |
||||||
|
|
||||||
createOnEnter (event) { |
state = { |
||||||
if (event.key === 'Enter') { |
seedPhrase: '', |
||||||
this.createNewVaultAndRestore() |
password: '', |
||||||
} |
confirmPassword: '', |
||||||
|
seedPhraseError: null, |
||||||
|
passwordError: null, |
||||||
|
confirmPasswordError: null, |
||||||
} |
} |
||||||
|
|
||||||
cancel () { |
parseSeedPhrase = (seedPhrase) => { |
||||||
this.props.unMarkPasswordForgotten() |
return seedPhrase |
||||||
.then(this.props.history.push(DEFAULT_ROUTE)) |
.match(/\w+/g) |
||||||
|
.join(' ') |
||||||
} |
} |
||||||
|
|
||||||
createNewVaultAndRestore () { |
handleSeedPhraseChange (seedPhrase) { |
||||||
this.setState({ error: null }) |
let seedPhraseError = null |
||||||
|
|
||||||
// check password
|
if (seedPhrase && this.parseSeedPhrase(seedPhrase).split(' ').length !== 12) { |
||||||
var passwordBox = document.getElementById('password-box') |
seedPhraseError = this.context.t('seedPhraseReq') |
||||||
var password = passwordBox.value |
|
||||||
var passwordConfirmBox = document.getElementById('password-box-confirm') |
|
||||||
var passwordConfirm = passwordConfirmBox.value |
|
||||||
|
|
||||||
if (password.length < 8) { |
|
||||||
this.setState({ error: 'Password not long enough' }) |
|
||||||
return |
|
||||||
} |
} |
||||||
|
|
||||||
if (password !== passwordConfirm) { |
this.setState({ seedPhrase, seedPhraseError }) |
||||||
this.setState({ error: 'Passwords don\'t match' }) |
|
||||||
return |
|
||||||
} |
} |
||||||
|
|
||||||
// check seed
|
handlePasswordChange (password) { |
||||||
var seedBox = document.querySelector('textarea.twelve-word-phrase') |
const { confirmPassword } = this.state |
||||||
var seed = seedBox.value.trim() |
let confirmPasswordError = null |
||||||
if (seed.split(' ').length !== 12) { |
let passwordError = null |
||||||
this.setState({ error: 'Seed phrases are 12 words long' }) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
// submit
|
if (password && password.length < 8) { |
||||||
this.props.createNewVaultAndRestore(password, seed) |
passwordError = this.context.t('passwordNotLongEnough') |
||||||
.then(() => this.props.history.push(DEFAULT_ROUTE)) |
|
||||||
.catch(({ message }) => { |
|
||||||
this.setState({ error: message }) |
|
||||||
log.error(message) |
|
||||||
}) |
|
||||||
} |
} |
||||||
|
|
||||||
render () { |
if (confirmPassword && password !== confirmPassword) { |
||||||
const { error } = this.state |
confirmPasswordError = this.context.t('passwordsDontMatch') |
||||||
this.persistentFormParentId = 'restore-vault-form' |
} |
||||||
|
|
||||||
return ( |
this.setState({ password, passwordError, confirmPasswordError }) |
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', [ |
} |
||||||
|
|
||||||
h('h3.flex-center.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
marginBottom: 24, |
|
||||||
width: '100%', |
|
||||||
fontSize: '20px', |
|
||||||
padding: 6, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
this.props.t('restoreVault'), |
|
||||||
]), |
|
||||||
|
|
||||||
// wallet seed entry
|
|
||||||
h('h3', 'Wallet Seed'), |
|
||||||
h('textarea.twelve-word-phrase.letter-spacey', { |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'wallet-seed', |
|
||||||
}, |
|
||||||
placeholder: this.props.t('secretPhrase'), |
|
||||||
}), |
|
||||||
|
|
||||||
// password
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box', |
|
||||||
placeholder: this.props.t('newPassword8Chars'), |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'password', |
|
||||||
}, |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 12, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
// confirm password
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box-confirm', |
|
||||||
placeholder: this.props.t('confirmPassword'), |
|
||||||
onKeyPress: this.createOnEnter.bind(this), |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'password-confirmation', |
|
||||||
}, |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 16, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
error && ( |
handleConfirmPasswordChange (confirmPassword) { |
||||||
h('span.error.in-progress-notification', error) |
const { password } = this.state |
||||||
), |
let confirmPasswordError = null |
||||||
|
|
||||||
// submit
|
if (password !== confirmPassword) { |
||||||
h('.flex-row.flex-space-between', { |
confirmPasswordError = this.context.t('passwordsDontMatch') |
||||||
style: { |
} |
||||||
marginTop: 30, |
|
||||||
width: '50%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// cancel
|
this.setState({ confirmPassword, confirmPasswordError }) |
||||||
h('button.primary', { |
} |
||||||
onClick: () => this.cancel(), |
|
||||||
}, this.props.t('cancel')), |
|
||||||
|
|
||||||
// submit
|
onClick = () => { |
||||||
h('button.primary', { |
const { password, seedPhrase } = this.state |
||||||
onClick: this.createNewVaultAndRestore.bind(this), |
const { |
||||||
}, this.props.t('ok')), |
createNewVaultAndRestore, |
||||||
|
leaveImportSeedScreenState, |
||||||
|
history, |
||||||
|
} = this.props |
||||||
|
|
||||||
]), |
leaveImportSeedScreenState() |
||||||
]) |
createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase)) |
||||||
) |
.then(() => history.push(DEFAULT_ROUTE)) |
||||||
} |
|
||||||
} |
} |
||||||
|
|
||||||
RestoreVaultPage.propTypes = { |
hasError () { |
||||||
history: PropTypes.object, |
const { passwordError, confirmPasswordError, seedPhraseError } = this.state |
||||||
|
return passwordError || confirmPasswordError || seedPhraseError |
||||||
} |
} |
||||||
|
|
||||||
const mapStateToProps = state => { |
render () { |
||||||
const { appState: { warning, forgottenPassword } } = state |
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 { |
return ( |
||||||
warning, |
<div className="first-view-main-wrapper"> |
||||||
forgottenPassword, |
<div className="first-view-main"> |
||||||
|
<div className="import-account"> |
||||||
|
<a |
||||||
|
className="import-account__back-button" |
||||||
|
onClick={e => { |
||||||
|
e.preventDefault() |
||||||
|
this.props.history.goBack() |
||||||
|
}} |
||||||
|
href="#" |
||||||
|
> |
||||||
|
{`< Back`} |
||||||
|
</a> |
||||||
|
<div className="import-account__title"> |
||||||
|
{ this.context.t('restoreAccountWithSeed') } |
||||||
|
</div> |
||||||
|
<div className="import-account__selector-label"> |
||||||
|
{ this.context.t('secretPhrase') } |
||||||
|
</div> |
||||||
|
<div className="import-account__input-wrapper"> |
||||||
|
<label className="import-account__input-label">Wallet Seed</label> |
||||||
|
<textarea |
||||||
|
className="import-account__secret-phrase" |
||||||
|
onChange={e => this.handleSeedPhraseChange(e.target.value)} |
||||||
|
value={this.state.seedPhrase} |
||||||
|
placeholder={this.context.t('separateEachWord')} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<span className="error"> |
||||||
|
{ seedPhraseError } |
||||||
|
</span> |
||||||
|
<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" |
||||||
|
largeLabel |
||||||
|
/> |
||||||
|
<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" |
||||||
|
largeLabel |
||||||
|
/> |
||||||
|
<button |
||||||
|
className="first-time-flow__button" |
||||||
|
onClick={() => !disabled && this.onClick()} |
||||||
|
disabled={disabled} |
||||||
|
> |
||||||
|
{this.context.t('restore')} |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
const mapDispatchToProps = dispatch => { |
RestoreVaultPage.contextTypes = { |
||||||
return { |
t: PropTypes.func, |
||||||
createNewVaultAndRestore: (password, seed) => { |
|
||||||
return dispatch(createNewVaultAndRestore(password, seed)) |
|
||||||
}, |
|
||||||
unMarkPasswordForgotten: () => dispatch(unMarkPasswordForgotten()), |
|
||||||
} |
|
||||||
} |
} |
||||||
|
|
||||||
module.exports = compose( |
export default connect( |
||||||
withRouter, |
({ appState: { warning, isLoading } }) => ({ warning, isLoading }), |
||||||
connect(mapStateToProps, mapDispatchToProps) |
dispatch => ({ |
||||||
|
leaveImportSeedScreenState: () => { |
||||||
|
dispatch(unMarkPasswordForgotten()) |
||||||
|
}, |
||||||
|
createNewVaultAndRestore: (pw, seed) => dispatch(createNewVaultAndRestore(pw, seed)), |
||||||
|
}) |
||||||
)(RestoreVaultPage) |
)(RestoreVaultPage) |
||||||
|
Loading…
Reference in new issue