Skip to content

Commit

Permalink
Feature/transaction history multi asset (#461)
Browse files Browse the repository at this point in the history
* Create Transaction component for rendering txid link

* Updated transaction history to include all assets in transactions

* Fixed TransactionHistoryType definition

* Fixes all flow errors (#462)

* Fixes all flow errors

* Fix type

* Use BigNumber instead numeral

* Fix flow

* fix flow issues
  • Loading branch information
mhuggins authored and dvdschwrtz committed Jan 4, 2018
1 parent 0724d26 commit 6d37c38
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 80 deletions.
18 changes: 9 additions & 9 deletions __tests__/components/TransactionHistory.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ const transactions = {
wallet: {
transactions: [
{
type: 'NEO',
amount: '50',
NEO: 50,
GAS: 0.00000000,
txid: '76938979'
},
{
type: 'GAS',
amount: '0.40000000',
NEO: 0,
GAS: 0.40000000,
txid: '76938980'
}
]
Expand Down Expand Up @@ -82,7 +82,7 @@ describe('TransactionHistory', () => {
test('correctly renders no transaction history', (done) => {
const { wrapper } = setup(initialState, false)

const columnHeader = wrapper.find('.columnHeader')
const columnHeader = wrapper.find('#columnHeader')
expect(columnHeader.text()).toEqual('Transaction History ')

const transactionList = wrapper.find('#transactionList')
Expand All @@ -96,10 +96,10 @@ describe('TransactionHistory', () => {

const transactionList = wrapper.find('#transactionList')
expect(transactionList.children().length).toEqual(2)
expect(transactionList.childAt(0).find('.txid').text()).toEqual(transactions.wallet.transactions[0].txid)
expect(transactionList.childAt(1).find('.txid').text()).toEqual(transactions.wallet.transactions[1].txid)
expect(transactionList.childAt(0).find('.amount').text()).toEqual(`${transactions.wallet.transactions[0].amount} ${transactions.wallet.transactions[0].type}`)
expect(transactionList.childAt(1).find('.amount').text()).toEqual(`${transactions.wallet.transactions[1].amount} ${transactions.wallet.transactions[1].type}`)
expect(transactionList.childAt(0).find('.txid').first().text()).toEqual(transactions.wallet.transactions[0].txid)
expect(transactionList.childAt(1).find('.txid').first().text()).toEqual(transactions.wallet.transactions[1].txid)
expect(transactionList.childAt(0).find('.amountNEO').text()).toEqual('50 NEO')
expect(transactionList.childAt(1).find('.amountGAS').text()).toEqual('0.40000000 GAS')
done()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ exports[`TransactionHistory renders without crashing 1`] = `
<TransactionHistory
address="AWy7RNBVr9vDadRMK9p7i7Z1tL7GrLAxoh"
isLoadingTransactions={false}
net="TestNet"
store={
Object {
"clearActions": [Function],
Expand Down
30 changes: 30 additions & 0 deletions app/components/Blockchain/Transaction/Transaction.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// @flow
import React from 'react'
import classNames from 'classnames'

import { openExplorerTx } from '../../../core/explorer'
import styles from './Transaction.scss'

type Props = {
className?: string,
txid: string,
net: NetworkType,
explorer: ExplorerType
}

export default class Transaction extends React.Component<Props> {
render = () => {
const { txid, className } = this.props

return (
<span className={classNames(styles.transaction, className)} onClick={this.handleClick}>
{txid.substring(0, 32)}
</span>
)
}

handleClick = () => {
const { net, explorer, txid } = this.props
openExplorerTx(net, explorer, txid)
}
}
6 changes: 6 additions & 0 deletions app/components/Blockchain/Transaction/Transaction.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@import '../../../styles/variables';

.transaction {
color: $link-color;
cursor: pointer;
}
12 changes: 12 additions & 0 deletions app/components/Blockchain/Transaction/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @flow
import { connect } from 'react-redux'

import Transaction from './Transaction'
import { getBlockExplorer, getNetwork } from '../../../modules/metadata'

const mapStateToProps = (state: Object) => ({
net: getNetwork(state),
explorer: getBlockExplorer(state)
})

export default connect(mapStateToProps, () => ({}))(Transaction)
18 changes: 7 additions & 11 deletions app/containers/TransactionHistory/TransactionHistory.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// @flow
import React, { Component } from 'react'
import classNames from 'classnames'

import Loader from '../../components/Loader'

Expand All @@ -11,8 +10,7 @@ import styles from './TransactionHistory.scss'
type Props = {
address: string,
net: NetworkType,
transactions: Object,
explorer: ExplorerType,
transactions: Array<Object>,
syncTransactionHistory: Function,
isLoadingTransactions: boolean
}
Expand All @@ -24,17 +22,15 @@ export default class TransactionHistory extends Component<Props> {
}

render () {
const { transactions, net, explorer, isLoadingTransactions } = this.props
const { transactions, isLoadingTransactions } = this.props

return (
<div id='transactionInfo' className={styles.transactionInfo}>
<div className={classNames(styles.columnHeader, 'columnHeader')}>Transaction History {isLoadingTransactions && <Loader className={styles.updateLoader} />}</div>
<div className={classNames(styles.headerSpacer, 'headerSpacer')} />
<Transactions
transactions={transactions}
net={net}
explorer={explorer}
/>
<div id='columnHeader' className={styles.columnHeader}>
Transaction History {isLoadingTransactions && <Loader className={styles.updateLoader} />}
</div>
<div className={styles.headerSpacer} />
<Transactions className={styles.transactions} transactions={transactions} />
</div>
)
}
Expand Down
16 changes: 14 additions & 2 deletions app/containers/TransactionHistory/TransactionHistory.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
@import '../../styles/variables';

.transactionInfo {
display: flex;
flex-direction: column;
text-align: center;
position: relative;
min-height: 590px;
height: 100%;

.columnHeader,
.headerSpacer {
flex: 0 0 auto;
}

.transactions {
flex: 1 1 auto;
overflow: scroll;
}
}

.columnHeader {
Expand All @@ -22,4 +34,4 @@
right: 0;
left: auto;
top: -5px;
}
}
72 changes: 44 additions & 28 deletions app/containers/TransactionHistory/Transactions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,57 @@
import React from 'react'
import classNames from 'classnames'

import Transaction from '../../components/Blockchain/Transaction'
import { ASSETS } from '../../core/constants'
import { openExplorerTx } from '../../core/explorer'
import { formatGAS, formatNEO } from '../../core/formatters'
import { formatBalance } from '../../core/formatters'

import styles from './Transactions.scss'

type Props = {
net: NetworkType,
transactions: Object,
explorer: ExplorerType,
className?: string,
transactions: Array<Object>
}

const Transactions = ({ transactions, net, explorer }: Props) => {
if (transactions.length === 0) {
return <div className={styles.noTransactions}>No transactions</div>
export default class Transactions extends React.Component<Props> {
render () {
const { className, transactions } = this.props

if (transactions.length === 0) {
return <div className={classNames(styles.noTransactions, className)}>No transactions</div>
}

return (
<ul id='transactionList' className={classNames(styles.transactionList, className)}>
{transactions.map((tx) => (
<li key={tx.txid} className={styles.row}>
<Transaction className={classNames(styles.txid, 'txid')} txid={tx.txid} />
{this.renderAmounts(tx)}
</li>
))}
</ul>
)
}

return (
<ul id='transactionList' className={styles.transactionList}>
{
transactions.map((t) => {
let formatAmount = t.type === ASSETS.NEO ? formatNEO(t.amount) : formatGAS(t.amount)
return (
<li key={t.txid} className={styles.row}>
<div
className={classNames(styles.txid, 'txid')}
onClick={() => openExplorerTx(net, explorer, t.txid)}>
{t.txid.substring(0, 32)}
</div>
<div className={classNames(styles.amount, 'amount')}>{formatAmount} {t.type}</div>
</li>
)
})}
</ul>
)
}
renderAmounts (tx: Object) {
const forceRenderNEO = tx[ASSETS.NEO] !== 0 || tx[ASSETS.GAS] === 0

return (
<div className={styles.amounts}>
{this.renderAmount(tx, ASSETS.NEO, forceRenderNEO)}
{this.renderAmount(tx, ASSETS.GAS)}
</div>
)
}

renderAmount (tx: Object, symbol: SymbolType, forceRender: boolean = false) {
const amount = tx[symbol]

export default Transactions
if (forceRender || amount !== 0) {
return (
<div className={classNames(styles.amount, `amount${symbol}`)}>
{formatBalance(symbol, amount)} {symbol}
</div>
)
}
}
}
34 changes: 19 additions & 15 deletions app/containers/TransactionHistory/Transactions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,38 @@
.transactionList {
margin: 0;
padding: 0;
overflow-y: auto;
height: 590px;
margin: 20px;
}

.row {
display: flex;
align-items: stretch;
list-style-type: none;
font-weight: 200;
border-bottom: 1px solid $spacer-color;
padding-bottom: 10px;
margin-bottom: 10px;

.txid {
flex: 0 0 auto;
}

.amounts {
flex: 1 1 auto;
white-space: nowrap;
}
}

.txid {
position: relative;
top: 2px;
display: inline-block;
width: 44%;
margin-left: 4%;
text-align: left;
font-family: 'courier new';
font-size: .7em;
cursor: pointer;
}

.amount {
display: inline-block;
width: 44%;
margin-right: 4%;
text-align: right;
color: $thin-text-color;
}
.amounts {
.amount {
display: block;
text-align: right;
color: $thin-text-color;
}
}
4 changes: 0 additions & 4 deletions app/containers/TransactionHistory/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@ import { bindActionCreators } from 'redux'

import { syncTransactionHistory, getIsLoadingTransactions } from '../../modules/transactions'
import { getAddress } from '../../modules/account'
import { getBlockExplorer, getNetwork } from '../../modules/metadata'
import { getTransactions } from '../../modules/wallet'

import TransactionHistory from './TransactionHistory'

const mapStateToProps = (state: Object) => ({
address: getAddress(state),
net: getNetwork(state),
transactions: getTransactions(state),
explorer: getBlockExplorer(state),
isLoadingTransactions: getIsLoadingTransactions(state)
})

Expand Down
7 changes: 3 additions & 4 deletions app/modules/transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ export const syncTransactionHistory = (net: NetworkType, address: string) => asy
dispatch(setIsLoadingTransaction(true))
const [err, transactions] = await asyncWrap(api.neonDB.getTransactionHistory(net, address))
if (!err && transactions) {
const txs = transactions.map(({ NEO, GAS, txid, block_index, neo_sent, neo_gas }: TransactionHistoryType) => ({
type: neo_sent ? ASSETS.NEO : ASSETS.GAS,
amount: neo_sent ? NEO : GAS,
const txs = transactions.map(({ NEO, GAS, txid, block_index }: TransactionHistoryType) => ({
txid,
block_index
[ASSETS.NEO]: NEO,
[ASSETS.GAS]: GAS
}))
dispatch(setIsLoadingTransaction(false))
dispatch(setTransactionHistory(txs))
Expand Down
4 changes: 2 additions & 2 deletions flow-typed/declarations.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ declare type NotificationType = {
declare type TransactionHistoryType = {
NEO: number,
GAS: number,
txid: number,
txid: string,
block_index: number,
neo_sent: boolean,
neo_gas: boolean
gas_sent: boolean
}

declare type ModalType = $Values<typeof MODAL_TYPES>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"isomorphic-fetch": "2.2.1",
"js-scrypt": "0.2.0",
"lodash": "4.17.4",
"neon-js": "git+https://github.com/cityofzion/neon-js.git#2.2.2",
"neon-js": "git+https://github.com/cityofzion/neon-js.git#2.3.0",
"node-hid": "0.5.7",
"numeral": "2.0.6",
"qrcode": "0.9.0",
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6119,9 +6119,9 @@ negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"

"neon-js@git+https://github.com/cityofzion/neon-js.git#2.2.2":
version "2.2.2"
resolved "git+https://github.com/cityofzion/neon-js.git#c39498f4b44d73dcb61e9f90c2d7cd4e22a50c40"
"neon-js@git+https://github.com/cityofzion/neon-js.git#2.3.0":
version "2.3.0"
resolved "git+https://github.com/cityofzion/neon-js.git#036b5b83b9891109e6e5ae892289609e1208392e"
dependencies:
axios "^0.16.2"
base-x "^3.0.2"
Expand Down

0 comments on commit 6d37c38

Please sign in to comment.