diff --git a/ui/app/components/transaction-breakdown/index.js b/ui/app/components/transaction-breakdown/index.js new file mode 100644 index 000000000..c887f504f --- /dev/null +++ b/ui/app/components/transaction-breakdown/index.js @@ -0,0 +1 @@ +export { default } from './transaction-breakdown.component' diff --git a/ui/app/components/transaction-breakdown/index.scss b/ui/app/components/transaction-breakdown/index.scss new file mode 100644 index 000000000..1bb108943 --- /dev/null +++ b/ui/app/components/transaction-breakdown/index.scss @@ -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; + } + } +} diff --git a/ui/app/components/transaction-breakdown/tests/transaction-breakdown.component.test.js b/ui/app/components/transaction-breakdown/tests/transaction-breakdown.component.test.js new file mode 100644 index 000000000..d18cd420c --- /dev/null +++ b/ui/app/components/transaction-breakdown/tests/transaction-breakdown.component.test.js @@ -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( + , + { 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) + }) +}) diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown-row/index.js b/ui/app/components/transaction-breakdown/transaction-breakdown-row/index.js new file mode 100644 index 000000000..557bf75fb --- /dev/null +++ b/ui/app/components/transaction-breakdown/transaction-breakdown-row/index.js @@ -0,0 +1 @@ +export { default } from './transaction-breakdown-row.component' diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown-row/index.scss b/ui/app/components/transaction-breakdown/transaction-breakdown-row/index.scss new file mode 100644 index 000000000..8c73be1a6 --- /dev/null +++ b/ui/app/components/transaction-breakdown/transaction-breakdown-row/index.scss @@ -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; + } +} diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown-row/tests/transaction-breakdown-row.component.test.js b/ui/app/components/transaction-breakdown/transaction-breakdown-row/tests/transaction-breakdown-row.component.test.js new file mode 100644 index 000000000..c19399dbb --- /dev/null +++ b/ui/app/components/transaction-breakdown/transaction-breakdown-row/tests/transaction-breakdown-row.component.test.js @@ -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( + + Test + , + { 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( + + + , + { 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)) + }) +}) diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js b/ui/app/components/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js new file mode 100644 index 000000000..c11ff8efa --- /dev/null +++ b/ui/app/components/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js @@ -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 ( +
+
+ { title } +
+
+ { children } +
+
+ ) + } +} diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown.component.js b/ui/app/components/transaction-breakdown/transaction-breakdown.component.js new file mode 100644 index 000000000..a168b53dc --- /dev/null +++ b/ui/app/components/transaction-breakdown/transaction-breakdown.component.js @@ -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 ( +
+ + + + + + + + + + + +
+ + +
+
+
+
+ ) + } +} diff --git a/ui/app/helpers/transactions.util.js b/ui/app/helpers/transactions.util.js index 54df54aa8..b88b00ac6 100644 --- a/ui/app/helpers/transactions.util.js +++ b/ui/app/helpers/transactions.util.js @@ -16,6 +16,8 @@ import { UNKNOWN_FUNCTION_KEY, } from '../constants/transactions' +import { addCurrencies } from '../conversion-util' + abiDecoder.addABI(abi) export function getTokenData (data = {}) { @@ -103,3 +105,13 @@ export async function isSmartContractAddress (address) { const code = await global.eth.getCode(address) return code && code !== '0x' } + +export function addHex (...args) { + const total = args.reduce((acc, base) => { + return addCurrencies(acc, base, { + toNumericBase: 'hex', + }) + }) + + return ethUtil.addHexPrefix(total) +}