// Copyright 2015-2017 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity. If not, see . import moment from 'moment'; import dateDifference from 'date-difference'; import { FormattedMessage } from 'react-intl'; import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router'; import { txLink } from '~/3rdparty/etherscan/links'; import IdentityIcon from '~/ui/IdentityIcon'; import IdentityName from '~/ui/IdentityName'; import MethodDecoding from '~/ui/MethodDecoding'; import MethodDecodingStore from '~/ui/MethodDecoding/methodDecodingStore'; import styles from '../txList.css'; class TxRow extends Component { static contextTypes = { api: PropTypes.object.isRequired }; static propTypes = { accountAddresses: PropTypes.array.isRequired, address: PropTypes.string.isRequired, blockNumber: PropTypes.object, contractAddresses: PropTypes.array.isRequired, netVersion: PropTypes.string.isRequired, tx: PropTypes.object.isRequired, block: PropTypes.object, className: PropTypes.string, cancelTransaction: PropTypes.func, editTransaction: PropTypes.func, historic: PropTypes.bool }; static defaultProps = { historic: true }; state = { isCancelOpen: false, isEditOpen: false, canceled: false, editing: false, isContract: false, isDeploy: false }; methodDecodingStore = MethodDecodingStore.get(this.context.api); componentWillMount () { const { address, tx } = this.props; this .methodDecodingStore .lookup(address, tx) .then((lookup) => { const newState = { isContract: lookup.contract, isDeploy: lookup.deploy }; this.setState(newState); }); } render () { const { address, className, historic, netVersion, tx } = this.props; return ( { this.renderBlockNumber(tx.blockNumber) } { this.renderAddress(tx.from, false) } { this.renderEtherValue(tx.value) }
{ `${tx.hash.substr(2, 6)}...${tx.hash.slice(-6)}` }
{ this.renderAddress(tx.to || tx.creates, !!tx.creates) } ); } renderAddress (address, isDeploy = false) { const isKnownContract = this.getIsKnownContract(address); let esLink = null; if (address && (!isDeploy || isKnownContract)) { esLink = ( ); } return (
{ esLink || 'DEPLOY' }
); } renderEtherValue (_value) { const { api } = this.context; const { isContract, isDeploy } = this.state; // Always show the value if ETH transfer, ie. not // a contract or a deployment const fullValue = !(isContract || isDeploy); const value = api.util.fromWei(_value); if (value.eq(0) && !fullValue) { return
{ ' ' }
; } return (
{ value.toFormat(5) }ETH
); } renderBlockNumber (_blockNumber) { const { block } = this.props; const blockNumber = _blockNumber.toNumber(); return (
{ blockNumber && block ? moment(block.timestamp).fromNow() : null }
{ blockNumber ? _blockNumber.toFormat() : this.renderCancelToggle() }
); } renderCancelToggle () { const { canceled, editing, isCancelOpen, isEditOpen } = this.state; if (canceled) { return (
); } if (editing) { return (
); } if (!isCancelOpen && !isEditOpen) { const pendingStatus = this.getCondition(); const isPending = pendingStatus === 'pending'; return (
{ isPending ? (
) : (
{ pendingStatus }
) } {' | '} { isPending ? (
) : null }
); } let which; if (isCancelOpen) { which = ( ); } else { which = ( ); } return (
); } getIsKnownContract (address) { const { contractAddresses } = this.props; return contractAddresses .map((a) => a.toLowerCase()) .includes(address.toLowerCase()); } addressLink (address) { const { accountAddresses } = this.props; const isAccount = accountAddresses.includes(address); const isContract = this.getIsKnownContract(address); if (isContract) { return `/contracts/${address}`; } if (isAccount) { return `/accounts/${address}`; } return `/addresses/${address}`; } getCondition = () => { const { blockNumber, tx } = this.props; let { time, block = 0 } = tx.condition || {}; if (time) { if ((time.getTime() - Date.now()) >= 0) { return ( ); } } if (blockNumber) { block = blockNumber.minus(block); if (block.toNumber() < 0) { return ( ); } } return 'pending'; } cancelTx = () => { const { cancelTransaction, tx } = this.props; cancelTransaction(this, tx); } editTx = () => { const { editTransaction, tx } = this.props; editTransaction(this, tx); } setCancel = () => { this.setState({ isCancelOpen: true }); } setEdit = () => { this.setState({ isEditOpen: true }); } revertEditCancel = () => { this.setState({ isCancelOpen: false, isEditOpen: false }); } } function mapStateToProps (initState) { const { accounts, contracts } = initState.personal; const accountAddresses = Object.keys(accounts); const contractAddresses = Object.keys(contracts); return (state) => { const { netVersion } = state.nodeStatus; return { accountAddresses, contractAddresses, netVersion }; }; } export default connect( mapStateToProps, null )(TxRow);