From 31175625b446cb5d18b17db23018bca8b14d280c Mon Sep 17 00:00:00 2001 From: Chi Kei Chan Date: Thu, 21 Mar 2019 16:03:30 -0700 Subject: Folder restructure (#6304) * Remove ui/app/keychains/ * Remove ui/app/img/ (unused images) * Move conversion-util to helpers/utils/ * Move token-util to helpers/utils/ * Move /helpers/*.js inside /helpers/utils/ * Move util tests inside /helpers/utils/ * Renameand move confirm-transaction/util.js to helpers/utils/ * Move higher-order-components to helpers/higher-order-components/ * Move infura-conversion.json to helpers/constants/ * Move all utility functions to helpers/utils/ * Move pages directory to top-level * Move all constants to helpers/constants/ * Move metametrics inside helpers/ * Move app and root inside pages/ * Move routes inside helpers/ * Re-organize ducks/ * Move reducers to ducks/ * Move selectors inside selectors/ * Move test out of test folder * Move action, reducer, store inside store/ * Move ui components inside ui/ * Move UI components inside ui/ * Move connected components inside components/app/ * Move i18n-helper inside helpers/ * Fix unit tests * Fix unit test * Move pages components * Rename routes component * Move reducers to ducks/index * Fix bad path in unit test --- ui/app/pages/keychains/index.scss | 197 ++++++++++++++++++++++++++++++++ ui/app/pages/keychains/restore-vault.js | 197 ++++++++++++++++++++++++++++++++ ui/app/pages/keychains/reveal-seed.js | 177 ++++++++++++++++++++++++++++ 3 files changed, 571 insertions(+) create mode 100644 ui/app/pages/keychains/index.scss create mode 100644 ui/app/pages/keychains/restore-vault.js create mode 100644 ui/app/pages/keychains/reveal-seed.js (limited to 'ui/app/pages/keychains') diff --git a/ui/app/pages/keychains/index.scss b/ui/app/pages/keychains/index.scss new file mode 100644 index 000000000..868185419 --- /dev/null +++ b/ui/app/pages/keychains/index.scss @@ -0,0 +1,197 @@ +.first-view-main-wrapper { + display: flex; + width: 100%; + height: 100%; + justify-content: center; + padding: 0 10px; +} + +.first-view-main { + display: flex; + flex-direction: row; + justify-content: flex-start; +} + +@media screen and (min-width: 1281px) { + .first-view-main { + width: 62vw; + } +} + +.import-account { + display: flex; + flex-flow: column nowrap; + margin: 60px 0 30px 0; + position: relative; + max-width: initial; +} + +@media only screen and (max-width: 575px) { + .import-account{ + margin: 24px; + display: flex; + flex-flow: column nowrap; + width: calc(100vw - 80px); + } + + .import-account__title { + width: initial !important; + } + + .first-view-main { + height: 100%; + flex-direction: column; + align-items: center; + justify-content: flex-start; + margin-top: 12px; + } + + .first-view-phone-invisible { + display: none; + } + + .first-time-flow__input { + width: 100%; + } + + .import-account__secret-phrase { + width: initial !important; + height: initial !important; + min-height: 190px; + } +} + +.import-account__title { + color: #1B344D; + font-size: 40px; + line-height: 51px; + margin-bottom: 10px; +} + +.import-account__back-button { + margin-bottom: 18px; + color: #22232c; + font-size: 16px; + line-height: 21px; + position: absolute; + top: -25px; +} + +.import-account__secret-phrase { + height: 190px; + width: 495px; + border: 1px solid #CDCDCD; + border-radius: 6px; + background-color: #FFFFFF; + padding: 17px; + font-size: 16px; +} + +.import-account__secret-phrase::placeholder { + color: #9B9B9B; + font-weight: 200; +} + +.import-account__faq-link { + font-size: 18px; + line-height: 23px; + font-family: Roboto; +} + +.import-account__selector-label { + color: #1B344D; + font-size: 16px; +} + +.import-account__dropdown { + width: 325px; + border: 1px solid #CDCDCD; + border-radius: 4px; + background-color: #FFFFFF; + margin-top: 14px; + color: #5B5D67; + font-family: Roboto; + font-size: 18px; + line-height: 23px; + padding: 14px 21px; + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + cursor: pointer; +} + +.import-account__description-text { + color: #757575; + font-size: 18px; + line-height: 23px; + margin-top: 21px; + font-family: Roboto; +} + +.import-account__input-wrapper { + display: flex; + flex-flow: column nowrap; + margin-top: 30px; +} + +.import-account__input-error-message { + margin-top: 10px; + width: 422px; + color: #FF001F; + font-size: 16px; + line-height: 21px; +} + +.import-account__input-label { + margin-bottom: 9px; + color: #1B344D; + font-size: 18px; + line-height: 23px; +} + +.import-account__input-label__disabled { + opacity: 0.5; +} + +.import-account__input { + width: 350px; +} + +@media only screen and (max-width: 575px) { + .import-account__input { + width: 100%; + } +} + +.import-account__file-input { + display: none; +} + +.import-account__file-input-label { + height: 53px; + width: 148px; + border: 1px solid #1B344D; + border-radius: 4px; + color: #1B344D; + font-family: Roboto; + font-size: 18px; + display: flex; + flex-flow: column nowrap; + align-items: center; + justify-content: center; + cursor: pointer; +} + +.import-account__file-picker-wrapper { + display: flex; + flex-flow: row nowrap; + align-items: center; +} + +.import-account__file-name { + color: #000000; + font-family: Roboto; + font-size: 18px; + line-height: 23px; + margin-left: 22px; +} diff --git a/ui/app/pages/keychains/restore-vault.js b/ui/app/pages/keychains/restore-vault.js new file mode 100644 index 000000000..574949258 --- /dev/null +++ b/ui/app/pages/keychains/restore-vault.js @@ -0,0 +1,197 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import {connect} from 'react-redux' +import { + createNewVaultAndRestore, + unMarkPasswordForgotten, +} from '../../store/actions' +import { DEFAULT_ROUTE } from '../../helpers/constants/routes' +import TextField from '../../components/ui/text-field' +import Button from '../../components/ui/button' + +class RestoreVaultPage extends Component { + static contextTypes = { + t: PropTypes.func, + metricsEvent: PropTypes.func, + } + + static propTypes = { + warning: PropTypes.string, + createNewVaultAndRestore: PropTypes.func.isRequired, + leaveImportSeedScreenState: PropTypes.func, + history: PropTypes.object, + isLoading: PropTypes.bool, + }; + + state = { + seedPhrase: '', + password: '', + confirmPassword: '', + seedPhraseError: null, + passwordError: null, + confirmPasswordError: null, + } + + parseSeedPhrase = (seedPhrase) => { + return seedPhrase + .match(/\w+/g) + .join(' ') + } + + handleSeedPhraseChange (seedPhrase) { + let seedPhraseError = null + + if (seedPhrase && this.parseSeedPhrase(seedPhrase).split(' ').length !== 12) { + seedPhraseError = this.context.t('seedPhraseReq') + } + + this.setState({ seedPhrase, seedPhraseError }) + } + + handlePasswordChange (password) { + const { confirmPassword } = this.state + let confirmPasswordError = null + let passwordError = null + + if (password && password.length < 8) { + passwordError = this.context.t('passwordNotLongEnough') + } + + if (confirmPassword && password !== confirmPassword) { + confirmPasswordError = this.context.t('passwordsDontMatch') + } + + this.setState({ password, passwordError, confirmPasswordError }) + } + + handleConfirmPasswordChange (confirmPassword) { + const { password } = this.state + let confirmPasswordError = null + + if (password !== confirmPassword) { + confirmPasswordError = this.context.t('passwordsDontMatch') + } + + this.setState({ confirmPassword, confirmPasswordError }) + } + + onClick = () => { + const { password, seedPhrase } = this.state + const { + createNewVaultAndRestore, + leaveImportSeedScreenState, + history, + } = this.props + + leaveImportSeedScreenState() + createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase)) + .then(() => { + this.context.metricsEvent({ + eventOpts: { + category: 'Retention', + action: 'userEntersSeedPhrase', + name: 'onboardingRestoredVault', + }, + }) + history.push(DEFAULT_ROUTE) + }) + } + + hasError () { + const { passwordError, confirmPasswordError, seedPhraseError } = this.state + return passwordError || confirmPasswordError || seedPhraseError + } + + render () { + const { + seedPhrase, + password, + confirmPassword, + seedPhraseError, + passwordError, + confirmPasswordError, + } = this.state + const { t } = this.context + const { isLoading } = this.props + const disabled = !seedPhrase || !password || !confirmPassword || isLoading || this.hasError() + + return ( +
+
+
+ { + e.preventDefault() + this.props.history.goBack() + }} + href="#" + > + {`< Back`} + +
+ { this.context.t('restoreAccountWithSeed') } +
+
+ { this.context.t('secretPhrase') } +
+
+ +