diff --git a/src/components/AccountPage/index.js b/src/components/AccountPage/index.js index 3a9d7fcf..73e97599 100644 --- a/src/components/AccountPage/index.js +++ b/src/components/AccountPage/index.js @@ -28,7 +28,7 @@ import Box from 'components/base/Box' import Button from 'components/base/Button' import FormattedVal from 'components/base/FormattedVal' import PillsDaysCount from 'components/PillsDaysCount' -import TransactionsList from 'components/TransactionsList' +import OperationsList from 'components/OperationsList' import AccountHeader from './AccountHeader' @@ -156,9 +156,9 @@ class AccountPage extends PureComponent { )} /> - diff --git a/src/components/DashboardPage/index.js b/src/components/DashboardPage/index.js index 6b65dccb..84054e0d 100644 --- a/src/components/DashboardPage/index.js +++ b/src/components/DashboardPage/index.js @@ -10,7 +10,7 @@ import chunk from 'lodash/chunk' import get from 'lodash/get' import sortBy from 'lodash/sortBy' -import type { Account, Accounts, T } from 'types/common' +import type { Account, Accounts, Operations, T } from 'types/common' import { getVisibleAccounts } from 'reducers/accounts' import { getCounterValue } from 'reducers/settings' @@ -23,7 +23,7 @@ import BalanceSummary from 'components/BalanceSummary' import Box from 'components/base/Box' import PillsDaysCount from 'components/PillsDaysCount' import Text from 'components/base/Text' -import TransactionsList from 'components/TransactionsList' +import OperationsList from 'components/OperationsList' import AccountCard from './AccountCard' import AccountsOrder from './AccountsOrder' @@ -48,21 +48,21 @@ type Props = { type State = { accountsChunk: Array>, - allTransactions: Array, + allOperations: Operations, selectedTime: string, daysCount: number, } const ACCOUNTS_BY_LINE = 3 -const ALL_TRANSACTIONS_LIMIT = 10 +const ALL_OPERATIONS_LIMIT = 10 -const getAllTransactions = accounts => { - const allTransactions = accounts.reduce((result, account) => { - const transactions = get(account, 'transactions', []) +const getAllOperations = accounts => { + const allOperations = accounts.reduce((result, account) => { + const operations = get(account, 'operations', []) result = [ ...result, - ...transactions.map(t => ({ + ...operations.map(t => ({ ...t, account, })), @@ -71,9 +71,9 @@ const getAllTransactions = accounts => { return result }, []) - return sortBy(allTransactions, t => t.receivedAt) + return sortBy(allOperations, t => t.receivedAt) .reverse() - .slice(0, ALL_TRANSACTIONS_LIMIT) + .slice(0, ALL_OPERATIONS_LIMIT) } const getAccountsChunk = accounts => { @@ -88,7 +88,7 @@ const getAccountsChunk = accounts => { class DashboardPage extends PureComponent { state = { accountsChunk: getAccountsChunk(this.props.accounts), - allTransactions: getAllTransactions(this.props.accounts), + allOperations: getAllOperations(this.props.accounts), selectedTime: 'week', daysCount: 7, } @@ -97,7 +97,7 @@ class DashboardPage extends PureComponent { if (nextProps.accounts !== this.props.accounts) { this.setState({ accountsChunk: getAccountsChunk(nextProps.accounts), - allTransactions: getAllTransactions(nextProps.accounts), + allOperations: getAllOperations(nextProps.accounts), }) } } @@ -110,7 +110,7 @@ class DashboardPage extends PureComponent { render() { const { push, accounts, t, counterValue } = this.props - const { accountsChunk, allTransactions, selectedTime, daysCount } = this.state + const { accountsChunk, allOperations, selectedTime, daysCount } = this.state const totalAccounts = accounts.length @@ -189,11 +189,11 @@ class DashboardPage extends PureComponent { ))} - push(`/account/${account.id}`)} /> diff --git a/src/components/TransactionsList/ConfirmationCheck.js b/src/components/OperationsList/ConfirmationCheck.js similarity index 92% rename from src/components/TransactionsList/ConfirmationCheck.js rename to src/components/OperationsList/ConfirmationCheck.js index ce0c5b45..0aa943cc 100644 --- a/src/components/TransactionsList/ConfirmationCheck.js +++ b/src/components/OperationsList/ConfirmationCheck.js @@ -36,7 +36,7 @@ const ConfirmationCheck = ({ return ( - isConfirmed ? t('transactionsList:confirmed') : t('transactionsList:notConfirmed') + isConfirmed ? t('operationsList:confirmed') : t('operationsList:notConfirmed') } > diff --git a/src/components/TransactionsList/index.js b/src/components/OperationsList/index.js similarity index 84% rename from src/components/TransactionsList/index.js rename to src/components/OperationsList/index.js index 16106acf..3221c8b5 100644 --- a/src/components/TransactionsList/index.js +++ b/src/components/OperationsList/index.js @@ -9,7 +9,7 @@ import noop from 'lodash/noop' import isEqual from 'lodash/isEqual' import { getIconByCoinType } from '@ledgerhq/currencies/react' -import type { Transaction as TransactionType, T } from 'types/common' +import type { Operation as OperationType, T } from 'types/common' import IconAngleDown from 'icons/AngleDown' import Box, { Card } from 'components/base/Box' @@ -55,7 +55,7 @@ HeaderCol.defaultProps = { children: undefined, } -const TransactionRaw = styled(Box).attrs({ +const OperationRaw = styled(Box).attrs({ horizontal: true, alignItems: 'center', })` @@ -97,7 +97,7 @@ const ShowMore = styled(Box).attrs({ } ` -const Transaction = ({ +const Operation = ({ t, onAccountClick, tx, @@ -106,14 +106,14 @@ const Transaction = ({ }: { t: T, onAccountClick?: Function, - tx: TransactionType, + tx: OperationType, withAccounts?: boolean, minConfirmations: number, }) => { const time = moment(tx.receivedAt) const Icon = getIconByCoinType(get(tx, 'account.currency.coinType')) return ( - + {time.format('DD MMM')} @@ -149,7 +149,7 @@ const Transaction = ({ }} > - {tx.balance > 0 ? t('transactionsList:from') : t('transactionsList:to')} + {tx.amount > 0 ? t('operationsList:from') : t('operationsList:to')} - + ) } -Transaction.defaultProps = { +Operation.defaultProps = { onAccountClick: noop, withAccounts: false, } @@ -193,14 +193,14 @@ Transaction.defaultProps = { type Props = { t: T, onAccountClick?: Function, - transactions: Array, + operations: Array, withAccounts?: boolean, minConfirmations: number, title?: string, canShowMore: boolean, } -class TransactionsList extends Component { +class OperationsList extends Component { static defaultProps = { onAccountClick: noop, withAccounts: false, @@ -221,16 +221,16 @@ class TransactionsList extends Component { return true } - return !isEqual(this._hashCache, this.getHashCache(nextProps.transactions)) + return !isEqual(this._hashCache, this.getHashCache(nextProps.operations)) } - getHashCache = (transactions: Array) => transactions.map(t => t.hash) + getHashCache = (operations: Array) => operations.map(t => t.hash) _hashCache = null render() { const { - transactions, + operations, title, withAccounts, onAccountClick, @@ -239,26 +239,26 @@ class TransactionsList extends Component { t, } = this.props - this._hashCache = this.getHashCache(transactions) + this._hashCache = this.getHashCache(operations) return ( - {t('transactionsList:date')} + {t('operationsList:date')} {withAccounts && ( - {t('transactionsList:account')} + {t('operationsList:account')} )} - {t('transactionsList:address')} + {t('operationsList:address')} - {t('transactionsList:amount')} + {t('operationsList:amount')} - {transactions.map(trans => ( - ( + { {canShowMore && ( - {t('transactionsList:showMore')} + {t('operationsList:showMore')} )} @@ -281,4 +281,4 @@ class TransactionsList extends Component { } } -export default translate()(TransactionsList) +export default translate()(OperationsList) diff --git a/src/components/TransactionsList/stories.js b/src/components/OperationsList/stories.js similarity index 56% rename from src/components/TransactionsList/stories.js rename to src/components/OperationsList/stories.js index ac7880bc..889b8eec 100644 --- a/src/components/TransactionsList/stories.js +++ b/src/components/OperationsList/stories.js @@ -1,28 +1,37 @@ // @flow import React from 'react' +import { getDefaultUnitByCoinType } from '@ledgerhq/currencies' import { storiesOf } from '@storybook/react' import { boolean } from '@storybook/addon-knobs' -import TransactionsList from 'components/TransactionsList' +import OperationsList from 'components/OperationsList' const stories = storiesOf('Components', module) -const transactions = [ +const unit = getDefaultUnitByCoinType(0) + +const operations = [ { address: '5c6ea1716520c7d6e038d36a3223faced3c', hash: '5c6ea1716520c7d6e038d36a3223faced3c4b8f7ffb69d9fb5bd527d562fdb62', - balance: 130000000, + amount: 130000000, receivedAt: '2018-01-09T16:03:52Z', + account: { + unit, + }, }, { address: '27416a48caab90fab053b507b8b6b9d4', hash: '27416a48caab90fab053b507b8b6b9d48fba75421d3bfdbae4b85f64024bc9c4', - balance: 65000000, + amount: -65000000, receivedAt: '2018-01-09T16:02:40Z', + account: { + unit, + }, }, ] -stories.add('TransactionsList', () => ( - +stories.add('OperationsList', () => ( + )) diff --git a/src/components/SelectAccount/stories.js b/src/components/SelectAccount/stories.js index be2ec8f3..845216b9 100644 --- a/src/components/SelectAccount/stories.js +++ b/src/components/SelectAccount/stories.js @@ -22,7 +22,7 @@ export const accounts = [...Array(20)].map(() => ({ name: chance.name(), path: '', rootPath: '', - transactions: [], + operations: [], unit: getDefaultUnitByCoinType(1), settings: { minConfirmations: 2, diff --git a/src/components/base/FormattedVal/index.js b/src/components/base/FormattedVal/index.js index 970feaaf..d30bed05 100644 --- a/src/components/base/FormattedVal/index.js +++ b/src/components/base/FormattedVal/index.js @@ -2,6 +2,7 @@ import React from 'react' import styled from 'styled-components' +import isUndefined from 'lodash/isUndefined' import type { Unit } from '@ledgerhq/currencies' @@ -27,6 +28,10 @@ function FormattedVal(props: Props) { const { fiat, isPercent, alwaysShowSign, showCode, ...p } = props let { val, unit } = props + if (isUndefined(val)) { + throw new Error('FormattedVal require a `val` prop. Received `undefined`') + } + const isNegative = val < 0 let text = '' diff --git a/src/components/modals/AddAccount/ImportAccounts.js b/src/components/modals/AddAccount/ImportAccounts.js index b4dbbf3d..a1b4b2e8 100644 --- a/src/components/modals/AddAccount/ImportAccounts.js +++ b/src/components/modals/AddAccount/ImportAccounts.js @@ -3,7 +3,7 @@ import React, { PureComponent } from 'react' import { translate } from 'react-i18next' -import type { T } from 'types/common' +import type { T, Accounts } from 'types/common' import Box from 'components/base/Box' import Button from 'components/base/Button' @@ -13,7 +13,7 @@ import Input from 'components/base/Input' type Props = { t: T, - accounts: Array, + accounts: Accounts, onImportAccounts: Function, } @@ -110,7 +110,7 @@ class ImportAccounts extends PureComponent { val={account.balance} /> - Transactions: {account.transactions.length} + Operations: {account.operations.length} ) diff --git a/src/components/modals/AddAccount/index.js b/src/components/modals/AddAccount/index.js index 88d73de1..98de020b 100644 --- a/src/components/modals/AddAccount/index.js +++ b/src/components/modals/AddAccount/index.js @@ -88,7 +88,7 @@ const Steps = { val={progress.balance || 0} /> - Transactions: {progress.transactions || 0} + Operations: {progress.operations || 0} {progress.success && Finish ! Next account in progress...} )} @@ -96,8 +96,8 @@ const Steps = { ), listAccounts: (props: Object) => { const { accounts, archivedAccounts } = props - const emptyAccounts = accounts.filter(account => account.transactions.length === 0) - const existingAccounts = accounts.filter(account => account.transactions.length > 0) + const emptyAccounts = accounts.filter(account => account.operations.length === 0) + const existingAccounts = accounts.filter(account => account.operations.length > 0) const canCreateAccount = props.canCreateAccount && emptyAccounts.length === 1 const newAccount = emptyAccounts[0] return ( diff --git a/src/components/modals/SettingsAccount.js b/src/components/modals/SettingsAccount.js index ad82bd5b..c1830381 100644 --- a/src/components/modals/SettingsAccount.js +++ b/src/components/modals/SettingsAccount.js @@ -50,8 +50,8 @@ const defaultState = { nameHovered: false, } -function hasNoTransactions(account: Account) { - return get(account, 'transactions.length', 0) === 0 +function hasNoOperations(account: Account) { + return get(account, 'operations.length', 0) === 0 } class SettingsAccount extends PureComponent { @@ -133,7 +133,7 @@ class SettingsAccount extends PureComponent { handleArchiveAccount = (account: Account) => () => { const { push, closeModal, updateAccount, removeAccount } = this.props - const shouldRemove = hasNoTransactions(account) + const shouldRemove = hasNoOperations(account) if (shouldRemove) { removeAccount(account) @@ -212,7 +212,7 @@ class SettingsAccount extends PureComponent { diff --git a/src/helpers/__tests__/balance.test.js b/src/helpers/__tests__/balance.test.js index b265162c..0a8c00b2 100644 --- a/src/helpers/__tests__/balance.test.js +++ b/src/helpers/__tests__/balance.test.js @@ -69,7 +69,7 @@ describe('helpers > balance', () => { ]) }) - test('should work if interval dont contain transactions', () => { + test('should work if interval dont contain operations', () => { const account = { coinType: 0, balanceByDay: { diff --git a/src/helpers/btc.js b/src/helpers/btc.js index 5e25cc99..f4349ee5 100644 --- a/src/helpers/btc.js +++ b/src/helpers/btc.js @@ -7,7 +7,7 @@ import groupBy from 'lodash/groupBy' import noop from 'lodash/noop' import uniqBy from 'lodash/uniqBy' -import type { Transactions } from 'types/common' +import type { Operations } from 'types/common' const GAP_LIMIT_ADDRESSES = 20 @@ -22,7 +22,7 @@ export const networks = [ }, ] -export function computeTransaction(addresses: Array) { +export function computeOperation(addresses: Array) { return (t: Object) => { const outputVal = t.outputs .filter(o => addresses.includes(o.address)) @@ -30,10 +30,11 @@ export function computeTransaction(addresses: Array) { const inputVal = t.inputs .filter(i => addresses.includes(i.address)) .reduce((acc, cur) => acc + cur.value, 0) - const balance = outputVal - inputVal + const amount = outputVal - inputVal return { - address: t.balance > 0 ? t.inputs[0].address : t.outputs[0].address, - balance, + id: t.hash, + address: t.amount > 0 ? t.inputs[0].address : t.outputs[0].address, + amount, confirmations: t.confirmations, hash: t.hash, receivedAt: t.received_at, @@ -41,8 +42,8 @@ export function computeTransaction(addresses: Array) { } } -export function getBalanceByDay(transactions: Transactions) { - const txsByDate = groupBy(transactions, tx => { +export function getBalanceByDay(operations: Operations) { + const txsByDate = groupBy(operations, tx => { const [date] = new Date(tx.receivedAt).toISOString().split('T') return date }) @@ -55,7 +56,7 @@ export function getBalanceByDay(transactions: Transactions) { const txs = txsByDate[k] balance += txs.reduce((r, v) => { - r += v.balance + r += v.amount return r }, 0) @@ -91,7 +92,7 @@ export async function getAccount({ const script = segwit ? parseInt(network.scriptHash, 10) : parseInt(network.pubKeyHash, 10) let balance = 0 - let transactions = [] + let operations = [] let lastAddress = null const pubKeyToSegwitAddress = (pubKey, scriptVersion) => { @@ -149,31 +150,31 @@ export async function getAccount({ let txs = [] - const transactionsOpts = { coin_type: coinType } + const operationsOpts = { coin_type: coinType } try { - txs = await ledger.getTransactions(listAddresses, transactionsOpts) + txs = await ledger.getTransactions(listAddresses, operationsOpts) txs = txs.filter(t => !allTxsHash.includes(t.hash)).reverse() } catch (e) { - console.log('getTransactions', e) // eslint-disable-line no-console + console.log('getOperations', e) // eslint-disable-line no-console } - const hasTransactions = txs.length > 0 + const hasOperations = txs.length > 0 - if (hasTransactions) { - const newTransactions = txs.map(computeTransaction(allAddresses)) - const txHashs = transactions.map(t => t.hash) + if (hasOperations) { + const newOperations = txs.map(computeOperation(allAddresses)) + const txHashs = operations.map(t => t.hash) - balance = newTransactions + balance = newOperations .filter(t => !txHashs.includes(t.hash)) - .reduce((result, v) => result + v.balance, balance) + .reduce((result, v) => result + v.amount, balance) lastAddress = getLastAddress(addresses, txs[0]) - transactions = uniqBy([...transactions, ...newTransactions], t => t.hash) + operations = uniqBy([...operations, ...newOperations], t => t.hash) onProgress({ balance, - transactions: transactions.length, + operations: operations.length, }) return nextPath(index + (GAP_LIMIT_ADDRESSES - 1)) @@ -189,11 +190,11 @@ export async function getAccount({ return { ...nextAddress, - addresses: transactions.length > 0 ? allAddresses : [], + addresses: operations.length > 0 ? allAddresses : [], balance, - balanceByDay: getBalanceByDay(transactions), + balanceByDay: getBalanceByDay(operations), rootPath, - transactions, + operations, } }) diff --git a/src/internals/accounts/sync.js b/src/internals/accounts/sync.js index 68064960..357772c3 100644 --- a/src/internals/accounts/sync.js +++ b/src/internals/accounts/sync.js @@ -4,9 +4,9 @@ import { getAccount, getHDNode, networks } from 'helpers/btc' const network = networks[1] -function syncAccount({ id, transactions, ...currentAccount }) { +function syncAccount({ id, operations, ...currentAccount }) { const hdnode = getHDNode({ xpub58: id, network }) - const allTxsHash = transactions.map(t => t.hash) + const allTxsHash = operations.map(t => t.hash) return getAccount({ hdnode, network, allTxsHash, segwit: true, ...currentAccount }).then( account => ({ id, diff --git a/src/internals/usb/wallet/accounts.js b/src/internals/usb/wallet/accounts.js index 038fcc53..d5b1f7de 100644 --- a/src/internals/usb/wallet/accounts.js +++ b/src/internals/usb/wallet/accounts.js @@ -154,11 +154,11 @@ export default async ({ network, rootPath: path, segwit, - onProgress: ({ transactions, ...progress }) => - transactions > 0 && onProgress({ account: currentAccount, transactions, ...progress }), + onProgress: ({ operations, ...progress }) => + operations > 0 && onProgress({ account: currentAccount, operations, ...progress }), }) - const hasTransactions = account.transactions.length > 0 + const hasOperations = account.operations.length > 0 accounts.push({ id: xpub58, @@ -166,7 +166,7 @@ export default async ({ ...account, }) - if (hasTransactions) { + if (hasOperations) { onProgress({ success: true, }) diff --git a/src/reducers/accounts.js b/src/reducers/accounts.js index e3aa7206..67d44e0f 100644 --- a/src/reducers/accounts.js +++ b/src/reducers/accounts.js @@ -16,12 +16,12 @@ export type AccountsState = Accounts const state: AccountsState = [] -function orderAccountsTransactions(account: Account) { - const { transactions } = account - transactions.sort((a, b) => new Date(b.receivedAt) - new Date(a.receivedAt)) +function orderAccountsOperations(account: Account) { + const { operations } = account + operations.sort((a, b) => new Date(b.receivedAt) - new Date(a.receivedAt)) return { ...account, - transactions, + operations, } } @@ -42,7 +42,7 @@ const handlers: Object = { ADD_ACCOUNT: ( state: AccountsState, { payload: account }: { payload: Account }, - ): AccountsState => [...state, orderAccountsTransactions(account)], + ): AccountsState => [...state, orderAccountsOperations(account)], UPDATE_ACCOUNT: ( state: AccountsState, @@ -58,7 +58,7 @@ const handlers: Object = { ...account, } - return orderAccountsTransactions(updatedAccount) + return orderAccountsOperations(updatedAccount) }), REMOVE_ACCOUNT: (state: AccountsState, { payload: account }: { payload: Account }) => @@ -96,7 +96,7 @@ export function getAccountById(state: { accounts: AccountsState }, id: string): } export function canCreateAccount(state: State): boolean { - return every(getAccounts(state), a => get(a, 'transactions.length', 0) > 0) + return every(getAccounts(state), a => get(a, 'operations.length', 0) > 0) } export function serializeAccounts(accounts: Array) { @@ -119,7 +119,7 @@ export function serializeAccounts(accounts: Array) { return { ...a, - transactions: account.transactions.map(t => ({ + operations: account.operations.map(t => ({ ...t, account: a, })), @@ -139,7 +139,7 @@ export function deserializeAccounts(accounts: Accounts) { name: account.name, path: account.path, rootPath: account.rootPath, - transactions: account.transactions.map(({ account, ...t }) => t), + operations: account.operations.map(({ account, ...t }) => t), unit: account.unit, settings: account.settings, })) diff --git a/src/renderer/events.js b/src/renderer/events.js index cc49ae99..f05fc56f 100644 --- a/src/renderer/events.js +++ b/src/renderer/events.js @@ -57,14 +57,14 @@ export function startSyncAccounts(accounts: Accounts) { syncAccountsInProgress = true sendEvent('accounts', 'sync.all', { accounts: accounts.map(account => { - const { id, coinType, rootPath, addresses, index, transactions } = account + const { id, coinType, rootPath, addresses, index, operations } = account return { id, coinType, allAddresses: addresses, currentIndex: index, rootPath, - transactions, + operations, } }), }) @@ -114,9 +114,9 @@ export default ({ store, locked }: { store: Object, locked: boolean }) => { return } - const { name, balance, balanceByDay, transactions } = existingAccount + const { name, balance, balanceByDay, operations } = existingAccount - if (account.transactions.length > 0) { + if (account.operations.length > 0) { d.sync(`Update account - ${name}`) const updatedAccount = { ...account, @@ -126,7 +126,7 @@ export default ({ store, locked }: { store: Object, locked: boolean }) => { return result }, {}), index: account.index || existingAccount.index, - transactions: [...transactions, ...account.transactions], + operations: [...operations, ...account.operations], } store.dispatch(updateAccount(updatedAccount)) } diff --git a/src/renderer/i18n/instanciate.js b/src/renderer/i18n/instanciate.js index 35edd84e..3088da6c 100644 --- a/src/renderer/i18n/instanciate.js +++ b/src/renderer/i18n/instanciate.js @@ -14,7 +14,7 @@ const commonConfig = { 'settings', 'sidebar', 'time', - 'transactionsList', + 'operationsList', 'update', ], fallbackLng: 'en', diff --git a/src/renderer/i18n/storybook.js b/src/renderer/i18n/storybook.js index 1f875ef7..01302f00 100644 --- a/src/renderer/i18n/storybook.js +++ b/src/renderer/i18n/storybook.js @@ -13,7 +13,7 @@ const resources = { settings: require('../../../static/i18n/en/settings.yml'), sidebar: require('../../../static/i18n/en/sidebar.yml'), time: require('../../../static/i18n/en/time.yml'), - transactionsList: require('../../../static/i18n/en/transactionsList.yml'), + operationsList: require('../../../static/i18n/en/operationsList.yml'), update: require('../../../static/i18n/en/update.yml'), } diff --git a/src/types/common.js b/src/types/common.js index 1711c904..1f9838d3 100644 --- a/src/types/common.js +++ b/src/types/common.js @@ -10,18 +10,19 @@ export type Device = { export type Devices = Array -// -------------------- Transactions +// -------------------- Operations -export type Transaction = { +export type Operation = { + id: string, account?: Account, address: string, - balance: number, + amount: number, hash: string, receivedAt: string, confirmations: number, } -export type Transactions = Array +export type Operations = Array // -------------------- Accounts @@ -42,7 +43,7 @@ export type Account = { name: string, path: string, rootPath: string, - transactions: Transactions, + operations: Operations, unit: Unit, settings: AccountSettings, } diff --git a/static/i18n/en/transactionsList.yml b/static/i18n/en/operationsList.yml similarity index 100% rename from static/i18n/en/transactionsList.yml rename to static/i18n/en/operationsList.yml diff --git a/static/i18n/fr/transactionsList.yml b/static/i18n/fr/operationsList.yml similarity index 100% rename from static/i18n/fr/transactionsList.yml rename to static/i18n/fr/operationsList.yml