import React, { Component } from "react"; import { Alert, Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemIcon, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress} from "@mui/material" import Countdown, { zeroPad, calcTimeDelta } from 'react-countdown'; import TradeBox from "./TradeBox"; // 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 MoneyIcon from '@mui/icons-material/Money'; import ArticleIcon from '@mui/icons-material/Article'; 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'); // pretty numbers function pn(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } export default class OrderPage extends Component { constructor(props) { super(props); this.state = { isExplicit: false, delay: 60000, // Refresh every 60 seconds by default currencies_dict: {"1":"USD"}, total_secs_expiry: 300, loading: true, }; this.orderId = this.props.match.params.orderId; this.getCurrencyDict(); this.getOrderDetails(); // Change refresh delay according to Order status this.statusToDelay = { "0": 3000, //'Waiting for maker bond' "1": 30000, //'Public' "2": 9999999, //'Deleted' "3": 3000, //'Waiting for taker bond' "4": 9999999, //'Cancelled' "5": 999999, //'Expired' "6": 3000, //'Waiting for trade collateral and buyer invoice' "7": 3000, //'Waiting only for seller trade collateral' "8": 10000, //'Waiting only for buyer invoice' "9": 10000, //'Sending fiat - In chatroom' "10": 15000, //'Fiat sent - In chatroom' "11": 300000, //'In dispute' "12": 9999999,//'Collaboratively cancelled' "13": 120000, //'Sending satoshis to buyer' "14": 9999999,//'Sucessful trade' "15": 10000, //'Failed lightning network routing' "16": 9999999,//'Maker lost dispute' "17": 9999999,//'Taker lost dispute' } } getOrderDetails() { this.setState(null) fetch('/api/order' + '?order_id=' + this.orderId) .then((response) => response.json()) .then((data) => {console.log(data) & this.setState({ loading: false, delay: this.setDelay(data.status), id: data.id, statusCode: data.status, statusText: data.status_message, type: data.type, currency: data.currency, currencyCode: this.getCurrencyCode(data.currency), amount: data.amount, paymentMethod: data.payment_method, isExplicit: data.is_explicit, premium: data.premium, satoshis: data.satoshis, makerId: data.maker, isParticipant: data.is_participant, urNick: data.ur_nick, makerNick: data.maker_nick, takerId: data.taker, takerNick: data.taker_nick, isMaker: data.is_maker, isTaker: data.is_taker, isBuyer: data.is_buyer, isSeller: data.is_seller, penalty: data.penalty, expiresAt: data.expires_at, badRequest: data.bad_request, bondInvoice: data.bond_invoice, bondSatoshis: data.bond_satoshis, escrowInvoice: data.escrow_invoice, escrowSatoshis: data.escrow_satoshis, invoiceAmount: data.invoice_amount, total_secs_expiry: data.total_secs_exp, numSimilarOrders: data.num_similar_orders, priceNow: data.price_now, premiumNow: data.premium_now, robotsInBook: data.robots_in_book, premiumPercentile: data.premium_percentile, numSimilarOrders: data.num_similar_orders }) }); } // These are used to refresh the data componentDidMount() { this.interval = setInterval(this.tick, this.state.delay); } componentDidUpdate() { clearInterval(this.interval); this.interval = setInterval(this.tick, this.state.delay); } componentWillUnmount() { clearInterval(this.interval); } tick = () => { this.getOrderDetails(); } // Fix to use proper react props handleClickBackButton=()=>{ window.history.back(); } // Countdown Renderer callback with condition countdownRenderer = ({ total, hours, minutes, seconds, completed }) => { if (completed) { // Render a completed state this.getOrderDetails(); return null; } else { var col = 'black' var fraction_left = (total/1000) / this.state.total_secs_expiry // Make orange at 25% of time left if (fraction_left < 0.25){col = 'orange'} // Make red at 10% of time left if (fraction_left < 0.1){col = 'red'} // Render a countdown, bold when less than 25% return ( fraction_left < 0.25 ? {hours}h {zeroPad(minutes)}m {zeroPad(seconds)}s :{hours}h {zeroPad(minutes)}m {zeroPad(seconds)}s ); } }; LinearDeterminate =()=> { const [progress, setProgress] = React.useState(0); React.useEffect(() => { const timer = setInterval(() => { setProgress((oldProgress) => { var left = calcTimeDelta( new Date(this.state.expiresAt)).total /1000; return (left / this.state.total_secs_expiry) * 100; }); }, 1000); return () => { clearInterval(timer); }; }, []); return ( ); } handleClickTakeOrderButton=()=>{ console.log(this.state) const requestOptions = { method: 'POST', headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),}, body: JSON.stringify({ 'action':'take', }), }; fetch('/api/order/' + '?order_id=' + this.orderId, requestOptions) .then((response) => response.json()) .then((data) => (this.setState({badRequest:data.bad_request}) & console.log(data) & this.getOrderDetails(data.id))); } getCurrencyDict() { fetch('/static/assets/currencies.json') .then((response) => response.json()) .then((data) => this.setState({ currencies_dict: data })); } // set delay to the one matching the order status. If no order status, set delay to 9999999 setDelay(val){ return val ? this.statusToDelay[val.toString()] : 99999999; } getCurrencyCode(val){ let code = val ? this.state.currencies_dict[val.toString()] : "" return code } handleClickCancelOrderButton=()=>{ console.log(this.state) 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) => (console.log(data) & this.getOrderDetails(data.id))); } orderBox=()=>{ return( {this.state.type ? "Sell " : "Buy "} Order Details {this.state.isParticipant ? <> {this.state.takerNick!='None' ? <> : "" } :"" } {/* If there is live Price and Premium data, show it. Otherwise show the order maker settings */} {this.state.priceNow? : (this.state.isExplicit ? : ) } {/* If the user has a penalty/limit */} {this.state.penalty ? <> You cannot take an order yet! Wait {this.state.penalty} seconds : null} {/* Participants cannot see the Back or Take Order buttons */} {this.state.isParticipant ? "" : <> } {/* Makers can cancel before trade escrow deposited (status <9)*/} {/* Only free cancel before bond locked (status 0)*/} {this.state.isMaker & this.state.statusCode < 9 ? :""} {this.state.isMaker & this.state.statusCode > 0 & this.state.statusCode < 9 ? Cancelling now forfeits the maker bond :""} {/* Takers can cancel before commiting the bond (status 3)*/} {this.state.isTaker & this.state.statusCode == 3 ? :""} ) } orderDetailsPage (){ return( this.state.badRequest ?
{this.state.badRequest}
: (this.state.isParticipant ? {this.orderBox()} : {this.orderBox()} ) ) } render (){ return ( // Only so nothing shows while requesting the first batch of data this.state.loading ? : this.orderDetailsPage() ); } }