aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/app/components/currency-display/currency-display.component.js24
-rw-r--r--ui/app/components/currency-display/currency-display.container.js20
-rw-r--r--ui/app/components/currency-display/index.js1
-rw-r--r--ui/app/components/currency-display/tests/currency-display.component.test.js27
-rw-r--r--ui/app/components/currency-display/tests/currency-display.container.test.js61
-rw-r--r--ui/app/components/token-currency-display/index.js1
-rw-r--r--ui/app/components/token-currency-display/token-currency-display.component.js54
-rw-r--r--ui/app/components/token-view-balance/tests/token-view-balance.component.test.js71
-rw-r--r--ui/app/components/token-view-balance/token-view-balance.component.js26
-rw-r--r--ui/app/components/token-view-balance/token-view-balance.container.js18
-rw-r--r--ui/app/components/transaction-action/tests/transaction-action.component.test.js102
-rw-r--r--ui/app/components/transaction-list-item/transaction-list-item.component.js61
-rw-r--r--ui/app/components/transaction-list-item/transaction-list-item.container.js32
-rw-r--r--ui/app/constants/common.js1
14 files changed, 425 insertions, 74 deletions
diff --git a/ui/app/components/currency-display/currency-display.component.js b/ui/app/components/currency-display/currency-display.component.js
new file mode 100644
index 000000000..f1bb933d7
--- /dev/null
+++ b/ui/app/components/currency-display/currency-display.component.js
@@ -0,0 +1,24 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+
+export default class CurrencyDisplay extends PureComponent {
+ static propTypes = {
+ className: PropTypes.string,
+ displayValue: PropTypes.string,
+ prefix: PropTypes.string,
+ }
+
+ render () {
+ const { className, displayValue, prefix } = this.props
+ const text = `${prefix || ''}${displayValue}`
+
+ return (
+ <div
+ className={className}
+ title={text}
+ >
+ { text }
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/currency-display/currency-display.container.js b/ui/app/components/currency-display/currency-display.container.js
new file mode 100644
index 000000000..b36bba52a
--- /dev/null
+++ b/ui/app/components/currency-display/currency-display.container.js
@@ -0,0 +1,20 @@
+import { connect } from 'react-redux'
+import CurrencyDisplay from './currency-display.component'
+import { getValueFromWeiHex, formatCurrency } from '../../helpers/confirm-transaction/util'
+import { ETH } from '../../constants/common'
+
+const mapStateToProps = (state, ownProps) => {
+ const { value, numberOfDecimals = 2, currency } = ownProps
+ const { metamask: { currentCurrency, conversionRate } } = state
+
+ const toCurrency = currency === ETH ? ETH : currentCurrency
+ const convertedValue = getValueFromWeiHex({ value, toCurrency, conversionRate, numberOfDecimals })
+ const formattedValue = formatCurrency(convertedValue, toCurrency)
+ const displayValue = `${formattedValue} ${toCurrency.toUpperCase()}`
+
+ return {
+ displayValue,
+ }
+}
+
+export default connect(mapStateToProps)(CurrencyDisplay)
diff --git a/ui/app/components/currency-display/index.js b/ui/app/components/currency-display/index.js
new file mode 100644
index 000000000..38f08765f
--- /dev/null
+++ b/ui/app/components/currency-display/index.js
@@ -0,0 +1 @@
+export { default } from './currency-display.container'
diff --git a/ui/app/components/currency-display/tests/currency-display.component.test.js b/ui/app/components/currency-display/tests/currency-display.component.test.js
new file mode 100644
index 000000000..d9ef052f1
--- /dev/null
+++ b/ui/app/components/currency-display/tests/currency-display.component.test.js
@@ -0,0 +1,27 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import CurrencyDisplay from '../currency-display.component'
+
+describe('CurrencyDisplay Component', () => {
+ it('should render text with a className', () => {
+ const wrapper = shallow(<CurrencyDisplay
+ displayValue="$123.45"
+ className="currency-display"
+ />)
+
+ assert.ok(wrapper.hasClass('currency-display'))
+ assert.equal(wrapper.text(), '$123.45')
+ })
+
+ it('should render text with a prefix', () => {
+ const wrapper = shallow(<CurrencyDisplay
+ displayValue="$123.45"
+ className="currency-display"
+ prefix="-"
+ />)
+
+ assert.ok(wrapper.hasClass('currency-display'))
+ assert.equal(wrapper.text(), '-$123.45')
+ })
+})
diff --git a/ui/app/components/currency-display/tests/currency-display.container.test.js b/ui/app/components/currency-display/tests/currency-display.container.test.js
new file mode 100644
index 000000000..474ce5378
--- /dev/null
+++ b/ui/app/components/currency-display/tests/currency-display.container.test.js
@@ -0,0 +1,61 @@
+import assert from 'assert'
+import proxyquire from 'proxyquire'
+
+let mapStateToProps
+
+proxyquire('../currency-display.container.js', {
+ 'react-redux': {
+ connect: ms => {
+ mapStateToProps = ms
+ return () => ({})
+ },
+ },
+})
+
+describe('CurrencyDisplay container', () => {
+ describe('mapStateToProps()', () => {
+ it('should return the correct props', () => {
+ const mockState = {
+ metamask: {
+ conversionRate: 280.45,
+ currentCurrency: 'usd',
+ },
+ }
+
+ const tests = [
+ {
+ props: {
+ value: '0x2386f26fc10000',
+ numberOfDecimals: 2,
+ currency: 'usd',
+ },
+ result: {
+ displayValue: '$2.80 USD',
+ },
+ },
+ {
+ props: {
+ value: '0x2386f26fc10000',
+ },
+ result: {
+ displayValue: '$2.80 USD',
+ },
+ },
+ {
+ props: {
+ value: '0x1193461d01595930',
+ currency: 'ETH',
+ numberOfDecimals: 3,
+ },
+ result: {
+ displayValue: '1.266 ETH',
+ },
+ },
+ ]
+
+ tests.forEach(({ props, result }) => {
+ assert.deepEqual(mapStateToProps(mockState, props), result)
+ })
+ })
+ })
+})
diff --git a/ui/app/components/token-currency-display/index.js b/ui/app/components/token-currency-display/index.js
new file mode 100644
index 000000000..6065cae1f
--- /dev/null
+++ b/ui/app/components/token-currency-display/index.js
@@ -0,0 +1 @@
+export { default } from './token-currency-display.component'
diff --git a/ui/app/components/token-currency-display/token-currency-display.component.js b/ui/app/components/token-currency-display/token-currency-display.component.js
new file mode 100644
index 000000000..e992442d4
--- /dev/null
+++ b/ui/app/components/token-currency-display/token-currency-display.component.js
@@ -0,0 +1,54 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import CurrencyDisplay from '../currency-display/currency-display.component'
+import { getTokenData } from '../../helpers/transactions.util'
+import { calcTokenAmount } from '../../token-util'
+
+export default class TokenCurrencyDisplayContainer extends PureComponent {
+ static propTypes = {
+ transactionData: PropTypes.string,
+ token: PropTypes.object,
+ }
+
+ state = {
+ displayValue: '',
+ }
+
+ componentDidMount () {
+ this.setDisplayValue()
+ }
+
+ componentDidUpdate (prevProps) {
+ const { transactionData } = this.props
+ const { transactionData: prevTransactionData } = prevProps
+
+ if (transactionData !== prevTransactionData) {
+ this.setDisplayValue()
+ }
+ }
+
+ setDisplayValue () {
+ const { transactionData: data, token } = this.props
+ const { decimals = '', symbol = '' } = token
+ const tokenData = getTokenData(data)
+
+ let displayValue
+
+ if (tokenData.params && tokenData.params.length === 2) {
+ const tokenValue = tokenData.params[1].value
+ const tokenAmount = calcTokenAmount(tokenValue, decimals)
+ displayValue = `${tokenAmount} ${symbol}`
+ }
+
+ this.setState({ displayValue })
+ }
+
+ render () {
+ return (
+ <CurrencyDisplay
+ {...this.props}
+ displayValue={this.state.displayValue}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/token-view-balance/tests/token-view-balance.component.test.js b/ui/app/components/token-view-balance/tests/token-view-balance.component.test.js
new file mode 100644
index 000000000..909b4dc7f
--- /dev/null
+++ b/ui/app/components/token-view-balance/tests/token-view-balance.component.test.js
@@ -0,0 +1,71 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import sinon from 'sinon'
+import TokenBalance from '../../token-balance'
+import CurrencyDisplay from '../../currency-display'
+import { SEND_ROUTE } from '../../../routes'
+import TokenViewBalance from '../token-view-balance.component'
+
+const propsMethodSpies = {
+ showDepositModal: sinon.spy(),
+}
+
+const historySpies = {
+ push: sinon.spy(),
+}
+
+const t = (str1, str2) => str2 ? str1 + str2 : str1
+
+describe('TokenViewBalance Component', () => {
+ afterEach(() => {
+ propsMethodSpies.showDepositModal.resetHistory()
+ historySpies.push.resetHistory()
+ })
+
+ it('should render ETH balance properly', () => {
+ const wrapper = shallow(<TokenViewBalance
+ showDepositModal={propsMethodSpies.showDepositModal}
+ history={historySpies}
+ network="3"
+ ethBalance={123}
+ fiatBalance={456}
+ currentCurrency="usd"
+ />, { context: { t } })
+
+ assert.equal(wrapper.find('.token-view-balance').length, 1)
+ assert.equal(wrapper.find('.token-view-balance__button').length, 2)
+ assert.equal(wrapper.find(CurrencyDisplay).length, 2)
+
+ const buttons = wrapper.find('.token-view-balance__buttons')
+ assert.equal(propsMethodSpies.showDepositModal.callCount, 0)
+ buttons.childAt(0).simulate('click')
+ assert.equal(propsMethodSpies.showDepositModal.callCount, 1)
+ assert.equal(historySpies.push.callCount, 0)
+ buttons.childAt(1).simulate('click')
+ assert.equal(historySpies.push.callCount, 1)
+ assert.equal(historySpies.push.getCall(0).args[0], SEND_ROUTE)
+ })
+
+ it('should render token balance properly', () => {
+ const token = {
+ address: '0x35865238f0bec9d5ce6abff0fdaebe7b853dfcc5',
+ decimals: '2',
+ symbol: 'ABC',
+ }
+
+ const wrapper = shallow(<TokenViewBalance
+ showDepositModal={propsMethodSpies.showDepositModal}
+ history={historySpies}
+ network="3"
+ ethBalance={123}
+ fiatBalance={456}
+ currentCurrency="usd"
+ selectedToken={token}
+ />, { context: { t } })
+
+ assert.equal(wrapper.find('.token-view-balance').length, 1)
+ assert.equal(wrapper.find('.token-view-balance__button').length, 1)
+ assert.equal(wrapper.find(TokenBalance).length, 1)
+ })
+})
diff --git a/ui/app/components/token-view-balance/token-view-balance.component.js b/ui/app/components/token-view-balance/token-view-balance.component.js
index f74cc4926..89e9246e2 100644
--- a/ui/app/components/token-view-balance/token-view-balance.component.js
+++ b/ui/app/components/token-view-balance/token-view-balance.component.js
@@ -3,8 +3,9 @@ import PropTypes from 'prop-types'
import Button from '../button'
import Identicon from '../identicon'
import TokenBalance from '../token-balance'
+import CurrencyDisplay from '../currency-display'
import { SEND_ROUTE } from '../../routes'
-import { formatCurrency } from '../../helpers/confirm-transaction/util'
+import { ETH } from '../../constants/common'
export default class TokenViewBalance extends PureComponent {
static contextTypes = {
@@ -16,14 +17,11 @@ export default class TokenViewBalance extends PureComponent {
selectedToken: PropTypes.object,
history: PropTypes.object,
network: PropTypes.string,
- ethBalance: PropTypes.string,
- fiatBalance: PropTypes.string,
- currentCurrency: PropTypes.string,
+ balance: PropTypes.string,
}
renderBalance () {
- const { selectedToken, ethBalance, fiatBalance, currentCurrency } = this.props
- const formattedFiatBalance = formatCurrency(fiatBalance, currentCurrency)
+ const { selectedToken, balance } = this.props
return selectedToken
? (
@@ -34,12 +32,16 @@ export default class TokenViewBalance extends PureComponent {
/>
) : (
<div className="token-view-balance__balance">
- <div className="token-view-balance__primary-balance">
- { `${ethBalance} ETH` }
- </div>
- <div className="token-view-balance__secondary-balance">
- { formattedFiatBalance }
- </div>
+ <CurrencyDisplay
+ className="token-view-balance__primary-balance"
+ value={balance}
+ currency={ETH}
+ numberOfDecimals={3}
+ />
+ <CurrencyDisplay
+ className="token-view-balance__secondary-balance"
+ value={balance}
+ />
</div>
)
}
diff --git a/ui/app/components/token-view-balance/token-view-balance.container.js b/ui/app/components/token-view-balance/token-view-balance.container.js
index 692e6e32f..f6cdc30e1 100644
--- a/ui/app/components/token-view-balance/token-view-balance.container.js
+++ b/ui/app/components/token-view-balance/token-view-balance.container.js
@@ -4,29 +4,17 @@ import { compose } from 'recompose'
import TokenViewBalance from './token-view-balance.component'
import { getSelectedToken, getSelectedAddress } from '../../selectors'
import { showModal } from '../../actions'
-import { getValueFromWeiHex } from '../../helpers/confirm-transaction/util'
const mapStateToProps = state => {
const selectedAddress = getSelectedAddress(state)
- const { metamask } = state
- const { network, accounts, currentCurrency, conversionRate } = metamask
+ const { metamask: { network, accounts } } = state
const account = accounts[selectedAddress]
- const { balance: value } = account
-
- const ethBalance = getValueFromWeiHex({
- value, toCurrency: 'ETH', conversionRate, numberOfDecimals: 3,
- })
-
- const fiatBalance = getValueFromWeiHex({
- value, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2,
- })
+ const { balance } = account
return {
selectedToken: getSelectedToken(state),
network,
- ethBalance,
- fiatBalance,
- currentCurrency,
+ balance,
}
}
diff --git a/ui/app/components/transaction-action/tests/transaction-action.component.test.js b/ui/app/components/transaction-action/tests/transaction-action.component.test.js
new file mode 100644
index 000000000..bba997c20
--- /dev/null
+++ b/ui/app/components/transaction-action/tests/transaction-action.component.test.js
@@ -0,0 +1,102 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import TransactionAction from '../transaction-action.component'
+
+describe('TransactionAction Component', () => {
+ const tOrDefault = key => key
+
+ describe('Outgoing transaction', () => {
+ it('should render -- when methodData is still fetching', () => {
+ const methodData = { data: {}, done: false, error: null }
+ const transaction = {
+ id: 1,
+ status: 'confirmed',
+ submittedTime: 1534045442919,
+ time: 1534045440641,
+ txParams: {
+ from: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6',
+ gas: '0x5208',
+ gasPrice: '0x3b9aca00',
+ nonce: '0x96',
+ to: '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706',
+ value: '0x2386f26fc10000',
+ },
+ }
+
+ const wrapper = shallow(<TransactionAction
+ methodData={methodData}
+ transaction={transaction}
+ className="transaction-action"
+ />, { context: { tOrDefault }})
+
+ assert.equal(wrapper.find('.transaction-action').length, 1)
+ assert.equal(wrapper.text(), '--')
+ })
+
+ it('should render Outgoing', () => {
+ const methodData = { data: {}, done: true, error: null }
+ const transaction = {
+ id: 1,
+ status: 'confirmed',
+ submittedTime: 1534045442919,
+ time: 1534045440641,
+ txParams: {
+ from: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6',
+ gas: '0x5208',
+ gasPrice: '0x3b9aca00',
+ nonce: '0x96',
+ to: '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706',
+ value: '0x2386f26fc10000',
+ },
+ }
+
+ const wrapper = shallow(<TransactionAction
+ methodData={methodData}
+ transaction={transaction}
+ className="transaction-action"
+ />, { context: { tOrDefault }})
+
+ assert.equal(wrapper.find('.transaction-action').length, 1)
+ assert.equal(wrapper.text(), 'outgoing')
+ })
+
+ it('should render Approved', () => {
+ const methodData = {
+ data: {
+ name: 'Approve',
+ params: [
+ { type: 'address' },
+ { type: 'uint256' },
+ ],
+ },
+ done: true,
+ error: null,
+ }
+ const transaction = {
+ id: 1,
+ status: 'confirmed',
+ submittedTime: 1534045442919,
+ time: 1534045440641,
+ txParams: {
+ from: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6',
+ gas: '0x5208',
+ gasPrice: '0x3b9aca00',
+ nonce: '0x96',
+ to: '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706',
+ value: '0x2386f26fc10000',
+ data: '0x095ea7b300000000000000000000000050a9d56c2b8ba9a5c7f2c08c3d26e0499f23a7060000000000000000000000000000000000000000000000000000000000000003',
+ },
+ }
+
+ const wrapper = shallow(<TransactionAction
+ methodData={methodData}
+ transaction={transaction}
+ className="transaction-action"
+ />, { context: { tOrDefault }})
+
+ assert.equal(wrapper.find('.transaction-action').length, 1)
+ assert.equal(wrapper.text(), 'approve')
+ })
+ })
+})
diff --git a/ui/app/components/transaction-list-item/transaction-list-item.component.js b/ui/app/components/transaction-list-item/transaction-list-item.component.js
index a47f29023..da1741731 100644
--- a/ui/app/components/transaction-list-item/transaction-list-item.component.js
+++ b/ui/app/components/transaction-list-item/transaction-list-item.component.js
@@ -3,21 +3,24 @@ import PropTypes from 'prop-types'
import Identicon from '../identicon'
import TransactionStatus from '../transaction-status'
import TransactionAction from '../transaction-action'
+import CurrencyDisplay from '../currency-display'
+import TokenCurrencyDisplay from '../token-currency-display'
import prefixForNetwork from '../../../lib/etherscan-prefix-for-network'
import { CONFIRM_TRANSACTION_ROUTE } from '../../routes'
import { UNAPPROVED_STATUS, TOKEN_METHOD_TRANSFER } from '../../constants/transactions'
+import { ETH } from '../../constants/common'
export default class TransactionListItem extends PureComponent {
static propTypes = {
history: PropTypes.object,
transaction: PropTypes.object,
- ethTransactionAmount: PropTypes.string,
- fiatDisplayValue: PropTypes.string,
+ value: PropTypes.string,
methodData: PropTypes.object,
showRetry: PropTypes.bool,
retryTransaction: PropTypes.func,
setSelectedToken: PropTypes.func,
nonceAndDate: PropTypes.string,
+ token: PropTypes.object,
}
handleClick = () => {
@@ -55,18 +58,50 @@ export default class TransactionListItem extends PureComponent {
.then(id => history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`))
}
+ renderPrimaryCurrency () {
+ const { token, transaction: { txParams: { data } = {} } = {}, value } = this.props
+
+ return token
+ ? (
+ <TokenCurrencyDisplay
+ className="transaction-list-item__amount transaction-list-item__amount--primary"
+ token={token}
+ transactionData={data}
+ prefix="-"
+ />
+ ) : (
+ <CurrencyDisplay
+ className="transaction-list-item__amount transaction-list-item__amount--primary"
+ value={value}
+ prefix="-"
+ />
+ )
+ }
+
+ renderSecondaryCurrency () {
+ const { token, value } = this.props
+
+ return token
+ ? null
+ : (
+ <CurrencyDisplay
+ className="transaction-list-item__amount transaction-list-item__amount--secondary"
+ prefix="-"
+ value={value}
+ numberOfDecimals={2}
+ currency={ETH}
+ />
+ )
+ }
+
render () {
const {
transaction,
- ethTransactionAmount,
- fiatDisplayValue,
methodData,
showRetry,
nonceAndDate,
} = this.props
const { txParams = {} } = transaction
- const fiatDisplayText = `-${fiatDisplayValue}`
- const ethDisplayText = ethTransactionAmount && `-${ethTransactionAmount} ETH`
return (
<div
@@ -94,18 +129,8 @@ export default class TransactionListItem extends PureComponent {
className="transaction-list-item__status"
status={transaction.status}
/>
- <div
- className="transaction-list-item__amount transaction-list-item__amount--primary"
- title={fiatDisplayText}
- >
- { fiatDisplayText }
- </div>
- <div
- className="transaction-list-item__amount transaction-list-item__amount--secondary"
- title={ethDisplayText}
- >
- { ethDisplayText }
- </div>
+ { this.renderPrimaryCurrency() }
+ { this.renderSecondaryCurrency() }
</div>
{
showRetry && !methodData.isFetching && (
diff --git a/ui/app/components/transaction-list-item/transaction-list-item.container.js b/ui/app/components/transaction-list-item/transaction-list-item.container.js
index 209ddb9f6..47644241a 100644
--- a/ui/app/components/transaction-list-item/transaction-list-item.container.js
+++ b/ui/app/components/transaction-list-item/transaction-list-item.container.js
@@ -4,42 +4,16 @@ import { compose } from 'recompose'
import withMethodData from '../../higher-order-components/with-method-data'
import TransactionListItem from './transaction-list-item.component'
import { setSelectedToken, retryTransaction } from '../../actions'
-import { getEthFromWeiHex, getValueFromWeiHex, hexToDecimal } from '../../helpers/conversions.util'
-import { getTokenData } from '../../helpers/transactions.util'
-import { formatCurrency } from '../../helpers/confirm-transaction/util'
-import { calcTokenAmount } from '../../token-util'
+import { hexToDecimal } from '../../helpers/conversions.util'
import { formatDate } from '../../util'
const mapStateToProps = (state, ownProps) => {
- const { metamask } = state
- const { currentCurrency, conversionRate } = metamask
- const { transaction: { txParams: { value, data, nonce } = {}, time } = {}, token } = ownProps
-
- let ethTransactionAmount, fiatDisplayValue
-
- if (token) {
- const { decimals = '', symbol = '' } = token
- const tokenData = getTokenData(data)
-
- if (tokenData.params && tokenData.params.length === 2) {
- const tokenValue = tokenData.params[1].value
- const tokenAmount = calcTokenAmount(tokenValue, decimals)
- fiatDisplayValue = `${tokenAmount} ${symbol}`
- }
- } else {
- ethTransactionAmount = getEthFromWeiHex({ value, conversionRate })
- const fiatTransactionAmount = getValueFromWeiHex({
- value, conversionRate, toCurrency: currentCurrency, numberOfDecimals: 2,
- })
- const fiatFormattedAmount = formatCurrency(fiatTransactionAmount, currentCurrency)
- fiatDisplayValue = `${fiatFormattedAmount} ${currentCurrency.toUpperCase()}`
- }
+ const { transaction: { txParams: { value, nonce } = {}, time } = {} } = ownProps
const nonceAndDate = nonce ? `#${hexToDecimal(nonce)} - ${formatDate(time)}` : formatDate(time)
return {
- ethTransactionAmount,
- fiatDisplayValue,
+ value,
nonceAndDate,
}
}
diff --git a/ui/app/constants/common.js b/ui/app/constants/common.js
new file mode 100644
index 000000000..28731ce33
--- /dev/null
+++ b/ui/app/constants/common.js
@@ -0,0 +1 @@
+export const ETH = 'ETH'