mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add UniqueImageScreen
This commit is contained in:
parent
4e446410eb
commit
e1497fafa6
@ -13,6 +13,7 @@ export default class Breadcrumbs extends Component {
|
||||
<div className="breadcrumbs">
|
||||
{Array(total).fill().map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="breadcrumb"
|
||||
style={{backgroundColor: i === currentIndex ? '#D8D8D8' : '#FFFFFF'}}
|
||||
/>
|
||||
|
@ -1,15 +1,53 @@
|
||||
import React, {Component, PropTypes} from 'react'
|
||||
import {connect} from 'react-redux';
|
||||
import {createNewVaultAndKeychain} from '../../../../ui/app/actions'
|
||||
import LoadingScreen from './loading-screen'
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
|
||||
export default class CreatePasswordScreen extends Component {
|
||||
class CreatePasswordScreen extends Component {
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
createAccount: PropTypes.func.isRequired,
|
||||
next: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
state = {
|
||||
password: '',
|
||||
confirmPassword: ''
|
||||
}
|
||||
|
||||
isValid() {
|
||||
const {password, confirmPassword} = this.state;
|
||||
|
||||
if (!password || !confirmPassword) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password.length < 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return password === confirmPassword;
|
||||
}
|
||||
|
||||
createAccount = () => {
|
||||
if (!this.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {password} = this.state;
|
||||
const {createAccount, next} = this.props;
|
||||
|
||||
createAccount(password)
|
||||
.then(next);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
const { isLoading } = this.props
|
||||
|
||||
return isLoading
|
||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||
: (
|
||||
<div className="create-password">
|
||||
<div className="create-password__title">
|
||||
Create Password
|
||||
@ -28,6 +66,8 @@ export default class CreatePasswordScreen extends Component {
|
||||
/>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
disabled={!this.isValid()}
|
||||
onClick={this.createAccount}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
@ -42,5 +82,11 @@ export default class CreatePasswordScreen extends Component {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ appState: { isLoading } }) => ({ isLoading }),
|
||||
dispatch => ({
|
||||
createAccount: password => dispatch(createNewVaultAndKeychain(password))
|
||||
})
|
||||
)(CreatePasswordScreen)
|
||||
|
@ -1,18 +1,21 @@
|
||||
$primary
|
||||
|
||||
.first-time-flow {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.create-password {
|
||||
.create-password,
|
||||
.unique-image {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
margin: 67px 0 0 146px;
|
||||
max-width: 350px;
|
||||
max-width: 35rem;
|
||||
}
|
||||
|
||||
.create-password__title {
|
||||
height: 102px;
|
||||
.create-password__title,
|
||||
.unique-image__title {
|
||||
width: 280px;
|
||||
color: #1B344D;
|
||||
font-size: 40px;
|
||||
@ -29,6 +32,23 @@
|
||||
margin-bottom: 54px;
|
||||
}
|
||||
|
||||
.unique-image__title {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.unique-image__body-text {
|
||||
width: 335px;
|
||||
color: #1B344D;
|
||||
font-size: 16px;
|
||||
line-height: 23px;
|
||||
font-family: Montserrat UltraLight;
|
||||
}
|
||||
|
||||
.unique-image__body-text +
|
||||
.unique-image__body-text {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.first-time-flow__input {
|
||||
width: 350px;
|
||||
font-size: 18px;
|
||||
@ -57,6 +77,11 @@
|
||||
transition: 200ms ease-in-out;
|
||||
}
|
||||
|
||||
button.first-time-flow__button[disabled] {
|
||||
background-color: rgba(247, 134, 28, 0.9);
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
button.first-time-flow__button:hover {
|
||||
transform: scale(1);
|
||||
background-color: rgba(247, 134, 28, 0.9);
|
||||
@ -83,3 +108,26 @@ button.first-time-flow__button:hover {
|
||||
.breadcrumb + .breadcrumb {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.loading-screen {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
margin-top: 143px;
|
||||
}
|
||||
|
||||
.loading-screen .spinner {
|
||||
margin-bottom: 25px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.loading-screen__message {
|
||||
color: #1B344D;
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
font-family: Montserrat UltraLight;
|
||||
}
|
@ -1,14 +1,20 @@
|
||||
import React, {Component, PropTypes} from 'react'
|
||||
import {connect} from 'react-redux';
|
||||
import CreatePasswordScreen from './create-password-screen'
|
||||
import UniqueImageScreen from './unique-image-screen'
|
||||
|
||||
export default class FirstTimeFlow extends Component {
|
||||
class FirstTimeFlow extends Component {
|
||||
|
||||
static propTypes = {
|
||||
screenType: PropTypes.string
|
||||
isInitialized: PropTypes.bool,
|
||||
seedWords: PropTypes.string,
|
||||
noActiveNotices: PropTypes.bool
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
screenType: FirstTimeFlow.CREATE_PASSWORD
|
||||
isInitialized: false,
|
||||
seedWords: '',
|
||||
noActiveNotices: false
|
||||
};
|
||||
|
||||
static SCREEN_TYPE = {
|
||||
@ -20,9 +26,23 @@ export default class FirstTimeFlow extends Component {
|
||||
BUY_ETHER: 'buy_ether'
|
||||
};
|
||||
|
||||
static getScreenType = ({isInitialized, noActiveNotices, seedWords}) => {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
screenType: this.getScreenType()
|
||||
}
|
||||
}
|
||||
|
||||
setScreenType(screenType) {
|
||||
this.setState({ screenType })
|
||||
}
|
||||
|
||||
getScreenType() {
|
||||
const {isInitialized, seedWords, noActiveNotices} = this.props;
|
||||
const {SCREEN_TYPE} = FirstTimeFlow
|
||||
|
||||
return SCREEN_TYPE.UNIQUE_IMAGE
|
||||
|
||||
if (!isInitialized) {
|
||||
return SCREEN_TYPE.CREATE_PASSWORD
|
||||
}
|
||||
@ -39,9 +59,19 @@ export default class FirstTimeFlow extends Component {
|
||||
renderScreen() {
|
||||
const {SCREEN_TYPE} = FirstTimeFlow
|
||||
|
||||
switch (this.props.screenType) {
|
||||
switch (this.state.screenType) {
|
||||
case SCREEN_TYPE.CREATE_PASSWORD:
|
||||
return <CreatePasswordScreen />
|
||||
return (
|
||||
<CreatePasswordScreen
|
||||
next={() => this.setScreenType(SCREEN_TYPE.UNIQUE_IMAGE)}
|
||||
/>
|
||||
)
|
||||
case SCREEN_TYPE.UNIQUE_IMAGE:
|
||||
return (
|
||||
<UniqueImageScreen
|
||||
next={() => this.setScreenType(SCREEN_TYPE.TERM_OF_USE)}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return <noscript />
|
||||
}
|
||||
@ -56,3 +86,12 @@ export default class FirstTimeFlow extends Component {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ metamask: { isInitialized, seedWords, noActiveNotices } }) => ({
|
||||
isInitialized,
|
||||
seedWords,
|
||||
noActiveNotices
|
||||
})
|
||||
)(FirstTimeFlow)
|
||||
|
||||
|
11
mascara/src/app/first-time/loading-screen.js
Normal file
11
mascara/src/app/first-time/loading-screen.js
Normal file
@ -0,0 +1,11 @@
|
||||
import React, {Component, PropTypes} from 'react'
|
||||
import Spinner from './Spinner'
|
||||
|
||||
export default function LoadingScreen({ className = '', loadingMessage }) {
|
||||
return (
|
||||
<div className={`${className} loading-screen`}>
|
||||
<Spinner color="#1B344D" />
|
||||
<div className="loading-screen__message">{loadingMessage}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
70
mascara/src/app/first-time/spinner.js
Normal file
70
mascara/src/app/first-time/spinner.js
Normal file
@ -0,0 +1,70 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function Spinner({ className = '', color = "#000000" }) {
|
||||
return (
|
||||
<div className={`spinner ${className}`}>
|
||||
<svg className="lds-spinner" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" style={{background: 'none'}}>
|
||||
<g transform="rotate(0 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(30 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(60 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.75s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(90 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(120 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(150 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.5s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(180 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(210 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(240 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.25s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(270 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(300 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
<g transform="rotate(330 50 50)">
|
||||
<rect x={47} y={16} rx={0} ry={0} width={6} height={20} fill={color}>
|
||||
<animate attributeName="opacity" values="1;0" dur="1s" begin="0s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
40
mascara/src/app/first-time/unique-image-screen.js
Normal file
40
mascara/src/app/first-time/unique-image-screen.js
Normal file
@ -0,0 +1,40 @@
|
||||
import React, {Component, PropTypes} from 'react'
|
||||
import {connect} from 'react-redux';
|
||||
import Identicon from '../../../../ui/app/components/identicon'
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
|
||||
class UniqueImageScreen extends Component {
|
||||
static propTypes = {
|
||||
address: PropTypes.string.isRequired,
|
||||
next: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="unique-image">
|
||||
<Identicon address={this.props.address} diameter={70} />
|
||||
<div className="unique-image__title">You unique account image</div>
|
||||
<div className="unique-image__body-text">
|
||||
This image was programmatically generated for you by your new account number.
|
||||
</div>
|
||||
<div className="unique-image__body-text">
|
||||
You’ll see this image everytime you need to confirm a transaction.
|
||||
</div>
|
||||
<button
|
||||
className="first-time-flow__button"
|
||||
onClick={this.props.next}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<Breadcrumbs total={3} currentIndex={1} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ metamask: { identities } }) => ({
|
||||
address: Object.entries(identities)
|
||||
.map(([key]) => key)[0]
|
||||
})
|
||||
)(UniqueImageScreen)
|
@ -130,6 +130,7 @@
|
||||
"react-simple-file-input": "^2.0.0",
|
||||
"react-tooltip-component": "^0.3.0",
|
||||
"readable-stream": "^2.3.3",
|
||||
"recompose": "^0.25.0",
|
||||
"redux": "^3.0.5",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-thunk": "^2.2.0",
|
||||
|
@ -243,19 +243,26 @@ function createNewVaultAndKeychain (password) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
log.debug(`background.createNewVaultAndKeychain`)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
background.createNewVaultAndKeychain(password, (err) => {
|
||||
if (err) {
|
||||
return dispatch(actions.displayWarning(err.message))
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
log.debug(`background.placeSeedWords`)
|
||||
background.placeSeedWords((err) => {
|
||||
if (err) {
|
||||
return dispatch(actions.displayWarning(err.message))
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
forceUpdateMetamaskState(dispatch)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,10 +106,7 @@ App.prototype.render = function () {
|
||||
this.renderNetworkDropdown(),
|
||||
this.renderDropdown(),
|
||||
|
||||
h(Loading, {
|
||||
isLoading: isLoading || isLoadingNetwork,
|
||||
loadingMessage: loadMessage,
|
||||
}),
|
||||
this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }),
|
||||
|
||||
// panel content
|
||||
h('.app-primary' + (transForward ? '.from-right' : '.from-left'), {
|
||||
@ -401,6 +398,17 @@ App.prototype.renderDropdown = function () {
|
||||
])
|
||||
}
|
||||
|
||||
App.prototype.renderLoadingIndicator = function({ isLoading, isLoadingNetwork, loadMessage }) {
|
||||
const { isMascara } = this.props;
|
||||
|
||||
return isMascara
|
||||
? null
|
||||
: h(Loading, {
|
||||
isLoading: isLoading || isLoadingNetwork,
|
||||
loadingMessage: loadMessage,
|
||||
})
|
||||
}
|
||||
|
||||
App.prototype.renderBackButton = function (style, justArrow = false) {
|
||||
var props = this.props
|
||||
return (
|
||||
@ -420,19 +428,13 @@ App.prototype.renderBackButton = function (style, justArrow = false) {
|
||||
)
|
||||
}
|
||||
|
||||
App.prototype.renderMascaraFirstTime = function () {
|
||||
return 'hi'
|
||||
}
|
||||
|
||||
App.prototype.renderPrimary = function () {
|
||||
log.debug('rendering primary')
|
||||
var props = this.props
|
||||
const {isMascara, isOnboarding} = props
|
||||
|
||||
if (isMascara && isOnboarding) {
|
||||
return h(MascaraFirstTime, {
|
||||
screenType: MascaraFirstTime.getScreenType(props)
|
||||
})
|
||||
return h(MascaraFirstTime)
|
||||
}
|
||||
|
||||
// notices
|
||||
|
Loading…
Reference in New Issue
Block a user