diff --git a/app/background/wallet/client.js b/app/background/wallet/client.js index eb09e749e..056f9e679 100644 --- a/app/background/wallet/client.js +++ b/app/background/wallet/client.js @@ -42,4 +42,5 @@ export const clientStub = ipcRendererInjector => makeClient(ipcRendererInjector, 'zap', 'importName', 'rpcGetWalletInfo', + 'listWallets' ]); diff --git a/app/background/wallet/service.js b/app/background/wallet/service.js index 6d0562ba3..ee95a10f3 100644 --- a/app/background/wallet/service.js +++ b/app/background/wallet/service.js @@ -29,7 +29,6 @@ const Covenant = require('hsd/lib/primitives/covenant'); // const walletHeightKey = 'wallet:lastSyncHeight'; -const WALLET_ID = 'allison'; const randomAddrs = { [NETWORKS.TESTNET]: 'ts1qfcljt5ylsa9rcyvppvl8k8gjnpeh079drfrmzq', [NETWORKS.REGTEST]: 'rs1qh57neh8npuxeyxfsl35373vshs0d40cvxx57aj', @@ -46,6 +45,11 @@ class WalletService { this.nodeService = nodeService; } + setWallet = (name) => { + this.didSelectWallet = false; + this.name = name; + }; + reset = async () => { await this._ensureClient(); @@ -68,7 +72,7 @@ class WalletService { this.network, this.apiKey, ); - + this.setName(null); return true; } catch (e) { console.error(e); @@ -83,18 +87,18 @@ class WalletService { getWalletInfo = async () => { await this._ensureClient(); - return this.client.getInfo(WALLET_ID); + return this.client.getInfo(this.name); }; getAccountInfo = async () => { await this._ensureClient(); - return this.client.getAccount(WALLET_ID, 'default'); + return this.client.getAccount(this.name, 'default'); }; getCoin = async (hash, index) => { await this._ensureClient(); - return this.client.getCoin(WALLET_ID, hash, index); + return this.client.getCoin(this.name, hash, index); }; getNames = async () => { @@ -102,14 +106,12 @@ class WalletService { return this.client.execute('getnames'); }; - createNewWallet = async (passphraseOrXPub, isLedger) => { + createNewWallet = async (name, passphraseOrXPub, isLedger) => { await this._ensureClient(); - - await this.reset(); - this.didSelectWallet = false; + this.setWallet(name); if (isLedger) { - return this.client.createWallet(WALLET_ID, { + return this.client.createWallet(name, { watchOnly: true, accountKey: passphraseOrXPub, }); @@ -122,7 +124,7 @@ class WalletService { watchOnly: false, mnemonic: mnemonic.getPhrase(), }; - return this.client.createWallet(WALLET_ID, options); + return this.client.createWallet(name, options); }; checkRescanStatus = async () => { @@ -189,10 +191,9 @@ class WalletService { }); }; - importSeed = async (passphrase, mnemonic) => { + importSeed = async (name, passphrase, mnemonic) => { await this._ensureClient(); - - await this.reset(); + this.setWallet(name); this.didSelectWallet = false; const options = { passphrase, @@ -200,14 +201,14 @@ class WalletService { // menmonics with trailing whitespace mnemonic: mnemonic.trim(), }; - const res = await this.client.createWallet(WALLET_ID, options); + const res = await this.client.createWallet(this.name, options); this.rescan(0); return res; }; generateReceivingAddress = async () => { await this._ensureClient(); - return this.client.createAddress(WALLET_ID, 'default'); + return this.client.createAddress(this.name, 'default'); }; getAuctionInfo = async (name) => { @@ -216,12 +217,12 @@ class WalletService { getTransactionHistory = async () => { await this._ensureClient(); - return this.client.getHistory(WALLET_ID, 'default'); + return this.client.getHistory(this.name, 'default'); }; getPendingTransactions = async () => { await this._ensureClient(); - return this.client.getPending(WALLET_ID, 'default'); + return this.client.getPending(this.name, 'default'); }; getBids = async () => { @@ -230,12 +231,12 @@ class WalletService { getMasterHDKey = () => this._ledgerDisabled( 'cannot get HD key for watch-only wallet', - () => this.client.getMaster(WALLET_ID), + () => this.client.getMaster(this.name), ); setPassphrase = (newPass) => this._ledgerDisabled( 'cannot set passphrase for watch-only wallet', - () => this.client.setPassphrase(WALLET_ID, newPass), + () => this.client.setPassphrase(this.name, newPass), ); revealSeed = (passphrase) => this._ledgerDisabled( @@ -268,7 +269,7 @@ class WalletService { estimateTxFee = async (to, amount, feeRate, subtractFee = false) => { await this._ensureClient(); const feeRateBaseUnits = Number(toBaseUnits(feeRate)); - const createdTx = await this.client.createTX(WALLET_ID, { + const createdTx = await this.client.createTX(this.name, { rate: feeRateBaseUnits, outputs: [{ value: Number(toBaseUnits(amount)), @@ -356,7 +357,7 @@ class WalletService { send = (to, amount, fee) => this._ledgerProxy( () => this._executeRPC('createsendtoaddress', [to, Number(amount), '', '', false, 'default']), - () => this.client.send(WALLET_ID, { + () => this.client.send(this.name, { rate: Number(toBaseUnits(fee)), outputs: [{ value: Number(toBaseUnits(amount)), @@ -367,19 +368,22 @@ class WalletService { lock = () => this._ledgerProxy( () => null, - () => this.client.lock(WALLET_ID), + () => this.client.lock(this.name), ); - unlock = (passphrase) => this._ledgerProxy( - () => null, - () => this.client.unlock(WALLET_ID, passphrase), - ); + unlock = (name, passphrase) => { + this.setWallet(name); + return this._ledgerProxy( + () => null, + () => this.client.unlock(this.name, passphrase), + ); + }; isLocked = () => this._ledgerProxy( () => false, async () => { try { - const info = await this.client.getInfo(WALLET_ID); + const info = await this.client.getInfo(this.name); return info === null || info.master.until === 0; } catch (e) { console.error(e); @@ -390,7 +394,7 @@ class WalletService { getNonce = async (options) => { await this._ensureClient(); - return this.client.getNonce(WALLET_ID, options.name, options); + return this.client.getNonce(this.name, options.name, options); }; importNonce = async (options) => { @@ -399,7 +403,7 @@ class WalletService { zap = async () => { await this._ensureClient(); - return this.client.zap(WALLET_ID, 'default', 1); + return this.client.zap(this.name, 'default', 1); }; importName = (name, start) => { @@ -525,6 +529,8 @@ class WalletService { throw new Error('Transaction never appeared in the mempool.'); }; + listWallets = () => this.client.getWallets(); + _onNodeStart = async (networkName, network, apiKey) => { const conn = await getConnection(); @@ -606,7 +612,7 @@ class WalletService { return this.pendingSelection; } - this.pendingSelection = this.client.execute('selectwallet', [WALLET_ID]); + this.pendingSelection = this.client.execute('selectwallet', [this.name]); await this.pendingSelection; this.pendingSelection = null; this.didSelectWallet = true; @@ -685,6 +691,7 @@ const methods = { zap: service.zap, importName: service.importName, rpcGetWalletInfo: service.rpcGetWalletInfo, + listWallets: service.listWallets, }; export async function start(server) { diff --git a/app/ducks/node.js b/app/ducks/node.js index 06b9587c2..94f9cf0aa 100644 --- a/app/ducks/node.js +++ b/app/ducks/node.js @@ -1,7 +1,7 @@ import { clientStub } from '../background/node/client'; import { clientStub as connClientStub } from '../background/connections/client'; import { getNetwork, setNetwork, getInitializationState } from '../db/system'; -import { fetchWallet, fetchTransactions } from './walletActions'; +import { fetchWallet, fetchTransactions, listWallets } from './walletActions'; import { getWatching } from './watching'; import * as logger from '../utils/logClient'; import { onNewBlock } from './backgroundMonitor'; @@ -109,6 +109,7 @@ export const start = (network) => async (dispatch, getState) => { }, }); await dispatch(setNodeInfo()); + await dispatch(listWallets()); await dispatch(fetchWallet()); if (await getInitializationState(network)) { setTimeout(async () => { diff --git a/app/ducks/walletActions.js b/app/ducks/walletActions.js index 6aed135f5..cc381c9af 100644 --- a/app/ducks/walletActions.js +++ b/app/ducks/walletActions.js @@ -16,7 +16,9 @@ import { STOP_SYNC_WALLET, SYNC_WALLET_PROGRESS, UNLOCK_WALLET, - SET_API_KEY, SET_FETCHING, + SET_API_KEY, + SET_FETCHING, + SET_WALLETS, } from './walletReducer'; import { NEW_BLOCK_STATUS } from './nodeReducer'; @@ -43,9 +45,9 @@ export const setWallet = opts => { }; }; -export const completeInitialization = (passphrase) => async (dispatch, getState) => { +export const completeInitialization = (name, passphrase) => async (dispatch, getState) => { const network = getState().node.network; - await walletClient.unlock(passphrase); + await walletClient.unlock(name, passphrase); await setInitializationState(network, true); await dispatch(fetchWallet()); dispatch({ @@ -94,8 +96,8 @@ export const revealSeed = (passphrase) => async () => { return walletClient.revealSeed(passphrase); }; -export const unlockWallet = passphrase => async (dispatch) => { - await walletClient.unlock(passphrase); +export const unlockWallet = (name, passphrase) => async (dispatch) => { + await walletClient.unlock(name, passphrase); dispatch({ type: UNLOCK_WALLET, }); @@ -108,7 +110,7 @@ export const lockWallet = () => async (dispatch) => { }); }; -export const removeWallet = () => async (dispatch, getState) => { +export const reset = () => async (dispatch, getState) => { const network = getState().node.network; await walletClient.reset(); await setInitializationState(network, false); @@ -265,6 +267,15 @@ export const watchActivity = () => dispatch => { } }; +export const listWallets = () => async (dispatch) => { + const wallets = await walletClient.listWallets(); + + dispatch({ + type: SET_WALLETS, + payload: wallets, + }); +}; + async function parseInputsOutputs(net, tx) { // Look for covenants. A TX with multiple covenant types is not supported let covAction = null; @@ -353,7 +364,7 @@ async function parseInputsOutputs(net, tx) { type: 'UNKNOWN', meta: {}, fee: tx.fee, - value: 0 + value: 0, }; } diff --git a/app/ducks/walletReducer.js b/app/ducks/walletReducer.js index a6abe0895..7db19513b 100644 --- a/app/ducks/walletReducer.js +++ b/app/ducks/walletReducer.js @@ -16,6 +16,7 @@ export const SYNC_WALLET_PROGRESS = 'app/wallet/syncWalletProgress'; export const GET_PASSPHRASE = 'app/wallet/getPassphrase'; export const SET_API_KEY = 'app/wallet/setApiKey'; export const SET_FETCHING = 'app/wallet/setFetching'; +export const SET_WALLETS = 'app/wallet/setWallets'; export function getInitialState() { return { @@ -37,6 +38,7 @@ export function getInitialState() { walletSync: false, walletSyncProgress: 0, getPassphrase: {get: false}, + wallets: [], }; } @@ -66,17 +68,17 @@ export default function walletReducer(state = getInitialState(), {type, payload} case LOCK_WALLET: return { ...state, - isLocked: true + isLocked: true, }; case UNLOCK_WALLET: return { ...state, - isLocked: false + isLocked: false, }; case SET_TRANSACTIONS: return { ...state, - transactions: payload + transactions: payload, }; case INCREMENT_IDLE: return { @@ -113,6 +115,11 @@ export default function walletReducer(state = getInitialState(), {type, payload} ...state, isFetching: payload, }; + case SET_WALLETS: + return { + ...state, + wallets: payload, + }; default: return state; } diff --git a/app/pages/AcountLogin/index.js b/app/pages/AcountLogin/index.js index f96c580b4..7f25bc5fe 100644 --- a/app/pages/AcountLogin/index.js +++ b/app/pages/AcountLogin/index.js @@ -5,52 +5,73 @@ import c from 'classnames'; import * as walletActions from '../../ducks/walletActions'; import './login.scss'; import Submittable from '../../components/Submittable'; -import { Link } from 'react-router-dom'; +import { Link, Redirect } from 'react-router-dom'; +import Dropdown from '../../components/Dropdown'; +import { withRouter } from 'react-router'; @connect( - () => ({}), + (state) => ({ + wallets: state.wallet.wallets, + }), dispatch => ({ - unlockWallet: passphrase => dispatch(walletActions.unlockWallet(passphrase)) - }) + unlockWallet: (name, passphrase) => dispatch(walletActions.unlockWallet(name, passphrase)), + fetchWallet: () => dispatch(walletActions.fetchWallet()), + }), ) +@withRouter export default class AccountLogin extends Component { static propTypes = { - unlockWallet: PropTypes.func.isRequired + unlockWallet: PropTypes.func.isRequired, }; static defaultProps = { - className: '' + className: '', }; state = { passphrase: '', - showError: false + showError: false, + chosenWallet: 0, }; async handleLogin(passphrase) { try { - await this.props.unlockWallet(passphrase); + await this.props.unlockWallet( + this.props.wallets[this.state.chosenWallet], + passphrase, + ); + await this.props.fetchWallet(); + this.props.history.push('/account'); } catch (error) { - return this.setState({ showError: true }); + return this.setState({showError: true}); } } render() { - const { passphrase, showError } = this.state; + const {passphrase, showError} = this.state; + + if (!this.props.wallets.length) { + return ; + } return (
Log in to your wallet
this.handleLogin(passphrase)}> + ({label: w}))} + currentIndex={this.state.chosenWallet} + onChange={(i) => this.setState({chosenWallet: i})} + />
- this.setState({ passphrase: e.target.value, showError: false }) + this.setState({passphrase: e.target.value, showError: false}) } value={passphrase} autoFocus @@ -73,6 +94,12 @@ export default class AccountLogin extends Component { > Restore with your seed phrase + + Create new wallet +
); } diff --git a/app/pages/App/index.js b/app/pages/App/index.js index 41364f557..c63f6554c 100644 --- a/app/pages/App/index.js +++ b/app/pages/App/index.js @@ -22,18 +22,24 @@ import YourBids from '../YourBids'; import Watching from '../Watching'; import SearchTLD from '../SearchTLD'; import * as walletActions from '../../ducks/walletActions'; +import { listWallets } from '../../ducks/walletActions'; import './app.scss'; import AccountLogin from '../AcountLogin'; import PassphraseModal from '../AcountLogin/PassphraseModal'; import * as node from '../../ducks/node'; import { onNewBlock } from '../../ducks/backgroundMonitor'; -import Notification from '../../components/Notification'; -import SplashScreen from "../../components/SplashScreen"; -import WalletSync from "../../components/WalletSync"; +import SplashScreen from '../../components/SplashScreen'; import NetworkPicker from '../NetworkPicker'; import IdleModal from '../../components/IdleModal'; -import { LedgerModal } from '../../components/LedgerModal'; +@connect( + (state) => ({ + wallets: state.wallet.wallets, + }), + (dispatch) => ({ + listWallets: () => dispatch(listWallets()), + }), +) class App extends Component { static propTypes = { error: PropTypes.string.isRequired, @@ -46,20 +52,22 @@ class App extends Component { }; state = { - isLoading: true + isLoading: true, + isListingWallets: true }; async componentDidMount() { this.setState({isLoading: true}); await this.props.startNode(); this.props.watchActivity(); - setTimeout(() => this.setState({isLoading: false}), 1000) + await this.props.listWallets(); + setTimeout(() => this.setState({isLoading: false}), 1000); } render() { // TODO: Confirm that error shows properly if (this.props.error) { - return + return ; } if (this.state.isLoading || this.props.isChangingNetworks) { @@ -77,52 +85,106 @@ class App extends Component { } renderContent() { - const { isLocked, initialized } = this.props; - - if (isLocked || !initialized) { - return ( - - , true, true)} - /> - - - - - - {this.renderDefault()} - - ); - } - return ( - - - - {this.renderRoutes()} - + + , true, true)} + /> + + + + + + + + + + + + + + + + + + ); } uninitializedWrapper(Component, isMainMenu = false, autoHeight = false) { - const { history, isRunning } = this.props; + const {history, isRunning} = this.props; if (isMainMenu) { return () => (
-
+
- { isRunning && } + {isRunning && }
-
- ) + ); } return () => ( @@ -135,58 +197,12 @@ class App extends Component {
-
- ) - } - - renderRoutes() { - return ( - - - - - - - - - - - - - {this.renderDefault()} - ); } @@ -214,22 +230,19 @@ class App extends Component { ); } +} - renderDefault = () => { - let {isLocked, initialized} = this.props; - - - if (!initialized) { - return ; - } +const ProtectedRoute = (props) => { + if (!props.wallets.length) { + return ; + } - if (isLocked) { - return ; - } + if (props.isLocked) { + return ; + } - return ; - }; -} + return ; +}; export default withRouter( connect( @@ -244,6 +257,6 @@ export default withRouter( watchActivity: () => dispatch(walletActions.watchActivity()), startNode: () => dispatch(node.startApp()), onNewBlock: () => dispatch(onNewBlock()), - }) - )(App) + }), + )(App), ); diff --git a/app/pages/Onboarding/ConfirmSeed/index.js b/app/pages/Onboarding/ConfirmSeed/index.js index 6c2d8c99e..71b5138f4 100644 --- a/app/pages/Onboarding/ConfirmSeed/index.js +++ b/app/pages/Onboarding/ConfirmSeed/index.js @@ -62,11 +62,6 @@ export default class ConfirmSeed extends Component { placeholder="Enter your seed phrase" onKeyDown={this.handleKeyDown} onChange={e => this.setState({ words: e.target.value })} - onPaste={e => { - e.preventDefault(); - this.setState({ pasteAttempted: true }); - setTimeout(() => this.setState({ pasteAttempted: false }), 1000); - }} value={this.state.words} autoFocus /> diff --git a/app/pages/Onboarding/CreateNewAccount/index.js b/app/pages/Onboarding/CreateNewAccount/index.js index 78c268ce1..1cab8c511 100644 --- a/app/pages/Onboarding/CreateNewAccount/index.js +++ b/app/pages/Onboarding/CreateNewAccount/index.js @@ -7,6 +7,7 @@ import CreatePassword from '../CreatePassword/index'; import BackUpSeedWarning from '../BackUpSeedWarning/index'; import CopySeed from '../../CopySeed/index'; import ConfirmSeed from '../ConfirmSeed/index'; +import SetName from '../SetName/index'; import * as walletActions from '../../../ducks/walletActions'; import '../ImportSeedEnterMnemonic/importenter.scss'; import '../ImportSeedWarning/importwarning.scss'; @@ -22,6 +23,7 @@ const BACK_UP_SEED_WARNING = 2; const COPY_SEEDPHRASE = 3; const CONFIRM_SEEDPHRASE = 4; const OPT_IN_ANALYTICS = 5; +const SET_NAME = 6; class CreateNewAccount extends Component { static propTypes = { @@ -30,9 +32,9 @@ class CreateNewAccount extends Component { }; state = { - currentStep: CREATE_PASSWORD, + currentStep: SET_NAME, seedphrase: '', - pasphrase: '', + passphrase: '', isLoading: false, }; @@ -42,7 +44,7 @@ class CreateNewAccount extends Component { return ( { this.setState({ currentStep: CREATE_PASSWORD, @@ -51,12 +53,26 @@ class CreateNewAccount extends Component { onBack={() => this.props.history.push('/funding-options')} /> ); - case CREATE_PASSWORD: + case SET_NAME: return ( - this.props.history.push('/funding-options')} + onNext={(name) => { + this.setState({currentStep: CREATE_PASSWORD, name}); + }} + onCancel={() => this.props.history.push('/funding-options')} + /> + ); + case CREATE_PASSWORD: + return ( + this.setState({ + currentStep: SET_NAME + })} onNext={async (passphrase) => { const optInState = await analytics.getOptIn(); let currentStep = BACK_UP_SEED_WARNING; @@ -72,8 +88,8 @@ class CreateNewAccount extends Component { case OPT_IN_ANALYTICS: return ( this.setState({currentStep: CREATE_PASSWORD})} onNext={async (optInState) => { await analytics.setOptIn(optInState); @@ -85,12 +101,12 @@ class CreateNewAccount extends Component { case BACK_UP_SEED_WARNING: return ( this.setState({currentStep: CREATE_PASSWORD})} onNext={async () => { this.setState({isLoading: true}); - await walletClient.createNewWallet(); + await walletClient.createNewWallet(this.state.name); const masterHDKey = await walletClient.getMasterHDKey(); await walletClient.setPassphrase(this.state.passphrase); this.setState({currentStep: COPY_SEEDPHRASE, seedphrase: masterHDKey.mnemonic.phrase, isLoading: false}); @@ -102,8 +118,8 @@ class CreateNewAccount extends Component { case COPY_SEEDPHRASE: return ( this.setState({currentStep: BACK_UP_SEED_WARNING})} onNext={() => this.setState({currentStep: CONFIRM_SEEDPHRASE})} @@ -113,13 +129,13 @@ class CreateNewAccount extends Component { case CONFIRM_SEEDPHRASE: return ( this.setState({currentStep: COPY_SEEDPHRASE})} onNext={async () => { - await this.props.completeInitialization(this.state.passphrase); - this.props.history.push('/'); + await this.props.completeInitialization(this.state.name, this.state.passphrase); + this.props.history.push('/account'); }} onCancel={() => this.props.history.push('/funding-options')} /> @@ -136,7 +152,7 @@ export default withRouter( network: state.node.network, }), dispatch => ({ - completeInitialization: (passphrase) => dispatch(walletActions.completeInitialization(passphrase)), + completeInitialization: (name, passphrase) => dispatch(walletActions.completeInitialization(name, passphrase)), }), )(CreateNewAccount), ); diff --git a/app/pages/Onboarding/FundAccessOptions/index.js b/app/pages/Onboarding/FundAccessOptions/index.js index a1cf70ba2..da3fca55a 100644 --- a/app/pages/Onboarding/FundAccessOptions/index.js +++ b/app/pages/Onboarding/FundAccessOptions/index.js @@ -1,9 +1,7 @@ import React, { Component } from 'react'; -import { withRouter } from 'react-router-dom'; +import { withRouter, Link } from 'react-router-dom'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -// import classNames from 'classnames'; -// import * as auctions.js from '../../../ducks/extension'; import './access.scss'; class FundAccessOptions extends Component { @@ -41,8 +39,17 @@ class FundAccessOptions extends Component { className="funding-options__footer__secondary-btn" onClick={() => this.props.history.push('/existing-options')} > - I already have a wallet + Import a wallet + + {!!this.props.wallets.length && ( + + Return to login + + )} ); @@ -51,7 +58,9 @@ class FundAccessOptions extends Component { export default withRouter( connect( - state => ({}), + state => ({ + wallets: state.wallet.wallets + }), dispatch => ({}) )(FundAccessOptions) ); diff --git a/app/pages/Onboarding/ImportSeedFlow/index.js b/app/pages/Onboarding/ImportSeedFlow/index.js index ffe26b3d9..4089f9186 100644 --- a/app/pages/Onboarding/ImportSeedFlow/index.js +++ b/app/pages/Onboarding/ImportSeedFlow/index.js @@ -13,6 +13,7 @@ import * as logger from '../../../utils/logClient'; import OptInAnalytics from '../OptInAnalytics'; import { clientStub as aClientStub } from '../../../background/analytics/client'; import { showError } from '../../../ducks/notifications'; +import SetName from '../SetName'; const analytics = aClientStub(() => require('electron').ipcRenderer); @@ -21,6 +22,7 @@ const WARNING_STEP = 'WARNING'; const CREATE_PASSWORD = 'CREATE_PASSWORD'; const ENTRY_STEP = 'ENTRY'; const OPT_IN_ANALYTICS = 'ANALYTICS'; +const SET_NAME = 'SET_NAME'; class ImportSeedFlow extends Component { static propTypes = { @@ -38,6 +40,7 @@ class ImportSeedFlow extends Component { state = { currentStep: WARNING_STEP, + name: '', passphrase: '', mnemonic: '', isLoading: false, @@ -57,10 +60,24 @@ class ImportSeedFlow extends Component { case WARNING_STEP: return ( this.props.history.push('/existing-options')} - onNext={() => this.goTo(CREATE_PASSWORD)} + onNext={() => this.goTo(SET_NAME)} + onCancel={() => this.props.history.push('/funding-options')} + /> + ); + case SET_NAME: + return ( + this.setState({ + currentStep: WARNING_STEP, + })} + onNext={(name) => { + this.setState({currentStep: CREATE_PASSWORD, name}); + }} onCancel={() => this.props.history.push('/funding-options')} /> ); @@ -120,10 +137,11 @@ class ImportSeedFlow extends Component { finishFlow = async mnemonic => { this.setState({isLoading: true}); try { - await walletClient.importSeed(this.state.passphrase, mnemonic); - await this.props.completeInitialization(this.state.passphrase); + await walletClient.importSeed(this.state.name, this.state.passphrase, mnemonic); + await this.props.completeInitialization(this.state.name, this.state.passphrase); await this.props.fetchWallet(); await this.props.fetchTransactions(); + this.props.history.push('/account'); } catch (e) { this.props.showError(e.message); logger.error(`Error received from ImportSeedFlow - finishFlow]\n\n${e.message}\n${e.stack}\n`); @@ -139,7 +157,7 @@ export default withRouter( network: state.node.network, }), dispatch => ({ - completeInitialization: (passphrase) => dispatch(walletActions.completeInitialization(passphrase)), + completeInitialization: (name, passphrase) => dispatch(walletActions.completeInitialization(name, passphrase)), waitForWalletSync: () => dispatch(walletActions.waitForWalletSync()), startWalletSync: () => dispatch(walletActions.startWalletSync()), showError: (message) => dispatch(showError(message)), diff --git a/app/pages/Onboarding/SetName/create.scss b/app/pages/Onboarding/SetName/create.scss new file mode 100644 index 000000000..fe54e56e3 --- /dev/null +++ b/app/pages/Onboarding/SetName/create.scss @@ -0,0 +1,97 @@ +@import '../../../variables'; + +.create-password { + @extend %col-nowrap; + height: 100%; + + &__header { + @extend %row-nowrap; + align-items: center; + justify-content: center; + padding: 1.125rem 1.625rem 0.5rem; + } + + &__header_text { + @extend %header_text; + margin-bottom: 1.125rem; + } + + &__body-text { + @extend %h4; + color: $manatee-gray; + margin-bottom: 1.375rem; + } + + &__cancel { + @extend %link; + flex: 1 0 auto; + text-align: right; + font-size: 0.8rem; + } + + &__status-bar { + padding: 0 1.625rem; + } + + &__content { + @extend %col-nowrap; + padding: 1.25rem 1.875rem; + flex: 1 1 auto; + // height: 0; + } + + &__input { + @extend %box-input; + width: 100%; + box-sizing: border-box; + margin-bottom: 12px; + + input { + width: 100%; + } + + &--error { + box-shadow: 0 0 0 1.25px rgba($orange-red, 0.5); + } + } + + &__error { + color: $orange-red; + font-size: 0.75rem; + margin: -6px 0.375rem 12px 0.375rem; + + &:empty { + margin: 0; + } + } + + &__footer { + padding: 1.25rem 1.875rem 1.875rem 1.875rem; + + &__removed-padding-top { + padding-top: 0; + } + } +} + +.create_back { + margin-right: 7px; + position: relative; + bottom: 1px; +} + +.create_status_bar { + margin: 0.8rem 0 1rem; +} + +.clickable { + cursor: pointer; +} + +.login_password_input { + @extend %box-input; + width: 90%; + margin: 10px 0rem; + border: 1px solid #e2e2e2; + border-radius: 8px; +} diff --git a/app/pages/Onboarding/SetName/index.js b/app/pages/Onboarding/SetName/index.js new file mode 100644 index 000000000..e3161a45f --- /dev/null +++ b/app/pages/Onboarding/SetName/index.js @@ -0,0 +1,84 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import c from 'classnames'; +import './create.scss'; +import Submittable from '../../../components/Submittable'; +import WizardHeader from '../../../components/WizardHeader'; + +@connect() +export default class CreatePassword extends Component { + static propTypes = { + currentStep: PropTypes.number.isRequired, + totalSteps: PropTypes.number.isRequired, + onBack: PropTypes.func.isRequired, + onNext: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + }; + + constructor(props) { + super(props); + this.state = { + name: '', + }; + } + + onSubmit = () => { + this.props.onNext(this.state.name); + }; + + isValidName = () => { + return this.state.name.match(/^[a-z0-9]+$/); + }; + + onChange = name => e => { + this.setState({ + [name]: e.target.value, + }); + }; + + render() { + const {currentStep, totalSteps, onBack} = this.props; + + return ( +
+ +
+ +
+ Name this wallet +
+
+ The name can only contain alphanumeric lowercase characters. +
+
+ +
+
+
+
+ +
+
+ ); + } +} diff --git a/app/pages/Settings/index.js b/app/pages/Settings/index.js index db2191d75..981f39a96 100644 --- a/app/pages/Settings/index.js +++ b/app/pages/Settings/index.js @@ -40,7 +40,7 @@ const analytics = aClientStub(() => require('electron').ipcRenderer); }), dispatch => ({ lockWallet: () => dispatch(walletActions.lockWallet()), - removeWallet: () => dispatch(walletActions.removeWallet()), + reset: () => dispatch(walletActions.reset()), stopNode: () => dispatch(nodeActions.stop()), startNode: () => dispatch(nodeActions.start()), setCustomRPCStatus: isConnected => dispatch(setCustomRPCStatus(isConnected)), @@ -55,7 +55,7 @@ export default class Settings extends Component { isRunning: PropTypes.bool.isRequired, isChangingNodeStatus: PropTypes.bool.isRequired, lockWallet: PropTypes.func.isRequired, - removeWallet: PropTypes.func.isRequired, + reset: PropTypes.func.isRequired, stopNode: PropTypes.func.isRequired, startNode: PropTypes.func.isRequired, setCustomRPCStatus: PropTypes.func.isRequired, @@ -207,10 +207,10 @@ export default class Settings extends Component { () => history.push('/settings/wallet/reveal-seed'), )} {this.renderSection( - 'Remove wallet', - 'This will remove all data from Bob. Proceed with caution.', - 'Remove Wallet ', - () => history.push('/settings/wallet/new-wallet'), + 'Create new wallet', + 'This will allow you to create a new wallet', + 'Create New', + () => history.push('/funding-options'), )} ); @@ -314,15 +314,6 @@ export default class Settings extends Component { { this.renderContent() } - ( - this.props.removeWallet()} - nextRoute="/" - /> - )} - />