1515 * limitations under the License.
1616 */
1717
18- import { Component } from 'react' ;
18+ import { useState } from 'react' ;
19+ import { useTranslation } from 'react-i18next' ;
1920import * as accountApi from '../../api/account' ;
20- import { translate , TranslateProps } from '../../decorators/translate' ;
2121import { A } from '../anchor/anchor' ;
2222import { Dialog } from '../dialog/dialog' ;
2323import { CopyableInput } from '../copy/Copy' ;
@@ -30,176 +30,155 @@ import { Note } from './note';
3030import parentStyle from './transactions.module.css' ;
3131import style from './transaction.module.css' ;
3232
33- interface State {
34- transactionDialog : boolean ;
35- transactionInfo ?: accountApi . ITransaction ;
36- }
33+ type Props = {
34+ accountCode : accountApi . AccountCode ;
35+ index : number ;
36+ explorerURL : string ;
37+ } & accountApi . ITransaction ;
3738
38- interface TransactionProps extends accountApi . ITransaction {
39- accountCode : accountApi . AccountCode ;
40- index : number ;
41- explorerURL : string ;
42- }
39+ export const Transaction = ( {
40+ accountCode,
41+ index,
42+ internalID,
43+ explorerURL,
44+ type,
45+ amount,
46+ feeRatePerKb,
47+ numConfirmations,
48+ numConfirmationsComplete,
49+ time,
50+ addresses,
51+ status,
52+ note = '' ,
53+ } : Props ) => {
54+ const { i18n, t } = useTranslation ( ) ;
55+ const [ transactionDialog , setTransactionDialog ] = useState < boolean > ( false ) ;
56+ const [ transactionInfo , setTransactionInfo ] = useState < accountApi . ITransaction > ( ) ;
4357
44- type Props = TransactionProps & TranslateProps ;
45-
46- class Transaction extends Component < Props , State > {
47- public readonly state : State = {
48- transactionDialog : false ,
49- } ;
50-
51- private parseTimeShort = ( time : string ) => {
58+ const parseTimeShort = ( time : string ) => {
5259 const options = {
5360 year : 'numeric' ,
5461 month : 'numeric' ,
5562 day : 'numeric' ,
5663 } as Intl . DateTimeFormatOptions ;
57- return new Date ( Date . parse ( time ) ) . toLocaleString ( this . props . i18n . language , options ) ;
64+ return new Date ( Date . parse ( time ) ) . toLocaleString ( i18n . language , options ) ;
5865 } ;
5966
60- private showDetails = ( ) => {
61- accountApi . getTransaction ( this . props . accountCode , this . props . internalID ) . then ( transaction => {
67+ const showDetails = ( ) => {
68+ accountApi . getTransaction ( accountCode , internalID ) . then ( transaction => {
6269 if ( ! transaction ) {
63- console . error ( 'Unable to retrieve transaction ' + this . props . internalID ) ;
70+ console . error ( 'Unable to retrieve transaction ' + internalID ) ;
6471 return null ;
6572 }
66- this . setState ( {
67- transactionInfo : transaction ,
68- transactionDialog : true ,
69- } ) ;
73+ setTransactionInfo ( transaction ) ;
74+ setTransactionDialog ( true ) ;
7075 } )
7176 . catch ( console . error ) ;
7277 } ;
7378
74- private hideDetails = ( ) => {
75- this . setState ( { transactionDialog : false } ) ;
76- } ;
79+ const arrow = status === 'failed' ? (
80+ < Warning style = { { maxWidth : '18px' } } />
81+ ) : type === 'receive' ? (
82+ < ArrowIn />
83+ ) : type === 'send' ? (
84+ < ArrowOut />
85+ ) : (
86+ < ArrowSelf />
87+ ) ;
88+ const sign = ( ( type === 'send' ) && '−' ) || ( ( type === 'receive' ) && '+' ) || '' ;
89+ const typeClassName = ( status === 'failed' && style . failed ) || ( type === 'send' && style . send ) || ( type === 'receive' && style . receive ) || '' ;
90+ const sDate = time ? parseTimeShort ( time ) : '---' ;
91+ const statusText = t ( `transaction.status.${ status } ` ) ;
92+ const progress = numConfirmations < numConfirmationsComplete ? ( numConfirmations / numConfirmationsComplete ) * 100 : 100 ;
7793
78- public render ( ) {
79- const {
80- t,
81- index,
82- explorerURL,
83- type,
84- amount,
85- feeRatePerKb,
86- numConfirmations,
87- numConfirmationsComplete,
88- time,
89- addresses,
90- status,
91- note = '' ,
92- } = this . props ;
93- const {
94- transactionDialog,
95- transactionInfo,
96- } = this . state ;
97- const arrow = status === 'failed' ? (
98- < Warning style = { { maxWidth : '18px' } } />
99- ) : type === 'receive' ? (
100- < ArrowIn />
101- ) : type === 'send' ? (
102- < ArrowOut />
103- ) : (
104- < ArrowSelf />
105- ) ;
106- const sign = ( ( type === 'send' ) && '−' ) || ( ( type === 'receive' ) && '+' ) || '' ;
107- const typeClassName = ( status === 'failed' && style . failed ) || ( type === 'send' && style . send ) || ( type === 'receive' && style . receive ) || '' ;
108- const sDate = time ? this . parseTimeShort ( time ) : '---' ;
109- const statusText = {
110- complete : t ( 'transaction.status.complete' ) ,
111- pending : t ( 'transaction.status.pending' ) ,
112- failed : t ( 'transaction.status.failed' ) ,
113- } [ status ] ;
114- const progress = numConfirmations < numConfirmationsComplete ? ( numConfirmations / numConfirmationsComplete ) * 100 : 100 ;
115-
116- return (
117- < div className = { [ style . container , index === 0 ? style . first : '' ] . join ( ' ' ) } >
118- < div className = { [ parentStyle . columns , style . row ] . join ( ' ' ) } >
119- < div className = { parentStyle . columnGroup } >
120- < div className = { parentStyle . type } > { arrow } </ div >
121- < div className = { parentStyle . date } >
122- < span className = { style . columnLabel } >
123- { t ( 'transaction.details.date' ) } :
124- </ span >
125- < span className = { style . date } > { sDate } </ span >
126- </ div >
127- { note ? (
128- < div className = { parentStyle . activity } >
129- < span className = { style . address } >
130- { note }
131- </ span >
132- </ div >
133- ) : (
134- < div className = { parentStyle . activity } >
135- < span className = { style . label } >
136- { t ( type === 'receive' ? 'transaction.tx.received' : 'transaction.tx.sent' ) }
137- </ span >
138- < span className = { style . address } >
139- { addresses [ 0 ] }
140- { addresses . length > 1 && (
141- < span className = { style . badge } >
142- (+{ addresses . length - 1 } )
143- </ span >
144- ) }
145- </ span >
146- </ div >
147- ) }
148- < div className = { [ parentStyle . action , parentStyle . hideOnMedium ] . join ( ' ' ) } >
149- < button type = "button" className = { style . action } onClick = { this . showDetails } >
150- < ExpandIcon expand = { ! transactionDialog } />
151- </ button >
152- </ div >
94+ return (
95+ < div className = { [ style . container , index === 0 ? style . first : '' ] . join ( ' ' ) } >
96+ < div className = { [ parentStyle . columns , style . row ] . join ( ' ' ) } >
97+ < div className = { parentStyle . columnGroup } >
98+ < div className = { parentStyle . type } > { arrow } </ div >
99+ < div className = { parentStyle . date } >
100+ < span className = { style . columnLabel } >
101+ { t ( 'transaction.details.date' ) } :
102+ </ span >
103+ < span className = { style . date } > { sDate } </ span >
153104 </ div >
154- < div className = { parentStyle . columnGroup } >
155- < div className = { parentStyle . status } >
156- < span className = { style . columnLabel } >
157- { t ( 'transaction.details.status' ) } :
105+ { note ? (
106+ < div className = { parentStyle . activity } >
107+ < span className = { style . address } >
108+ { note }
158109 </ span >
159- < ProgressRing
160- className = "m-right-quarter"
161- width = { 14 }
162- value = { progress }
163- isComplete = { numConfirmations >= numConfirmationsComplete }
164- />
165- < span className = { style . status } > { statusText } </ span >
166110 </ div >
167- < div className = { parentStyle . fiat } >
168- < span className = { `${ style . fiat } ${ typeClassName } ` } >
169- < FiatConversion amount = { amount } sign = { sign } noAction />
111+ ) : (
112+ < div className = { parentStyle . activity } >
113+ < span className = { style . label } >
114+ { t ( type === 'receive' ? 'transaction.tx.received' : 'transaction.tx.sent' ) }
170115 </ span >
171- </ div >
172- < div className = { `${ parentStyle . currency } ${ typeClassName } ` } >
173- < span
174- className = { `${ style . amount } ${ style . amountOverflow } ` }
175- data-unit = { ` ${ amount . unit } ` } >
176- { sign }
177- < Amount amount = { amount . amount } unit = { amount . unit } />
178- < span className = { style . currencyUnit } > { amount . unit } </ span >
116+ < span className = { style . address } >
117+ { addresses [ 0 ] }
118+ { addresses . length > 1 && (
119+ < span className = { style . badge } >
120+ (+{ addresses . length - 1 } )
121+ </ span >
122+ ) }
179123 </ span >
180124 </ div >
181- < div className = { [ parentStyle . action , parentStyle . showOnMedium ] . join ( ' ' ) } >
182- < button type = "button" className = { style . action } onClick = { this . showDetails } >
183- < ExpandIcon expand = { ! transactionDialog } />
184- </ button >
185- </ div >
125+ ) }
126+ < div className = { [ parentStyle . action , parentStyle . hideOnMedium ] . join ( ' ' ) } >
127+ < button type = "button" className = { style . action } onClick = { showDetails } >
128+ < ExpandIcon expand = { ! transactionDialog } />
129+ </ button >
130+ </ div >
131+ </ div >
132+ < div className = { parentStyle . columnGroup } >
133+ < div className = { parentStyle . status } >
134+ < span className = { style . columnLabel } >
135+ { t ( 'transaction.details.status' ) } :
136+ </ span >
137+ < ProgressRing
138+ className = "m-right-quarter"
139+ width = { 14 }
140+ value = { progress }
141+ isComplete = { numConfirmations >= numConfirmationsComplete }
142+ />
143+ < span className = { style . status } > { statusText } </ span >
144+ </ div >
145+ < div className = { parentStyle . fiat } >
146+ < span className = { `${ style . fiat } ${ typeClassName } ` } >
147+ < FiatConversion amount = { amount } sign = { sign } noAction />
148+ </ span >
149+ </ div >
150+ < div className = { `${ parentStyle . currency } ${ typeClassName } ` } >
151+ < span
152+ className = { `${ style . amount } ${ style . amountOverflow } ` }
153+ data-unit = { ` ${ amount . unit } ` } >
154+ { sign }
155+ < Amount amount = { amount . amount } unit = { amount . unit } />
156+ < span className = { style . currencyUnit } > { amount . unit } </ span >
157+ </ span >
158+ </ div >
159+ < div className = { [ parentStyle . action , parentStyle . showOnMedium ] . join ( ' ' ) } >
160+ < button type = "button" className = { style . action } onClick = { showDetails } >
161+ < ExpandIcon expand = { ! transactionDialog } />
162+ </ button >
186163 </ div >
187164 </ div >
188- { /*
189- Amount and Confirmations info are displayed using props data
190- instead of transactionInfo because they are live updated.
191- */ }
192- < Dialog
193- open = { transactionDialog }
194- title = { t ( 'transaction.details.title' ) }
195- onClose = { this . hideDetails }
196- slim
197- medium >
198- { transactionInfo && < >
165+ </ div >
166+ { /*
167+ Amount and Confirmations info are displayed using props data
168+ instead of transactionInfo because they are live updated.
169+ */ }
170+ < Dialog
171+ open = { transactionDialog }
172+ title = { t ( 'transaction.details.title' ) }
173+ onClose = { ( ) => setTransactionDialog ( false ) }
174+ slim
175+ medium >
176+ { transactionInfo && (
177+ < >
199178 < Note
200- accountCode = { this . props . accountCode }
201- internalID = { this . props . internalID }
202- note = { this . props . note }
179+ accountCode = { accountCode }
180+ internalID = { internalID }
181+ note = { note }
203182 />
204183 < div className = { style . detail } >
205184 < label > { t ( 'transaction.details.type' ) } </ label >
@@ -360,13 +339,9 @@ class Transaction extends Component<Props, State> {
360339 { t ( 'transaction.explorerTitle' ) }
361340 </ A >
362341 </ div >
363- </ > }
364- </ Dialog >
365- </ div >
366- ) ;
367- }
368- }
369-
370- const HOC = translate ( ) ( Transaction ) ;
371-
372- export { HOC as Transaction } ;
342+ </ >
343+ ) }
344+ </ Dialog >
345+ </ div >
346+ ) ;
347+ } ;
0 commit comments