Add TransactionBreakdown component

This commit is contained in:
Alexander Tseung 2018-08-31 12:36:07 -07:00
parent 084158f1a2
commit fd51ab1229
9 changed files with 240 additions and 0 deletions

View File

@ -0,0 +1 @@
export { default } from './transaction-breakdown.component'

View File

@ -0,0 +1,23 @@
@import './transaction-breakdown-row/index';
.transaction-breakdown {
&__card {
background: $white;
height: 100%;
}
&__row-title {
text-transform: capitalize;
}
&__value {
text-align: end;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&--eth-total {
font-weight: 500;
}
}
}

View File

@ -0,0 +1,37 @@
import React from 'react'
import assert from 'assert'
import { shallow } from 'enzyme'
import TransactionBreakdown from '../transaction-breakdown.component'
import TransactionBreakdownRow from '../transaction-breakdown-row'
import Card from '../../card'
describe('TransactionBreakdown Component', () => {
it('should render properly', () => {
const transaction = {
history: [],
id: 1,
status: 'confirmed',
txParams: {
from: '0x1',
gas: '0x5208',
gasPrice: '0x3b9aca00',
nonce: '0xa4',
to: '0x2',
value: '0x2386f26fc10000',
},
}
const wrapper = shallow(
<TransactionBreakdown
transaction={transaction}
className="test-class"
/>,
{ context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
)
assert.ok(wrapper.hasClass('transaction-breakdown'))
assert.ok(wrapper.hasClass('test-class'))
assert.equal(wrapper.find(Card).length, 1)
assert.equal(wrapper.find(Card).find(TransactionBreakdownRow).length, 4)
})
})

View File

@ -0,0 +1 @@
export { default } from './transaction-breakdown-row.component'

View File

@ -0,0 +1,19 @@
.transaction-breakdown-row {
font-size: .75rem;
color: $scorpion;
display: flex;
justify-content: space-between;
padding: 8px 0;
&:not(:last-child) {
border-bottom: 1px solid #d8d8d8;
}
&__title {
padding-right: 8px;
}
&__value {
min-width: 0;
}
}

View File

@ -0,0 +1,39 @@
import React from 'react'
import assert from 'assert'
import { shallow } from 'enzyme'
import TransactionBreakdownRow from '../transaction-breakdown-row.component'
import Button from '../../../button'
describe('TransactionBreakdownRow Component', () => {
it('should render text properly', () => {
const wrapper = shallow(
<TransactionBreakdownRow
title="test"
className="test-class"
>
Test
</TransactionBreakdownRow>,
{ context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
)
assert.ok(wrapper.hasClass('transaction-breakdown-row'))
assert.equal(wrapper.find('.transaction-breakdown-row__title').text(), 'test')
assert.equal(wrapper.find('.transaction-breakdown-row__value').text(), 'Test')
})
it('should render components properly', () => {
const wrapper = shallow(
<TransactionBreakdownRow
title="test"
className="test-class"
>
<Button onClick={() => {}} >Button</Button>
</TransactionBreakdownRow>,
{ context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }
)
assert.ok(wrapper.hasClass('transaction-breakdown-row'))
assert.equal(wrapper.find('.transaction-breakdown-row__title').text(), 'test')
assert.ok(wrapper.find('.transaction-breakdown-row__value').find(Button))
})
})

View File

@ -0,0 +1,26 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
export default class TransactionBreakdownRow extends PureComponent {
static propTypes = {
title: PropTypes.string,
children: PropTypes.node,
className: PropTypes.string,
}
render () {
const { title, children, className } = this.props
return (
<div className={classnames('transaction-breakdown-row', className)}>
<div className="transaction-breakdown-row__title">
{ title }
</div>
<div className="transaction-breakdown-row__value">
{ children }
</div>
</div>
)
}
}

View File

@ -0,0 +1,82 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import TransactionBreakdownRow from './transaction-breakdown-row'
import Card from '../card'
import CurrencyDisplay from '../currency-display'
import HexToDecimal from '../hex-to-decimal'
import { ETH, GWEI } from '../../constants/common'
import { getHexGasTotal } from '../../helpers/confirm-transaction/util'
import { addHex } from '../../helpers/transactions.util'
export default class TransactionBreakdown extends PureComponent {
static contextTypes = {
t: PropTypes.func,
}
static propTypes = {
transaction: PropTypes.object,
className: PropTypes.string,
}
static defaultProps = {
transaction: {},
}
render () {
const { t } = this.context
const { transaction, className } = this.props
const { txParams: { gas, gasPrice, value } = {} } = transaction
const hexGasTotal = getHexGasTotal({ gasLimit: gas, gasPrice })
const totalInHex = addHex(hexGasTotal, value)
return (
<div className={classnames('transaction-breakdown', className)}>
<Card
title={t('transaction')}
className="transaction-breakdown__card"
>
<TransactionBreakdownRow title={t('amount')}>
<CurrencyDisplay
className="transaction-breakdown__value"
currency={ETH}
value={value}
/>
</TransactionBreakdownRow>
<TransactionBreakdownRow
title={`${t('gasLimit')} (${t('units')})`}
className="transaction-breakdown__row-title"
>
<HexToDecimal
className="transaction-breakdown__value"
value={gas}
/>
</TransactionBreakdownRow>
<TransactionBreakdownRow title={t('gasPrice')}>
<CurrencyDisplay
className="transaction-breakdown__value"
currency={ETH}
denomination={GWEI}
value={gasPrice}
hideLabel
/>
</TransactionBreakdownRow>
<TransactionBreakdownRow title={t('total')}>
<div>
<CurrencyDisplay
className="transaction-breakdown__value transaction-breakdown__value--eth-total"
currency={ETH}
value={totalInHex}
numberOfDecimals={6}
/>
<CurrencyDisplay
className="transaction-breakdown__value"
value={totalInHex}
/>
</div>
</TransactionBreakdownRow>
</Card>
</div>
)
}
}

View File

@ -16,6 +16,8 @@ import {
UNKNOWN_FUNCTION_KEY, UNKNOWN_FUNCTION_KEY,
} from '../constants/transactions' } from '../constants/transactions'
import { addCurrencies } from '../conversion-util'
abiDecoder.addABI(abi) abiDecoder.addABI(abi)
export function getTokenData (data = {}) { export function getTokenData (data = {}) {
@ -103,3 +105,13 @@ export async function isSmartContractAddress (address) {
const code = await global.eth.getCode(address) const code = await global.eth.getCode(address)
return code && code !== '0x' return code && code !== '0x'
} }
export function addHex (...args) {
const total = args.reduce((acc, base) => {
return addCurrencies(acc, base, {
toNumericBase: 'hex',
})
})
return ethUtil.addHexPrefix(total)
}