From bdc4a6964ae83faa8229c50870e3bcc9b9074989 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Fri, 30 Mar 2018 14:51:11 -0700 Subject: Fix merge conflicts. Refactor renderPrimary into Home component --- mascara/src/app/first-time/notice-screen.js | 5 +- ui/app/app.js | 442 ++++++++++----------- ui/app/components/pages/add-token.js | 2 +- ui/app/components/pages/home.js | 333 ++++++++++++++++ ui/app/components/pages/keychains/restore-vault.js | 26 +- ui/app/components/pages/signature-request.js | 284 ------------- ui/app/components/pages/unlock.js | 147 ++++--- ui/app/components/signature-request.js | 17 +- ui/app/conf-tx.js | 44 +- ui/app/routes.js | 4 +- 10 files changed, 694 insertions(+), 610 deletions(-) create mode 100644 ui/app/components/pages/home.js delete mode 100644 ui/app/components/pages/signature-request.js diff --git a/mascara/src/app/first-time/notice-screen.js b/mascara/src/app/first-time/notice-screen.js index 90213fe16..a342f059c 100644 --- a/mascara/src/app/first-time/notice-screen.js +++ b/mascara/src/app/first-time/notice-screen.js @@ -42,10 +42,7 @@ class NoticeScreen extends Component { acceptTerms = () => { const { markNoticeRead, lastUnreadNotice, history } = this.props markNoticeRead(lastUnreadNotice) - .then(() => { - history.push(DEFAULT_ROUTE) - this.setState({ atBottom: false }) - }) + .then(() => history.push(DEFAULT_ROUTE)) } onScroll = debounce(() => { diff --git a/ui/app/app.js b/ui/app/app.js index 719830fda..5d47a4189 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -27,6 +27,7 @@ const ConfirmTxScreen = require('./conf-tx') const WalletView = require('./components/wallet-view') // other views +const Home = require('./components/pages/home') const Authenticated = require('./components/pages/authenticated') const Initialized = require('./components/pages/initialized') const Settings = require('./components/pages/settings') @@ -36,7 +37,6 @@ const RevealSeedPage = require('./components/pages/keychains/reveal-seed') const AddTokenPage = require('./components/pages/add-token') const CreateAccountPage = require('./components/pages/create-account') const NoticeScreen = require('./components/pages/notice') -const SignatureRequestPage = require('./components/pages/signature-request') const Loading = require('./components/loading') const NetworkIndicator = require('./components/network') @@ -69,11 +69,11 @@ const { } = require('./routes') class App extends Component { - constructor (props) { - super(props) + // constructor (props) { + // super(props) - this.renderPrimary = this.renderPrimary.bind(this) - } + // this.renderPrimary = this.renderPrimary.bind(this) + // } componentWillMount () { const { currentCurrency, setCurrentCurrencyToUSD } = this.props @@ -116,12 +116,11 @@ class App extends Component { exact, component: MascaraNoticeScreen, }), - h(Authenticated, { path: CONFIRM_TRANSACTION_ROUTE, exact, component: ConfirmTxScreen }), + h(Authenticated, { path: CONFIRM_TRANSACTION_ROUTE, component: ConfirmTxScreen }), h(Authenticated, { path: SEND_ROUTE, exact, component: SendTransactionScreen2 }), h(Authenticated, { path: ADD_TOKEN_ROUTE, exact, component: AddTokenPage }), h(Authenticated, { path: NEW_ACCOUNT_ROUTE, component: CreateAccountPage }), - h(Authenticated, { path: SIGNATURE_REQUEST_ROUTE, exact, component: SignatureRequestPage }), - h(Authenticated, { path: DEFAULT_ROUTE, exact, component: this.renderPrimary }), + h(Authenticated, { path: DEFAULT_ROUTE, exact, component: Home }), ]) ) } @@ -357,233 +356,205 @@ class App extends Component { }) } - renderBackButton (style, justArrow = false) { - const { dispatch } = this.props - - return ( - h('.flex-row', { - key: 'leftArrow', - style: style, - onClick: () => dispatch(actions.goBackToInitView()), - }, [ - h('i.fa.fa-arrow-left.cursor-pointer'), - justArrow ? null : h('div.cursor-pointer', { - style: { - marginLeft: '3px', - }, - onClick: () => dispatch(actions.goBackToInitView()), - }, 'BACK'), - ]) - ) - } - - renderPrimary () { - log.debug('rendering primary') - const { - noActiveNotices, - lostAccounts, - forgottenPassword, - currentView, - activeAddress, - unapprovedTxs = {}, - seedWords, - unapprovedMsgCount = 0, - unapprovedPersonalMsgCount = 0, - unapprovedTypedMessagesCount = 0, - } = this.props - - // seed words - if (seedWords) { - log.debug('rendering seed words') - return h(Redirect, { - to: { - pathname: REVEAL_SEED_ROUTE, - }, - }) - } - - if (forgottenPassword) { - log.debug('rendering restore vault screen') - return h(Redirect, { - to: { - pathname: RESTORE_VAULT_ROUTE, - }, - }) - } - - // notices - if (!noActiveNotices || (lostAccounts && lostAccounts.length > 0)) { - return h(Redirect, { - to: { - pathname: NOTICE_ROUTE, - }, - }) - } - - // unapprovedTxs - if (Object.keys(unapprovedTxs).length) { - return h(Redirect, { - to: { - pathname: CONFIRM_TRANSACTION_ROUTE, - }, - }) - } - - // unapproved messages - if (unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount > 0) { - return h(Redirect, { - to: { - pathname: SIGNATURE_REQUEST_ROUTE, - }, - }) - } - - // if (!props.noActiveNotices) { - // log.debug('rendering notice screen for unread notices.') - // return h(NoticeScreen, { - // notice: props.lastUnreadNotice, - // key: 'NoticeScreen', - // onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)), - // }) - // } else if (props.lostAccounts && props.lostAccounts.length > 0) { - // log.debug('rendering notice screen for lost accounts view.') - // return h(NoticeScreen, { - // notice: generateLostAccountsNotice(props.lostAccounts), - // key: 'LostAccountsNotice', - // onConfirm: () => props.dispatch(actions.markAccountsFound()), - // }) - // } - - // if (props.seedWords) { - // log.debug('rendering seed words') - // return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) - // } - - // show initialize screen - // if (!isInitialized || forgottenPassword) { - // // show current view - // log.debug('rendering an initialize screen') - // // switch (props.currentView.name) { - - // // case 'restoreVault': - // // log.debug('rendering restore vault screen') - // // return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) - - // // default: - // // log.debug('rendering menu screen') - // // return h(InitializeScreen, {key: 'menuScreenInit'}) - // // } - // } - - // // show unlock screen - // if (!props.isUnlocked) { - // return h(MainContainer, { - // currentViewName: props.currentView.name, - // isUnlocked: props.isUnlocked, - // }) - // } - - // show current view - switch (currentView.name) { - - case 'accountDetail': - log.debug('rendering main container') - return h(MainContainer, {key: 'account-detail'}) - - // case 'sendTransaction': - // log.debug('rendering send tx screen') - - // // Going to leave this here until we are ready to delete SendTransactionScreen v1 - // // const SendComponentToRender = checkFeatureToggle('send-v2') - // // ? SendTransactionScreen2 - // // : SendTransactionScreen - - // return h(SendTransactionScreen2, {key: 'send-transaction'}) - - // case 'sendToken': - // log.debug('rendering send token screen') - - // // Going to leave this here until we are ready to delete SendTransactionScreen v1 - // // const SendTokenComponentToRender = checkFeatureToggle('send-v2') - // // ? SendTransactionScreen2 - // // : SendTokenScreen - - // return h(SendTransactionScreen2, {key: 'sendToken'}) - - case 'newKeychain': - log.debug('rendering new keychain screen') - return h(NewKeyChainScreen, {key: 'new-keychain'}) - - // case 'confTx': - // log.debug('rendering confirm tx screen') - // return h(Redirect, { - // to: { - // pathname: CONFIRM_TRANSACTION_ROUTE, - // }, - // }) - // return h(ConfirmTxScreen, {key: 'confirm-tx'}) - - // case 'add-token': - // log.debug('rendering add-token screen from unlock screen.') - // return h(AddTokenScreen, {key: 'add-token'}) - - // case 'config': - // log.debug('rendering config screen') - // return h(Settings, {key: 'config'}) - - // case 'import-menu': - // log.debug('rendering import screen') - // return h(Import, {key: 'import-menu'}) - - // case 'reveal-seed-conf': - // log.debug('rendering reveal seed confirmation screen') - // return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'}) - - // case 'info': - // log.debug('rendering info screen') - // return h(Settings, {key: 'info', tab: 'info'}) - - case 'buyEth': - log.debug('rendering buy ether screen') - return h(BuyView, {key: 'buyEthView'}) - - case 'onboardingBuyEth': - log.debug('rendering onboarding buy ether screen') - return h(MascaraBuyEtherScreen, {key: 'buyEthView'}) - - case 'qr': - log.debug('rendering show qr screen') - return h('div', { - style: { - position: 'absolute', - height: '100%', - top: '0px', - left: '0px', - }, - }, [ - h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { - onClick: () => this.props.dispatch(actions.backToAccountDetail(activeAddress)), - style: { - marginLeft: '10px', - marginTop: '50px', - }, - }), - h('div', { - style: { - position: 'absolute', - left: '44px', - width: '285px', - }, - }, [ - h(QrView, {key: 'qr'}), - ]), - ]) - - default: - log.debug('rendering default, account detail screen') - return h(MainContainer, {key: 'account-detail'}) - } - } + // renderPrimary () { + // log.debug('rendering primary') + // const { + // noActiveNotices, + // lostAccounts, + // forgottenPassword, + // currentView, + // activeAddress, + // unapprovedTxs = {}, + // seedWords, + // unapprovedMsgCount = 0, + // unapprovedPersonalMsgCount = 0, + // unapprovedTypedMessagesCount = 0, + // } = this.props + + // // seed words + // if (seedWords) { + // log.debug('rendering seed words') + // return h(Redirect, { + // to: { + // pathname: REVEAL_SEED_ROUTE, + // }, + // }) + // } + + // if (forgottenPassword) { + // log.debug('rendering restore vault screen') + // return h(Redirect, { + // to: { + // pathname: RESTORE_VAULT_ROUTE, + // }, + // }) + // } + + // // notices + // if (!noActiveNotices || (lostAccounts && lostAccounts.length > 0)) { + // return h(Redirect, { + // to: { + // pathname: NOTICE_ROUTE, + // }, + // }) + // } + + // // unapprovedTxs and unapproved messages + // if (Object.keys(unapprovedTxs).length || + // unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount > 0) { + // return h(Redirect, { + // to: { + // pathname: CONFIRM_TRANSACTION_ROUTE, + // }, + // }) + // } + + // // if (!props.noActiveNotices) { + // // log.debug('rendering notice screen for unread notices.') + // // return h(NoticeScreen, { + // // notice: props.lastUnreadNotice, + // // key: 'NoticeScreen', + // // onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)), + // // }) + // // } else if (props.lostAccounts && props.lostAccounts.length > 0) { + // // log.debug('rendering notice screen for lost accounts view.') + // // return h(NoticeScreen, { + // // notice: generateLostAccountsNotice(props.lostAccounts), + // // key: 'LostAccountsNotice', + // // onConfirm: () => props.dispatch(actions.markAccountsFound()), + // // }) + // // } + + // // if (props.seedWords) { + // // log.debug('rendering seed words') + // // return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) + // // } + + // // show initialize screen + // // if (!isInitialized || forgottenPassword) { + // // // show current view + // // log.debug('rendering an initialize screen') + // // // switch (props.currentView.name) { + + // // // case 'restoreVault': + // // // log.debug('rendering restore vault screen') + // // // return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) + + // // // default: + // // // log.debug('rendering menu screen') + // // // return h(InitializeScreen, {key: 'menuScreenInit'}) + // // // } + // // } + + // // // show unlock screen + // // if (!props.isUnlocked) { + // // return h(MainContainer, { + // // currentViewName: props.currentView.name, + // // isUnlocked: props.isUnlocked, + // // }) + // // } + + // // show current view + // switch (currentView.name) { + + // case 'accountDetail': + // log.debug('rendering main container') + // return h(MainContainer, {key: 'account-detail'}) + + // // case 'sendTransaction': + // // log.debug('rendering send tx screen') + + // // // Going to leave this here until we are ready to delete SendTransactionScreen v1 + // // // const SendComponentToRender = checkFeatureToggle('send-v2') + // // // ? SendTransactionScreen2 + // // // : SendTransactionScreen + + // // return h(SendTransactionScreen2, {key: 'send-transaction'}) + + // // case 'sendToken': + // // log.debug('rendering send token screen') + + // // // Going to leave this here until we are ready to delete SendTransactionScreen v1 + // // // const SendTokenComponentToRender = checkFeatureToggle('send-v2') + // // // ? SendTransactionScreen2 + // // // : SendTokenScreen + + // // return h(SendTransactionScreen2, {key: 'sendToken'}) + + // case 'newKeychain': + // log.debug('rendering new keychain screen') + // return h(NewKeyChainScreen, {key: 'new-keychain'}) + + // // case 'confTx': + // // log.debug('rendering confirm tx screen') + // // return h(Redirect, { + // // to: { + // // pathname: CONFIRM_TRANSACTION_ROUTE, + // // }, + // // }) + // // return h(ConfirmTxScreen, {key: 'confirm-tx'}) + + // // case 'add-token': + // // log.debug('rendering add-token screen from unlock screen.') + // // return h(AddTokenScreen, {key: 'add-token'}) + + // // case 'config': + // // log.debug('rendering config screen') + // // return h(Settings, {key: 'config'}) + + // // case 'import-menu': + // // log.debug('rendering import screen') + // // return h(Import, {key: 'import-menu'}) + + // // case 'reveal-seed-conf': + // // log.debug('rendering reveal seed confirmation screen') + // // return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'}) + + // // case 'info': + // // log.debug('rendering info screen') + // // return h(Settings, {key: 'info', tab: 'info'}) + + // case 'buyEth': + // log.debug('rendering buy ether screen') + // return h(BuyView, {key: 'buyEthView'}) + + // case 'onboardingBuyEth': + // log.debug('rendering onboarding buy ether screen') + // return h(MascaraBuyEtherScreen, {key: 'buyEthView'}) + + // case 'qr': + // log.debug('rendering show qr screen') + // return h('div', { + // style: { + // position: 'absolute', + // height: '100%', + // top: '0px', + // left: '0px', + // }, + // }, [ + // h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { + // onClick: () => this.props.dispatch(actions.backToAccountDetail(activeAddress)), + // style: { + // marginLeft: '10px', + // marginTop: '50px', + // }, + // }), + // h('div', { + // style: { + // position: 'absolute', + // left: '44px', + // width: '285px', + // }, + // }, [ + // h(QrView, {key: 'qr'}), + // ]), + // ]) + + // default: + // log.debug('rendering default, account detail screen') + // return h(MainContainer, {key: 'account-detail'}) + // } + // } toggleMetamaskActive () { if (!this.props.isUnlocked) { @@ -676,6 +647,7 @@ App.propTypes = { betaUI: PropTypes.bool, isMouseUser: PropTypes.bool, setMouseUserState: PropTypes.func, + t: PropTypes.func, } function mapStateToProps (state) { diff --git a/ui/app/components/pages/add-token.js b/ui/app/components/pages/add-token.js index b33373c19..61c245c32 100644 --- a/ui/app/components/pages/add-token.js +++ b/ui/app/components/pages/add-token.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const classnames = require('classnames') const h = require('react-hyperscript') -const connect = require('./metamask-connect') +const connect = require('../../metamask-connect') const R = require('ramda') const Fuse = require('fuse.js') const contractMap = require('eth-contract-metadata') diff --git a/ui/app/components/pages/home.js b/ui/app/components/pages/home.js new file mode 100644 index 000000000..4f8c00768 --- /dev/null +++ b/ui/app/components/pages/home.js @@ -0,0 +1,333 @@ +const { Component } = require('react') +const PropTypes = require('prop-types') +const connect = require('../../metamask-connect') +const { Redirect, withRouter } = require('react-router-dom') +const { compose } = require('recompose') +const h = require('react-hyperscript') +const actions = require('../../actions') + +// init +const NewKeyChainScreen = require('../../new-keychain') +// mascara +const MascaraBuyEtherScreen = require('../../../../mascara/src/app/first-time/buy-ether-screen').default + +// accounts +const MainContainer = require('../../main-container') + +// other views +const BuyView = require('../../components/buy-button-subview') +const QrView = require('../../components/qr-code') + +// Routes +const { + REVEAL_SEED_ROUTE, + RESTORE_VAULT_ROUTE, + CONFIRM_TRANSACTION_ROUTE, + NOTICE_ROUTE, +} = require('../../routes') + +class Home extends Component { + componentDidMount () { + const { + unapprovedTxs = {}, + unapprovedMsgCount = 0, + unapprovedPersonalMsgCount = 0, + unapprovedTypedMessagesCount = 0, + } = this.props + + console.log('IN HOME COMPONENDIMOUNT') + // unapprovedTxs and unapproved messages + if (Object.keys(unapprovedTxs).length || + unapprovedTypedMessagesCount + unapprovedMsgCount + unapprovedPersonalMsgCount > 0) { + console.log('IN HOME SHOULD REDIRECT') + this.props.history.push(CONFIRM_TRANSACTION_ROUTE) + } + } + + render () { + log.debug('rendering primary') + const { + noActiveNotices, + lostAccounts, + forgottenPassword, + currentView, + activeAddress, + seedWords, + } = this.props + + // seed words + if (seedWords) { + log.debug('rendering seed words') + return h(Redirect, { + to: { + pathname: REVEAL_SEED_ROUTE, + }, + }) + } + + if (forgottenPassword) { + log.debug('rendering restore vault screen') + return h(Redirect, { + to: { + pathname: RESTORE_VAULT_ROUTE, + }, + }) + } + + // notices + if (!noActiveNotices || (lostAccounts && lostAccounts.length > 0)) { + return h(Redirect, { + to: { + pathname: NOTICE_ROUTE, + }, + }) + } + + // if (!props.noActiveNotices) { + // log.debug('rendering notice screen for unread notices.') + // return h(NoticeScreen, { + // notice: props.lastUnreadNotice, + // key: 'NoticeScreen', + // onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)), + // }) + // } else if (props.lostAccounts && props.lostAccounts.length > 0) { + // log.debug('rendering notice screen for lost accounts view.') + // return h(NoticeScreen, { + // notice: generateLostAccountsNotice(props.lostAccounts), + // key: 'LostAccountsNotice', + // onConfirm: () => props.dispatch(actions.markAccountsFound()), + // }) + // } + + // if (props.seedWords) { + // log.debug('rendering seed words') + // return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) + // } + + // show initialize screen + // if (!isInitialized || forgottenPassword) { + // // show current view + // log.debug('rendering an initialize screen') + // // switch (props.currentView.name) { + + // // case 'restoreVault': + // // log.debug('rendering restore vault screen') + // // return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) + + // // default: + // // log.debug('rendering menu screen') + // // return h(InitializeScreen, {key: 'menuScreenInit'}) + // // } + // } + + // // show unlock screen + // if (!props.isUnlocked) { + // return h(MainContainer, { + // currentViewName: props.currentView.name, + // isUnlocked: props.isUnlocked, + // }) + // } + + // show current view + switch (currentView.name) { + + case 'accountDetail': + log.debug('rendering main container') + return h(MainContainer, {key: 'account-detail'}) + + // case 'sendTransaction': + // log.debug('rendering send tx screen') + + // // Going to leave this here until we are ready to delete SendTransactionScreen v1 + // // const SendComponentToRender = checkFeatureToggle('send-v2') + // // ? SendTransactionScreen2 + // // : SendTransactionScreen + + // return h(SendTransactionScreen2, {key: 'send-transaction'}) + + // case 'sendToken': + // log.debug('rendering send token screen') + + // // Going to leave this here until we are ready to delete SendTransactionScreen v1 + // // const SendTokenComponentToRender = checkFeatureToggle('send-v2') + // // ? SendTransactionScreen2 + // // : SendTokenScreen + + // return h(SendTransactionScreen2, {key: 'sendToken'}) + + case 'newKeychain': + log.debug('rendering new keychain screen') + return h(NewKeyChainScreen, {key: 'new-keychain'}) + + // case 'confTx': + // log.debug('rendering confirm tx screen') + // return h(Redirect, { + // to: { + // pathname: CONFIRM_TRANSACTION_ROUTE, + // }, + // }) + // return h(ConfirmTxScreen, {key: 'confirm-tx'}) + + // case 'add-token': + // log.debug('rendering add-token screen from unlock screen.') + // return h(AddTokenScreen, {key: 'add-token'}) + + // case 'config': + // log.debug('rendering config screen') + // return h(Settings, {key: 'config'}) + + // case 'import-menu': + // log.debug('rendering import screen') + // return h(Import, {key: 'import-menu'}) + + // case 'reveal-seed-conf': + // log.debug('rendering reveal seed confirmation screen') + // return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'}) + + // case 'info': + // log.debug('rendering info screen') + // return h(Settings, {key: 'info', tab: 'info'}) + + case 'buyEth': + log.debug('rendering buy ether screen') + return h(BuyView, {key: 'buyEthView'}) + + case 'onboardingBuyEth': + log.debug('rendering onboarding buy ether screen') + return h(MascaraBuyEtherScreen, {key: 'buyEthView'}) + + case 'qr': + log.debug('rendering show qr screen') + return h('div', { + style: { + position: 'absolute', + height: '100%', + top: '0px', + left: '0px', + }, + }, [ + h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { + onClick: () => this.props.dispatch(actions.backToAccountDetail(activeAddress)), + style: { + marginLeft: '10px', + marginTop: '50px', + }, + }), + h('div', { + style: { + position: 'absolute', + left: '44px', + width: '285px', + }, + }, [ + h(QrView, {key: 'qr'}), + ]), + ]) + + default: + log.debug('rendering default, account detail screen') + return h(MainContainer, {key: 'account-detail'}) + } + } +} + +Home.propTypes = { + currentCurrency: PropTypes.string, + isLoading: PropTypes.bool, + loadingMessage: PropTypes.string, + network: PropTypes.string, + provider: PropTypes.object, + frequentRpcList: PropTypes.array, + currentView: PropTypes.object, + sidebarOpen: PropTypes.bool, + isMascara: PropTypes.bool, + isOnboarding: PropTypes.bool, + isUnlocked: PropTypes.bool, + networkDropdownOpen: PropTypes.bool, + history: PropTypes.object, + dispatch: PropTypes.func, + selectedAddress: PropTypes.string, + noActiveNotices: PropTypes.bool, + lostAccounts: PropTypes.array, + isInitialized: PropTypes.bool, + forgottenPassword: PropTypes.bool, + activeAddress: PropTypes.string, + unapprovedTxs: PropTypes.object, + seedWords: PropTypes.string, + unapprovedMsgCount: PropTypes.number, + unapprovedPersonalMsgCount: PropTypes.number, + unapprovedTypedMessagesCount: PropTypes.number, + welcomeScreenSeen: PropTypes.bool, + isPopup: PropTypes.bool, + isMouseUser: PropTypes.bool, + t: PropTypes.func, +} + +function mapStateToProps (state) { + const { appState, metamask } = state + const { + networkDropdownOpen, + sidebarOpen, + isLoading, + loadingMessage, + } = appState + + const { + accounts, + address, + isInitialized, + noActiveNotices, + seedWords, + unapprovedTxs, + lastUnreadNotice, + lostAccounts, + unapprovedMsgCount, + unapprovedPersonalMsgCount, + unapprovedTypedMessagesCount, + } = metamask + const selected = address || Object.keys(accounts)[0] + + return { + // state from plugin + networkDropdownOpen, + sidebarOpen, + isLoading, + loadingMessage, + noActiveNotices, + isInitialized, + isUnlocked: state.metamask.isUnlocked, + selectedAddress: state.metamask.selectedAddress, + currentView: state.appState.currentView, + activeAddress: state.appState.activeAddress, + transForward: state.appState.transForward, + isMascara: state.metamask.isMascara, + isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized), + isPopup: state.metamask.isPopup, + seedWords: state.metamask.seedWords, + unapprovedTxs, + unapprovedMsgs: state.metamask.unapprovedMsgs, + unapprovedMsgCount, + unapprovedPersonalMsgCount, + unapprovedTypedMessagesCount, + menuOpen: state.appState.menuOpen, + network: state.metamask.network, + provider: state.metamask.provider, + forgottenPassword: state.appState.forgottenPassword, + lastUnreadNotice, + lostAccounts, + frequentRpcList: state.metamask.frequentRpcList || [], + currentCurrency: state.metamask.currentCurrency, + isMouseUser: state.appState.isMouseUser, + isRevealingSeedWords: state.metamask.isRevealingSeedWords, + Qr: state.appState.Qr, + welcomeScreenSeen: state.metamask.welcomeScreenSeen, + + // state needed to get account dropdown temporarily rendering from app bar + selected, + } +} + +module.exports = compose( + withRouter, + connect(mapStateToProps) +)(Home) diff --git a/ui/app/components/pages/keychains/restore-vault.js b/ui/app/components/pages/keychains/restore-vault.js index 749da9758..24ebf89e3 100644 --- a/ui/app/components/pages/keychains/restore-vault.js +++ b/ui/app/components/pages/keychains/restore-vault.js @@ -2,9 +2,9 @@ const { withRouter } = require('react-router-dom') const PropTypes = require('prop-types') const { compose } = require('recompose') const PersistentForm = require('../../../../lib/persistent-form') -const { connect } = require('react-redux') +const connect = require('../../../metamask-connect') const h = require('react-hyperscript') -const { createNewVaultAndRestore } = require('../../../actions') +const { createNewVaultAndRestore, unMarkPasswordForgotten } = require('../../../actions') const { DEFAULT_ROUTE } = require('../../../routes') class RestoreVaultPage extends PersistentForm { @@ -22,6 +22,11 @@ class RestoreVaultPage extends PersistentForm { } } + cancel () { + this.props.unMarkPasswordForgotten() + .then(this.props.history.goBack()) + } + createNewVaultAndRestore () { this.setState({ error: null }) @@ -51,7 +56,7 @@ class RestoreVaultPage extends PersistentForm { // submit this.props.createNewVaultAndRestore(password, seed) - .then(() => history.push(DEFAULT_ROUTE)) + .then(() => this.props.history.push(DEFAULT_ROUTE)) .catch(({ message }) => { this.setState({ error: message }) log.error(message) @@ -76,7 +81,7 @@ class RestoreVaultPage extends PersistentForm { padding: 6, }, }, [ - 'Restore Vault', + this.props.t('restoreVault'), ]), // wallet seed entry @@ -85,14 +90,14 @@ class RestoreVaultPage extends PersistentForm { dataset: { persistentFormId: 'wallet-seed', }, - placeholder: 'Enter your secret twelve word phrase here to restore your vault.', + placeholder: this.props.t('secretPhrase'), }), // password h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: 'New Password (min 8 chars)', + placeholder: this.props.t('newPassword8Chars'), dataset: { persistentFormId: 'password', }, @@ -106,7 +111,7 @@ class RestoreVaultPage extends PersistentForm { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: 'Confirm Password', + placeholder: this.props.t('confirmPassword'), onKeyPress: this.createOnEnter.bind(this), dataset: { persistentFormId: 'password-confirmation', @@ -130,12 +135,14 @@ class RestoreVaultPage extends PersistentForm { }, [ // cancel - h('button.primary', { onClick: () => history.goBack() }, 'CANCEL'), + h('button.primary', { + onClick: () => this.cancel(), + }, this.props.t('cancel')), // submit h('button.primary', { onClick: this.createNewVaultAndRestore.bind(this), - }, 'OK'), + }, this.props.t('ok')), ]), ]) @@ -161,6 +168,7 @@ const mapDispatchToProps = dispatch => { createNewVaultAndRestore: (password, seed) => { return dispatch(createNewVaultAndRestore(password, seed)) }, + unMarkPasswordForgotten: () => dispatch(unMarkPasswordForgotten()), } } diff --git a/ui/app/components/pages/signature-request.js b/ui/app/components/pages/signature-request.js deleted file mode 100644 index e9271fce1..000000000 --- a/ui/app/components/pages/signature-request.js +++ /dev/null @@ -1,284 +0,0 @@ -const { Component } = require('react') -const h = require('react-hyperscript') -const PropTypes = require('prop-types') -const Identicon = require('../identicon') -const { connect } = require('react-redux') -const ethUtil = require('ethereumjs-util') -const classnames = require('classnames') - -const AccountDropdownMini = require('../dropdowns/account-dropdown-mini') - -const t = require('../../../i18n') -const { conversionUtil } = require('../../conversion-util') -const { DEFAULT_ROUTE } = require('../../routes') - -const { - getSelectedAccount, - getCurrentAccountWithSendEtherInfo, - getSelectedAddress, - accountsWithSendEtherInfoSelector, - conversionRateSelector, -} = require('../../selectors.js') - -class SignatureRequest extends Component { - constructor (props) { - super(props) - - this.state = { - selectedAccount: props.selectedAccount, - accountDropdownOpen: false, - } - } - - componentWillMount () { - const { - unapprovedMsgCount = 0, - unapprovedPersonalMsgCount = 0, - unapprovedTypedMessagesCount = 0, - } = this.props - - if (unapprovedMsgCount + unapprovedPersonalMsgCount + unapprovedTypedMessagesCount < 1) { - this.props.history.push(DEFAULT_ROUTE) - } - } - - renderHeader () { - return h('div.request-signature__header', [ - - h('div.request-signature__header-background'), - - h('div.request-signature__header__text', t('sigRequest')), - - h('div.request-signature__header__tip-container', [ - h('div.request-signature__header__tip'), - ]), - - ]) - } - - renderAccountDropdown () { - const { - selectedAccount, - accountDropdownOpen, - } = this.state - - const { accounts } = this.props - - return h('div.request-signature__account', [ - - h('div.request-signature__account-text', [t('account') + ':']), - - h(AccountDropdownMini, { - selectedAccount, - accounts, - onSelect: selectedAccount => this.setState({ selectedAccount }), - dropdownOpen: accountDropdownOpen, - openDropdown: () => this.setState({ accountDropdownOpen: true }), - closeDropdown: () => this.setState({ accountDropdownOpen: false }), - }), - - ]) - } - - renderBalance () { - const { balance, conversionRate } = this.props - - const balanceInEther = conversionUtil(balance, { - fromNumericBase: 'hex', - toNumericBase: 'dec', - fromDenomination: 'WEI', - numberOfDecimals: 6, - conversionRate, - }) - - return h('div.request-signature__balance', [ - - h('div.request-signature__balance-text', [t('balance')]), - - h('div.request-signature__balance-value', `${balanceInEther} ETH`), - - ]) - } - - renderAccountInfo () { - return h('div.request-signature__account-info', [ - - this.renderAccountDropdown(), - - this.renderRequestIcon(), - - this.renderBalance(), - - ]) - } - - renderRequestIcon () { - const { requesterAddress } = this.props - - return h('div.request-signature__request-icon', [ - h(Identicon, { - diameter: 40, - address: requesterAddress, - }), - ]) - } - - renderRequestInfo () { - return h('div.request-signature__request-info', [ - - h('div.request-signature__headline', [ - t('yourSigRequested'), - ]), - - ]) - } - - msgHexToText (hex) { - try { - const stripped = ethUtil.stripHexPrefix(hex) - const buff = Buffer.from(stripped, 'hex') - return buff.toString('utf8') - } catch (e) { - return hex - } - } - - renderBody () { - let rows - let notice = t('youSign') + ':' - - const { txData } = this.props - const { type, msgParams: { data } } = txData - - if (type === 'personal_sign') { - rows = [{ name: t('message'), value: this.msgHexToText(data) }] - } else if (type === 'eth_signTypedData') { - rows = data - } else if (type === 'eth_sign') { - rows = [{ name: t('message'), value: data }] - notice = t('signNotice') - } - - return h('div.request-signature__body', {}, [ - - this.renderAccountInfo(), - - this.renderRequestInfo(), - - h('div.request-signature__notice', { - className: classnames({ - 'request-signature__notice': type === 'personal_sign' || type === 'eth_signTypedData', - 'request-signature__warning': type === 'eth_sign', - }), - }, [notice]), - - h('div.request-signature__rows', [ - - ...rows.map(({ name, value }) => { - return h('div.request-signature__row', [ - h('div.request-signature__row-title', [`${name}:`]), - h('div.request-signature__row-value', value), - ]) - }), - - ]), - - ]) - } - - renderFooter () { - const { - txData = {}, - signPersonalMessage, - signTypedMessage, - cancelPersonalMessage, - cancelTypedMessage, - signMessage, - cancelMessage, - history, - } = this.props - - const { type } = txData - - let cancel = () => Promise.resolve() - let sign = () => Promise.resolve() - const { msgParams: params = {}, id } = txData - params.id = id - params.metamaskId = id - - switch (type) { - case 'personal_sign': - cancel = () => cancelPersonalMessage(params) - sign = () => signPersonalMessage(params) - break - case 'eth_signTypedData': - cancel = () => cancelTypedMessage(params) - sign = () => signTypedMessage(params) - break - case 'eth_sign': - cancel = () => cancelMessage(params) - sign = () => signMessage(params) - break - } - - return h('div.request-signature__footer', [ - h('button.btn-secondary--lg.request-signature__footer__cancel-button', { - onClick: () => { - cancel().then(() => history.push(DEFAULT_ROUTE)) - }, - }, t('cancel')), - h('button.btn-primary--lg', { - onClick: () => { - sign().then(() => history.push(DEFAULT_ROUTE)) - }, - }, t('sign')), - ]) - } - - render () { - return ( - h('div.request-signature__container', [ - - this.renderHeader(), - - this.renderBody(), - - this.renderFooter(), - - ]) - ) - } -} - -SignatureRequest.propTypes = { - txData: PropTypes.object, - signPersonalMessage: PropTypes.func, - cancelPersonalMessage: PropTypes.func, - signTypedMessage: PropTypes.func, - cancelTypedMessage: PropTypes.func, - signMessage: PropTypes.func, - cancelMessage: PropTypes.func, - requesterAddress: PropTypes.string, - accounts: PropTypes.array, - conversionRate: PropTypes.number, - balance: PropTypes.string, - selectedAccount: PropTypes.object, - history: PropTypes.object, - unapprovedMsgCount: PropTypes.number, - unapprovedPersonalMsgCount: PropTypes.number, - unapprovedTypedMessagesCount: PropTypes.number, -} - -const mapStateToProps = state => { - return { - balance: getSelectedAccount(state).balance, - selectedAccount: getCurrentAccountWithSendEtherInfo(state), - selectedAddress: getSelectedAddress(state), - requester: null, - requesterAddress: null, - accounts: accountsWithSendEtherInfoSelector(state), - conversionRate: conversionRateSelector(state), - } -} - -module.exports = connect(mapStateToProps)(SignatureRequest) diff --git a/ui/app/components/pages/unlock.js b/ui/app/components/pages/unlock.js index 3d7a9091c..ed4b9ded7 100644 --- a/ui/app/components/pages/unlock.js +++ b/ui/app/components/pages/unlock.js @@ -1,14 +1,22 @@ const { Component } = require('react') const PropTypes = require('prop-types') -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const { withRouter } = require('react-router-dom') const { compose } = require('recompose') -const { tryUnlockMetamask, forgotPassword, markPasswordForgotten } = require('../../actions') +const { + tryUnlockMetamask, + forgotPassword, + markPasswordForgotten, + setNetworkEndpoints, + setFeatureFlag, +} = require('../../actions') +const environmentType = require('../../../../app/scripts/lib/environment-type') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter const Mascot = require('../mascot') -const { DEFAULT_ROUTE } = require('../../routes') +const { OLD_UI_NETWORK_TYPE } = require('../../../../app/scripts/config').enums +const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../routes') class UnlockScreen extends Component { constructor (props) { @@ -77,70 +85,76 @@ class UnlockScreen extends Component { render () { const { error } = this.state - const { markPasswordForgotten } = this.props - return ( - h('.unlock-page.main-container', [ - h('.flex-column', { + h('.unlock-screen', [ + + h(Mascot, { + animationEventEmitter: this.animationEventEmitter, + }), + + h('h1', { + style: { + fontSize: '1.4em', + textTransform: 'uppercase', + color: '#7F8082', + }, + }, this.props.t('appName')), + + h('input.large-input', { + type: 'password', + id: 'password-box', + placeholder: 'enter password', + style: { + background: 'white', + }, + onKeyPress: this.onKeyPress.bind(this), + onInput: this.inputChanged.bind(this), + }), + + h('.error', { + style: { + display: error ? 'block' : 'none', + padding: '0 20px', + textAlign: 'center', + }, + }, error), + + h('button.primary.cursor-pointer', { + onClick: this.onSubmit.bind(this), + style: { + margin: 10, + }, + }, this.props.t('login')), + + h('p.pointer', { + onClick: () => { + this.props.markPasswordForgotten() + this.props.history.push(RESTORE_VAULT_ROUTE) + + console.log('typeeee', environmentType()) + if (environmentType() === 'popup') { + global.platform.openExtensionInBrowser() + } + }, + style: { + fontSize: '0.8em', + color: 'rgb(247, 134, 28)', + textDecoration: 'underline', + }, + }, this.props.t('restoreFromSeed')), + + h('p.pointer', { + onClick: () => { + this.props.useOldInterface() + .then(() => this.props.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)) + }, style: { - width: 'inherit', + fontSize: '0.8em', + color: '#aeaeae', + textDecoration: 'underline', + marginTop: '32px', }, - }, [ - h('.unlock-screen.flex-column.flex-center.flex-grow', [ - - h(Mascot, { - animationEventEmitter: this.animationEventEmitter, - }), - - h('h1', { - style: { - fontSize: '1.4em', - textTransform: 'uppercase', - color: '#7F8082', - }, - }, 'MetaMask'), - - h('input.large-input', { - type: 'password', - id: 'password-box', - placeholder: 'enter password', - style: { - background: 'white', - }, - onKeyPress: this.onKeyPress.bind(this), - onInput: this.inputChanged.bind(this), - }), - - h('.error', { - style: { - display: error ? 'block' : 'none', - padding: '0 20px', - textAlign: 'center', - }, - }, error), - - h('button.primary.cursor-pointer', { - onClick: this.onSubmit.bind(this), - style: { - margin: 10, - }, - }, 'Unlock'), - - h('.flex-row.flex-center.flex-grow', [ - h('p.pointer', { - onClick: () => { - markPasswordForgotten() - global.platform.openExtensionInBrowser() - }, - style: { - fontSize: '0.8em', - color: 'rgb(247, 134, 28)', - textDecoration: 'underline', - }, - }, 'Restore from seed phrase'), - ]), - ]), - ]), + }, this.props.t('classicInterface')), ]) ) } @@ -152,6 +166,9 @@ UnlockScreen.propTypes = { markPasswordForgotten: PropTypes.func, history: PropTypes.object, isUnlocked: PropTypes.bool, + t: PropTypes.func, + useOldInterface: PropTypes.func, + setNetworkEndpoints: PropTypes.func, } const mapStateToProps = state => { @@ -166,6 +183,8 @@ const mapDispatchToProps = dispatch => { forgotPassword: () => dispatch(forgotPassword()), tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)), markPasswordForgotten: () => dispatch(markPasswordForgotten()), + useOldInterface: () => dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')), + setNetworkEndpoints: type => dispatch(setNetworkEndpoints(type)), } } diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index b76c1e60f..92feb70ba 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -5,6 +5,8 @@ const Identicon = require('./identicon') const connect = require('../metamask-connect') const ethUtil = require('ethereumjs-util') const classnames = require('classnames') +const { compose } = require('recompose') +const { withRouter } = require('react-router-dom') const AccountDropdownMini = require('./dropdowns/account-dropdown-mini') @@ -19,6 +21,8 @@ const { conversionRateSelector, } = require('../selectors.js') +const { DEFAULT_ROUTE } = require('../routes') + function mapStateToProps (state) { return { balance: getSelectedAccount(state).balance, @@ -37,7 +41,10 @@ function mapDispatchToProps (dispatch) { } } -module.exports = connect(mapStateToProps, mapDispatchToProps)(SignatureRequest) +module.exports = compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(SignatureRequest) inherits(SignatureRequest, Component) function SignatureRequest (props) { @@ -223,10 +230,14 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.btn-secondary--lg.request-signature__footer__cancel-button', { - onClick: cancel, + onClick: event => { + cancel(event).then(() => this.props.history.push(DEFAULT_ROUTE)) + }, }, this.props.t('cancel')), h('button.btn-primary--lg', { - onClick: sign, + onClick: event => { + sign(event).then(() => this.props.history.push(DEFAULT_ROUTE)) + }, }, this.props.t('sign')), ]) } diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index 57ae89dc6..35ec6c7af 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -2,12 +2,13 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('./metamask-connect') -const { withRouter } = require('react-router-dom') +const { withRouter, Redirect } = require('react-router-dom') const { compose } = require('recompose') const actions = require('./actions') const txHelper = require('../lib/tx-helper') const PendingTx = require('./components/pending-tx') +const SignatureRequest = require('./components/signature-request') // const PendingMsg = require('./components/pending-msg') // const PendingPersonalMsg = require('./components/pending-personal-msg') // const PendingTypedMsg = require('./components/pending-typed-msg') @@ -55,6 +56,7 @@ function ConfirmTxScreen () { } ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) { + console.log('CONFTX COMPONENTDIDUPDATE') const { unapprovedTxs, network, @@ -67,6 +69,7 @@ ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) { const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network) if (prevTx.status === 'dropped' && unconfTxList.length === 0) { + console.log('CONFTX REDIRECTINGTODEFAULT') this.props.history.push(DEFAULT_ROUTE) } } @@ -87,6 +90,7 @@ ConfirmTxScreen.prototype.render = function () { } = props var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) + console.log('UNCONF', unconfTxList, props.index, props) var txData = unconfTxList[props.index] || {} var txParams = txData.params || {} @@ -108,7 +112,13 @@ ConfirmTxScreen.prototype.render = function () { */ log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`) - if (unconfTxList.length === 0) return h(Loading) + if (unconfTxList.length === 0) { + return h(Redirect, { + to: { + pathname: DEFAULT_ROUTE, + }, + }) + } return currentTxView({ // Properties @@ -136,11 +146,27 @@ ConfirmTxScreen.prototype.render = function () { function currentTxView (opts) { log.info('rendering current tx view') const { txData } = opts - const { txParams } = txData + const { txParams, msgParams } = txData + console.log('TXPARAMS', txParams, msgParams) if (txParams) { log.debug('txParams detected, rendering pending tx') return h(PendingTx, opts) + } else if (msgParams) { + log.debug('msgParams detected, rendering pending msg') + + return h(SignatureRequest, opts) + + // if (type === 'eth_sign') { + // log.debug('rendering eth_sign message') + // return h(PendingMsg, opts) + // } else if (type === 'personal_sign') { + // log.debug('rendering personal_sign message') + // return h(PendingPersonalMsg, opts) + // } else if (type === 'eth_signTypedData') { + // log.debug('rendering eth_signTypedData message') + // return h(PendingTypedMsg, opts) + // } } return h(Loading) @@ -174,7 +200,7 @@ ConfirmTxScreen.prototype.signMessage = function (msgData, event) { var params = msgData.msgParams params.metamaskId = msgData.id this.stopPropagation(event) - this.props.dispatch(actions.signMsg(params)) + return this.props.dispatch(actions.signMsg(params)) } ConfirmTxScreen.prototype.stopPropagation = function (event) { @@ -188,7 +214,7 @@ ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) { var params = msgData.msgParams params.metamaskId = msgData.id this.stopPropagation(event) - this.props.dispatch(actions.signPersonalMsg(params)) + return this.props.dispatch(actions.signPersonalMsg(params)) } ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) { @@ -196,25 +222,25 @@ ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) { var params = msgData.msgParams params.metamaskId = msgData.id this.stopPropagation(event) - this.props.dispatch(actions.signTypedMsg(params)) + return this.props.dispatch(actions.signTypedMsg(params)) } ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) { log.info('canceling message') this.stopPropagation(event) - this.props.dispatch(actions.cancelMsg(msgData)) + return this.props.dispatch(actions.cancelMsg(msgData)) } ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) { log.info('canceling personal message') this.stopPropagation(event) - this.props.dispatch(actions.cancelPersonalMsg(msgData)) + return this.props.dispatch(actions.cancelPersonalMsg(msgData)) } ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) { log.info('canceling typed message') this.stopPropagation(event) - this.props.dispatch(actions.cancelTypedMsg(msgData)) + return this.props.dispatch(actions.cancelTypedMsg(msgData)) } ConfirmTxScreen.prototype.goHome = function (event) { diff --git a/ui/app/routes.js b/ui/app/routes.js index aadf91cf5..d3b305b40 100644 --- a/ui/app/routes.js +++ b/ui/app/routes.js @@ -10,12 +10,13 @@ const NEW_ACCOUNT_ROUTE = '/new-account' const IMPORT_ACCOUNT_ROUTE = '/new-account/import' const SEND_ROUTE = '/send' const CONFIRM_TRANSACTION_ROUTE = '/confirm-transaction' +const SIGNATURE_REQUEST_ROUTE = '/confirm-transaction/signature-request' const NOTICE_ROUTE = '/notice' -const SIGNATURE_REQUEST_ROUTE = '/signature-request' const WELCOME_ROUTE = '/welcome' const INITIALIZE_ROUTE = '/initialize' const INITIALIZE_IMPORT_ACCOUNT_ROUTE = '/initialize/import-account' const INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE = '/initialize/import-with-seed-phrase' +const INITIALIZE_UNIQUE_IMAGE_ROUTE = '/initialize/unique-image' module.exports = { DEFAULT_ROUTE, @@ -36,4 +37,5 @@ module.exports = { INITIALIZE_ROUTE, INITIALIZE_IMPORT_ACCOUNT_ROUTE, INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE, + INITIALIZE_UNIQUE_IMAGE_ROUTE, } -- cgit