diff options
Add UniqueImageScreen
Diffstat (limited to 'mascara/src/app/first-time')
-rw-r--r-- | mascara/src/app/first-time/breadcrumbs.js | 1 | ||||
-rw-r--r-- | mascara/src/app/first-time/create-password-screen.js | 112 | ||||
-rw-r--r-- | mascara/src/app/first-time/index.css | 56 | ||||
-rw-r--r-- | mascara/src/app/first-time/index.js | 51 | ||||
-rw-r--r-- | mascara/src/app/first-time/loading-screen.js | 11 | ||||
-rw-r--r-- | mascara/src/app/first-time/spinner.js | 70 | ||||
-rw-r--r-- | mascara/src/app/first-time/unique-image-screen.js | 40 |
7 files changed, 298 insertions, 43 deletions
diff --git a/mascara/src/app/first-time/breadcrumbs.js b/mascara/src/app/first-time/breadcrumbs.js index cbd0da1a1..f8460d200 100644 --- a/mascara/src/app/first-time/breadcrumbs.js +++ b/mascara/src/app/first-time/breadcrumbs.js @@ -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'}} /> diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js index 4b4cea51d..e4b0425ce 100644 --- a/mascara/src/app/first-time/create-password-screen.js +++ b/mascara/src/app/first-time/create-password-screen.js @@ -1,46 +1,92 @@ 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 ( - <div className="create-password"> - <div className="create-password__title"> - Create Password + const { isLoading } = this.props + + return isLoading + ? <LoadingScreen loadingMessage="Creating your new account" /> + : ( + <div className="create-password"> + <div className="create-password__title"> + Create Password + </div> + <input + className="first-time-flow__input" + type="password" + placeholder="New Password (min 8 characters)" + onChange={e => this.setState({password: e.target.value})} + /> + <input + className="first-time-flow__input create-password__confirm-input" + type="password" + placeholder="Confirm Password" + onChange={e => this.setState({confirmPassword: e.target.value})} + /> + <button + className="first-time-flow__button" + disabled={!this.isValid()} + onClick={this.createAccount} + > + Create + </button> + <a + href="" + className="first-time-flow__link create-password__import-link" + onClick={e => e.preventDefault()} + > + Import an account + </a> + <Breadcrumbs total={3} currentIndex={0} /> </div> - <input - className="first-time-flow__input" - type="password" - placeholder="New Password (min 8 characters)" - onChange={e => this.setState({password: e.target.value})} - /> - <input - className="first-time-flow__input create-password__confirm-input" - type="password" - placeholder="Confirm Password" - onChange={e => this.setState({confirmPassword: e.target.value})} - /> - <button - className="first-time-flow__button" - > - Create - </button> - <a - href="" - className="first-time-flow__link create-password__import-link" - onClick={e => e.preventDefault()} - > - Import an account - </a> - <Breadcrumbs total={3} currentIndex={0} /> - </div> - ) + ) } +} -}
\ No newline at end of file +export default connect( + ({ appState: { isLoading } }) => ({ isLoading }), + dispatch => ({ + createAccount: password => dispatch(createNewVaultAndKeychain(password)) + }) +)(CreatePasswordScreen) diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index dbcde5004..5193b412f 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -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); @@ -82,4 +107,27 @@ 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; }
\ No newline at end of file diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index 1a9a00eec..4bc03c09c 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -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) + diff --git a/mascara/src/app/first-time/loading-screen.js b/mascara/src/app/first-time/loading-screen.js new file mode 100644 index 000000000..b90465e09 --- /dev/null +++ b/mascara/src/app/first-time/loading-screen.js @@ -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> + ); +} diff --git a/mascara/src/app/first-time/spinner.js b/mascara/src/app/first-time/spinner.js new file mode 100644 index 000000000..78dca9a88 --- /dev/null +++ b/mascara/src/app/first-time/spinner.js @@ -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> + ); +} diff --git a/mascara/src/app/first-time/unique-image-screen.js b/mascara/src/app/first-time/unique-image-screen.js new file mode 100644 index 000000000..ae1512d47 --- /dev/null +++ b/mascara/src/app/first-time/unique-image-screen.js @@ -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) |