import { ICeloTransaction , NetworkDefinition } from "@anthem/utils" ; import { Card , Code , Elevation , Position , Tooltip } from "@blueprintjs/core" ; import { CeloLogo } from "assets/icons" ; import { LinkIcon } from "assets/images" ; import { FiatCurrency } from "constants/fiat" ; import { ILocale } from "i18n/catalog" ; import Modules from "modules/root" ; import React from "react" ; import { Link } from "react-router-dom" ; import { capitalizeString , copyTextToClipboard , formatAddressString , } from "tools/client-utils" ; import { denomToUnit } from "tools/currency-utils" ; import { formatDate , formatTime } from "tools/date-utils" ; import { TranslateMethodProps } from "tools/i18n-utils" ; import { multiply } from "tools/math-utils" ; import AddressIconComponent from "ui/AddressIconComponent" ; import { Row } from "ui/SharedComponents" ; import { ClickableEventRow , EventContextBox , EventIcon , EventIconBox , EventRow , EventRowBottom , EventRowItem , EventText , TransactionCardStyles , TransactionLinkText , } from "./TransactionComponents" ; /** ===========================================================================
 * Types & Config
 * ============================================================================
 */ interface IProps extends TranslateMethodProps { isDetailView ? : boolean ; transaction : ICeloTransaction ; address : string ; locale : ILocale ; isDesktop : boolean ; fiatCurrency : FiatCurrency ; network : NetworkDefinition ; setAddress : typeof Modules . actions . ledger . setAddress ; onCopySuccess : ( address : string ) => void ; } /** ===========================================================================
 * React Component
 * ============================================================================
 */ class CeloTransactionListItem extends React . PureComponent < IProps , { } > { render ( ) { const { transaction } = this . props ; const tagData = maybeGetValueFromTags ( transaction ) ; return ( < Card style = { TransactionCardStyles } elevation = { Elevation . TWO } > < EventRow data - cy = "transaction-list-item" > { this . renderTypeAndTimestamp ( transaction ) } { this . renderAddressBlocks ( transaction ) } { this . renderHash ( transaction ) } < /EventRow> < EventRowBottom > { this . renderBlockNumber ( transaction ) } { this . renderTransactionValues ( transaction ) } { this . renderBlockExplorerLink ( transaction ) } < /EventRowBottom> { tagData && ( < EventRowBottom > { this . renderTagValues ( tagData ) } < /EventRowBottom>)} < /Card>); } renderTypeAndTimestamp = ( transaction ) => { const { contract , type } = getCeloTransactionType ( transaction ) ; const time = Number ( transaction . timestamp ) * 1000 ; return ( < EventRowItem style = { { minWidth : 300 } } > < EventIconBox > < EventIcon src = { CeloLogo } /> < /EventIconBox> < EventContextBox > < Row > { ! ! contract && < Code style = { { marginRight : 6 } } > { contract } < /Code>} < EventText style = { { fontWeight : "bold" } } > { type } < /EventText> < /Row> < EventText data - cy = "transaction-timestamp" > { formatDate ( time ) } { formatTime ( time ) } < /EventText> < /EventContextBox> < /EventRowItem>); } ; renderBlockNumber = ( transaction ) => { const { blockNumber } = transaction ; return ( < EventRowItem style = { { minWidth : 300 } } > < EventIconBox /> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > Block Number < /EventText> < EventText data - cy = "transaction-block-number" > { blockNumber } < /EventText> < /EventContextBox> < /EventRowItem>); } ; renderHash = ( transaction ) => { const { hash } = transaction ; const TxHashLink = this . props . isDetailView ? ( < ClickableEventRow onClick = { ( ) => copyTextToClipboard ( hash ) } > < EventIconBox > < LinkIcon /> < /EventIconBox> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > Hash < /EventText> < TransactionLinkText style = { { fontWeight : 100 , fontSize : 13 } } > { hash . slice ( 0 , 15 ) } ... < /TransactionLinkText> < /EventContextBox> < /ClickableEventRow>) : (<Link data-cy="transaction-hash-link" to={`txs/$ { hash } `}>
        <ClickableEventRow onClick={() => null}>
          <EventIconBox>
            <LinkIcon />
          </EventIconBox>
          <EventContextBox>
            <EventText style={{ fontWeight: "bold" }}>Hash</EventText>
            <EventText style={{ fontWeight: 100, fontSize: 13 }} data-cy="transaction-block-number">
              {hash.slice(0, 15)}...
            </EventText>
          </EventContextBox>
        </ClickableEventRow>
      </Link>);
        return this.props.isDetailView && this.props.isDesktop ? (<Tooltip position={Position.TOP} content="Click to copy hash">
        {TxHashLink}
      </Tooltip>) : (TxHashLink);
    };
    renderBlockExplorerLink = (transaction) => {
        const { hash } = transaction;
        const link = ` https : return ( < a target = "_blank" href = { link } rel = "noopener noreferrer" > < ClickableEventRow onClick = { ( ) => null } > < EventIconBox > < LinkIcon /> < /EventIconBox> < EventContextBox > < EventText style = { { fontWeight : 200 } } > View on Celo Explorer < /EventText> < /EventContextBox> < /ClickableEventRow> < /a>); } ; renderAddressBlocks = ( transaction ) => { const { from , to } = transaction ; return ( < > { ! ! from ? this . renderAddressBox ( from , "From" ) : null } { ! ! to ? this . renderAddressBox ( to , "To" ) : null } < />); } ; renderAddressBox = ( address , titleText ) => { return ( < ClickableEventRow style = { { minWidth : 215 } } onClick = { this . handleLinkToAddress ( address ) } > < EventIconBox > < AddressIconComponent address = { address } networkName = { this . props . network . name } validatorOperatorAddressMap = { new Map ( ) } / > < /EventIconBox> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > { titleText } < /EventText> < EventText style = { { fontWeight : 100 , fontSize : 13 } } > { formatAddressString ( address , true ) } < /EventText> < /EventContextBox> < /ClickableEventRow>); } ; renderTransactionValues = ( transaction ) => { const { network } = this . props ; const size = network . denominationSize ; const { value , gasUsed , gasPrice } = transaction . details ; const fee = multiply ( gasUsed , gasPrice ) ; return ( < > < EventRowItem style = { { minWidth : 215 } } > < EventIconBox /> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > Value < /EventText> < EventText data - cy = "transaction-value" > { denomToUnit ( value , size ) } { network . denom } < /EventText> < /EventContextBox> < /EventRowItem> < EventRowItem style = { { minWidth : 215 } } > < EventIconBox /> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > Fee < /EventText> < EventText data - cy = "transaction-fee" > { denomToUnit ( fee , size ) } { network . denom } < /EventText> < /EventContextBox> < /EventRowItem> < />); } ; renderTagValues = ( data ) => { const { network } = this . props ; const size = network . denominationSize ; const entries = Object . entries ( data ) ; const KEYS_TO_OMIT = new Set ( [ "units" ] ) ; return ( < > < EventRowItem style = { { minWidth : 300 } } > < EventIconBox /> < EventContextBox > < Row > < EventText style = { { fontWeight : "bold" } } > Contract Call < /EventText> < /Row> < /EventContextBox> < /EventRowItem> { entries . filter ( ( [ key ] ) => { return ! KEYS_TO_OMIT . has ( key . toLowerCase ( ) ) ; } ) . map ( ( [ key , value ] ) => { const addressKeys = new Set ( [ "validator" , "group" , "account" , "proposer" , "from" , "to" , "owner" , "spender" , ] ) ; const keyRepresentsAddress = addressKeys . has ( key ) ; if ( key === "value" ) { return ( < EventRowItem key = { key } style = { { minWidth : 215 } } > < EventIconBox /> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > { capitalizeString ( key ) } < /EventText> < EventText data - cy = "transaction-value" > { denomToUnit ( value , size ) } { network . denom } < /EventText> < /EventContextBox> < /EventRowItem>); } else if ( keyRepresentsAddress ) { return ( < ClickableEventRow key = { key } style = { { minWidth : 215 } } onClick = { ( ) => copyTextToClipboard ( value ) } > < EventIconBox > < AddressIconComponent address = { value } networkName = { this . props . network . name } validatorOperatorAddressMap = { new Map ( ) } / > < /EventIconBox> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > { capitalizeString ( key ) } < /EventText> < EventText style = { { fontWeight : 100 , fontSize : 13 } } > { formatAddressString ( value , true ) } < /EventText> < /EventContextBox> < /ClickableEventRow>); } else { return ( < ClickableEventRow key = { key } style = { { minWidth : 215 } } onClick = { ( ) => copyTextToClipboard ( value ) } > < EventIconBox /> < EventContextBox > < EventText style = { { fontWeight : "bold" } } > { capitalizeString ( key ) } < /EventText> < EventText style = { { fontWeight : 100 , fontSize : 13 } } > { value } < /EventText> < /EventContextBox> < /ClickableEventRow>); } } ) } < />); } ; handleLinkToAddress = ( address ) => ( ) => { this . props . setAddress ( address , { showToastForError : true } ) ; } ; } /** ===========================================================================
 * Utils
 * ============================================================================
 */ /**
 * Split a string by capital letters, e.g. "LockedGold" -> "Locked Gold".
 */ const splitByCapitalLetters = ( str ) => str . split ( /(?=[A-Z])/ ) . join ( " " ) ; /**
 * Derive transaction type from Celo transaction tags.
 */ const getCeloTransactionType = ( transaction ) => { const { tags } = transaction ; if ( tags . length ) { const { eventname , source } = tags [ 0 ] ; const contract = splitByCapitalLetters ( source ) ; const type = splitByCapitalLetters ( eventname ) ; return { contract , type } ; } else { return { contract : "" , type : "Celo Transaction" } ; } } ; /**
 * Try to extract the transaction value information from the transaction tags.
 */ const maybeGetValueFromTags = ( transaction ) : Nullable < { [ key ] : string ; } > => { const { tags } = transaction ; try { const { parameters } = tags [ 0 ] ; const data = JSON . parse ( parameters ) ; if ( "value" in data ) { return data ; } } catch ( err ) { } return null ; } ; /** ===========================================================================
 * Export
 * ============================================================================
 */ export default CeloTransactionListItem ;