Browse Source

Use common currencies list when adding account

master
meriadec 7 years ago
parent
commit
73c7e7b552
No known key found for this signature in database GPG Key ID: 1D2FC2305E2CB399
  1. 11
      src/components/AccountPage.js
  2. 4
      src/components/DashboardPage/AccountCard.js
  3. 6
      src/components/DashboardPage/index.js
  4. 5
      src/components/SelectAccount/stories.js
  5. 2
      src/components/SideBar/index.js
  6. 8
      src/components/TransactionsList/index.js
  7. 29
      src/components/base/FormattedVal.js
  8. 76
      src/components/modals/AddAccount/index.js
  9. 15
      src/internals/usb/wallet/index.js
  10. 63
      src/stories/currencies.stories.js
  11. 6
      src/types/common.js

11
src/components/AccountPage.js

@ -39,6 +39,13 @@ const mapDispatchToProps = {
openModal, openModal,
} }
function enrichTransactionsWithAccount(transactions, account) {
return transactions.map(t => ({
...t,
account,
}))
}
class AccountPage extends PureComponent<Props> { class AccountPage extends PureComponent<Props> {
render() { render() {
const { account, accountData, openModal, t } = this.props const { account, accountData, openModal, t } = this.props
@ -100,7 +107,9 @@ class AccountPage extends PureComponent<Props> {
</Box> </Box>
</Box> </Box>
<Card p={0} px={4} title={t('AccountPage.lastOperations')}> <Card p={0} px={4} title={t('AccountPage.lastOperations')}>
<TransactionsList transactions={accountData.transactions} /> <TransactionsList
transactions={enrichTransactionsWithAccount(accountData.transactions, account)}
/>
</Card> </Card>
</Fragment> </Fragment>
)} )}

4
src/components/DashboardPage/AccountCard.js

@ -27,7 +27,7 @@ const AccountCard = ({
</Box> </Box>
<Box> <Box>
<Box style={{ textTransform: 'uppercase' }} fontSize={0} color="warmGrey"> <Box style={{ textTransform: 'uppercase' }} fontSize={0} color="warmGrey">
{account.type} {account.unit.code}
</Box> </Box>
<Box fontSize={4} color="dark"> <Box fontSize={4} color="dark">
{account.name} {account.name}
@ -40,7 +40,7 @@ const AccountCard = ({
<FormattedVal <FormattedVal
alwaysShowSign={false} alwaysShowSign={false}
color="dark" color="dark"
currency={account.type} unit={account.unit}
showCode showCode
val={account.data.balance} val={account.data.balance}
/> />

6
src/components/DashboardPage/index.js

@ -96,11 +96,7 @@ const getAllTransactions = accounts => {
...result, ...result,
...transactions.map(t => ({ ...transactions.map(t => ({
...t, ...t,
account: { account,
id: account.id,
name: account.name,
type: account.type,
},
})), })),
] ]

5
src/components/SelectAccount/stories.js

@ -3,6 +3,7 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { storiesOf } from '@storybook/react' import { storiesOf } from '@storybook/react'
import Chance from 'chance' import Chance from 'chance'
import { getCurrencyByCoinType, getDefaultUnitByCoinType } from '@ledgerhq/currencies'
import { SelectAccount } from 'components/SelectAccount' import { SelectAccount } from 'components/SelectAccount'
@ -12,7 +13,9 @@ const stories = storiesOf('SelectAccount', module)
const accounts = [...Array(20)].map(() => ({ const accounts = [...Array(20)].map(() => ({
id: chance.string(), id: chance.string(),
name: chance.name(), name: chance.name(),
type: 'BTC', coinType: 0,
currency: getCurrencyByCoinType(0),
unit: getDefaultUnitByCoinType(0),
data: { data: {
address: chance.string(), address: chance.string(),
balance: chance.floating({ min: 0, max: 20 }), balance: chance.floating({ min: 0, max: 20 }),

2
src/components/SideBar/index.js

@ -106,7 +106,7 @@ class SideBar extends PureComponent<Props> {
<FormattedVal <FormattedVal
alwaysShowSign={false} alwaysShowSign={false}
color="warmGrey" color="warmGrey"
currency={account.type} unit={account.unit}
showCode showCode
val={account.data ? account.data.balance : 0} val={account.data ? account.data.balance : 0}
/> />

8
src/components/TransactionsList/index.js

@ -121,7 +121,13 @@ const Transaction = ({
</Box> </Box>
</Cell> </Cell>
<Cell size={AMOUNT_COL_SIZE} justifyContent="flex-end"> <Cell size={AMOUNT_COL_SIZE} justifyContent="flex-end">
<FormattedVal val={tx.balance} currency="BTC" showCode fontSize={4} alwaysShowSign /> <FormattedVal
val={tx.balance}
unit={tx.account.unit}
showCode
fontSize={4}
alwaysShowSign
/>
</Cell> </Cell>
</TransactionRaw> </TransactionRaw>
) )

29
src/components/base/FormattedVal.js

@ -4,6 +4,7 @@ import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { formatCurrencyUnit } from '@ledgerhq/currencies' import { formatCurrencyUnit } from '@ledgerhq/currencies'
import type { Unit } from '@ledgerhq/currencies'
import Text from 'components/base/Text' import Text from 'components/base/Text'
@ -12,31 +13,16 @@ const T = styled(Text).attrs({
color: p => (p.isNegative ? p.theme.colors.grenade : p.theme.colors.green), color: p => (p.isNegative ? p.theme.colors.grenade : p.theme.colors.green),
})`` })``
const currencies = {
BTC: {
name: 'bitcoin',
code: 'BTC',
symbol: 'b',
magnitude: 8,
},
USD: {
name: 'dollar',
code: 'USD',
symbol: '$',
magnitude: 0,
},
}
type Props = { type Props = {
val: number, val: number,
isPercent?: boolean, isPercent?: boolean,
currency?: any, unit?: Unit | null,
alwaysShowSign?: boolean, alwaysShowSign?: boolean,
showCode?: boolean, showCode?: boolean,
} }
function FormattedVal(props: Props) { function FormattedVal(props: Props) {
const { val, isPercent, currency, alwaysShowSign, showCode, ...p } = props const { val, isPercent, unit, alwaysShowSign, showCode, ...p } = props
const isNegative = val < 0 const isNegative = val < 0
@ -45,11 +31,10 @@ function FormattedVal(props: Props) {
if (isPercent) { if (isPercent) {
text = `${alwaysShowSign ? (isNegative ? '- ' : '+ ') : ''}${val} %` text = `${alwaysShowSign ? (isNegative ? '- ' : '+ ') : ''}${val} %`
} else { } else {
const curr = currency ? currencies[currency.toUpperCase()] : null if (!unit) {
if (!curr) { return ''
return `[invalid currency ${currency || '(null)'}]`
} }
text = formatCurrencyUnit(curr, val, { text = formatCurrencyUnit(unit, val, {
alwaysShowSign, alwaysShowSign,
showCode, showCode,
}) })
@ -63,7 +48,7 @@ function FormattedVal(props: Props) {
} }
FormattedVal.defaultProps = { FormattedVal.defaultProps = {
currency: null, unit: null,
isPercent: false, isPercent: false,
alwaysShowSign: false, alwaysShowSign: false,
showCode: false, showCode: false,

76
src/components/modals/AddAccount/index.js

@ -6,6 +6,9 @@ import { compose } from 'redux'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import differenceBy from 'lodash/differenceBy' import differenceBy from 'lodash/differenceBy'
import { listCurrencies, getDefaultUnitByCoinType } from '@ledgerhq/currencies'
import type { Currency } from '@ledgerhq/currencies'
import { MODAL_ADD_ACCOUNT } from 'constants' import { MODAL_ADD_ACCOUNT } from 'constants'
@ -30,25 +33,24 @@ import CreateAccount from './CreateAccount'
import ImportAccounts from './ImportAccounts' import ImportAccounts from './ImportAccounts'
import RestoreAccounts from './RestoreAccounts' import RestoreAccounts from './RestoreAccounts'
const currencies = [ const currencies = listCurrencies().map(currency => ({
{ key: currency.coinType,
key: 'btc', name: currency.name,
name: 'Bitcoin', data: currency,
}, }))
]
const Steps = { const Steps = {
chooseWallet: (props: Object) => ( chooseCurrency: (props: Object) => (
<form onSubmit={props.onSubmit}> <form onSubmit={props.onSubmit}>
<Box flow={3}> <Box flow={3}>
<Box flow={1}> <Box flow={1}>
<Label>{props.t('common.currency')}</Label> <Label>{props.t('common.currency')}</Label>
<Select <Select
placeholder={props.t('common.chooseWalletPlaceholder')} placeholder={props.t('common.chooseWalletPlaceholder')}
onChange={item => props.onChangeInput('wallet')(item.key)} onChange={item => props.onChangeCurrency(item.data)}
renderSelected={item => item.name} renderSelected={item => item.name}
items={currencies} items={currencies}
value={currencies.find(c => c.key === props.value.wallet)} value={props.currency ? currencies.find(c => c.key === props.currency.coinType) : null}
/> />
</Box> </Box>
<Box horizontal justifyContent="flex-end"> <Box horizontal justifyContent="flex-end">
@ -62,7 +64,7 @@ const Steps = {
connectDevice: (props: Object) => ( connectDevice: (props: Object) => (
<Box> <Box>
<Box>Connect your Ledger: {props.connected ? 'ok' : 'ko'}</Box> <Box>Connect your Ledger: {props.connected ? 'ok' : 'ko'}</Box>
<Box>Start {props.wallet.toUpperCase()} App on your Ledger: ko</Box> <Box>Start {props.currency.name} App on your Ledger: ko</Box>
</Box> </Box>
), ),
inProgress: (props: Object) => ( inProgress: (props: Object) => (
@ -95,11 +97,7 @@ const Steps = {
}, },
} }
type InputValue = { type Step = 'chooseCurrency' | 'connectDevice' | 'inProgress' | 'listAccounts'
wallet: string,
}
type Step = 'chooseWallet' | 'connectDevice' | 'inProgress' | 'listAccounts'
type Props = { type Props = {
t: T, t: T,
@ -113,8 +111,8 @@ type Props = {
} }
type State = { type State = {
inputValue: InputValue,
step: Step, step: Step,
currency: Currency | null,
accounts: Accounts, accounts: Accounts,
progress: null | Object, progress: null | Object,
} }
@ -133,12 +131,10 @@ const mapDispatchToProps = {
} }
const defaultState = { const defaultState = {
inputValue: { currency: null,
wallet: '',
},
accounts: [], accounts: [],
progress: null, progress: null,
step: 'chooseWallet', step: 'chooseCurrency',
} }
class AddAccountModal extends PureComponent<Props, State> { class AddAccountModal extends PureComponent<Props, State> {
@ -176,36 +172,36 @@ class AddAccountModal extends PureComponent<Props, State> {
getWalletInfos() { getWalletInfos() {
const { currentDevice, accounts } = this.props const { currentDevice, accounts } = this.props
const { inputValue } = this.state const { currency } = this.state
if (currentDevice === null) { if (currentDevice === null || currency === null) {
return return
} }
sendEvent('usb', 'wallet.getAccounts', { sendEvent('usb', 'wallet.getAccounts', {
pathDevice: currentDevice.path, pathDevice: currentDevice.path,
wallet: inputValue.wallet, coinType: currency.coinType,
currentAccounts: accounts.map(acc => acc.id), currentAccounts: accounts.map(acc => acc.id),
}) })
} }
getStepProps() { getStepProps() {
const { currentDevice, archivedAccounts, canCreateAccount, updateAccount, t } = this.props const { currentDevice, archivedAccounts, canCreateAccount, updateAccount, t } = this.props
const { inputValue, step, progress, accounts } = this.state const { currency, step, progress, accounts } = this.state
const props = (predicate, props) => (predicate ? props : {}) const props = (predicate, props) => (predicate ? props : {})
return { return {
...props(step === 'chooseWallet', { ...props(step === 'chooseCurrency', {
t, t,
value: inputValue, currency,
onChangeCurrency: this.handleChangeCurrency,
onSubmit: this.handleSubmit, onSubmit: this.handleSubmit,
onChangeInput: this.handleChangeInput,
}), }),
...props(step === 'connectDevice', { ...props(step === 'connectDevice', {
t, t,
connected: currentDevice !== null, connected: currentDevice !== null,
wallet: inputValue.wallet, currency,
}), }),
...props(step === 'inProgress', { ...props(step === 'inProgress', {
t, t,
@ -247,23 +243,11 @@ class AddAccountModal extends PureComponent<Props, State> {
handleImportAccounts = accounts => accounts.forEach(account => this.addAccount(account)) handleImportAccounts = accounts => accounts.forEach(account => this.addAccount(account))
handleChangeInput = (key: $Keys<InputValue>) => (value: $Values<InputValue>) => handleChangeCurrency = (currency: Currency) => this.setState({ currency })
this.setState(prev => ({
inputValue: {
...prev.inputValue,
[key]: value,
},
}))
handleSubmit = (e: SyntheticEvent<HTMLFormElement>) => { handleSubmit = (e: SyntheticEvent<HTMLFormElement>) => {
e.preventDefault() e.preventDefault()
const { inputValue } = this.state
if (inputValue.wallet.trim() === '') {
return
}
this.setState({ this.setState({
step: 'connectDevice', step: 'connectDevice',
}) })
@ -277,13 +261,19 @@ class AddAccountModal extends PureComponent<Props, State> {
}) })
addAccount = ({ id, name, ...data }) => { addAccount = ({ id, name, ...data }) => {
const { inputValue } = this.state const { currency } = this.state
const { addAccount } = this.props const { addAccount } = this.props
if (currency === null) {
return
}
addAccount({ addAccount({
id, id,
name, name,
type: inputValue.wallet, coinType: currency.coinType,
currency,
unit: getDefaultUnitByCoinType(currency.coinType),
data, data,
}) })
} }

15
src/internals/usb/wallet/index.js

@ -4,30 +4,31 @@ import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import getAllAccounts, { verifyAddress } from './accounts' import getAllAccounts, { verifyAddress } from './accounts'
async function getAllAccountsByWallet({ pathDevice, wallet, currentAccounts, onProgress }) { async function getAllAccountsByCoinType({ pathDevice, coinType, currentAccounts, onProgress }) {
const transport = await CommNodeHid.open(pathDevice) const transport = await CommNodeHid.open(pathDevice)
if (wallet === 'btc') { // 0: BTC
if (coinType === 0) {
return getAllAccounts({ transport, currentAccounts, onProgress }) return getAllAccounts({ transport, currentAccounts, onProgress })
} }
throw new Error('invalid wallet') throw new Error('invalid coinType')
} }
export default (sendEvent: Function) => ({ export default (sendEvent: Function) => ({
getAccounts: async ({ getAccounts: async ({
pathDevice, pathDevice,
wallet, coinType,
currentAccounts, currentAccounts,
}: { }: {
pathDevice: string, pathDevice: string,
wallet: string, coinType: number,
currentAccounts: Array<*>, currentAccounts: Array<*>,
}) => { }) => {
try { try {
const data = await getAllAccountsByWallet({ const data = await getAllAccountsByCoinType({
pathDevice, pathDevice,
wallet, coinType,
currentAccounts, currentAccounts,
onProgress: progress => sendEvent('wallet.getAccounts.progress', progress, { kill: false }), onProgress: progress => sendEvent('wallet.getAccounts.progress', progress, { kill: false }),
}) })

63
src/stories/currencies.stories.js

@ -0,0 +1,63 @@
// @flow
import React, { Fragment, createElement } from 'react'
import { storiesOf } from '@storybook/react'
import { listCurrencies } from '@ledgerhq/currencies'
import type { Currency } from '@ledgerhq/currencies'
const stories = storiesOf('currencies', module)
const currencies: Array<Currency> = listCurrencies()
stories.add('currencies list', () => (
<div>
<table border="1">
<thead>
<tr>
<td>{'coin type'}</td>
<td>{'name'}</td>
<td>{'color'}</td>
<td>{'icon'}</td>
<td>{'units'}</td>
</tr>
</thead>
<tbody>
{currencies.map(cur => (
<tr key={cur.coinType}>
<td>{cur.coinType}</td>
<td>{cur.name}</td>
<td>
{cur.color ? (
<Fragment>
<div
style={{
width: 50,
height: 25,
backgroundColor: cur.color,
}}
/>
<div>{cur.color}</div>
</Fragment>
) : (
'-'
)}
</td>
<td>{cur.icon ? createElement(cur.icon, { size: 30 }) : '-'}</td>
<td>
{cur.units && (
<ul style={{ paddingRight: 10 }}>
{cur.units.map(unit => (
<li key={unit.code}>
{unit.code} ({unit.magnitude})
</li>
))}
</ul>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
))

6
src/types/common.js

@ -1,5 +1,7 @@
// @flow // @flow
import type { Unit, Currency } from '@ledgerhq/currencies'
export type Device = { export type Device = {
vendorId: string, vendorId: string,
productId: string, productId: string,
@ -32,7 +34,9 @@ export type Account = {
data?: AccountData, data?: AccountData,
id: string, id: string,
name: string, name: string,
type: string, coinType: number,
currency: Currency,
unit: Unit,
} }
export type Accounts = Array<Account> export type Accounts = Array<Account>

Loading…
Cancel
Save