Add route for Mascara confirm seed

feature/default_network_editable
Alexander Tseung 7 years ago
parent ec5e0a711c
commit d9ea2df6c2
  1. 133
      mascara/src/app/first-time/confirm-seed-screen.js
  2. 123
      mascara/src/app/first-time/seed-screen.js
  3. 11
      ui/app/app.js
  4. 4
      ui/app/routes.js

@ -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 PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { connect } from 'react-redux'
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 {confirmSeedWords} from '../../../../ui/app/actions'
import Breadcrumbs from './breadcrumbs'
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 => (
<svg
@ -44,7 +42,6 @@ class BackupPhraseScreen extends Component {
isLoading: PropTypes.bool.isRequired,
address: PropTypes.string.isRequired,
seedWords: PropTypes.string,
confirmSeedWords: PropTypes.func.isRequired,
history: PropTypes.object,
};
@ -52,19 +49,10 @@ class BackupPhraseScreen extends Component {
seedWords: '',
}
static PAGE = {
SECRET: 'secret',
CONFIRM: 'confirm',
}
constructor (props) {
const {seedWords} = props
super(props)
this.state = {
isShowingSecret: false,
page: BackupPhraseScreen.PAGE.SECRET,
selectedSeeds: [],
shuffledSeeds: seedWords && shuffle(seedWords.split(' ')),
}
}
@ -102,6 +90,7 @@ class BackupPhraseScreen extends Component {
renderSecretScreen () {
const { isShowingSecret } = this.state
const { history } = this.props
return (
<div className="backup-phrase__content-wrapper">
@ -116,10 +105,7 @@ class BackupPhraseScreen extends Component {
{this.renderSecretWordsContainer()}
<button
className="first-time-flow__button"
onClick={() => isShowingSecret && this.setState({
isShowingSecret: false,
page: BackupPhraseScreen.PAGE.CONFIRM,
})}
onClick={() => isShowingSecret && history.push(CONFIRM_SEED_ROUTE)}
disabled={!isShowingSecret}
>
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 () {
return (
<div className="first-time-flow">
@ -243,9 +136,8 @@ class BackupPhraseScreen extends Component {
? <LoadingScreen loadingMessage="Creating your new account" />
: (
<div className="backup-phrase">
{this.renderBack()}
<Identicon address={this.props.address} diameter={70} />
{this.renderContent()}
{this.renderSecretScreen()}
</div>
)
}
@ -261,9 +153,6 @@ export default compose(
seedWords,
isLoading,
address: selectedAddress,
}),
dispatch => ({
confirmSeedWords: () => dispatch(confirmSeedWords()),
})
)
)(BackupPhraseScreen)

@ -9,7 +9,8 @@ const actions = require('./actions')
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 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
const InitializeMenuScreen = require('./first-time/init-menu')
const NewKeyChainScreen = require('./new-keychain')
@ -51,6 +52,7 @@ const {
UNLOCK_ROUTE,
SETTINGS_ROUTE,
REVEAL_SEED_ROUTE,
CONFIRM_SEED_ROUTE,
RESTORE_VAULT_ROUTE,
ADD_TOKEN_ROUTE,
IMPORT_ACCOUNT_ROUTE,
@ -90,7 +92,12 @@ class App extends Component {
path: REVEAL_SEED_ROUTE,
exact,
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: SETTINGS_ROUTE, component: Settings }),

@ -2,7 +2,8 @@ const DEFAULT_ROUTE = '/'
const UNLOCK_ROUTE = '/unlock'
const SETTINGS_ROUTE = '/settings'
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 ADD_TOKEN_ROUTE = '/add-token'
const IMPORT_ACCOUNT_ROUTE = '/import-account'
@ -17,6 +18,7 @@ module.exports = {
SETTINGS_ROUTE,
INFO_ROUTE,
REVEAL_SEED_ROUTE,
CONFIRM_SEED_ROUTE,
RESTORE_VAULT_ROUTE,
ADD_TOKEN_ROUTE,
IMPORT_ACCOUNT_ROUTE,

Loading…
Cancel
Save