2022-01-02 00:19:18 +00:00
import React , { Component } from "react" ;
2022-04-05 14:25:53 +00:00
import { withTranslation , Trans } from "react-i18next" ;
2022-03-22 17:49:57 +00:00
import { TextField , Chip , Tooltip , Badge , Tab , Tabs , Alert , Paper , CircularProgress , Button , Grid , Typography , List , ListItem , ListItemIcon , ListItemText , ListItemAvatar , Avatar , Divider , Box , LinearProgress , Dialog , DialogActions , DialogContent , DialogContentText , DialogTitle } from "@mui/material"
2022-01-14 00:43:26 +00:00
import Countdown , { zeroPad , calcTimeDelta } from 'react-countdown' ;
2022-01-27 22:51:57 +00:00
import MediaQuery from 'react-responsive'
2022-04-05 14:25:53 +00:00
import currencyDict from '../../static/assets/currencies.json' ;
2022-01-27 22:51:57 +00:00
2022-03-30 14:26:13 +00:00
import PaymentText from './PaymentText'
2022-01-08 13:08:03 +00:00
import TradeBox from "./TradeBox" ;
2022-01-16 18:32:34 +00:00
import getFlags from './getFlags'
2022-01-02 00:19:18 +00:00
2022-01-14 12:00:53 +00:00
// icons
import AccessTimeIcon from '@mui/icons-material/AccessTime' ;
import NumbersIcon from '@mui/icons-material/Numbers' ;
import PriceChangeIcon from '@mui/icons-material/PriceChange' ;
import PaymentsIcon from '@mui/icons-material/Payments' ;
import ArticleIcon from '@mui/icons-material/Article' ;
2022-04-05 14:25:53 +00:00
import { t } from "i18next" ;
2022-01-08 15:34:09 +00:00
2022-04-15 16:22:49 +00:00
import { getCookie } from "../utils/cookies" ;
2022-01-05 00:13:08 +00:00
2022-01-03 14:27:25 +00:00
// pretty numbers
function pn ( x ) {
2022-02-17 02:45:18 +00:00
var parts = x . toString ( ) . split ( "." ) ;
parts [ 0 ] = parts [ 0 ] . replace ( /\B(?=(\d{3})+(?!\d))/g , "," ) ;
return parts . join ( "." ) ;
2022-01-03 14:27:25 +00:00
}
2022-04-05 14:25:53 +00:00
class OrderPage extends Component {
2022-01-02 12:59:48 +00:00
constructor ( props ) {
super ( props ) ;
this . state = {
2022-01-27 17:43:17 +00:00
is _explicit : false ,
2022-01-15 12:00:11 +00:00
delay : 60000 , // Refresh every 60 seconds by default
2022-01-22 23:05:03 +00:00
total _secs _exp : 300 ,
2022-01-14 14:19:25 +00:00
loading : true ,
2022-01-18 15:23:57 +00:00
openCancel : false ,
2022-01-23 19:02:25 +00:00
openCollaborativeCancel : false ,
2022-02-03 18:27:39 +00:00
openInactiveMaker : false ,
2022-01-29 14:42:54 +00:00
showContractBox : 1 ,
2022-01-02 12:59:48 +00:00
} ;
this . orderId = this . props . match . params . orderId ;
2022-01-02 13:24:35 +00:00
this . getOrderDetails ( ) ;
2022-01-15 12:00:11 +00:00
2022-01-23 19:02:25 +00:00
// Refresh delays according to Order status
2022-01-15 12:00:11 +00:00
this . statusToDelay = {
2022-02-10 19:28:59 +00:00
"0" : 2000 , //'Waiting for maker bond'
"1" : 25000 , //'Public'
"2" : 999999 , //'Deleted'
"3" : 2000 , //'Waiting for taker bond'
"4" : 999999 , //'Cancelled'
"5" : 999999 , //'Expired'
2022-02-24 20:47:46 +00:00
"6" : 6000 , //'Waiting for trade collateral and buyer invoice'
"7" : 8000 , //'Waiting only for seller trade collateral'
2022-01-23 20:23:25 +00:00
"8" : 8000 , //'Waiting only for buyer invoice'
2022-02-10 19:28:59 +00:00
"9" : 10000 , //'Sending fiat - In chatroom'
"10" : 10000 , //'Fiat sent - In chatroom'
"11" : 30000 , //'In dispute'
"12" : 999999 , //'Collaboratively cancelled'
"13" : 3000 , //'Sending satoshis to buyer'
"14" : 999999 , //'Sucessful trade'
"15" : 10000 , //'Failed lightning network routing'
"16" : 180000 , //'Wait for dispute resolution'
"17" : 180000 , //'Maker lost dispute'
"18" : 180000 , //'Taker lost dispute'
2022-01-15 14:22:07 +00:00
}
2022-01-02 12:59:48 +00:00
}
2022-01-02 00:19:18 +00:00
2022-01-22 23:05:03 +00:00
completeSetState = ( newStateVars ) => {
2022-01-23 20:23:25 +00:00
// In case the reply only has "bad_request"
// Do not substitute these two for "undefined" as
// otherStateVars will fail to assign values
if ( newStateVars . currency == null ) {
newStateVars . currency = this . state . currency
newStateVars . status = this . state . status
}
2022-01-22 23:05:03 +00:00
var otherStateVars = {
2022-03-22 17:49:57 +00:00
amount : newStateVars . amount ? newStateVars . amount : null ,
2022-01-19 22:44:31 +00:00
loading : false ,
2022-01-22 23:05:03 +00:00
delay : this . setDelay ( newStateVars . status ) ,
currencyCode : this . getCurrencyCode ( newStateVars . currency ) ,
2022-01-24 18:34:52 +00:00
penalty : newStateVars . penalty , // in case penalty time has finished, it goes back to null
2022-01-24 22:53:55 +00:00
invoice _expired : newStateVars . invoice _expired // in case invoice had expired, it goes back to null when it is valid again
2022-01-22 23:05:03 +00:00
} ;
2022-01-24 17:54:44 +00:00
2022-01-22 23:05:03 +00:00
var completeStateVars = Object . assign ( { } , newStateVars , otherStateVars ) ;
this . setState ( completeStateVars ) ;
2022-01-19 22:44:31 +00:00
}
2022-01-23 19:02:25 +00:00
2022-01-02 13:24:35 +00:00
getOrderDetails ( ) {
2022-01-09 01:23:13 +00:00
this . setState ( null )
2022-01-02 13:24:35 +00:00
fetch ( '/api/order' + '?order_id=' + this . orderId )
2022-01-02 12:59:48 +00:00
. then ( ( response ) => response . json ( ) )
2022-01-22 23:05:03 +00:00
. then ( ( data ) => this . completeSetState ( data ) ) ;
2022-01-02 12:59:48 +00:00
}
2022-01-09 01:23:13 +00:00
// These are used to refresh the data
componentDidMount ( ) {
this . interval = setInterval ( this . tick , this . state . delay ) ;
}
2022-01-15 12:00:11 +00:00
componentDidUpdate ( ) {
clearInterval ( this . interval ) ;
2022-01-09 01:23:13 +00:00
this . interval = setInterval ( this . tick , this . state . delay ) ;
}
2022-01-15 12:00:11 +00:00
2022-01-09 01:23:13 +00:00
componentWillUnmount ( ) {
clearInterval ( this . interval ) ;
}
tick = ( ) => {
this . getOrderDetails ( ) ;
}
2022-04-15 16:22:49 +00:00
// Countdown Renderer callback with condition
2022-01-14 00:43:26 +00:00
countdownRenderer = ( { total , hours , minutes , seconds , completed } ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-14 00:43:26 +00:00
if ( completed ) {
// Render a completed state
2022-04-05 14:25:53 +00:00
return ( < span > { t ( "The order has expired" ) } < / s p a n > ) ;
2022-01-18 15:23:57 +00:00
2022-01-14 00:43:26 +00:00
} else {
2022-03-24 13:41:32 +00:00
var col = 'inherit'
2022-01-22 23:05:03 +00:00
var fraction _left = ( total / 1000 ) / this . state . total _secs _exp
2022-01-14 12:00:53 +00:00
// Make orange at 25% of time left
2022-01-14 00:43:26 +00:00
if ( fraction _left < 0.25 ) { col = 'orange' }
// Make red at 10% of time left
if ( fraction _left < 0.1 ) { col = 'red' }
2022-01-14 12:00:53 +00:00
// Render a countdown, bold when less than 25%
2022-01-14 00:43:26 +00:00
return (
fraction _left < 0.25 ? < b > < span style = { { color : col } } > { hours } h { zeroPad ( minutes ) } m { zeroPad ( seconds ) } s < / s p a n > < / b >
: < span style = { { color : col } } > { hours } h { zeroPad ( minutes ) } m { zeroPad ( seconds ) } s < / s p a n >
) ;
}
} ;
2022-04-15 16:22:49 +00:00
// Countdown Renderer callback with condition
2022-01-26 11:44:45 +00:00
countdownPenaltyRenderer = ( { minutes , seconds , completed } ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-26 11:44:45 +00:00
if ( completed ) {
// Render a completed state
2022-04-05 14:25:53 +00:00
return ( < span > { t ( "Penalty lifted, good to go!" ) } < / s p a n > ) ;
2022-04-15 16:22:49 +00:00
2022-01-26 11:44:45 +00:00
} else {
return (
2022-04-05 14:25:53 +00:00
< span > { t ( "You cannot take an order yet! Wait {{timeMin}}m {{timeSec}}s" , { timeMin : zeroPad ( minutes ) , timeSec : zeroPad ( seconds ) } ) } < / s p a n >
2022-01-26 11:44:45 +00:00
) ;
}
} ;
2022-04-15 16:22:49 +00:00
2022-03-22 17:49:57 +00:00
handleTakeAmountChange = ( e ) => {
if ( e . target . value != "" & e . target . value != null ) {
this . setState ( { takeAmount : parseFloat ( e . target . value ) } )
} else {
this . setState ( { takeAmount : e . target . value } )
}
}
amountHelperText = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-03-22 17:49:57 +00:00
if ( this . state . takeAmount < this . state . min _amount & this . state . takeAmount != "" ) {
2022-04-05 14:25:53 +00:00
return t ( "Too low" )
2022-03-22 17:49:57 +00:00
} else if ( this . state . takeAmount > this . state . max _amount & this . state . takeAmount != "" ) {
2022-04-05 14:25:53 +00:00
return t ( "Too high" )
2022-03-22 17:49:57 +00:00
} else {
return null
}
}
takeOrderButton = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-03-22 17:49:57 +00:00
if ( this . state . has _range ) {
return (
< Grid containter xs = { 12 } align = "center" alignItems = "stretch" justifyContent = "center" style = { { display : "flex" } } >
< this . InactiveMakerDialog / >
< div style = { { maxWidth : 120 } } >
2022-04-05 14:25:53 +00:00
< Tooltip placement = "top" enterTouchDelay = "500" enterDelay = "700" enterNextDelay = "2000" title = { t ( "Enter amount of fiat to exchange for bitcoin" ) } >
2022-03-24 15:43:31 +00:00
< Paper elevation = { 5 } sx = { { maxHeight : 40 } } >
2022-03-22 17:49:57 +00:00
< TextField
2022-04-15 16:22:49 +00:00
error = { ( this . state . takeAmount < this . state . min _amount || this . state . takeAmount > this . state . max _amount ) & this . state . takeAmount != "" }
2022-03-22 17:49:57 +00:00
helperText = { this . amountHelperText ( ) }
2022-04-05 14:25:53 +00:00
label = { t ( "Amount {{currencyCode}}" , { currencyCode : this . state . currencyCode } ) }
2022-03-22 17:49:57 +00:00
size = "small"
2022-04-15 16:22:49 +00:00
type = "number"
2022-03-22 17:49:57 +00:00
required = "true"
value = { this . state . takeAmount }
inputProps = { {
min : this . state . min _amount ,
2022-04-15 16:22:49 +00:00
max : this . state . max _amount ,
2022-03-22 17:49:57 +00:00
style : { textAlign : "center" }
} }
onChange = { this . handleTakeAmountChange }
/ >
< / P a p e r >
< / T o o l t i p >
< / d i v >
2022-03-24 15:43:31 +00:00
< div style = { { height : 38 , top : '1px' , position : 'relative' , display : ( this . state . takeAmount < this . state . min _amount || this . state . takeAmount > this . state . max _amount || this . state . takeAmount == "" || this . state . takeAmount == null ) ? '' : 'none' } } >
2022-04-05 14:25:53 +00:00
< Tooltip placement = "top" enterTouchDelay = "0" enterDelay = "500" enterNextDelay = "1200" title = { t ( "You must specify an amount first" ) } >
2022-03-24 15:43:31 +00:00
< Paper elevation = { 4 } >
2022-04-15 16:22:49 +00:00
< Button sx = { { height : 38 } } variant = 'contained' color = 'primary'
2022-03-24 15:43:31 +00:00
disabled = { true } >
2022-04-05 14:25:53 +00:00
{ t ( "Take Order" ) }
2022-03-24 15:43:31 +00:00
< / B u t t o n >
< / P a p e r >
< / T o o l t i p >
< / d i v >
< div style = { { height : 38 , top : '1px' , position : 'relative' , display : ( this . state . takeAmount < this . state . min _amount || this . state . takeAmount > this . state . max _amount || this . state . takeAmount == "" || this . state . takeAmount == null ) ? 'none' : '' } } >
< Paper elevation = { 4 } >
2022-04-15 16:22:49 +00:00
< Button sx = { { height : 38 } } variant = 'contained' color = 'primary'
2022-03-24 15:43:31 +00:00
onClick = { this . state . maker _status == 'Inactive' ? this . handleClickOpenInactiveMakerDialog : this . takeOrder } >
2022-04-05 14:25:53 +00:00
{ t ( "Take Order" ) }
2022-03-24 15:43:31 +00:00
< / B u t t o n >
< / P a p e r >
2022-03-22 17:49:57 +00:00
< / d i v >
< / G r i d >
)
} else {
return (
< >
2022-02-03 18:27:39 +00:00
< this . InactiveMakerDialog / >
2022-04-15 16:22:49 +00:00
< Button variant = 'contained' color = 'primary'
2022-03-22 17:49:57 +00:00
onClick = { this . state . maker _status == 'Inactive' ? this . handleClickOpenInactiveMakerDialog : this . takeOrder } >
2022-04-05 14:25:53 +00:00
{ t ( "Take Order" ) }
2022-03-22 17:49:57 +00:00
< / B u t t o n >
< / >
)
2022-02-01 16:27:02 +00:00
}
2022-03-22 17:49:57 +00:00
}
countdownTakeOrderRenderer = ( { seconds , completed } ) => {
if ( isNaN ( seconds ) ) { return ( < this . takeOrderButton / > ) }
2022-02-01 16:27:02 +00:00
if ( completed ) {
// Render a completed state
2022-03-22 17:49:57 +00:00
return ( < this . takeOrderButton / > ) ;
2022-02-01 16:27:02 +00:00
} else {
2022-02-02 09:29:05 +00:00
return (
2022-04-05 14:25:53 +00:00
< Tooltip enterTouchDelay = "0" title = { t ( "Wait until you can take an order" ) } > < div >
< Button disabled = { true } variant = 'contained' color = 'primary' > { t ( "Take Order" ) } < / B u t t o n >
2022-02-02 09:29:05 +00:00
< / d i v > < / T o o l t i p > )
2022-02-01 16:27:02 +00:00
}
} ;
2022-01-26 11:44:45 +00:00
2022-01-14 00:43:26 +00:00
LinearDeterminate = ( ) => {
const [ progress , setProgress ] = React . useState ( 0 ) ;
2022-04-15 16:22:49 +00:00
2022-01-14 00:43:26 +00:00
React . useEffect ( ( ) => {
const timer = setInterval ( ( ) => {
setProgress ( ( oldProgress ) => {
2022-01-22 23:05:03 +00:00
var left = calcTimeDelta ( new Date ( this . state . expires _at ) ) . total / 1000 ;
return ( left / this . state . total _secs _exp ) * 100 ;
2022-01-14 00:43:26 +00:00
} ) ;
} , 1000 ) ;
2022-04-15 16:22:49 +00:00
2022-01-14 00:43:26 +00:00
return ( ) => {
clearInterval ( timer ) ;
} ;
} , [ ] ) ;
2022-04-15 16:22:49 +00:00
2022-01-14 00:43:26 +00:00
return (
< Box sx = { { width : '100%' } } >
< LinearProgress variant = "determinate" value = { progress } / >
< / B o x >
) ;
}
2022-02-03 18:27:39 +00:00
takeOrder = ( ) => {
2022-02-01 16:27:02 +00:00
this . setState ( { loading : true } )
const requestOptions = {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' , 'X-CSRFToken' : getCookie ( 'csrftoken' ) , } ,
body : JSON . stringify ( {
'action' : 'take' ,
2022-03-22 17:49:57 +00:00
'amount' : this . state . takeAmount ,
2022-02-01 16:27:02 +00:00
} ) ,
2022-01-05 00:13:08 +00:00
} ;
fetch ( '/api/order/' + '?order_id=' + this . orderId , requestOptions )
. then ( ( response ) => response . json ( ) )
2022-01-22 23:05:03 +00:00
. then ( ( data ) => this . completeSetState ( data ) ) ;
2022-01-05 00:13:08 +00:00
}
2022-04-15 16:22:49 +00:00
2022-01-15 15:12:26 +00:00
// set delay to the one matching the order status. If null order status, delay goes to 9999999.
setDelay = ( status ) => {
return status >= 0 ? this . statusToDelay [ status . toString ( ) ] : 99999999 ;
2022-01-15 14:22:07 +00:00
}
2022-01-08 12:48:03 +00:00
getCurrencyCode ( val ) {
2022-04-15 16:22:49 +00:00
let code = val ? currencyDict [ val . toString ( ) ] : ""
2022-01-09 15:28:12 +00:00
return code
2022-01-08 12:48:03 +00:00
}
2022-01-05 00:13:08 +00:00
2022-01-18 15:23:57 +00:00
handleClickConfirmCancelButton = ( ) => {
2022-02-01 16:27:02 +00:00
this . setState ( { loading : true } )
const requestOptions = {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' , 'X-CSRFToken' : getCookie ( 'csrftoken' ) , } ,
body : JSON . stringify ( {
'action' : 'cancel' ,
} ) ,
} ;
fetch ( '/api/order/' + '?order_id=' + this . orderId , requestOptions )
. then ( ( response ) => response . json ( ) )
. then ( ( data ) => this . getOrderDetails ( data . id ) ) ;
2022-01-18 15:23:57 +00:00
this . handleClickCloseConfirmCancelDialog ( ) ;
}
handleClickOpenConfirmCancelDialog = ( ) => {
this . setState ( { openCancel : true } ) ;
} ;
handleClickCloseConfirmCancelDialog = ( ) => {
this . setState ( { openCancel : false } ) ;
} ;
CancelDialog = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-18 15:23:57 +00:00
return (
< Dialog
open = { this . state . openCancel }
onClose = { this . handleClickCloseConfirmCancelDialog }
aria - labelledby = "cancel-dialog-title"
aria - describedby = "cancel-dialog-description"
>
< DialogTitle id = "cancel-dialog-title" >
2022-04-05 14:25:53 +00:00
{ t ( "Cancel the order?" ) }
2022-01-18 15:23:57 +00:00
< / D i a l o g T i t l e >
< DialogContent >
< DialogContentText id = "cancel-dialog-description" >
2022-04-05 14:25:53 +00:00
{ t ( "If the order is cancelled now you will lose your bond." ) }
2022-01-18 15:23:57 +00:00
< / D i a l o g C o n t e n t T e x t >
< / D i a l o g C o n t e n t >
< DialogActions >
2022-04-05 14:25:53 +00:00
< Button onClick = { this . handleClickCloseConfirmCancelDialog } autoFocus > { t ( "Go back" ) } < / B u t t o n >
< Button onClick = { this . handleClickConfirmCancelButton } > { t ( "Confirm Cancel" ) } < / B u t t o n >
2022-01-18 15:23:57 +00:00
< / D i a l o g A c t i o n s >
< / D i a l o g >
)
}
2022-02-03 18:27:39 +00:00
handleClickOpenInactiveMakerDialog = ( ) => {
this . setState ( { openInactiveMaker : true } ) ;
} ;
handleClickCloseInactiveMakerDialog = ( ) => {
this . setState ( { openInactiveMaker : false } ) ;
} ;
InactiveMakerDialog = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-02-03 18:27:39 +00:00
return (
< Dialog
open = { this . state . openInactiveMaker }
onClose = { this . handleClickCloseInactiveMakerDialog }
aria - labelledby = "inactive-maker-dialog-title"
aria - describedby = "inactive-maker-description"
>
< DialogTitle id = "inactive-maker-dialog-title" >
2022-04-05 14:25:53 +00:00
{ t ( "The maker is away" ) }
2022-02-03 18:27:39 +00:00
< / D i a l o g T i t l e >
< DialogContent >
< DialogContentText id = "cancel-dialog-description" >
2022-04-05 14:25:53 +00:00
{ t ( "By taking this order you risk wasting your time. If the maker does not proceed in time, you will be compensated in satoshis for 50% of the maker bond." ) }
2022-02-03 18:27:39 +00:00
< / D i a l o g C o n t e n t T e x t >
< / D i a l o g C o n t e n t >
< DialogActions >
2022-04-05 14:25:53 +00:00
< Button onClick = { this . handleClickCloseInactiveMakerDialog } autoFocus > { t ( "Go back" ) } < / B u t t o n >
< Button onClick = { this . takeOrder } > { t ( "Take Order" ) } < / B u t t o n >
2022-02-03 18:27:39 +00:00
< / D i a l o g A c t i o n s >
< / D i a l o g >
)
}
2022-01-23 19:02:25 +00:00
handleClickConfirmCollaborativeCancelButton = ( ) => {
const requestOptions = {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' , 'X-CSRFToken' : getCookie ( 'csrftoken' ) , } ,
body : JSON . stringify ( {
'action' : 'cancel' ,
} ) ,
} ;
fetch ( '/api/order/' + '?order_id=' + this . orderId , requestOptions )
. then ( ( response ) => response . json ( ) )
2022-01-30 13:18:32 +00:00
. then ( ( data ) => this . getOrderDetails ( data . id ) ) ;
2022-01-23 19:02:25 +00:00
this . handleClickCloseCollaborativeCancelDialog ( ) ;
}
handleClickOpenCollaborativeCancelDialog = ( ) => {
this . setState ( { openCollaborativeCancel : true } ) ;
} ;
handleClickCloseCollaborativeCancelDialog = ( ) => {
this . setState ( { openCollaborativeCancel : false } ) ;
} ;
CollaborativeCancelDialog = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-23 19:02:25 +00:00
return (
< Dialog
open = { this . state . openCollaborativeCancel }
onClose = { this . handleClickCloseCollaborativeCancelDialog }
aria - labelledby = "collaborative-cancel-dialog-title"
aria - describedby = "collaborative-cancel-dialog-description"
>
< DialogTitle id = "cancel-dialog-title" >
2022-04-05 14:25:53 +00:00
{ t ( "Collaborative cancel the order?" ) }
2022-01-23 19:02:25 +00:00
< / D i a l o g T i t l e >
< DialogContent >
< DialogContentText id = "cancel-dialog-description" >
2022-04-05 14:25:53 +00:00
{ t ( "The trade escrow has been posted. The order can be cancelled only if both, maker and taker, agree to cancel." ) }
2022-01-23 19:02:25 +00:00
< / D i a l o g C o n t e n t T e x t >
< / D i a l o g C o n t e n t >
< DialogActions >
2022-04-05 14:25:53 +00:00
< Button onClick = { this . handleClickCloseCollaborativeCancelDialog } autoFocus > { t ( "Go back" ) } < / B u t t o n >
< Button onClick = { this . handleClickConfirmCollaborativeCancelButton } > { t ( "Ask for Cancel" ) } < / B u t t o n >
2022-01-23 19:02:25 +00:00
< / D i a l o g A c t i o n s >
< / D i a l o g >
)
}
2022-03-12 11:24:11 +00:00
BackButton = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-03-12 11:24:11 +00:00
// If order has expired, show back button.
if ( this . state . status == 5 ) {
return (
< Grid item xs = { 12 } align = "center" >
2022-04-05 14:25:53 +00:00
< Button variant = 'contained' color = 'secondary' onClick = { this . props . history . goBack } > { t ( "Back" ) } < / B u t t o n >
2022-03-12 11:24:11 +00:00
< / G r i d >
) }
return ( null )
}
2022-01-18 15:23:57 +00:00
CancelButton = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-18 15:23:57 +00:00
// If maker and Waiting for Bond. Or if taker and Waiting for bond.
2022-04-15 16:22:49 +00:00
// Simply allow to cancel without showing the cancel dialog.
2022-01-30 15:18:03 +00:00
if ( ( this . state . is _maker & [ 0 , 1 ] . includes ( this . state . status ) ) || this . state . is _taker & this . state . status == 3 ) {
2022-01-18 15:23:57 +00:00
return (
< Grid item xs = { 12 } align = "center" >
2022-04-05 14:25:53 +00:00
< Button variant = 'contained' color = 'secondary' onClick = { this . handleClickConfirmCancelButton } > { t ( "Cancel" ) } < / B u t t o n >
2022-01-18 15:23:57 +00:00
< / G r i d >
) }
// If the order does not yet have an escrow deposited. Show dialog
// to confirm forfeiting the bond
2022-01-30 15:18:03 +00:00
if ( [ 3 , 6 , 7 ] . includes ( this . state . status ) ) {
2022-01-23 19:02:25 +00:00
return (
< div id = "openDialogCancelButton" >
< Grid item xs = { 12 } align = "center" >
< this . CancelDialog / >
2022-04-05 14:25:53 +00:00
< Button variant = 'contained' color = 'secondary' onClick = { this . handleClickOpenConfirmCancelDialog } > { t ( "Cancel" ) } < / B u t t o n >
2022-01-23 19:02:25 +00:00
< / G r i d >
< / d i v >
) }
2022-04-15 16:22:49 +00:00
2022-01-23 19:02:25 +00:00
// If the escrow is Locked, show the collaborative cancel button.
2022-04-15 16:22:49 +00:00
2022-01-23 19:02:25 +00:00
if ( [ 8 , 9 ] . includes ( this . state . status ) ) {
2022-01-18 15:23:57 +00:00
return (
< Grid item xs = { 12 } align = "center" >
2022-01-23 19:02:25 +00:00
< this . CollaborativeCancelDialog / >
2022-04-05 14:25:53 +00:00
< Button variant = 'contained' color = 'secondary' onClick = { this . handleClickOpenCollaborativeCancelDialog } > { t ( "Collaborative Cancel" ) } < / B u t t o n >
2022-01-18 15:23:57 +00:00
< / G r i d >
) }
2022-01-23 19:02:25 +00:00
2022-01-18 15:23:57 +00:00
// If none of the above do not return a cancel button.
return ( null )
2022-01-08 15:34:09 +00:00
}
2022-01-30 19:45:37 +00:00
// Colors for the status badges
statusBadgeColor ( status ) {
2022-02-03 18:06:30 +00:00
if ( status == 'Active' ) { return ( "success" ) }
if ( status == 'Seen recently' ) { return ( "warning" ) }
if ( status == 'Inactive' ) { return ( 'error' ) }
2022-01-30 19:45:37 +00:00
}
2022-02-01 16:27:02 +00:00
2022-01-08 13:08:03 +00:00
orderBox = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-08 13:08:03 +00:00
return (
2022-01-27 22:51:57 +00:00
< Grid container spacing = { 1 } >
2022-01-03 12:11:33 +00:00
< Grid item xs = { 12 } align = "center" >
2022-01-27 22:51:57 +00:00
< MediaQuery minWidth = { 920 } >
< Typography component = "h5" variant = "h5" >
2022-04-05 14:25:53 +00:00
{ t ( "Order Box" ) }
2022-01-27 22:51:57 +00:00
< / T y p o g r a p h y >
< / M e d i a Q u e r y >
2022-01-03 19:15:13 +00:00
< Paper elevation = { 12 } style = { { padding : 8 , } } >
2022-01-05 00:13:08 +00:00
< List dense = "true" >
2022-01-05 02:03:03 +00:00
< ListItem >
2022-01-03 12:11:33 +00:00
< ListItemAvatar sx = { { width : 56 , height : 56 } } >
2022-04-05 14:25:53 +00:00
< Tooltip placement = "top" enterTouchDelay = "0" title = { t ( this . state . maker _status ) } >
2022-02-03 18:06:30 +00:00
< Badge variant = "dot" overlap = "circular" badgeContent = "" color = { this . statusBadgeColor ( this . state . maker _status ) } >
2022-01-30 19:45:37 +00:00
< Avatar className = "flippedSmallAvatar"
2022-04-15 16:22:49 +00:00
alt = { this . state . maker _nick }
src = { window . location . origin + '/static/assets/avatars/' + this . state . maker _nick + '.png' }
2022-01-30 19:45:37 +00:00
/ >
< / B a d g e >
2022-02-02 09:29:05 +00:00
< / T o o l t i p >
2022-01-03 12:11:33 +00:00
< / L i s t I t e m A v a t a r >
2022-04-05 14:25:53 +00:00
< ListItemText primary = { this . state . maker _nick + ( this . state . type ? " " + t ( "(Seller)" ) : " " + t ( "(Buyer)" ) ) } secondary = { t ( "Order maker" ) } align = "right" / >
2022-01-03 12:11:33 +00:00
< / L i s t I t e m >
2022-01-05 02:03:03 +00:00
2022-01-22 23:05:03 +00:00
{ this . state . is _participant ?
2022-01-05 02:03:03 +00:00
< >
2022-01-22 23:05:03 +00:00
{ this . state . taker _nick != 'None' ?
2022-01-05 02:03:03 +00:00
< >
2022-02-02 09:29:05 +00:00
< Divider / >
2022-01-05 02:03:03 +00:00
< ListItem align = "left" >
2022-04-05 14:25:53 +00:00
< ListItemText primary = { this . state . taker _nick + ( this . state . type ? " " + t ( "(Buyer)" ) : " " + t ( "(Seller)" ) ) } secondary = { t ( "Order taker" ) } / >
2022-04-15 16:22:49 +00:00
< ListItemAvatar >
2022-04-05 14:25:53 +00:00
< Tooltip enterTouchDelay = "0" title = { t ( this . state . taker _status ) } >
2022-02-03 18:06:30 +00:00
< Badge variant = "dot" overlap = "circular" badgeContent = "" color = { this . statusBadgeColor ( this . state . taker _status ) } >
2022-01-30 19:45:37 +00:00
< Avatar className = "smallAvatar"
2022-04-15 16:22:49 +00:00
alt = { this . state . taker _nick }
2022-01-30 19:45:37 +00:00
src = { window . location . origin + '/static/assets/avatars/' + this . state . taker _nick + '.png' }
/ >
< / B a d g e >
2022-02-02 09:29:05 +00:00
< / T o o l t i p >
2022-01-05 02:03:03 +00:00
< / L i s t I t e m A v a t a r >
2022-04-15 16:22:49 +00:00
< / L i s t I t e m >
< / > :
2022-01-05 12:18:54 +00:00
""
2022-01-05 02:03:03 +00:00
}
2022-04-05 14:25:53 +00:00
< Divider > < Chip label = { t ( "Order Details" ) } / > < / D i v i d e r >
2022-01-05 12:18:54 +00:00
< ListItem >
2022-01-14 12:00:53 +00:00
< ListItemIcon >
< ArticleIcon / >
< / L i s t I t e m I c o n >
2022-04-05 14:25:53 +00:00
< ListItemText primary = { t ( this . state . status _message ) } secondary = { t ( "Order status" ) } / >
2022-01-05 12:18:54 +00:00
< / L i s t I t e m >
2022-02-02 09:29:05 +00:00
< Divider / >
2022-01-05 02:03:03 +00:00
< / >
2022-04-05 14:25:53 +00:00
: < Divider > < Chip label = { t ( "Order Details" ) } / > < / D i v i d e r >
2022-01-05 02:03:03 +00:00
}
2022-04-15 16:22:49 +00:00
2022-01-03 12:11:33 +00:00
< ListItem >
2022-01-14 12:00:53 +00:00
< ListItemIcon >
2022-03-27 15:23:00 +00:00
< div style = { { zoom : 1.25 , opacity : 0.7 , '-ms-zoom' : 1.25 , '-webkit-zoom' : 1.25 , '-moz-transform' : 'scale(1.25,1.25)' , '-moz-transform-origin' : 'left center' } } >
2022-03-27 11:39:33 +00:00
{ getFlags ( this . state . currencyCode ) }
< / d i v >
2022-01-14 12:00:53 +00:00
< / L i s t I t e m I c o n >
2022-03-22 17:49:57 +00:00
{ this . state . has _range & this . state . amount == null ?
< ListItemText primary = { parseFloat ( Number ( this . state . min _amount ) . toPrecision ( 2 ) )
2022-04-05 14:25:53 +00:00
+ "-" + parseFloat ( Number ( this . state . max _amount ) . toPrecision ( 2 ) ) + " " + this . state . currencyCode } secondary = { t ( "Amount range" ) } / >
2022-03-22 17:49:57 +00:00
:
2022-01-16 18:32:34 +00:00
< ListItemText primary = { parseFloat ( parseFloat ( this . state . amount ) . toFixed ( 4 ) )
2022-04-05 14:25:53 +00:00
+ " " + this . state . currencyCode } secondary = { t ( "Amount" ) } / >
2022-03-22 17:49:57 +00:00
}
2022-01-03 12:11:33 +00:00
< / L i s t I t e m >
< Divider / >
2022-03-22 17:49:57 +00:00
2022-01-03 12:11:33 +00:00
< ListItem >
2022-01-14 12:00:53 +00:00
< ListItemIcon >
< PaymentsIcon / >
< / L i s t I t e m I c o n >
2022-04-05 14:25:53 +00:00
< ListItemText primary = { < PaymentText size = { 20 } othersText = { t ( "Others" ) } verbose = { true } text = { this . state . payment _method } / > } secondary = { this . state . currency == 1000 ? t ( "Swap destination" ) : t ( "Accepted payment methods" ) } / >
2022-01-03 12:11:33 +00:00
< / L i s t I t e m >
< Divider / >
2022-01-14 12:00:53 +00:00
{ /* If there is live Price and Premium data, show it. Otherwise show the order maker settings */ }
2022-01-03 12:11:33 +00:00
< ListItem >
2022-01-14 12:00:53 +00:00
< ListItemIcon >
< PriceChangeIcon / >
< / L i s t I t e m I c o n >
2022-04-15 16:22:49 +00:00
{ this . state . price _now ?
2022-04-05 14:25:53 +00:00
< ListItemText primary = { t ( "{{price}} {{currencyCode}}/BTC - Premium: {{premium}}%" , { price : pn ( this . state . price _now ) , currencyCode : this . state . currencyCode , premium : this . state . premium _now } ) } secondary = { t ( "Price and Premium" ) } / >
2022-01-14 12:00:53 +00:00
:
2022-04-15 16:22:49 +00:00
( this . state . is _explicit ?
2022-04-05 14:25:53 +00:00
< ListItemText primary = { pn ( this . state . satoshis ) } secondary = { t ( "Amount of Satoshis" ) } / >
2022-01-14 12:00:53 +00:00
:
2022-04-05 14:25:53 +00:00
< ListItemText primary = { parseFloat ( parseFloat ( this . state . premium ) . toFixed ( 2 ) ) + "%" } secondary = { t ( "Premium over market price" ) } / >
2022-01-14 12:00:53 +00:00
)
2022-04-15 16:22:49 +00:00
}
2022-01-03 12:11:33 +00:00
< / L i s t I t e m >
< Divider / >
2022-01-05 02:03:03 +00:00
2022-01-03 12:11:33 +00:00
< ListItem >
2022-01-14 12:00:53 +00:00
< ListItemIcon >
< NumbersIcon / >
< / L i s t I t e m I c o n >
2022-04-05 14:25:53 +00:00
< ListItemText primary = { this . orderId } secondary = { t ( "Order ID" ) } / >
2022-01-03 12:11:33 +00:00
< / L i s t I t e m >
2022-01-05 02:03:03 +00:00
< Divider / >
< ListItem >
2022-01-14 12:00:53 +00:00
< ListItemIcon >
< AccessTimeIcon / >
< / L i s t I t e m I c o n >
2022-04-05 14:25:53 +00:00
< ListItemText secondary = { t ( "Expires in" ) } >
2022-01-22 23:05:03 +00:00
< Countdown date = { new Date ( this . state . expires _at ) } renderer = { this . countdownRenderer } / >
2022-01-14 00:43:26 +00:00
< / L i s t I t e m T e x t >
2022-01-05 02:03:03 +00:00
< / L i s t I t e m >
2022-01-14 00:43:26 +00:00
< this . LinearDeterminate / >
2022-01-03 12:11:33 +00:00
< / L i s t >
2022-04-15 16:22:49 +00:00
2022-01-10 12:10:32 +00:00
{ /* If the user has a penalty/limit */ }
2022-04-15 16:22:49 +00:00
{ this . state . penalty ?
2022-01-10 12:10:32 +00:00
< >
< Divider / >
< Grid item xs = { 12 } align = "center" >
< Alert severity = "warning" sx = { { maxWidth : 360 } } >
2022-02-01 16:27:02 +00:00
< Countdown date = { new Date ( this . state . penalty ) } renderer = { this . countdownPenaltyRenderer } / >
2022-04-15 16:22:49 +00:00
< / A l e r t >
2022-01-10 12:10:32 +00:00
< / G r i d >
< / >
2022-04-15 16:22:49 +00:00
: null }
2022-01-23 19:02:25 +00:00
{ /* If the counterparty asked for collaborative cancel */ }
2022-04-15 16:22:49 +00:00
{ this . state . pending _cancel ?
2022-01-23 19:02:25 +00:00
< >
< Divider / >
< Grid item xs = { 12 } align = "center" >
< Alert severity = "warning" sx = { { maxWidth : 360 } } >
2022-04-05 14:25:53 +00:00
{ t ( "{{nickname}} is asking for a collaborative cancel" , { nickname : this . state . is _maker ? this . state . taker _nick : this . state . maker _nick } ) }
2022-04-15 16:22:49 +00:00
< / A l e r t >
2022-01-23 19:02:25 +00:00
< / G r i d >
< / >
2022-04-15 16:22:49 +00:00
: null }
2022-01-23 19:02:25 +00:00
{ /* If the user has asked for a collaborative cancel */ }
2022-04-15 16:22:49 +00:00
{ this . state . asked _for _cancel ?
2022-01-23 19:02:25 +00:00
< >
< Divider / >
< Grid item xs = { 12 } align = "center" >
< Alert severity = "warning" sx = { { maxWidth : 360 } } >
2022-04-05 14:25:53 +00:00
{ t ( "You asked for a collaborative cancellation" ) }
2022-04-15 16:22:49 +00:00
< / A l e r t >
2022-01-23 19:02:25 +00:00
< / G r i d >
< / >
2022-04-15 16:22:49 +00:00
: null }
2022-01-05 02:03:03 +00:00
2022-01-05 00:13:08 +00:00
< / P a p e r >
2022-01-08 13:08:03 +00:00
< / G r i d >
2022-04-15 16:22:49 +00:00
2022-01-23 19:02:25 +00:00
< Grid item xs = { 12 } align = "center" >
{ /* Participants can see the "Cancel" Button, but cannot see the "Back" or "Take Order" buttons */ }
2022-03-12 11:24:11 +00:00
{ this . state . is _participant ?
< >
< this . CancelButton / >
< this . BackButton / >
2022-04-15 16:22:49 +00:00
< / >
2022-01-23 19:02:25 +00:00
:
< Grid container spacing = { 1 } >
< Grid item xs = { 12 } align = "center" >
2022-02-01 16:27:02 +00:00
< Countdown date = { new Date ( this . state . penalty ) } renderer = { this . countdownTakeOrderRenderer } / >
2022-01-23 19:02:25 +00:00
< / G r i d >
< Grid item xs = { 12 } align = "center" >
2022-04-05 14:25:53 +00:00
< Button variant = 'contained' color = 'secondary' onClick = { this . props . history . goBack } > { t ( "Back" ) } < / B u t t o n >
2022-01-23 19:02:25 +00:00
< / G r i d >
2022-01-08 13:08:03 +00:00
< / G r i d >
2022-01-23 19:02:25 +00:00
}
< / G r i d >
2022-01-18 15:23:57 +00:00
< / G r i d >
2022-01-08 13:08:03 +00:00
)
}
2022-04-15 16:22:49 +00:00
2022-01-27 22:51:57 +00:00
doubleOrderPageDesktop = ( ) => {
return (
< Grid container xs = { 12 } align = "center" spacing = { 2 } >
< Grid item xs = { 6 } align = "left" style = { { width : 330 } } >
{ this . orderBox ( ) }
< / G r i d >
< Grid item xs = { 6 } align = "left" >
2022-01-31 22:42:43 +00:00
< TradeBox push = { this . props . history . push } width = { 330 } data = { this . state } completeSetState = { this . completeSetState } / >
2022-01-27 22:51:57 +00:00
< / G r i d >
< / G r i d >
)
}
2022-04-15 16:22:49 +00:00
2022-01-29 14:42:54 +00:00
a11yProps ( index ) {
return {
id : ` simple-tab- ${ index } ` ,
'aria-controls' : ` simple-tabpanel- ${ index } ` ,
} ;
}
2022-01-27 22:51:57 +00:00
doubleOrderPagePhone = ( ) => {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-29 14:42:54 +00:00
const [ value , setValue ] = React . useState ( this . state . showContractBox ) ;
2022-01-27 22:51:57 +00:00
const handleChange = ( event , newValue ) => {
2022-01-29 14:42:54 +00:00
this . setState ( { showContractBox : newValue } )
2022-01-27 22:51:57 +00:00
setValue ( newValue ) ;
} ;
return (
2022-03-24 13:41:32 +00:00
< Box sx = { { width : '100%' } } >
2022-01-27 22:51:57 +00:00
< Box sx = { { borderBottom : 1 , borderColor : 'divider' } } >
2022-01-29 14:42:54 +00:00
< Tabs value = { value } onChange = { handleChange } variant = "fullWidth" >
2022-04-05 14:25:53 +00:00
< Tab label = { t ( "Order" ) } { ... this . a11yProps ( 0 ) } / >
< Tab label = { t ( "Contract" ) } { ... this . a11yProps ( 1 ) } / >
2022-01-27 22:51:57 +00:00
< / T a b s >
< / B o x >
2022-01-29 14:42:54 +00:00
< Grid container spacing = { 2 } >
< Grid item >
< div style = { { width : 330 , display : this . state . showContractBox == 0 ? '' : 'none' } } >
{ this . orderBox ( ) }
< / d i v >
< div style = { { display : this . state . showContractBox == 1 ? '' : 'none' } } >
2022-01-31 22:42:43 +00:00
< TradeBox push = { this . props . history . push } width = { 330 } data = { this . state } completeSetState = { this . completeSetState } / >
2022-01-29 14:42:54 +00:00
< / d i v >
2022-01-27 22:51:57 +00:00
< / G r i d >
2022-01-29 14:42:54 +00:00
< / G r i d >
2022-01-27 22:51:57 +00:00
< / B o x >
) ;
}
2022-01-09 20:05:19 +00:00
orderDetailsPage ( ) {
2022-04-05 14:25:53 +00:00
const { t } = this . props ;
2022-01-09 20:05:19 +00:00
return (
2022-01-22 23:05:03 +00:00
this . state . bad _request ?
2022-01-08 13:08:03 +00:00
< div align = 'center' >
< Typography component = "subtitle2" variant = "subtitle2" color = "secondary" >
2022-04-05 14:25:53 +00:00
{ /* IMPLEMENT I18N for bad_request */ }
{ t ( this . state . bad _request ) } < br / >
2022-01-08 13:08:03 +00:00
< / T y p o g r a p h y >
2022-04-05 14:25:53 +00:00
< Button variant = 'contained' color = 'secondary' onClick = { this . props . history . goBack } > { t ( "Back" ) } < / B u t t o n >
2022-01-08 13:08:03 +00:00
< / d i v >
:
2022-04-15 16:22:49 +00:00
( this . state . is _participant ?
2022-01-27 22:51:57 +00:00
< >
{ /* Desktop View */ }
< MediaQuery minWidth = { 920 } >
< this . doubleOrderPageDesktop / >
< / M e d i a Q u e r y >
{ /* SmarPhone View */ }
< MediaQuery maxWidth = { 919 } >
< this . doubleOrderPagePhone / >
< / M e d i a Q u e r y >
< / >
2022-01-08 13:08:03 +00:00
:
2022-01-27 22:51:57 +00:00
< Grid item xs = { 12 } align = "center" style = { { width : 330 } } >
2022-01-08 13:08:03 +00:00
{ this . orderBox ( ) }
< / G r i d > )
2022-01-09 20:05:19 +00:00
)
}
render ( ) {
2022-04-15 16:22:49 +00:00
return (
2022-01-09 20:05:19 +00:00
// Only so nothing shows while requesting the first batch of data
2022-01-14 14:19:25 +00:00
this . state . loading ? < CircularProgress / > : this . orderDetailsPage ( )
2022-01-02 12:59:48 +00:00
) ;
}
2022-01-09 14:29:10 +00:00
}
2022-04-05 14:25:53 +00:00
2022-04-15 16:22:49 +00:00
export default withTranslation ( ) ( OrderPage ) ;