1- import React , { useEffect , useState , useMemo } from 'react'
1+ import React , { useEffect , useState , useMemo , useCallback } from 'react'
22import { useTranslation } from 'react-i18next'
3- import { Stack , DetailsList , Text , CheckboxVisibility , IColumn } from 'office-ui-fabric-react'
3+ import { Stack , DetailsList , Text , CheckboxVisibility , IColumn , Icon } from 'office-ui-fabric-react'
44import { currentWallet as currentWalletCache } from 'services/localCache'
5- import { getTransaction , showErrorMessage } from 'services/remote'
5+ import { getTransaction , showErrorMessage , getAllNetworks , getCurrentNetworkID , openExternal } from 'services/remote'
6+ import { ckbCore } from 'services/chain'
67
78import { transactionState } from 'states/initStates/chain'
89
910import { localNumberFormatter , uniformTimeFormatter , shannonToCKBFormatter } from 'utils/formatters'
1011import { ErrorCode } from 'utils/const'
12+ import { explorerNavButton } from './style.module.scss'
1113
1214const MIN_CELL_WIDTH = 70
1315
14- const inputColumns : IColumn [ ] = [
15- {
16- key : 'lockHash' ,
17- name : 'Lock Hash' ,
18- minWidth : 100 ,
19- maxWidth : 200 ,
20- onRender : ( item : any ) => (
21- < span title = { item . lockHash || 'none' } className = "textOverflow" >
22- { item . lockHash || 'none' }
23- </ span >
24- ) ,
25- } ,
26- {
27- key : 'outPointCell' ,
28- name : 'OutPoint Cell' ,
29- minWidth : 150 ,
30- onRender : ( item : any ) => {
31- const text = item . previousOutput ? `${ item . previousOutput . txHash } [${ item . previousOutput . index } ]` : 'none'
32- return (
33- < span title = { text } className = "textOverflow" >
34- { text }
35- </ span >
36- )
37- } ,
38- } ,
39- {
40- key : 'capacity' ,
41- name : 'Capacity' ,
42- minWidth : 200 ,
43- maxWidth : 250 ,
44- } ,
45- ] . map (
46- ( col ) : IColumn => ( {
47- ariaLabel : col . name ,
48- fieldName : col . key ,
49- ...col ,
50- } )
51- )
52- const outputColumns : IColumn [ ] = [
53- {
54- key : 'index' ,
55- name : 'Index' ,
56- minWidth : 80 ,
57- maxWidth : 150 ,
58- onRender : ( item ?: any | State . DetailedOutput ) => {
59- if ( item ) {
60- return item . outPoint . index
61- }
62- return null
63- } ,
64- } ,
65- {
66- key : 'lockHash' ,
67- name : 'Lock Hash' ,
68- minWidth : 150 ,
69- } ,
70- {
71- key : 'capacity' ,
72- name : 'Capacity' ,
73- minWidth : 200 ,
74- maxWidth : 250 ,
75- onRender : ( output ?: State . DetailedOutput ) => {
76- if ( output ) {
77- return `${ shannonToCKBFormatter ( output . capacity ) } CKB`
78- }
79- return null
80- } ,
81- } ,
82- ] . map ( col => ( {
83- ariaLabel : col . name ,
84- fieldName : col . key ,
85- ...col ,
86- } ) )
87-
88- const basicInfoColumns : IColumn [ ] = [
89- {
90- key : 'label' ,
91- name : 'Label' ,
92- minWidth : 100 ,
93- maxWidth : 150 ,
94- } ,
95- {
96- key : 'value' ,
97- name : 'value' ,
98- minWidth : 450 ,
99- } ,
100- ] . map (
101- ( col ) : IColumn => ( {
102- minWidth : MIN_CELL_WIDTH ,
103- ariaLabel : col . name ,
104- fieldName : col . key ,
105- ...col ,
106- } )
107- )
10816const Transaction = ( ) => {
10917 const [ t ] = useTranslation ( )
11018 const [ transaction , setTransaction ] = useState ( transactionState )
19+ const [ addressPrefix , setAddressPrefix ] = useState ( ckbCore . utils . AddressPrefix . Mainnet )
11120 const [ error , setError ] = useState ( { code : '' , message : '' } )
21+
22+ const inputColumns : IColumn [ ] = useMemo (
23+ ( ) =>
24+ [
25+ {
26+ key : 'index' ,
27+ name : t ( 'transaction.index' ) ,
28+ minWidth : 60 ,
29+ maxWidth : 60 ,
30+ onRender : ( _item ?: any , index ?: number ) => {
31+ if ( undefined !== index ) {
32+ return index
33+ }
34+ return null
35+ } ,
36+ } ,
37+ {
38+ key : 'outPointCell' ,
39+ name : 'OutPoint Cell' ,
40+ minWidth : 150 ,
41+ maxWidth : 600 ,
42+ onRender : ( item : any ) => {
43+ const text = item . previousOutput ? `${ item . previousOutput . txHash } [${ item . previousOutput . index } ]` : 'none'
44+ return (
45+ < span title = { text } className = "textOverflow" >
46+ { text }
47+ </ span >
48+ )
49+ } ,
50+ } ,
51+ {
52+ key : 'capacity' ,
53+ name : t ( 'transaction.amount' ) ,
54+ minWidth : 100 ,
55+ maxWidth : 250 ,
56+ onRender : ( input ?: State . DetailedOutput ) => {
57+ if ( input ) {
58+ return `${ shannonToCKBFormatter ( input . capacity ) } CKB`
59+ }
60+ return null
61+ } ,
62+ } ,
63+ ] . map (
64+ ( col ) : IColumn => ( {
65+ ariaLabel : col . name ,
66+ fieldName : col . key ,
67+ ...col ,
68+ } )
69+ ) ,
70+ [ t ]
71+ )
72+
73+ const outputColumns : IColumn [ ] = useMemo (
74+ ( ) =>
75+ [
76+ {
77+ key : 'index' ,
78+ name : t ( 'transaction.index' ) ,
79+ minWidth : 60 ,
80+ maxWidth : 60 ,
81+ onRender : ( item ?: any | State . DetailedOutput ) => {
82+ if ( item ) {
83+ return item . outPoint . index
84+ }
85+ return null
86+ } ,
87+ } ,
88+ {
89+ key : 'address' ,
90+ name : t ( 'transaction.address' ) ,
91+ minWidth : 200 ,
92+ maxWidth : 500 ,
93+ onRender : ( output ?: State . DetailedOutput , _index ?: number , column ?: IColumn ) => {
94+ if ( ! output ) {
95+ return null
96+ }
97+ try {
98+ const address = ckbCore . utils . bech32Address ( output . lock . args [ 0 ] , {
99+ prefix : addressPrefix ,
100+ type : ckbCore . utils . AddressType . HashIdx ,
101+ codeHashIndex : '0x00' ,
102+ } )
103+ if ( column && ( column . calculatedWidth || 0 ) < 450 ) {
104+ return (
105+ < div
106+ title = { address }
107+ style = { {
108+ overflow : 'hidden' ,
109+ display : 'flex' ,
110+ } }
111+ className = "monospacedFont"
112+ >
113+ < span className = "textOverflow" > { address . slice ( 0 , - 6 ) } </ span >
114+ < span > { address . slice ( - 6 ) } </ span >
115+ </ div >
116+ )
117+ }
118+ return (
119+ < span title = { address } className = "monospacedFont" >
120+ { address }
121+ </ span >
122+ )
123+ } catch {
124+ return null
125+ }
126+ } ,
127+ } ,
128+ {
129+ key : 'capacity' ,
130+ name : t ( 'transaction.amount' ) ,
131+ minWidth : 100 ,
132+ maxWidth : 250 ,
133+ onRender : ( output ?: State . DetailedOutput ) => {
134+ if ( output ) {
135+ return `${ shannonToCKBFormatter ( output . capacity ) } CKB`
136+ }
137+ return null
138+ } ,
139+ } ,
140+ ] . map ( col => ( {
141+ ariaLabel : col . name ,
142+ fieldName : col . key ,
143+ ...col ,
144+ } ) ) ,
145+ [ addressPrefix , t ]
146+ )
147+
148+ const basicInfoColumns : IColumn [ ] = useMemo (
149+ ( ) =>
150+ [
151+ {
152+ key : 'label' ,
153+ name : 'label' ,
154+ minWidth : 100 ,
155+ maxWidth : 120 ,
156+ } ,
157+ {
158+ key : 'value' ,
159+ name : 'value' ,
160+ minWidth : 150 ,
161+ } ,
162+ ] . map (
163+ ( col ) : IColumn => ( {
164+ minWidth : MIN_CELL_WIDTH ,
165+ ariaLabel : col . name ,
166+ fieldName : col . key ,
167+ ...col ,
168+ } )
169+ ) ,
170+ [ ]
171+ )
172+
112173 useEffect ( ( ) => {
174+ Promise . all ( [ getAllNetworks ( ) , getCurrentNetworkID ( ) ] )
175+ . then ( ( [ networksRes , idRes ] ) => {
176+ if ( networksRes . status === 1 && idRes . status === 1 ) {
177+ const network = networksRes . result . find ( ( n : any ) => n . id === idRes . result )
178+ if ( ! network ) {
179+ throw new Error ( 'Cannot find current network in the network list' )
180+ }
181+
182+ setAddressPrefix (
183+ network . chain === process . env . REACT_APP_MAINNET_TAG
184+ ? ckbCore . utils . AddressPrefix . Mainnet
185+ : ckbCore . utils . AddressPrefix . Testnet
186+ )
187+ }
188+ } )
189+ . catch ( err => console . warn ( err ) )
190+
113191 const currentWallet = currentWalletCache . load ( )
114192 if ( currentWallet ) {
115193 const hash = window . location . href . split ( '/' ) . pop ( )
@@ -142,21 +220,26 @@ const Transaction = () => {
142220 } )
143221 } , [ ] )
144222
223+ // TODO: add conditional branch on mainnet and testnet
224+ const onExplorerBtnClick = useCallback ( ( ) => {
225+ openExternal ( `https://explorer.nervos.org/transaction/${ transaction . hash } ` )
226+ } , [ transaction . hash ] )
227+
145228 const basicInfoItems = useMemo (
146229 ( ) => [
147- { label : t ( 'history .transaction-hash' ) , value : transaction . hash || 'none' } ,
230+ { label : t ( 'transaction .transaction-hash' ) , value : transaction . hash || 'none' } ,
148231 {
149- label : t ( 'history.date' ) ,
232+ label : t ( 'transaction.block-number' ) ,
233+ value : localNumberFormatter ( transaction . blockNumber ) || 'none' ,
234+ } ,
235+ {
236+ label : t ( 'transaction.date' ) ,
150237 value : + ( transaction . timestamp || transaction . createdAt )
151238 ? uniformTimeFormatter ( + ( transaction . timestamp || transaction . createdAt ) )
152239 : 'none' ,
153240 } ,
154241 {
155- label : t ( 'history.blockNumber' ) ,
156- value : localNumberFormatter ( transaction . blockNumber ) || 'none' ,
157- } ,
158- {
159- label : t ( 'history.amount' ) ,
242+ label : t ( 'transaction.income' ) ,
160243 value : `${ shannonToCKBFormatter ( transaction . value ) } CKB` ,
161244 } ,
162245 ] ,
@@ -185,10 +268,12 @@ const Transaction = () => {
185268 isHeaderVisible = { false }
186269 />
187270 </ Stack >
188- < Stack tokens = { { childrenGap : 15 } } >
271+ < Stack tokens = { { childrenGap : 15 } } verticalFill >
189272 < Stack . Item >
190273 < Text variant = "xLarge" as = "h1" >
191- Inputs
274+ { `${ t ( 'transaction.inputs' ) } (${ transaction . inputs . length } /${ localNumberFormatter (
275+ transaction . inputsCount
276+ ) } )`}
192277 </ Text >
193278 < DetailsList
194279 items = { transaction . inputs }
@@ -200,7 +285,9 @@ const Transaction = () => {
200285 </ Stack . Item >
201286 < Stack . Item >
202287 < Text variant = "xLarge" as = "h1" >
203- Outputs
288+ { `${ t ( 'transaction.outputs' ) } (${ transaction . outputs . length } /${ localNumberFormatter (
289+ transaction . outputsCount
290+ ) } )`}
204291 </ Text >
205292 < DetailsList
206293 items = { transaction . outputs }
@@ -211,6 +298,15 @@ const Transaction = () => {
211298 />
212299 </ Stack . Item >
213300 </ Stack >
301+ < button
302+ type = "button"
303+ className = { explorerNavButton }
304+ title = { t ( 'transaction.view-in-explorer-button-title' ) }
305+ onClick = { onExplorerBtnClick }
306+ >
307+ < Icon iconName = "Explorer" />
308+ < span > { t ( 'transaction.view-in-explorer' ) } </ span >
309+ </ button >
214310 </ Stack >
215311 )
216312}
0 commit comments