Skip to content

Commit

Permalink
feat(management): added ability to import existing wallets through a …
Browse files Browse the repository at this point in the history
…PK (#1148)

* feat(management): added ability to import existing wallets through a PK

* chore(management): fix linting

* chore(management): fix negative number issue and adjust copy

* chore(management): added icons and hide imported wallets if empty

also fixes CI build

* chore(app): fix tests

* chore(renovate): adjust config
  • Loading branch information
Maurice Dalderup authored Oct 6, 2019
1 parent 1633f1c commit 84c24a1
Show file tree
Hide file tree
Showing 32 changed files with 493 additions and 301 deletions.
4 changes: 4 additions & 0 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
"packageNames": ["@cityofzion/neon-js"],
"allowedVersions": "< 4"
},
{
"packageNames": ["react", "react-dom", "react-is"],
"allowedVersions": "< 16.9.0"
},
{
"packageNames": ["electron-is-dev"],
"allowedVersions": "< 1"
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
"prop-types": "15.7.2",
"qrcode.react": "0.9.3",
"rc-tooltip": "3.7.3",
"react": "16.10.1",
"react": "16.8.6",
"react-click-outside": "3.0.1",
"react-dom": "16.10.1",
"react-is": "16.10.1",
"react-dom": "16.8.6",
"react-is": "16.8.6",
"react-redux": "5.1.1",
"react-router-dom": "4.3.1",
"react-scroll": "1.7.14",
Expand All @@ -62,6 +62,7 @@
"source-map-support": "0.5.13",
"spunky": "1.3.1",
"switch-tree": "0.2.2",
"unique-names-generator": "3.0.0",
"uuid": "3.3.3",
"what-input": "5.2.4",
"whatwg-url": "7.0.0"
Expand Down Expand Up @@ -112,13 +113,13 @@
"enzyme-adapter-react-16": "1.14.0",
"eslint": "6.5.1",
"eslint-config-airbnb": "18.0.1",
"eslint-config-prettier": "6.3.0",
"eslint-config-prettier": "6.4.0",
"eslint-import-resolver-babel-module": "5.1.0",
"eslint-plugin-import": "2.18.2",
"eslint-plugin-jest": "22.17.0",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-prettier": "3.1.1",
"eslint-plugin-react": "7.14.3",
"eslint-plugin-react": "7.16.0",
"identity-obj-proxy": "3.0.0",
"jest": "23.6.0",
"jest-canvas-mock": "2.1.1",
Expand Down
30 changes: 28 additions & 2 deletions src/renderer/account/components/Management/Management.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import React from 'react';
import { string, func, objectOf } from 'prop-types';
import classnames from 'classnames';

import ImportIcon from 'shared/images/wallet/import.svg';
import AddIcon from 'shared/images/wallet/add.svg';

import Page from 'shared/components/Page';
import accountShape from 'auth/shapes/accountShape';
import walletShape from 'auth/shapes/walletShape';
Expand Down Expand Up @@ -46,8 +49,20 @@ export default class Management extends React.PureComponent {
<React.Fragment>
<div className={styles.heading}>
<div className={styles.title}>My Account</div>
<div className={styles.link} role="button" tabIndex={0} onClick={this.handleAddAccount}>
New Address
<div className={styles.subHeader}>
<div className={styles.link} role="button" tabIndex={0} onClick={this.handleAddAccount}>
<AddIcon className={styles.icon} />
New Wallet
</div>
<div
className={styles.link}
role="button"
tabIndex={0}
onClick={this.handleImportAccount}
>
<ImportIcon className={styles.icon} />
Import Wallet
</div>
</div>
</div>
{!account.isHardware && (
Expand All @@ -65,4 +80,15 @@ export default class Management extends React.PureComponent {
account
});
};

handleImportAccount = () => {
const { newWallet, account } = this.props;

newWallet(<div />, {
title: 'Import a New Wallet',
className: styles.modal,
account,
isImport: true
});
};
}
15 changes: 14 additions & 1 deletion src/renderer/account/components/Management/Management.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,27 @@
@extend %labelColor;
}

.subHeader {
display: flex;
flex-direction: row;
}

.icon {
margin-right: 3px;
}

.link {
cursor: pointer;

font-weight: 500;
font-size: 12px;
line-height: 12px;
user-select: none;
color: $brand;
display: flex;

&:first-child {
margin-right: 15px;
}
}
}

Expand Down
28 changes: 23 additions & 5 deletions src/renderer/account/components/Management/Wallet/Wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export default class Wallet extends React.PureComponent {
setPassphrase: func.isRequired,
account: accountShape.isRequired,
confirm: func.isRequired,
changeActiveWallet: func.isRequired
changeActiveWallet: func.isRequired,
updateWallet: func.isRequired
};

static defaultProps = {
Expand Down Expand Up @@ -77,11 +78,18 @@ export default class Wallet extends React.PureComponent {
return (
<div className={styles.left}>
<div className={styles.icon}>{this.renderIcon()}</div>
<div>
<div className={styles.title}>
{coinName} Account {wallet.index + 1}
<div className={styles.wrapper}>
<div
className={styles.title}
contentEditable="true"
onBlur={this.handleChangeLabel}
suppressContentEditableWarning="true"
>
{wallet.walletLabel || 'Wallet'}
</div>
<div className={styles.subtitle}>
{coinName} Wallet {!wallet.isImport ? wallet.index + 1 : ''}
</div>
<div className={styles.subtitle}>Wallet</div>
</div>
</div>
);
Expand Down Expand Up @@ -121,6 +129,16 @@ export default class Wallet extends React.PureComponent {
}
};

handleChangeLabel = (e) => {
const { wallet, account, updateWallet } = this.props;
const newWallet = {
...wallet,
walletLabel: e.target.innerHTML
};

updateWallet({ account, wallet: newWallet });
};

handleSetPrimary = () => {
const { wallet, account, passphrase, changeActiveWallet, setPassphrase } = this.props;
const { walletId } = wallet;
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/account/components/Management/Wallet/Wallet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
flex-direction: row;
justify-content: space-between;

.wrapper {
width: 100px;
}

@media only screen and (max-width: $responsive-width) {
flex-direction: column;
}
Expand Down
11 changes: 10 additions & 1 deletion src/renderer/account/components/Management/Wallet/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { compose, withState } from 'recompose';
import { withActions, withData, progressValues } from 'spunky';

import authActions, { changeActiveWalletActions } from 'auth/actions/authActions';
import { updateWalletActions } from 'auth/actions/walletActions';
import withConfirm from 'shared/hocs/withConfirm';
import { withErrorToast, withSuccessToast } from 'shared/hocs/withToast';
import withProgressChange from 'shared/hocs/withProgressChange';
Expand All @@ -19,6 +20,9 @@ const mapClaimableActionsToProps = ({ reset }) => ({ resetClaimables: reset });
const mapChangeActiveWalletActionsToProps = (actions) => ({
changeActiveWallet: (data) => actions.call(data)
});
const mapUpdateWalletActionsToProps = (actions) => ({
updateWallet: (data) => actions.call(data)
});

export default compose(
withConfirm(),
Expand All @@ -27,6 +31,7 @@ export default compose(
withActions(changeActiveWalletActions, mapChangeActiveWalletActionsToProps),
withActions(balanceWithPricesActions, mapBalanceWithPricesActionsToProps),
withActions(claimableActions, mapClaimableActionsToProps),
withActions(updateWalletActions, mapUpdateWalletActionsToProps),

withSuccessToast(),
withProgressChange(changeActiveWalletActions, LOADED, (state, props) => {
Expand All @@ -37,8 +42,12 @@ export default compose(
props.showSuccessToast(`Primary wallet successfuly changed!`);
}
}),

withErrorToast(),
withProgressChange(updateWalletActions, FAILED, (state, props) => {
if (props.wallet.walletId === state.data.activeWalletId) {
props.showErrorToast(`Failed to persist wallet label. ${state.error}`);
}
}),
withProgressChange(changeActiveWalletActions, FAILED, (state, props) => {
// TODO this is triggered wallet-amount times without the if. Why?
if (props.wallet.walletId === state.data.activeWalletId) {
Expand Down
26 changes: 18 additions & 8 deletions src/renderer/account/components/Management/Wallets/Wallets.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { map } from 'lodash';
import { map, filter } from 'lodash';

import accountShape from 'auth/shapes/accountShape';
import walletsShape from 'auth/shapes/walletsShape';
Expand All @@ -9,16 +9,26 @@ import styles from './Wallets.scss';

const Wallets = ({ account, wallets }) => {
const { isHardware } = account;
const generatedWallets = filter(wallets, (wallet) => !wallet.isImport);
const importedWallets = filter(wallets, (wallet) => wallet.isImport);

return (
<div className={styles.wallets}>
<div className={styles.title}>
Accounts generated from {isHardware ? 'Ledger' : 'Keychain'}
<React.Fragment>
<div className={styles.wallets}>
<div className={styles.title}>{isHardware ? 'Ledger' : 'Keychain'} Accounts</div>
{map(generatedWallets, (wallet) => (
<Wallet wallet={wallet} key={`${wallet.walletId}`} />
))}
</div>
{map(wallets, (wallet) => (
<Wallet wallet={wallet} key={`${wallet.coinType}-${wallet.index}`} />
))}
</div>
{importedWallets.length > 0 && (
<div className={styles.wallets}>
<div className={styles.title}>Imported Wallets</div>
{map(importedWallets, (wallet) => (
<Wallet wallet={wallet} key={`${wallet.walletId}`} />
))}
</div>
)}
</React.Fragment>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import balanceShape from '../../../../../shapes/balanceShape';
import styles from './ConversionInput.scss';

export default class ConversionInput extends React.PureComponent {
assetInput = React.createRef();

currencyInput = React.createRef();

static propTypes = {
className: string,
asset: balanceShape.isRequired,
Expand All @@ -38,10 +42,6 @@ export default class ConversionInput extends React.PureComponent {
currencyValue: ''
};

assetInput = React.createRef();

currencyInput = React.createRef();

componentDidUpdate(prevProps) {
if (anyPropsChanged(prevProps, this.props, ['amount', 'price']) && !this.state.currencyFocus) {
this.updateCurrencyFromAsset();
Expand Down
23 changes: 22 additions & 1 deletion src/renderer/auth/actions/walletActions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { createActions } from 'spunky';

import { addWalletToAccount, getWalletsForAccount } from 'shared/wallet/WalletHelpers';
import {
addWalletToAccount,
getWalletsForAccount,
importWalletToAccount,
storeWalletForAccount
} from 'shared/wallet/WalletHelpers';
import { getStorage } from 'shared/lib/storage';

export const ID = 'wallets';
Expand All @@ -18,3 +23,19 @@ export const addWalletActions = createActions(
return getWalletsForAccount({ accountLabel: account.accountLabel });
}
);

// Setter - Import new wallets
export const importWalletActions = createActions(
ID,
({ account, passphrase, options }) => async () => {
await importWalletToAccount({ account, passphrase, options });
return getWalletsForAccount({ accountLabel: account.accountLabel });
}
);

// Setter - Update Wallet
export const updateWalletActions = createActions(ID, ({ account, wallet }) => async () => {
const { accountLabel } = account;
await storeWalletForAccount({ accountLabel, wallet, update: true });
return getWalletsForAccount({ accountLabel });
});
4 changes: 2 additions & 2 deletions src/renderer/auth/components/Auth/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export const LOGIN = 'Login';
export const REGISTER = 'Register';

export default class Auth extends React.PureComponent {
confirm = React.createRef();

static propTypes = {
className: string,
loading: bool.isRequired,
Expand All @@ -31,8 +33,6 @@ export default class Auth extends React.PureComponent {
accounts: null
};

confirm = React.createRef();

render() {
const { className, authenticated, onConfirm } = this.props;

Expand Down
4 changes: 2 additions & 2 deletions src/renderer/register/actions/registerCompletionActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export const verifyAndCreateWallet = async ({

const mnemonicArray = account.mnemonic.trim().split(' ');

// Validate password
// Validate passphrase
if (account.passphrase !== passphrase) {
throw new Error("You've entered a wrong password");
throw new Error("You've entered a wrong passphrase");
}

// Validate secret word
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ import MnemonicWordInput from './MnemonicWordInput';
import styles from './ImportView.scss';

export default class ImportView extends React.PureComponent {
mnemonicRefs = Array(24)
.fill(undefined)
.map(() => React.createRef());

showErrorToast = debounce((e) => {
this.props.showErrorToast(e);
}, 1000);

static propTypes = {
account: registerShape.isRequired,
loading: bool,
Expand All @@ -31,14 +39,6 @@ export default class ImportView extends React.PureComponent {
validMnemonic: false
};

mnemonicRefs = Array(24)
.fill(undefined)
.map(() => React.createRef());

showErrorToast = debounce((e) => {
this.props.showErrorToast(e);
}, 1000);

render() {
const { onCancel, loading, mnemonic, previousStep } = this.props;

Expand All @@ -64,7 +64,7 @@ export default class ImportView extends React.PureComponent {
</div>
<NavigationButtons
onBack={previousStep}
nextBtnText="Next: verify"
nextBtnText="Next: Verify"
disabled={loading || !this.state.validMnemonic}
isSubmit
/>
Expand Down
Loading

0 comments on commit 84c24a1

Please sign in to comment.