mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add route for Mascara confirm seed
This commit is contained in:
parent
ec5e0a711c
commit
d9ea2df6c2
133
mascara/src/app/first-time/confirm-seed-screen.js
Normal file
133
mascara/src/app/first-time/confirm-seed-screen.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import shuffle from 'lodash.shuffle'
|
||||||
|
import { compose, onlyUpdateForPropTypes } from 'recompose'
|
||||||
|
import Identicon from '../../../../ui/app/components/identicon'
|
||||||
|
import { confirmSeedWords } from '../../../../ui/app/actions'
|
||||||
|
import Breadcrumbs from './breadcrumbs'
|
||||||
|
import LoadingScreen from './loading-screen'
|
||||||
|
import { DEFAULT_ROUTE } from '../../../../ui/app/routes'
|
||||||
|
|
||||||
|
class ConfirmSeedScreen extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
isLoading: PropTypes.bool.isRequired,
|
||||||
|
address: PropTypes.string.isRequired,
|
||||||
|
seedWords: PropTypes.string,
|
||||||
|
confirmSeedWords: PropTypes.func.isRequired,
|
||||||
|
history: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
seedWords: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
const { seedWords } = props
|
||||||
|
this.state = {
|
||||||
|
selectedSeeds: [],
|
||||||
|
shuffledSeeds: seedWords && shuffle(seedWords.split(' ')),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { seedWords, history } = this.props
|
||||||
|
if (!seedWords) {
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { seedWords, confirmSeedWords, history } = this.props
|
||||||
|
const { selectedSeeds, shuffledSeeds } = this.state
|
||||||
|
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="first-time-flow">
|
||||||
|
{
|
||||||
|
this.props.isLoading
|
||||||
|
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||||
|
: (
|
||||||
|
<div className="backup-phrase">
|
||||||
|
<Identicon address={this.props.address} diameter={70} />
|
||||||
|
<div className="backup-phrase__content-wrapper">
|
||||||
|
<div>
|
||||||
|
<div className="backup-phrase__title">
|
||||||
|
Confirm your Secret Backup Phrase
|
||||||
|
</div>
|
||||||
|
<div className="backup-phrase__body-text">
|
||||||
|
Please select each phrase in order to make sure it is correct.
|
||||||
|
</div>
|
||||||
|
<div className="backup-phrase__confirm-secret">
|
||||||
|
{selectedSeeds.map(([_, word], i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
className="backup-phrase__confirm-seed-option"
|
||||||
|
>
|
||||||
|
{word}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="backup-phrase__confirm-seed-options">
|
||||||
|
{shuffledSeeds.map((word, i) => {
|
||||||
|
const isSelected = selectedSeeds
|
||||||
|
.filter(([index, seed]) => seed === word && index === i)
|
||||||
|
.length
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
className={classnames('backup-phrase__confirm-seed-option', {
|
||||||
|
'backup-phrase__confirm-seed-option--selected': isSelected,
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
if (!isSelected) {
|
||||||
|
this.setState({
|
||||||
|
selectedSeeds: [...selectedSeeds, [i, word]],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
selectedSeeds: selectedSeeds
|
||||||
|
.filter(([index, seed]) => !(seed === word && index === i)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{word}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className="first-time-flow__button"
|
||||||
|
onClick={() => isValid && confirmSeedWords().then(() => history.push(DEFAULT_ROUTE))}
|
||||||
|
disabled={!isValid}
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Breadcrumbs total={3} currentIndex={1} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
onlyUpdateForPropTypes,
|
||||||
|
connect(
|
||||||
|
({ metamask: { selectedAddress, seedWords }, appState: { isLoading } }) => ({
|
||||||
|
seedWords,
|
||||||
|
isLoading,
|
||||||
|
address: selectedAddress,
|
||||||
|
}),
|
||||||
|
dispatch => ({
|
||||||
|
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)(ConfirmSeedScreen)
|
@ -1,14 +1,12 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import {connect} from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import shuffle from 'lodash.shuffle'
|
import { compose, onlyUpdateForPropTypes } from 'recompose'
|
||||||
import {compose, onlyUpdateForPropTypes} from 'recompose'
|
|
||||||
import Identicon from '../../../../ui/app/components/identicon'
|
import Identicon from '../../../../ui/app/components/identicon'
|
||||||
import {confirmSeedWords} from '../../../../ui/app/actions'
|
|
||||||
import Breadcrumbs from './breadcrumbs'
|
import Breadcrumbs from './breadcrumbs'
|
||||||
import LoadingScreen from './loading-screen'
|
import LoadingScreen from './loading-screen'
|
||||||
import { DEFAULT_ROUTE } from '../../../../ui/app/routes'
|
import { DEFAULT_ROUTE, CONFIRM_SEED_ROUTE } from '../../../../ui/app/routes'
|
||||||
|
|
||||||
const LockIcon = props => (
|
const LockIcon = props => (
|
||||||
<svg
|
<svg
|
||||||
@ -44,7 +42,6 @@ class BackupPhraseScreen extends Component {
|
|||||||
isLoading: PropTypes.bool.isRequired,
|
isLoading: PropTypes.bool.isRequired,
|
||||||
address: PropTypes.string.isRequired,
|
address: PropTypes.string.isRequired,
|
||||||
seedWords: PropTypes.string,
|
seedWords: PropTypes.string,
|
||||||
confirmSeedWords: PropTypes.func.isRequired,
|
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,19 +49,10 @@ class BackupPhraseScreen extends Component {
|
|||||||
seedWords: '',
|
seedWords: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
static PAGE = {
|
|
||||||
SECRET: 'secret',
|
|
||||||
CONFIRM: 'confirm',
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
const {seedWords} = props
|
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
isShowingSecret: false,
|
isShowingSecret: false,
|
||||||
page: BackupPhraseScreen.PAGE.SECRET,
|
|
||||||
selectedSeeds: [],
|
|
||||||
shuffledSeeds: seedWords && shuffle(seedWords.split(' ')),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +90,7 @@ class BackupPhraseScreen extends Component {
|
|||||||
|
|
||||||
renderSecretScreen () {
|
renderSecretScreen () {
|
||||||
const { isShowingSecret } = this.state
|
const { isShowingSecret } = this.state
|
||||||
|
const { history } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="backup-phrase__content-wrapper">
|
<div className="backup-phrase__content-wrapper">
|
||||||
@ -116,10 +105,7 @@ class BackupPhraseScreen extends Component {
|
|||||||
{this.renderSecretWordsContainer()}
|
{this.renderSecretWordsContainer()}
|
||||||
<button
|
<button
|
||||||
className="first-time-flow__button"
|
className="first-time-flow__button"
|
||||||
onClick={() => isShowingSecret && this.setState({
|
onClick={() => isShowingSecret && history.push(CONFIRM_SEED_ROUTE)}
|
||||||
isShowingSecret: false,
|
|
||||||
page: BackupPhraseScreen.PAGE.CONFIRM,
|
|
||||||
})}
|
|
||||||
disabled={!isShowingSecret}
|
disabled={!isShowingSecret}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
@ -142,99 +128,6 @@ class BackupPhraseScreen extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderConfirmationScreen () {
|
|
||||||
const { seedWords, confirmSeedWords, history } = this.props
|
|
||||||
const { selectedSeeds, shuffledSeeds } = this.state
|
|
||||||
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="backup-phrase__content-wrapper">
|
|
||||||
<div>
|
|
||||||
<div className="backup-phrase__title">Confirm your Secret Backup Phrase</div>
|
|
||||||
<div className="backup-phrase__body-text">
|
|
||||||
Please select each phrase in order to make sure it is correct.
|
|
||||||
</div>
|
|
||||||
<div className="backup-phrase__confirm-secret">
|
|
||||||
{selectedSeeds.map(([_, word], i) => (
|
|
||||||
<button
|
|
||||||
key={i}
|
|
||||||
className="backup-phrase__confirm-seed-option"
|
|
||||||
>
|
|
||||||
{word}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="backup-phrase__confirm-seed-options">
|
|
||||||
{shuffledSeeds.map((word, i) => {
|
|
||||||
const isSelected = selectedSeeds
|
|
||||||
.filter(([index, seed]) => seed === word && index === i)
|
|
||||||
.length
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={i}
|
|
||||||
className={classnames('backup-phrase__confirm-seed-option', {
|
|
||||||
'backup-phrase__confirm-seed-option--selected': isSelected,
|
|
||||||
})}
|
|
||||||
onClick={() => {
|
|
||||||
if (!isSelected) {
|
|
||||||
this.setState({
|
|
||||||
selectedSeeds: [...selectedSeeds, [i, word]],
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
selectedSeeds: selectedSeeds
|
|
||||||
.filter(([index, seed]) => !(seed === word && index === i)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{word}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className="first-time-flow__button"
|
|
||||||
onClick={() => isValid && confirmSeedWords().then(() => history.push(DEFAULT_ROUTE))}
|
|
||||||
disabled={!isValid}
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderBack () {
|
|
||||||
return this.state.page === BackupPhraseScreen.PAGE.CONFIRM
|
|
||||||
? (
|
|
||||||
<a
|
|
||||||
className="backup-phrase__back-button"
|
|
||||||
onClick={e => {
|
|
||||||
e.preventDefault()
|
|
||||||
this.setState({
|
|
||||||
page: BackupPhraseScreen.PAGE.SECRET,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
href="#"
|
|
||||||
>
|
|
||||||
{`< Back`}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
|
|
||||||
renderContent () {
|
|
||||||
switch (this.state.page) {
|
|
||||||
case BackupPhraseScreen.PAGE.CONFIRM:
|
|
||||||
return this.renderConfirmationScreen()
|
|
||||||
case BackupPhraseScreen.PAGE.SECRET:
|
|
||||||
default:
|
|
||||||
return this.renderSecretScreen()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className="first-time-flow">
|
<div className="first-time-flow">
|
||||||
@ -243,9 +136,8 @@ class BackupPhraseScreen extends Component {
|
|||||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||||
: (
|
: (
|
||||||
<div className="backup-phrase">
|
<div className="backup-phrase">
|
||||||
{this.renderBack()}
|
|
||||||
<Identicon address={this.props.address} diameter={70} />
|
<Identicon address={this.props.address} diameter={70} />
|
||||||
{this.renderContent()}
|
{this.renderSecretScreen()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -261,9 +153,6 @@ export default compose(
|
|||||||
seedWords,
|
seedWords,
|
||||||
isLoading,
|
isLoading,
|
||||||
address: selectedAddress,
|
address: selectedAddress,
|
||||||
}),
|
|
||||||
dispatch => ({
|
|
||||||
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)(BackupPhraseScreen)
|
)(BackupPhraseScreen)
|
@ -9,7 +9,8 @@ const actions = require('./actions')
|
|||||||
const MascaraCreatePassword = require('../../mascara/src/app/first-time/create-password-screen').default
|
const MascaraCreatePassword = require('../../mascara/src/app/first-time/create-password-screen').default
|
||||||
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
|
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
|
||||||
const MascaraNoticeScreen = require('../../mascara/src/app/first-time/notice-screen').default
|
const MascaraNoticeScreen = require('../../mascara/src/app/first-time/notice-screen').default
|
||||||
const MascaraBackupPhraseScreen = require('../../mascara/src/app/first-time/backup-phrase-screen').default
|
const MascaraSeedScreen = require('../../mascara/src/app/first-time/seed-screen').default
|
||||||
|
const MascaraConfirmSeedScreen = require('../../mascara/src/app/first-time/confirm-seed-screen').default
|
||||||
// init
|
// init
|
||||||
const InitializeMenuScreen = require('./first-time/init-menu')
|
const InitializeMenuScreen = require('./first-time/init-menu')
|
||||||
const NewKeyChainScreen = require('./new-keychain')
|
const NewKeyChainScreen = require('./new-keychain')
|
||||||
@ -51,6 +52,7 @@ const {
|
|||||||
UNLOCK_ROUTE,
|
UNLOCK_ROUTE,
|
||||||
SETTINGS_ROUTE,
|
SETTINGS_ROUTE,
|
||||||
REVEAL_SEED_ROUTE,
|
REVEAL_SEED_ROUTE,
|
||||||
|
CONFIRM_SEED_ROUTE,
|
||||||
RESTORE_VAULT_ROUTE,
|
RESTORE_VAULT_ROUTE,
|
||||||
ADD_TOKEN_ROUTE,
|
ADD_TOKEN_ROUTE,
|
||||||
IMPORT_ACCOUNT_ROUTE,
|
IMPORT_ACCOUNT_ROUTE,
|
||||||
@ -90,7 +92,12 @@ class App extends Component {
|
|||||||
path: REVEAL_SEED_ROUTE,
|
path: REVEAL_SEED_ROUTE,
|
||||||
exact,
|
exact,
|
||||||
component: RevealSeedPage,
|
component: RevealSeedPage,
|
||||||
mascaraComponent: MascaraBackupPhraseScreen,
|
mascaraComponent: MascaraSeedScreen,
|
||||||
|
}),
|
||||||
|
h(MetamaskRoute, {
|
||||||
|
path: CONFIRM_SEED_ROUTE,
|
||||||
|
exact,
|
||||||
|
mascaraComponent: MascaraConfirmSeedScreen,
|
||||||
}),
|
}),
|
||||||
h(Unauthenticated, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
h(Unauthenticated, { path: UNLOCK_ROUTE, exact, component: UnlockPage }),
|
||||||
h(Unauthenticated, { path: SETTINGS_ROUTE, component: Settings }),
|
h(Unauthenticated, { path: SETTINGS_ROUTE, component: Settings }),
|
||||||
|
@ -2,7 +2,8 @@ const DEFAULT_ROUTE = '/'
|
|||||||
const UNLOCK_ROUTE = '/unlock'
|
const UNLOCK_ROUTE = '/unlock'
|
||||||
const SETTINGS_ROUTE = '/settings'
|
const SETTINGS_ROUTE = '/settings'
|
||||||
const INFO_ROUTE = '/settings/info'
|
const INFO_ROUTE = '/settings/info'
|
||||||
const REVEAL_SEED_ROUTE = '/reveal-seed-confirm'
|
const REVEAL_SEED_ROUTE = '/seed'
|
||||||
|
const CONFIRM_SEED_ROUTE = '/confirm-seed'
|
||||||
const RESTORE_VAULT_ROUTE = '/restore-vault'
|
const RESTORE_VAULT_ROUTE = '/restore-vault'
|
||||||
const ADD_TOKEN_ROUTE = '/add-token'
|
const ADD_TOKEN_ROUTE = '/add-token'
|
||||||
const IMPORT_ACCOUNT_ROUTE = '/import-account'
|
const IMPORT_ACCOUNT_ROUTE = '/import-account'
|
||||||
@ -17,6 +18,7 @@ module.exports = {
|
|||||||
SETTINGS_ROUTE,
|
SETTINGS_ROUTE,
|
||||||
INFO_ROUTE,
|
INFO_ROUTE,
|
||||||
REVEAL_SEED_ROUTE,
|
REVEAL_SEED_ROUTE,
|
||||||
|
CONFIRM_SEED_ROUTE,
|
||||||
RESTORE_VAULT_ROUTE,
|
RESTORE_VAULT_ROUTE,
|
||||||
ADD_TOKEN_ROUTE,
|
ADD_TOKEN_ROUTE,
|
||||||
IMPORT_ACCOUNT_ROUTE,
|
IMPORT_ACCOUNT_ROUTE,
|
||||||
|
Loading…
Reference in New Issue
Block a user