aboutsummaryrefslogtreecommitdiffstats
path: root/mascara/src/app/first-time
diff options
context:
space:
mode:
Diffstat (limited to 'mascara/src/app/first-time')
-rw-r--r--mascara/src/app/first-time/backup-phrase-screen.js7
-rw-r--r--mascara/src/app/first-time/breadcrumbs.js5
-rw-r--r--mascara/src/app/first-time/buy-ether-screen.js3
-rw-r--r--mascara/src/app/first-time/create-password-screen.js32
-rw-r--r--mascara/src/app/first-time/import-account-screen.js3
-rw-r--r--mascara/src/app/first-time/import-seed-phrase-screen.js170
-rw-r--r--mascara/src/app/first-time/index.css50
-rw-r--r--mascara/src/app/first-time/index.js43
-rw-r--r--mascara/src/app/first-time/loading-screen.js10
-rw-r--r--mascara/src/app/first-time/notice-screen.js72
-rw-r--r--mascara/src/app/first-time/unique-image-screen.js3
11 files changed, 258 insertions, 140 deletions
diff --git a/mascara/src/app/first-time/backup-phrase-screen.js b/mascara/src/app/first-time/backup-phrase-screen.js
index c68dacea2..9db61f3ab 100644
--- a/mascara/src/app/first-time/backup-phrase-screen.js
+++ b/mascara/src/app/first-time/backup-phrase-screen.js
@@ -1,5 +1,6 @@
-import React, {Component, PropTypes} from 'react'
-import {connect} from 'react-redux';
+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'
@@ -194,7 +195,7 @@ class BackupPhraseScreen extends Component {
</button>
</div>
</div>
- )
+ )
}
renderBack () {
diff --git a/mascara/src/app/first-time/breadcrumbs.js b/mascara/src/app/first-time/breadcrumbs.js
index f8460d200..b81a9fb9b 100644
--- a/mascara/src/app/first-time/breadcrumbs.js
+++ b/mascara/src/app/first-time/breadcrumbs.js
@@ -1,10 +1,11 @@
-import React, {Component, PropTypes} from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
export default class Breadcrumbs extends Component {
static propTypes = {
total: PropTypes.number,
- currentIndex: PropTypes.number
+ currentIndex: PropTypes.number,
};
render() {
diff --git a/mascara/src/app/first-time/buy-ether-screen.js b/mascara/src/app/first-time/buy-ether-screen.js
index 45b2df1c8..c5a560638 100644
--- a/mascara/src/app/first-time/buy-ether-screen.js
+++ b/mascara/src/app/first-time/buy-ether-screen.js
@@ -1,4 +1,5 @@
-import React, {Component, PropTypes} from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import classnames from 'classnames'
import {connect} from 'react-redux'
import {qrcode} from 'qrcode-npm'
diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js
index 21d29d72b..450d6a479 100644
--- a/mascara/src/app/first-time/create-password-screen.js
+++ b/mascara/src/app/first-time/create-password-screen.js
@@ -1,6 +1,7 @@
import EventEmitter from 'events'
-import React, {Component, PropTypes} from 'react'
-import {connect} from 'react-redux';
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
import {createNewVaultAndKeychain} from '../../../../ui/app/actions'
import LoadingScreen from './loading-screen'
import Breadcrumbs from './breadcrumbs'
@@ -12,12 +13,12 @@ class CreatePasswordScreen extends Component {
createAccount: PropTypes.func.isRequired,
goToImportWithSeedPhrase: PropTypes.func.isRequired,
goToImportAccount: PropTypes.func.isRequired,
- next: PropTypes.func.isRequired
+ next: PropTypes.func.isRequired,
}
state = {
password: '',
- confirmPassword: ''
+ confirmPassword: '',
}
constructor () {
@@ -25,40 +26,39 @@ class CreatePasswordScreen extends Component {
this.animationEventEmitter = new EventEmitter()
}
- isValid() {
- const {password, confirmPassword} = this.state;
+ isValid () {
+ const {password, confirmPassword} = this.state
if (!password || !confirmPassword) {
- return false;
+ return false
}
if (password.length < 8) {
- return false;
+ return false
}
- return password === confirmPassword;
+ return password === confirmPassword
}
createAccount = () => {
if (!this.isValid()) {
- return;
+ return
}
- const {password} = this.state;
- const {createAccount, next} = this.props;
+ const {password} = this.state
+ const {createAccount, next} = this.props
createAccount(password)
- .then(next);
+ .then(next)
}
- render() {
- const { isLoading, goToImportAccount, goToImportWithSeedPhrase } = this.props
+ render () {
+ const { isLoading, goToImportWithSeedPhrase } = this.props
return isLoading
? <LoadingScreen loadingMessage="Creating your new account" />
: (
<div>
- <h2 className="alpha-warning">Warning This is Experemental software and is a Developer BETA </h2>
<div className="first-view-main">
<div className="mascara-info">
<Mascot
diff --git a/mascara/src/app/first-time/import-account-screen.js b/mascara/src/app/first-time/import-account-screen.js
index bf8e209e4..ab0aca0f0 100644
--- a/mascara/src/app/first-time/import-account-screen.js
+++ b/mascara/src/app/first-time/import-account-screen.js
@@ -1,4 +1,5 @@
-import React, {Component, PropTypes} from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import classnames from 'classnames'
import LoadingScreen from './loading-screen'
diff --git a/mascara/src/app/first-time/import-seed-phrase-screen.js b/mascara/src/app/first-time/import-seed-phrase-screen.js
index d9a9dc835..de8d675e1 100644
--- a/mascara/src/app/first-time/import-seed-phrase-screen.js
+++ b/mascara/src/app/first-time/import-seed-phrase-screen.js
@@ -1,7 +1,13 @@
-import React, {Component, PropTypes} from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import {connect} from 'react-redux'
-import LoadingScreen from './loading-screen'
-import {createNewVaultAndRestore, hideWarning, displayWarning} from '../../../../ui/app/actions'
+import classnames from 'classnames'
+import {
+ createNewVaultAndRestore,
+ hideWarning,
+ displayWarning,
+ unMarkPasswordForgotten,
+} from '../../../../ui/app/actions'
class ImportSeedPhraseScreen extends Component {
static propTypes = {
@@ -10,8 +16,8 @@ class ImportSeedPhraseScreen extends Component {
next: PropTypes.func.isRequired,
createNewVaultAndRestore: PropTypes.func.isRequired,
hideWarning: PropTypes.func.isRequired,
- isLoading: PropTypes.bool.isRequired,
displayWarning: PropTypes.func,
+ leaveImportSeedScreenState: PropTypes.func,
};
state = {
@@ -20,88 +26,134 @@ class ImportSeedPhraseScreen extends Component {
confirmPassword: '',
}
- onClick = () => {
- const { password, seedPhrase, confirmPassword } = this.state
- const { createNewVaultAndRestore, next, displayWarning } = this.props
+ parseSeedPhrase = (seedPhrase) => {
+ return seedPhrase
+ .match(/\w+/g)
+ .join(' ')
+ }
- if (seedPhrase.split(' ').length !== 12) {
- this.warning = 'Seed Phrases are 12 words long'
- displayWarning(this.warning)
- return
- }
+ onChange = ({ seedPhrase, password, confirmPassword }) => {
+ const {
+ password: prevPassword,
+ confirmPassword: prevConfirmPassword,
+ } = this.state
+ const { displayWarning, hideWarning } = this.props
+
+ let warning = null
- if (password.length < 8) {
- this.warning = 'Passwords require a mimimum length of 8'
- displayWarning(this.warning)
- return
+ 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'
}
- if (password !== confirmPassword) {
- this.warning = 'Confirmed password does not match'
- displayWarning(this.warning)
- return
+ if (warning) {
+ displayWarning(warning)
+ } else {
+ hideWarning()
}
- this.warning = null
- createNewVaultAndRestore(password, seedPhrase)
+
+ seedPhrase && this.setState({ seedPhrase })
+ password && this.setState({ password })
+ confirmPassword && this.setState({ confirmPassword })
+ }
+
+ onClick = () => {
+ const { password, seedPhrase } = this.state
+ const {
+ createNewVaultAndRestore,
+ next,
+ displayWarning,
+ leaveImportSeedScreenState,
+ } = this.props
+
+ leaveImportSeedScreenState()
+ createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase))
.then(next)
}
render () {
- return this.props.isLoading
- ? <LoadingScreen loadingMessage="Creating your new account" />
- : (
- <div className="import-account">
- <a
- className="import-account__back-button"
- onClick={e => {
- e.preventDefault()
- this.props.back()
- }}
- href="#"
- >
- {`< Back`}
- </a>
- <div className="import-account__title">
- Import an Account with Seed Phrase
- </div>
- <div className="import-account__selector-label">
- Enter your secret twelve word phrase here to restore your vault.
- </div>
+ const { seedPhrase, password, confirmPassword } = this.state
+ const { warning } = this.props
+ const importDisabled = warning || !seedPhrase || !password || !confirmPassword
+ return (
+ <div className="import-account">
+ <a
+ className="import-account__back-button"
+ onClick={e => {
+ e.preventDefault()
+ this.props.back()
+ }}
+ href="#"
+ >
+ {`< Back`}
+ </a>
+ <div className="import-account__title">
+ Import an Account with Seed Phrase
+ </div>
+ <div className="import-account__selector-label">
+ Enter your secret twelve word phrase here to restore your vault.
+ </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.setState({seedPhrase: e.target.value})}
+ onChange={e => this.onChange({seedPhrase: e.target.value})}
+ value={this.state.seedPhrase}
+ placeholder="Separate each word with a single space"
/>
- <span
- className="error"
- >
- {this.props.warning}
- </span>
+ </div>
+ <span
+ className="error"
+ >
+ {this.props.warning}
+ </span>
+ <div className="import-account__input-wrapper">
+ <label className="import-account__input-label">New Password</label>
<input
className="first-time-flow__input"
type="password"
placeholder="New Password (min 8 characters)"
- onChange={e => this.setState({password: e.target.value})}
+ onChange={e => this.onChange({password: e.target.value})}
/>
+ </div>
+ <div className="import-account__input-wrapper">
+ <label
+ className="import-account__input-label"
+ className={classnames('import-account__input-label', {
+ 'import-account__input-label__disabled': password.length < 8,
+ })}
+ >Confirm Password</label>
<input
- className="first-time-flow__input create-password__confirm-input"
+ className={classnames('first-time-flow__input', {
+ 'first-time-flow__input__disabled': password.length < 8,
+ })}
type="password"
placeholder="Confirm Password"
- onChange={e => this.setState({confirmPassword: e.target.value})}
+ onChange={e => this.onChange({confirmPassword: e.target.value})}
+ disabled={password.length < 8}
/>
- <button
- className="first-time-flow__button"
- onClick={this.onClick}
- >
- Import
- </button>
</div>
- )
+ <button
+ className="first-time-flow__button"
+ onClick={() => !importDisabled && this.onClick()}
+ disabled={importDisabled}
+ >
+ Import
+ </button>
+ </div>
+ )
}
}
export default connect(
- ({ appState: { isLoading, warning } }) => ({ isLoading, warning }),
+ ({ appState: { warning } }) => ({ warning }),
dispatch => ({
+ leaveImportSeedScreenState: () => {
+ dispatch(unMarkPasswordForgotten())
+ },
createNewVaultAndRestore: (pw, seed) => dispatch(createNewVaultAndRestore(pw, seed)),
displayWarning: (warning) => dispatch(displayWarning(warning)),
hideWarning: () => dispatch(hideWarning()),
diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css
index f91c72f0e..f59eb4ce1 100644
--- a/mascara/src/app/first-time/index.css
+++ b/mascara/src/app/first-time/index.css
@@ -1,16 +1,18 @@
.first-time-flow {
- height: 100vh;
width: 100vw;
- background-color: #FFF;
+ background-color: #fff;
overflow: auto;
+ display: flex;
+ justify-content: center;
+ flex: 1 0 auto;
}
.alpha-warning {
background: #f7861c;
color: #fff;
line-height: 2em;
- padding-left: 2em;
+ padding-left: 10vw;
}
.first-view-main {
@@ -23,7 +25,6 @@
display: flex;
flex-flow: column;
margin-top: 70px;
- margin-right: 10vw;
width: 35vw;
max-width: 550px;
}
@@ -44,10 +45,18 @@
.buy-ether {
display: flex;
flex-flow: column nowrap;
- margin: 67px 0 0 146px;
+ margin: 67px 0 50px;
max-width: 35rem;
}
+.create-password {
+ margin: 67px 0 50px;
+}
+
+.import-account {
+ max-width: initial;
+}
+
@media only screen and (max-width: 575px) {
.create-password,
.unique-image,
@@ -135,14 +144,16 @@
.backup-phrase__title,
.import-account__title,
.buy-ether__title {
- width: 280px;
color: #1B344D;
font-size: 40px;
- font-weight: 500;
line-height: 51px;
margin-bottom: 24px;
}
+.import-account__title {
+ margin-bottom: 10px;
+}
+
.tou__title,
.backup-phrase__title {
width: 480px;
@@ -288,9 +299,7 @@
.import-account__back-button:hover {
margin-bottom: 18px;
color: #22232C;
- font-family: Montserrat Regular;
font-size: 16px;
- font-weight: 500;
line-height: 21px;
}
@@ -311,6 +320,12 @@ button.backup-phrase__reveal-button:hover {
.import-account__secret-phrase {
font-size: 16px;
+ margin: initial;
+}
+
+.import-account__secret-phrase::placeholder {
+ color: #9B9B9B;
+ font-weight: 200;
}
.backup-phrase__confirm-seed-options {
@@ -350,9 +365,7 @@ button.backup-phrase__confirm-seed-option:hover {
.import-account__selector-label {
color: #1B344D;
- font-family: Montserrat Light;
- font-size: 18px;
- line-height: 23px;
+ font-size: 16px;
}
.import-account__dropdown {
@@ -394,7 +407,6 @@ button.backup-phrase__confirm-seed-option:hover {
margin-top: 10px;
width: 422px;
color: #FF001F;
- font-family: Montserrat Light;
font-size: 16px;
line-height: 21px;
}
@@ -402,10 +414,12 @@ button.backup-phrase__confirm-seed-option:hover {
.import-account__input-label {
margin-bottom: 9px;
color: #1B344D;
- font-family: Montserrat Light;
font-size: 18px;
line-height: 23px;
- text-transform: uppercase;
+}
+
+.import-account__input-label__disabled {
+ opacity: 0.5;
}
.import-account__input {
@@ -549,11 +563,15 @@ button.backup-phrase__confirm-seed-option:hover {
width: 350px;
font-size: 18px;
line-height: 24px;
- padding: 15px 28px;
+ padding: 15px;
border: 1px solid #CDCDCD;
background-color: #FFFFFF;
}
+.first-time-flow__input__disabled {
+ opacity: 0.5;
+}
+
.first-time-flow__input::placeholder {
color: #9B9B9B;
font-weight: 200;
diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js
index 66b591bd8..da2f6bab9 100644
--- a/mascara/src/app/first-time/index.js
+++ b/mascara/src/app/first-time/index.js
@@ -1,4 +1,5 @@
-import React, {Component, PropTypes} from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import CreatePasswordScreen from './create-password-screen'
import UniqueImageScreen from './unique-image-screen'
@@ -6,7 +7,10 @@ import NoticeScreen from './notice-screen'
import BackupPhraseScreen from './backup-phrase-screen'
import ImportAccountScreen from './import-account-screen'
import ImportSeedPhraseScreen from './import-seed-phrase-screen'
-import {onboardingBuyEthView} from '../../../../ui/app/actions'
+import {
+ onboardingBuyEthView,
+ unMarkPasswordForgotten,
+} from '../../../../ui/app/actions'
class FirstTimeFlow extends Component {
@@ -32,6 +36,7 @@ class FirstTimeFlow extends Component {
NOTICE: 'notice',
BACK_UP_PHRASE: 'back_up_phrase',
CONFIRM_BACK_UP_PHRASE: 'confirm_back_up_phrase',
+ LOADING: 'loading',
};
constructor (props) {
@@ -50,11 +55,15 @@ class FirstTimeFlow extends Component {
isInitialized,
seedWords,
noActiveNotices,
+ forgottenPassword,
} = this.props
const {SCREEN_TYPE} = FirstTimeFlow
// return SCREEN_TYPE.NOTICE
+ if (forgottenPassword) {
+ return SCREEN_TYPE.IMPORT_SEED_PHRASE
+ }
if (!isInitialized) {
return SCREEN_TYPE.CREATE_PASSWORD
}
@@ -70,7 +79,13 @@ class FirstTimeFlow extends Component {
renderScreen () {
const {SCREEN_TYPE} = FirstTimeFlow
- const {goToBuyEtherView, address} = this.props
+ const {
+ goToBuyEtherView,
+ address,
+ restoreCreatePasswordScreen,
+ forgottenPassword,
+ leaveImportSeedScreenState,
+ } = this.props
switch (this.state.screenType) {
case SCREEN_TYPE.CREATE_PASSWORD:
@@ -91,8 +106,14 @@ class FirstTimeFlow extends Component {
case SCREEN_TYPE.IMPORT_SEED_PHRASE:
return (
<ImportSeedPhraseScreen
- back={() => this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD)}
- next={() => this.setScreenType(SCREEN_TYPE.NOTICE)}
+ back={() => {
+ leaveImportSeedScreenState()
+ this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD)
+ }}
+ next={() => {
+ const newScreenType = forgottenPassword ? null : SCREEN_TYPE.NOTICE
+ this.setScreenType(newScreenType)
+ }}
/>
)
case SCREEN_TYPE.UNIQUE_IMAGE:
@@ -129,13 +150,23 @@ class FirstTimeFlow extends Component {
}
export default connect(
- ({ metamask: { isInitialized, seedWords, noActiveNotices, selectedAddress } }) => ({
+ ({
+ metamask: {
+ isInitialized,
+ seedWords,
+ noActiveNotices,
+ selectedAddress,
+ forgottenPassword,
+ }
+ }) => ({
isInitialized,
seedWords,
noActiveNotices,
address: selectedAddress,
+ forgottenPassword,
}),
dispatch => ({
+ leaveImportSeedScreenState: () => dispatch(unMarkPasswordForgotten()),
goToBuyEtherView: address => dispatch(onboardingBuyEthView(address)),
})
)(FirstTimeFlow)
diff --git a/mascara/src/app/first-time/loading-screen.js b/mascara/src/app/first-time/loading-screen.js
index 732b7f2d7..01e1c1998 100644
--- a/mascara/src/app/first-time/loading-screen.js
+++ b/mascara/src/app/first-time/loading-screen.js
@@ -1,4 +1,5 @@
-import React, {Component, PropTypes} from 'react'
+import React from 'react'
+import PropTypes from 'prop-types'
import Spinner from './spinner'
export default function LoadingScreen({ className = '', loadingMessage }) {
@@ -7,5 +8,10 @@ export default function LoadingScreen({ className = '', loadingMessage }) {
<Spinner color="#1B344D" />
<div className="loading-screen__message">{loadingMessage}</div>
</div>
- );
+ )
+}
+
+LoadingScreen.propTypes = {
+ className: PropTypes.string,
+ loadingMessage: PropTypes.string,
}
diff --git a/mascara/src/app/first-time/notice-screen.js b/mascara/src/app/first-time/notice-screen.js
index d09070a95..0f0a7e95d 100644
--- a/mascara/src/app/first-time/notice-screen.js
+++ b/mascara/src/app/first-time/notice-screen.js
@@ -1,10 +1,12 @@
-import React, {Component, PropTypes} from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import Markdown from 'react-markdown'
import {connect} from 'react-redux'
import debounce from 'lodash.debounce'
import {markNoticeRead} from '../../../../ui/app/actions'
import Identicon from '../../../../ui/app/components/identicon'
import Breadcrumbs from './breadcrumbs'
+import LoadingScreen from './loading-screen'
class NoticeScreen extends Component {
static propTypes = {
@@ -12,25 +14,26 @@ class NoticeScreen extends Component {
lastUnreadNotice: PropTypes.shape({
title: PropTypes.string,
date: PropTypes.string,
- body: PropTypes.string
+ body: PropTypes.string,
}),
- next: PropTypes.func.isRequired
+ next: PropTypes.func.isRequired,
+ markNoticeRead: PropTypes.func,
};
static defaultProps = {
- lastUnreadNotice: {}
+ lastUnreadNotice: {},
};
state = {
atBottom: false,
}
- componentDidMount() {
+ componentDidMount () {
this.onScroll()
}
acceptTerms = () => {
- const { markNoticeRead, lastUnreadNotice, next } = this.props;
+ const { markNoticeRead, lastUnreadNotice, next } = this.props
const defer = markNoticeRead(lastUnreadNotice)
.then(() => this.setState({ atBottom: false }))
@@ -43,50 +46,53 @@ class NoticeScreen extends Component {
if (this.state.atBottom) return
const target = document.querySelector('.tou__body')
- const {scrollTop, offsetHeight, scrollHeight} = target;
- const atBottom = scrollTop + offsetHeight >= scrollHeight;
+ const {scrollTop, offsetHeight, scrollHeight} = target
+ const atBottom = scrollTop + offsetHeight >= scrollHeight
this.setState({atBottom: atBottom})
}, 25)
- render() {
+ render () {
const {
address,
- lastUnreadNotice: { title, body }
- } = this.props;
+ lastUnreadNotice: { title, body },
+ isLoading,
+ } = this.props
const { atBottom } = this.state
return (
- <div
- className="tou"
- onScroll={this.onScroll}
- >
- <Identicon address={address} diameter={70} />
- <div className="tou__title">{title}</div>
- <Markdown
- className="tou__body markdown"
- source={body}
- skipHtml
- />
- <button
- className="first-time-flow__button"
- onClick={atBottom && this.acceptTerms}
- disabled={!atBottom}
+ isLoading
+ ? <LoadingScreen />
+ : <div
+ className="tou"
+ onScroll={this.onScroll}
>
- Accept
- </button>
- <Breadcrumbs total={3} currentIndex={2} />
- </div>
+ <Identicon address={address} diameter={70} />
+ <div className="tou__title">{title}</div>
+ <Markdown
+ className="tou__body markdown"
+ source={body}
+ skipHtml
+ />
+ <button
+ className="first-time-flow__button"
+ onClick={atBottom && this.acceptTerms}
+ disabled={!atBottom}
+ >
+ Accept
+ </button>
+ <Breadcrumbs total={3} currentIndex={2} />
+ </div>
)
}
}
export default connect(
- ({ metamask: { selectedAddress, lastUnreadNotice } }) => ({
+ ({ metamask: { selectedAddress, lastUnreadNotice }, appState: { isLoading } }) => ({
lastUnreadNotice,
- address: selectedAddress
+ address: selectedAddress,
}),
dispatch => ({
- markNoticeRead: notice => dispatch(markNoticeRead(notice))
+ markNoticeRead: notice => dispatch(markNoticeRead(notice)),
})
)(NoticeScreen)
diff --git a/mascara/src/app/first-time/unique-image-screen.js b/mascara/src/app/first-time/unique-image-screen.js
index ef6bd28ab..46448aacf 100644
--- a/mascara/src/app/first-time/unique-image-screen.js
+++ b/mascara/src/app/first-time/unique-image-screen.js
@@ -1,4 +1,5 @@
-import React, {Component, PropTypes} from 'react'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import Identicon from '../../../../ui/app/components/identicon'
import Breadcrumbs from './breadcrumbs'