import React, { Component } from "react"; import { Link, Paper, Rating, Button, Grid, Typography, TextField, List, ListItem, ListItemText, Divider, ListItemIcon, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle} from "@mui/material" import QRCode from "react-qr-code"; import Chat from "./Chat" // Icons import SmartToyIcon from '@mui/icons-material/SmartToy'; import PercentIcon from '@mui/icons-material/Percent'; import BookIcon from '@mui/icons-material/Book'; 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 TradeBox extends Component { constructor(props) { super(props); this.state = { openConfirmFiatReceived: false, openConfirmDispute: false, badInvoice: false, badStatement: false, } } handleClickOpenConfirmDispute = () => { this.setState({openConfirmDispute: true}); }; handleClickCloseConfirmDispute = () => { this.setState({openConfirmDispute: false}); }; handleClickAgreeDisputeButton=()=>{ const requestOptions = { method: 'POST', headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),}, body: JSON.stringify({ 'action': "dispute", }), }; fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions) .then((response) => response.json()) .then((data) => (this.props.data = data)); this.handleClickCloseConfirmDispute(); } ConfirmDisputeDialog =() =>{ return( {"Do you want to open a dispute?"} The RoboSats staff will examine the statements and evidence provided by the participants. It is best if you provide a burner contact method on your statement for the staff to contact you. The satoshis in the trade escrow will be sent to the dispute winner, while the dispute loser will lose the bond. ) } handleClickOpenConfirmFiatReceived = () => { this.setState({openConfirmFiatReceived: true}); }; handleClickCloseConfirmFiatReceived = () => { this.setState({openConfirmFiatReceived: false}); }; handleClickTotallyConfirmFiatReceived = () =>{ this.handleClickConfirmButton(); this.handleClickCloseConfirmFiatReceived(); }; ConfirmFiatReceivedDialog =() =>{ return( {"Confirm you received " +this.props.data.currencyCode+ "?"} Confirming that you received the fiat will finalize the trade. The satoshis in the escrow will be released to the buyer. Only confirm after the {this.props.data.currencyCode+ " "} has arrived to your account. In addition, if you have received {this.props.data.currencyCode+ " "} and do not confirm the receipt, you risk losing your bond. ) } showQRInvoice=()=>{ return ( Robosats show commitment to their peers {this.props.data.isMaker ? Lock {pn(this.props.data.bondSatoshis)} Sats to PUBLISH order : Lock {pn(this.props.data.bondSatoshis)} Sats to TAKE the order } ); } showBondIsLocked=()=>{ return ( πŸ”’ Your {this.props.data.isMaker ? 'maker' : 'taker'} bond is locked ); } showEscrowQRInvoice=()=>{ return ( Deposit {pn(this.props.data.escrowSatoshis)} Sats as trade collateral {this.showBondIsLocked()} ); } showTakerFound=()=>{ // TODO Make some sound here! The maker might have been waiting for long return ( A taker has been found! Please wait for the taker to confirm his commitment by locking a bond. {this.showBondIsLocked()} ); } showMakerWait=()=>{ return ( Your order is public. Wait for a taker.

Be patient while robots check the book. It might take some time. This box will ring πŸ”Š once a robot takes your order.

Please note that if your premium is too high, or if your currency or payment methods are not popular, your order might expire untaken. Your bond will return to you (no action needed).

{/* TODO API sends data for a more confortable wait */}
{this.showBondIsLocked()}
) } handleInputInvoiceChanged=(e)=>{ this.setState({ invoice: e.target.value, badInvoice: false, }); } handleClickSubmitInvoiceButton=()=>{ this.setState({badInvoice:false}); const requestOptions = { method: 'POST', headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),}, body: JSON.stringify({ 'action':'update_invoice', 'invoice': this.state.invoice, }), }; fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions) .then((response) => response.json()) .then((data) => this.setState({badInvoice:data.bad_invoice}) & console.log(data)); } handleInputDisputeChanged=(e)=>{ this.setState({ statement: e.target.value, badStatement: false, }); } handleClickSubmitStatementButton=()=>{ this.setState({badInvoice:false}); const requestOptions = { method: 'POST', headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),}, body: JSON.stringify({ 'action':'submit_statement', 'statement': this.state.statement, }), }; fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions) .then((response) => response.json()) .then((data) => this.setState({badStatement:data.bad_statement}) & console.log(data)); } showInputInvoice(){ return ( // TODO Option to upload files and images Submit a LN invoice for {pn(this.props.data.invoiceAmount)} Sats The taker is committed! Before letting you send {" "+ parseFloat(parseFloat(this.props.data.amount).toFixed(4))+ " "+ this.props.data.currencyCode}, we want to make sure you are able to receive the BTC. Please provide a valid invoice for {pn(this.props.data.invoiceAmount)} Satoshis. {this.showBondIsLocked()} ) } // Asks the user for a dispute statement. showInDisputeStatement(){ return ( // TODO Option to upload files A dispute has been opened Please, submit your statement. Be clear and specific about what happened and provide the necessary evidence. It is best to provide a burner email, XMPP or telegram username to follow up with the staff. Disputes are solved at the discretion of real robots (aka humans), so be as helpful as possible to ensure a fair outcome. Max 5000 chars. {this.showBondIsLocked()} ) } showWaitingForEscrow(){ return( Your invoice looks good!πŸŽ‰

We are waiting for the seller to deposit the full trade BTC amount into the escrow.

Just hang on for a moment. If the seller does not deposit, you will get your bond back automatically.

{this.showBondIsLocked()}
) } showWaitingForBuyerInvoice(){ return( The trade collateral is locked! πŸŽ‰

We are waiting for the buyer to post a lightning invoice. Once he does, you will be able to directly communicate the fiat payment details.

Just hang on for a moment. If the buyer does not cooperate, you will get back the trade collateral and your bond automatically.

{this.showBondIsLocked()}
) } handleClickConfirmButton=()=>{ const requestOptions = { method: 'POST', headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),}, body: JSON.stringify({ 'action': "confirm", }), }; fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions) .then((response) => response.json()) .then((data) => (this.props.data = data)); } handleRatingChange=(e)=>{ const requestOptions = { method: 'POST', headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),}, body: JSON.stringify({ 'action': "rate", 'rating': e.target.value, }), }; fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions) .then((response) => response.json()) .then((data) => (this.props.data = data)); } showFiatSentButton(){ return( ) } showFiatReceivedButton(){ return( ) } showOpenDisputeButton(){ // TODO, show alert about how opening a dispute might involve giving away personal data and might mean losing the bond. Ask for double confirmation. return( ) } showOrderExpired(){ return( The order has expired ) } showChat=()=>{ //In Chatroom - No fiat sent - showChat(showSendButton, showReveiceButton, showDisputeButton) if(this.props.data.isBuyer & this.props.data.statusCode == 9){ var showSendButton=true; var showReveiceButton=false; var showDisputeButton=true; } if(this.props.data.isSeller & this.props.data.statusCode == 9){ var showSendButton=false; var showReveiceButton=false; var showDisputeButton=true; } //In Chatroom - Fiat sent - showChat(showSendButton, showReveiceButton, showDisputeButton) if(this.props.data.isBuyer & this.props.data.statusCode == 10){ var showSendButton=false; var showReveiceButton=false; var showDisputeButton=true; } if(this.props.data.isSeller & this.props.data.statusCode == 10){ var showSendButton=false; var showReveiceButton=true; var showDisputeButton=true; } return( Chatting with {this.props.data.isMaker ? this.props.data.takerNick : this.props.data.makerNick} {this.props.data.isSeller ? Say hi! Be helpful and concise. Let them know how to send you {this.props.data.currencyCode}. : Say hi! Ask for payment details and click "Confirm Sent" as soon as the payment is sent. } {showDisputeButton ? this.showOpenDisputeButton() : ""} {showSendButton ? this.showFiatSentButton() : ""} {showReveiceButton ? this.showFiatReceivedButton() : ""} {this.showBondIsLocked()} ) } showRateSelect(){ return( πŸŽ‰Trade finished!πŸ₯³ What do you think of {this.props.data.isMaker ? this.props.data.takerNick : this.props.data.makerNick}? ) } render() { return ( Contract Box {/* Maker and taker Bond request */} {this.props.data.bondInvoice ? this.showQRInvoice() : ""} {/* Waiting for taker and taker bond request */} {this.props.data.isMaker & this.props.data.statusCode == 1 ? this.showMakerWait() : ""} {this.props.data.isMaker & this.props.data.statusCode == 3 ? this.showTakerFound() : ""} {/* Send Invoice (buyer) and deposit collateral (seller) */} {this.props.data.isSeller & this.props.data.escrowInvoice != null ? this.showEscrowQRInvoice() : ""} {this.props.data.isBuyer & this.props.data.invoiceAmount != null ? this.showInputInvoice() : ""} {this.props.data.isBuyer & this.props.data.statusCode == 7 ? this.showWaitingForEscrow() : ""} {this.props.data.isSeller & this.props.data.statusCode == 8 ? this.showWaitingForBuyerInvoice() : ""} {/* In Chatroom */} {this.props.data.statusCode == 9 || this.props.data.statusCode == 10 ? this.showChat(): ""} {/* Trade Finished */} {(this.props.data.isSeller & this.props.data.statusCode > 12 & this.props.data.statusCode < 15) ? this.showRateSelect() : ""} {(this.props.data.isBuyer & this.props.data.statusCode == 14) ? this.showRateSelect() : ""} {/* Trade Finished - Payment Routing Failed */} {this.props.data.isBuyer & this.props.data.statusCode == 15 ? this.showUpdateInvoice() : ""} {/* Trade Finished - TODO Needs more planning */} {this.props.data.statusCode == 11 ? this.showInDisputeStatement() : ""} {/* Order has expired */} {this.props.data.statusCode == 5 ? this.showOrderExpired() : ""} {/* TODO */} {/* */} {/* */} ); } }