2022-01-02 00:19:18 +00:00
|
|
|
import React, { Component } from "react";
|
2022-02-02 09:29:05 +00:00
|
|
|
import { 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-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-01-08 15:34:09 +00:00
|
|
|
|
2022-01-05 00:13:08 +00:00
|
|
|
function getCookie(name) {
|
|
|
|
let cookieValue = null;
|
|
|
|
if (document.cookie && document.cookie !== '') {
|
|
|
|
const cookies = document.cookie.split(';');
|
|
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
|
|
const cookie = cookies[i].trim();
|
|
|
|
// Does this cookie string begin with the name we want?
|
|
|
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
|
|
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cookieValue;
|
|
|
|
}
|
|
|
|
const csrftoken = getCookie('csrftoken');
|
|
|
|
|
2022-01-03 14:27:25 +00:00
|
|
|
// pretty numbers
|
|
|
|
function pn(x) {
|
|
|
|
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
|
|
}
|
|
|
|
|
2022-01-02 00:19:18 +00:00
|
|
|
export default 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-14 00:43:26 +00:00
|
|
|
currencies_dict: {"1":"USD"},
|
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-08 12:48:03 +00:00
|
|
|
this.getCurrencyDict();
|
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-01-23 20:23:25 +00:00
|
|
|
"0": 2000, //'Waiting for maker bond'
|
2022-01-24 18:34:52 +00:00
|
|
|
"1": 25000, //'Public'
|
2022-01-23 19:02:25 +00:00
|
|
|
"2": 9999999, //'Deleted'
|
2022-01-23 20:23:25 +00:00
|
|
|
"3": 2000, //'Waiting for taker bond'
|
2022-01-23 19:02:25 +00:00
|
|
|
"4": 9999999, //'Cancelled'
|
|
|
|
"5": 999999, //'Expired'
|
|
|
|
"6": 3000, //'Waiting for trade collateral and buyer invoice'
|
|
|
|
"7": 3000, //'Waiting only for seller trade collateral'
|
2022-01-23 20:23:25 +00:00
|
|
|
"8": 8000, //'Waiting only for buyer invoice'
|
2022-01-23 19:02:25 +00:00
|
|
|
"9": 10000, //'Sending fiat - In chatroom'
|
2022-01-23 20:23:25 +00:00
|
|
|
"10": 10000, //'Fiat sent - In chatroom'
|
|
|
|
"11": 30000, //'In dispute'
|
2022-01-23 19:02:25 +00:00
|
|
|
"12": 9999999, //'Collaboratively cancelled'
|
|
|
|
"13": 3000, //'Sending satoshis to buyer'
|
|
|
|
"14": 9999999, //'Sucessful trade'
|
|
|
|
"15": 10000, //'Failed lightning network routing'
|
|
|
|
"16": 9999999, //'Maker lost dispute'
|
|
|
|
"17": 9999999, //'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-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-01-14 00:43:26 +00:00
|
|
|
// Countdown Renderer callback with condition
|
|
|
|
countdownRenderer = ({ total, hours, minutes, seconds, completed }) => {
|
|
|
|
if (completed) {
|
|
|
|
// Render a completed state
|
2022-01-18 15:23:57 +00:00
|
|
|
return (<span> The order has expired</span>);
|
|
|
|
|
2022-01-14 00:43:26 +00:00
|
|
|
} else {
|
|
|
|
var col = 'black'
|
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 </span></b>
|
|
|
|
:<span style={{color:col}}>{hours}h {zeroPad(minutes)}m {zeroPad(seconds)}s </span>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-26 11:44:45 +00:00
|
|
|
// Countdown Renderer callback with condition
|
|
|
|
countdownPenaltyRenderer = ({ minutes, seconds, completed }) => {
|
|
|
|
if (completed) {
|
|
|
|
// Render a completed state
|
2022-01-26 18:45:24 +00:00
|
|
|
return (<span> Penalty lifted, good to go!</span>);
|
2022-01-26 11:44:45 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
return (
|
2022-02-01 16:27:02 +00:00
|
|
|
<span> You cannot take an order yet! Wait {zeroPad(minutes)}m {zeroPad(seconds)}s </span>
|
2022-01-26 11:44:45 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
2022-02-01 16:27:02 +00:00
|
|
|
|
|
|
|
countdownTakeOrderRenderer = ({ seconds, completed }) => {
|
|
|
|
if(isNaN(seconds)){
|
2022-02-03 18:27:39 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<this.InactiveMakerDialog/>
|
|
|
|
<Button variant='contained' color='primary'
|
|
|
|
onClick={this.state.maker_status=='Inactive' ? this.handleClickOpenInactiveMakerDialog : this.takeOrder}>
|
|
|
|
Take Order
|
|
|
|
</Button>
|
|
|
|
</>)
|
2022-02-01 16:27:02 +00:00
|
|
|
}
|
|
|
|
if (completed) {
|
|
|
|
// Render a completed state
|
2022-02-03 18:27:39 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<this.InactiveMakerDialog/>
|
|
|
|
<Button variant='contained' color='primary'
|
|
|
|
onClick={this.state.maker_status=='Inactive' ? this.handleClickOpenInactiveMakerDialog : this.takeOrder}>
|
|
|
|
Take Order
|
|
|
|
</Button>
|
|
|
|
</>
|
|
|
|
);
|
2022-02-01 16:27:02 +00:00
|
|
|
} else{
|
2022-02-02 09:29:05 +00:00
|
|
|
return(
|
|
|
|
<Tooltip enterTouchDelay="0" title="Wait until you can take an order"><div>
|
2022-02-03 18:27:39 +00:00
|
|
|
<Button disabled={true} variant='contained' color='primary' onClick={this.takeOrder}>Take Order</Button>
|
2022-02-02 09:29:05 +00:00
|
|
|
</div></Tooltip>)
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
clearInterval(timer);
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Box sx={{ width: '100%' }}>
|
|
|
|
<LinearProgress variant="determinate" value={progress} />
|
|
|
|
</Box>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
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-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-02-01 16:27:02 +00:00
|
|
|
|
2022-01-08 12:48:03 +00:00
|
|
|
getCurrencyDict() {
|
2022-01-09 14:29:10 +00:00
|
|
|
fetch('/static/assets/currencies.json')
|
2022-01-08 12:48:03 +00:00
|
|
|
.then((response) => response.json())
|
|
|
|
.then((data) =>
|
|
|
|
this.setState({
|
|
|
|
currencies_dict: data
|
|
|
|
}));
|
|
|
|
}
|
2022-01-09 12:35:19 +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-01-09 15:28:12 +00:00
|
|
|
let code = val ? this.state.currencies_dict[val.toString()] : ""
|
|
|
|
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 =() =>{
|
|
|
|
return(
|
|
|
|
<Dialog
|
|
|
|
open={this.state.openCancel}
|
|
|
|
onClose={this.handleClickCloseConfirmCancelDialog}
|
|
|
|
aria-labelledby="cancel-dialog-title"
|
|
|
|
aria-describedby="cancel-dialog-description"
|
|
|
|
>
|
|
|
|
<DialogTitle id="cancel-dialog-title">
|
|
|
|
{"Cancel the order?"}
|
|
|
|
</DialogTitle>
|
|
|
|
<DialogContent>
|
|
|
|
<DialogContentText id="cancel-dialog-description">
|
|
|
|
If the order is cancelled now you will lose your bond.
|
|
|
|
</DialogContentText>
|
|
|
|
</DialogContent>
|
|
|
|
<DialogActions>
|
|
|
|
<Button onClick={this.handleClickCloseConfirmCancelDialog} autoFocus>Go back</Button>
|
|
|
|
<Button onClick={this.handleClickConfirmCancelButton}> Confirm Cancel </Button>
|
|
|
|
</DialogActions>
|
|
|
|
</Dialog>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-02-03 18:27:39 +00:00
|
|
|
handleClickOpenInactiveMakerDialog = () => {
|
|
|
|
this.setState({openInactiveMaker: true});
|
|
|
|
};
|
|
|
|
handleClickCloseInactiveMakerDialog = () => {
|
|
|
|
this.setState({openInactiveMaker: false});
|
|
|
|
};
|
|
|
|
|
|
|
|
InactiveMakerDialog =() =>{
|
|
|
|
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-02-03 21:51:42 +00:00
|
|
|
{"The maker is away"}
|
2022-02-03 18:27:39 +00:00
|
|
|
</DialogTitle>
|
|
|
|
<DialogContent>
|
|
|
|
<DialogContentText id="cancel-dialog-description">
|
2022-02-03 21:51:42 +00:00
|
|
|
By taking this order you risk wasting your time.
|
2022-02-03 18:27:39 +00:00
|
|
|
</DialogContentText>
|
|
|
|
</DialogContent>
|
|
|
|
<DialogActions>
|
|
|
|
<Button onClick={this.handleClickCloseInactiveMakerDialog} autoFocus>Go back</Button>
|
|
|
|
<Button onClick={this.takeOrder}> Take Order </Button>
|
|
|
|
</DialogActions>
|
|
|
|
</Dialog>
|
|
|
|
)
|
|
|
|
}
|
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 =() =>{
|
|
|
|
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">
|
|
|
|
{"Collaborative cancel the order?"}
|
|
|
|
</DialogTitle>
|
|
|
|
<DialogContent>
|
|
|
|
<DialogContentText id="cancel-dialog-description">
|
|
|
|
The trade escrow has been posted. The order can be cancelled only if both, maker and
|
|
|
|
taker, agree to cancel.
|
|
|
|
</DialogContentText>
|
|
|
|
</DialogContent>
|
|
|
|
<DialogActions>
|
|
|
|
<Button onClick={this.handleClickCloseCollaborativeCancelDialog} autoFocus>Go back</Button>
|
2022-01-29 14:42:54 +00:00
|
|
|
<Button onClick={this.handleClickConfirmCollaborativeCancelButton}> Ask for Cancel </Button>
|
2022-01-23 19:02:25 +00:00
|
|
|
</DialogActions>
|
|
|
|
</Dialog>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-01-18 15:23:57 +00:00
|
|
|
CancelButton = () => {
|
|
|
|
|
|
|
|
// If maker and Waiting for Bond. Or if taker and Waiting for bond.
|
|
|
|
// 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">
|
|
|
|
<Button variant='contained' color='secondary' onClick={this.handleClickConfirmCancelButton}>Cancel</Button>
|
|
|
|
</Grid>
|
|
|
|
)}
|
|
|
|
// 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/>
|
|
|
|
<Button variant='contained' color='secondary' onClick={this.handleClickOpenConfirmCancelDialog}>Cancel</Button>
|
|
|
|
</Grid>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
// If the escrow is Locked, show the collaborative cancel button.
|
|
|
|
|
|
|
|
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/>
|
|
|
|
<Button variant='contained' color='secondary' onClick={this.handleClickOpenCollaborativeCancelDialog}>Collaborative Cancel</Button>
|
2022-01-18 15:23:57 +00:00
|
|
|
</Grid>
|
|
|
|
)}
|
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=()=>{
|
|
|
|
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-02-02 09:29:05 +00:00
|
|
|
Order Box
|
2022-01-27 22:51:57 +00:00
|
|
|
</Typography>
|
|
|
|
</MediaQuery>
|
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-02-03 18:06:30 +00:00
|
|
|
<Tooltip placement="top" enterTouchDelay="0" title={this.state.maker_status} >
|
|
|
|
<Badge variant="dot" overlap="circular" badgeContent="" color={this.statusBadgeColor(this.state.maker_status)}>
|
2022-01-30 19:45:37 +00:00
|
|
|
<Avatar className="flippedSmallAvatar"
|
|
|
|
alt={this.state.maker_nick}
|
|
|
|
src={window.location.origin +'/static/assets/avatars/' + this.state.maker_nick + '.png'}
|
|
|
|
/>
|
|
|
|
</Badge>
|
2022-02-02 09:29:05 +00:00
|
|
|
</Tooltip>
|
2022-01-03 12:11:33 +00:00
|
|
|
</ListItemAvatar>
|
2022-01-22 23:05:03 +00:00
|
|
|
<ListItemText primary={this.state.maker_nick + (this.state.type ? " (Seller)" : " (Buyer)")} secondary="Order maker" align="right"/>
|
2022-01-03 12:11:33 +00:00
|
|
|
</ListItem>
|
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-01-22 23:05:03 +00:00
|
|
|
<ListItemText primary={this.state.taker_nick + (this.state.type ? " (Buyer)" : " (Seller)")} secondary="Order taker"/>
|
2022-01-05 02:03:03 +00:00
|
|
|
<ListItemAvatar >
|
2022-02-03 18:27:39 +00:00
|
|
|
<Tooltip enterTouchDelay="0" title={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"
|
|
|
|
alt={this.state.taker_nick}
|
|
|
|
src={window.location.origin +'/static/assets/avatars/' + this.state.taker_nick + '.png'}
|
|
|
|
/>
|
|
|
|
</Badge>
|
2022-02-02 09:29:05 +00:00
|
|
|
</Tooltip>
|
2022-01-05 02:03:03 +00:00
|
|
|
</ListItemAvatar>
|
2022-02-02 09:29:05 +00:00
|
|
|
</ListItem>
|
2022-01-05 02:03:03 +00:00
|
|
|
</>:
|
2022-01-05 12:18:54 +00:00
|
|
|
""
|
2022-01-05 02:03:03 +00:00
|
|
|
}
|
2022-02-02 09:29:05 +00:00
|
|
|
<Divider><Chip label='Order Details'/></Divider>
|
2022-01-05 12:18:54 +00:00
|
|
|
<ListItem>
|
2022-01-14 12:00:53 +00:00
|
|
|
<ListItemIcon>
|
|
|
|
<ArticleIcon/>
|
|
|
|
</ListItemIcon>
|
2022-01-22 23:05:03 +00:00
|
|
|
<ListItemText primary={this.state.status_message} secondary="Order status"/>
|
2022-01-05 12:18:54 +00:00
|
|
|
</ListItem>
|
2022-02-02 09:29:05 +00:00
|
|
|
<Divider/>
|
2022-01-05 02:03:03 +00:00
|
|
|
</>
|
2022-02-02 09:29:05 +00:00
|
|
|
:<Divider><Chip label='Order Details'/></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>
|
2022-01-16 18:32:34 +00:00
|
|
|
{getFlags(this.state.currencyCode)}
|
2022-01-14 12:00:53 +00:00
|
|
|
</ListItemIcon>
|
2022-01-16 18:32:34 +00:00
|
|
|
<ListItemText primary={parseFloat(parseFloat(this.state.amount).toFixed(4))
|
|
|
|
+" "+this.state.currencyCode} secondary="Amount"/>
|
2022-01-03 12:11:33 +00:00
|
|
|
</ListItem>
|
|
|
|
<Divider />
|
|
|
|
<ListItem>
|
2022-01-14 12:00:53 +00:00
|
|
|
<ListItemIcon>
|
|
|
|
<PaymentsIcon/>
|
|
|
|
</ListItemIcon>
|
2022-01-22 23:05:03 +00:00
|
|
|
<ListItemText primary={this.state.payment_method} secondary="Accepted payment methods"/>
|
2022-01-03 12:11:33 +00:00
|
|
|
</ListItem>
|
|
|
|
<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/>
|
|
|
|
</ListItemIcon>
|
2022-01-22 23:05:03 +00:00
|
|
|
{this.state.price_now?
|
|
|
|
<ListItemText primary={pn(this.state.price_now)+" "+this.state.currencyCode+"/BTC - Premium: "+this.state.premium_now+"%"} secondary="Price and Premium"/>
|
2022-01-14 12:00:53 +00:00
|
|
|
:
|
2022-01-27 17:43:17 +00:00
|
|
|
(this.state.is_explicit ?
|
2022-01-14 12:00:53 +00:00
|
|
|
<ListItemText primary={pn(this.state.satoshis)} secondary="Amount of Satoshis"/>
|
|
|
|
:
|
|
|
|
<ListItemText primary={parseFloat(parseFloat(this.state.premium).toFixed(2))+"%"} secondary="Premium over market price"/>
|
|
|
|
)
|
|
|
|
}
|
2022-01-03 12:11:33 +00:00
|
|
|
</ListItem>
|
|
|
|
<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/>
|
|
|
|
</ListItemIcon>
|
|
|
|
<ListItemText primary={this.orderId} secondary="Order ID"/>
|
2022-01-03 12:11:33 +00:00
|
|
|
</ListItem>
|
2022-01-05 02:03:03 +00:00
|
|
|
<Divider />
|
|
|
|
<ListItem>
|
2022-01-14 12:00:53 +00:00
|
|
|
<ListItemIcon>
|
|
|
|
<AccessTimeIcon/>
|
|
|
|
</ListItemIcon>
|
|
|
|
<ListItemText secondary="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
|
|
|
</ListItemText>
|
2022-01-05 02:03:03 +00:00
|
|
|
</ListItem>
|
2022-01-14 00:43:26 +00:00
|
|
|
<this.LinearDeterminate />
|
2022-01-03 12:11:33 +00:00
|
|
|
</List>
|
2022-01-10 12:10:32 +00:00
|
|
|
|
|
|
|
{/* If the user has a penalty/limit */}
|
|
|
|
{this.state.penalty ?
|
|
|
|
<>
|
|
|
|
<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-01-10 12:10:32 +00:00
|
|
|
</Alert>
|
|
|
|
</Grid>
|
|
|
|
</>
|
|
|
|
: null}
|
2022-01-23 19:02:25 +00:00
|
|
|
|
|
|
|
{/* If the counterparty asked for collaborative cancel */}
|
|
|
|
{this.state.pending_cancel ?
|
|
|
|
<>
|
|
|
|
<Divider />
|
|
|
|
<Grid item xs={12} align="center">
|
|
|
|
<Alert severity="warning" sx={{maxWidth:360}}>
|
|
|
|
{this.state.is_maker ? this.state.taker_nick : this.state.maker_nick} is asking for a collaborative cancel
|
|
|
|
</Alert>
|
|
|
|
</Grid>
|
|
|
|
</>
|
|
|
|
: null}
|
|
|
|
|
|
|
|
{/* If the user has asked for a collaborative cancel */}
|
|
|
|
{this.state.asked_for_cancel ?
|
|
|
|
<>
|
|
|
|
<Divider />
|
|
|
|
<Grid item xs={12} align="center">
|
|
|
|
<Alert severity="warning" sx={{maxWidth:360}}>
|
|
|
|
You asked for a collaborative cancellation
|
|
|
|
</Alert>
|
|
|
|
</Grid>
|
|
|
|
</>
|
|
|
|
: null}
|
2022-01-05 02:03:03 +00:00
|
|
|
|
2022-01-05 00:13:08 +00:00
|
|
|
</Paper>
|
2022-01-08 13:08:03 +00:00
|
|
|
</Grid>
|
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 */}
|
|
|
|
{this.state.is_participant ?
|
|
|
|
<this.CancelButton/>
|
|
|
|
:
|
|
|
|
<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
|
|
|
</Grid>
|
|
|
|
<Grid item xs={12} align="center">
|
2022-01-31 12:53:20 +00:00
|
|
|
<Button variant='contained' color='secondary' onClick={this.props.history.goBack}>Back</Button>
|
2022-01-23 19:02:25 +00:00
|
|
|
</Grid>
|
2022-01-08 13:08:03 +00:00
|
|
|
</Grid>
|
2022-01-23 19:02:25 +00:00
|
|
|
}
|
|
|
|
</Grid>
|
2022-01-18 15:23:57 +00:00
|
|
|
</Grid>
|
2022-01-08 13:08:03 +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()}
|
|
|
|
</Grid>
|
|
|
|
<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
|
|
|
</Grid>
|
|
|
|
</Grid>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
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-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(
|
|
|
|
<Box sx={{ width: '100%' }}>
|
|
|
|
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
2022-01-29 14:42:54 +00:00
|
|
|
<Tabs value={value} onChange={handleChange} variant="fullWidth" >
|
2022-02-02 09:29:05 +00:00
|
|
|
<Tab label="Order" {...this.a11yProps(0)} />
|
|
|
|
<Tab label="Contract" {...this.a11yProps(1)} />
|
2022-01-27 22:51:57 +00:00
|
|
|
</Tabs>
|
|
|
|
</Box>
|
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()}
|
|
|
|
</div>
|
|
|
|
<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
|
|
|
</div>
|
2022-01-27 22:51:57 +00:00
|
|
|
</Grid>
|
2022-01-29 14:42:54 +00:00
|
|
|
</Grid>
|
2022-01-27 22:51:57 +00:00
|
|
|
</Box>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-09 20:05:19 +00:00
|
|
|
orderDetailsPage (){
|
|
|
|
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-01-22 23:05:03 +00:00
|
|
|
{this.state.bad_request}<br/>
|
2022-01-08 13:08:03 +00:00
|
|
|
</Typography>
|
2022-01-31 12:53:20 +00:00
|
|
|
<Button variant='contained' color='secondary' onClick={this.props.history.goBack}>Back</Button>
|
2022-01-08 13:08:03 +00:00
|
|
|
</div>
|
|
|
|
:
|
2022-01-22 23:05:03 +00:00
|
|
|
(this.state.is_participant ?
|
2022-01-27 22:51:57 +00:00
|
|
|
<>
|
|
|
|
{/* Desktop View */}
|
|
|
|
<MediaQuery minWidth={920}>
|
|
|
|
<this.doubleOrderPageDesktop/>
|
|
|
|
</MediaQuery>
|
|
|
|
|
|
|
|
{/* SmarPhone View */}
|
|
|
|
<MediaQuery maxWidth={919}>
|
|
|
|
<this.doubleOrderPagePhone/>
|
|
|
|
</MediaQuery>
|
|
|
|
</>
|
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()}
|
|
|
|
</Grid>)
|
2022-01-09 20:05:19 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
render (){
|
|
|
|
return (
|
|
|
|
// 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
|
|
|
}
|