TransactionDataTable.tsx
1 import React from 'react'; 2 3 import translate from 'translations'; 4 import { TransactionData, TransactionReceipt } from 'types/transactions'; 5 import { NetworkConfig } from 'types/network'; 6 import { Identicon, UnitDisplay, NewTabLink, Address, CodeBlock } from 'components/ui'; 7 import './TransactionDataTable.scss'; 8 9 interface TableRow { 10 label: React.ReactElement<string> | string; 11 data: React.ReactElement<string> | string | number | null; 12 } 13 14 const MaybeLink: React.SFC<{ 15 href: string | null | undefined | false; 16 children: any; // Too many damn React element types 17 }> = ({ href, children }) => { 18 if (href) { 19 return <NewTabLink href={href}>{children}</NewTabLink>; 20 } else { 21 return <React.Fragment>{children}</React.Fragment>; 22 } 23 }; 24 25 interface Props { 26 data: TransactionData; 27 receipt: TransactionReceipt | null; 28 network: NetworkConfig; 29 } 30 31 const TransactionDataTable: React.SFC<Props> = ({ data, receipt, network }) => { 32 const explorer: { [key: string]: string | false | null } = {}; 33 const hasInputData = data.input && data.input !== '0x'; 34 35 if (!network.isCustom) { 36 explorer.tx = network.blockExplorer && network.blockExplorer.txUrl(data.hash); 37 explorer.block = 38 network.blockExplorer && 39 !!data.blockNumber && 40 network.blockExplorer.blockUrl(data.blockNumber); 41 explorer.to = network.blockExplorer && network.blockExplorer.addressUrl(data.to); 42 explorer.from = network.blockExplorer && network.blockExplorer.addressUrl(data.from); 43 explorer.contract = 44 network.blockExplorer && 45 receipt && 46 receipt.contractAddress && 47 network.blockExplorer.addressUrl(receipt.contractAddress); 48 } 49 50 let statusMsg = ''; 51 let statusType = ''; 52 let statusSeeMore = false; 53 if (receipt) { 54 if (receipt.status === 1) { 55 statusMsg = 'SUCCESSFUL'; 56 statusType = 'success'; 57 } else if (receipt.status === 0) { 58 statusMsg = 'FAILED'; 59 statusType = 'danger'; 60 statusSeeMore = true; 61 } else { 62 // Pre-byzantium transactions don't use status, and cannot have their 63 // success determined over the JSON RPC api 64 statusMsg = 'UNKNOWN'; 65 statusType = 'warning'; 66 statusSeeMore = true; 67 } 68 } else { 69 statusMsg = 'PENDING'; 70 statusType = 'warning'; 71 } 72 73 const rows: TableRow[] = [ 74 { 75 label: translate('TX_STATUS'), 76 data: ( 77 <React.Fragment> 78 <strong className={`TxData-row-data-status is-${statusType}`}>{statusMsg}</strong> 79 {statusSeeMore && 80 explorer.tx && 81 !network.isCustom && ( 82 <NewTabLink className="TxData-row-data-more" href={explorer.tx}> 83 (See more on {network.blockExplorer.name}) 84 </NewTabLink> 85 )} 86 </React.Fragment> 87 ) 88 }, 89 { 90 label: translate('X_TXHASH'), 91 data: <MaybeLink href={explorer.tx}>{data.hash}</MaybeLink> 92 }, 93 { 94 label: translate('TX_BLOCK_NUMB'), 95 data: receipt && <MaybeLink href={explorer.block}>{receipt.blockNumber}</MaybeLink> 96 }, 97 { 98 label: translate('OFFLINE_STEP1_LABEL_1'), 99 data: ( 100 <MaybeLink href={explorer.from}> 101 <Identicon address={data.from} size="26px" /> 102 <Address address={data.from} /> 103 </MaybeLink> 104 ) 105 }, 106 { 107 label: translate('OFFLINE_STEP2_LABEL_1'), 108 data: ( 109 <MaybeLink href={explorer.to}> 110 <Identicon address={data.to} size="26px" /> 111 <Address address={data.to} /> 112 </MaybeLink> 113 ) 114 }, 115 { 116 label: translate('SEND_AMOUNT_SHORT'), 117 data: <UnitDisplay value={data.value} unit="ether" symbol={network.unit} /> 118 }, 119 { 120 label: translate('OFFLINE_STEP2_LABEL_3'), 121 data: <UnitDisplay value={data.gasPrice} unit="gwei" symbol="Gwei" /> 122 }, 123 { 124 label: translate('OFFLINE_STEP2_LABEL_4'), 125 data: <UnitDisplay value={data.gas} unit="wei" /> 126 }, 127 { 128 label: translate('TX_GAS_USED'), 129 data: receipt && <UnitDisplay value={receipt.gasUsed} unit="wei" /> 130 }, 131 { 132 label: translate('CONFIRM_TX_FEE'), 133 data: receipt && ( 134 <UnitDisplay 135 value={receipt.gasUsed.mul(data.gasPrice)} 136 unit="ether" 137 symbol={network.unit} 138 /> 139 ) 140 }, 141 { 142 label: translate('NEW_CONTRACT_ADDR'), 143 data: receipt && 144 receipt.contractAddress && ( 145 <MaybeLink href={explorer.contract}> 146 <Address address={receipt.contractAddress} /> 147 </MaybeLink> 148 ) 149 }, 150 { 151 label: translate('OFFLINE_STEP2_LABEL_5'), 152 data: data.nonce 153 }, 154 { 155 label: translate('TRANS_DATA'), 156 data: hasInputData ? <CodeBlock>{data.input}</CodeBlock> : null 157 } 158 ]; 159 160 const filteredRows = rows.filter(row => !!row.data); 161 return ( 162 <table className="TxData table table-striped"> 163 <tbody> 164 {filteredRows.map((row, idx) => ( 165 <tr className="TxData-row" key={idx}> 166 <td className="TxData-row-label">{row.label}</td> 167 <td className="TxData-row-data">{row.data}</td> 168 </tr> 169 ))} 170 </tbody> 171 </table> 172 ); 173 }; 174 175 export default TransactionDataTable;