diff --git a/api/models.py b/api/models.py index bc7edd9f..9ad4be95 100644 --- a/api/models.py +++ b/api/models.py @@ -133,6 +133,27 @@ class Order(models.Model): maker_cancel = models.ForeignKey(LNPayment, related_name='maker_cancel', on_delete=models.SET_NULL, null=True, default=None, blank=True) taker_cancel = models.ForeignKey(LNPayment, related_name='taker_cancel', on_delete=models.SET_NULL, null=True, default=None, blank=True) + total_time_to_expire = { + 0 : int(config('EXP_MAKER_BOND_INVOICE')) , # 'Waiting for maker bond' + 1 : 60*60*int(config('PUBLIC_ORDER_DURATION')), # 'Public' + 2 : 0, # 'Deleted' + 3 : int(config('EXP_TAKER_BOND_INVOICE')), # 'Waiting for taker bond' + 4 : 0, # 'Cancelled' + 5 : 0, # 'Expired' + 6 : 60*int(config('INVOICE_AND_ESCROW_DURATION')), # 'Waiting for trade collateral and buyer invoice' + 7 : 60*int(config('INVOICE_AND_ESCROW_DURATION')), # 'Waiting only for seller trade collateral' + 8 : 60*int(config('INVOICE_AND_ESCROW_DURATION')), # 'Waiting only for buyer invoice' + 9 : 60*60*int(config('FIAT_EXCHANGE_DURATION')), # 'Sending fiat - In chatroom' + 10 : 60*60*int(config('FIAT_EXCHANGE_DURATION')), # 'Fiat sent - In chatroom' + 11 : 24*60*60, # 'In dispute' + 12 : 0, # 'Collaboratively cancelled' + 13 : 24*60*60, # 'Sending satoshis to buyer' + 14 : 24*60*60, # 'Sucessful trade' + 15 : 24*60*60, # 'Failed lightning network routing' + 16 : 24*60*60, # 'Maker lost dispute' + 17 : 24*60*60, # 'Taker lost dispute' + } + def __str__(self): # Make relational back to ORDER return (f'Order {self.id}: {self.Types(self.type).label} BTC for {float(self.amount)} {self.currency_dict[str(self.currency)]}') diff --git a/api/views.py b/api/views.py index 46dbd2d3..4d428cab 100644 --- a/api/views.py +++ b/api/views.py @@ -106,6 +106,7 @@ class OrderView(viewsets.ViewSet): return Response({'bad_request':'This order has been cancelled collaborativelly'},status.HTTP_400_BAD_REQUEST) data = ListOrderSerializer(order).data + data['total_secs_exp'] = Order.total_time_to_expire[order.status] # if user is under a limit (penalty), inform him. is_penalized, time_out = Logics.is_penalized(request.user) @@ -116,12 +117,21 @@ class OrderView(viewsets.ViewSet): data['is_maker'] = order.maker == request.user data['is_taker'] = order.taker == request.user data['is_participant'] = data['is_maker'] or data['is_taker'] - data['ur_nick'] = request.user.username - # 3) If not a participant and order is not public, forbid. + # 3.a) If not a participant and order is not public, forbid. if not data['is_participant'] and order.status != Order.Status.PUB: return Response({'bad_request':'You are not allowed to see this order'},status.HTTP_403_FORBIDDEN) + # 3.b If public + if order.status == Order.Status.PUB: + data['price_now'], data['premium_now'] = Logics.price_and_premium_now(order) + + # 3. c) If maker and Public, add num robots in book, premium percentile and num similar orders. + if data['is_maker']: + data['robots_in_book'] = None # TODO + data['premium_percentile'] = None # TODO + data['num_similar_orders'] = len(Order.objects.filter(currency=order.currency, status=Order.Status.PUB)) + # 4) Non participants can view details (but only if PUB) elif not data['is_participant'] and order.status != Order.Status.PUB: return Response(data, status=status.HTTP_200_OK) @@ -134,6 +144,7 @@ class OrderView(viewsets.ViewSet): data['status_message'] = Order.Status(order.status).label data['is_fiat_sent'] = order.is_fiat_sent data['is_disputed'] = order.is_disputed + data['ur_nick'] = request.user.username # If both bonds are locked, participants can see the final trade amount in sats. if order.taker_bond: @@ -281,14 +292,14 @@ class UserView(APIView): Response with Avatar and Nickname. ''' - # if request.user.id: - # context = {} - # context['nickname'] = request.user.username - # participant = not Logics.validate_already_maker_or_taker(request.user) - # context['bad_request'] = f'You are already logged in as {request.user}' - # if participant: - # context['bad_request'] = f'You are already logged in as as {request.user} and have an active order' - # return Response(context,status.HTTP_200_OK) + if request.user.id: + context = {} + context['nickname'] = request.user.username + participant = not Logics.validate_already_maker_or_taker(request.user) + context['bad_request'] = f'You are already logged in as {request.user}' + if participant: + context['bad_request'] = f'You are already logged in as as {request.user} and have an active order' + return Response(context,status.HTTP_200_OK) token = request.GET.get(self.lookup_url_kwarg) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 90a612e0..cf8cd9f7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1581,6 +1581,14 @@ "react-is": "^17.0.2" } }, + "@mui/icons-material": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.2.5.tgz", + "integrity": "sha512-uQiUz+l0xy+2jExyKyU19MkMAR2F7bQFcsQ5hdqAtsB14Jw2zlmIAD55mV6f0NxKCut7Rx6cA3ZpfzlzAfoK8Q==", + "requires": { + "@babel/runtime": "^7.16.3" + } + }, "@mui/material": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.2.7.tgz", diff --git a/frontend/package.json b/frontend/package.json index 15fb2128..55a83e36 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,6 +26,7 @@ "@emotion/styled": "^11.6.0", "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", + "@mui/icons-material": "^5.2.5", "@mui/material": "^5.2.7", "@mui/system": "^5.2.6", "material-ui-image": "^3.3.2", diff --git a/frontend/src/components/OrderPage.js b/frontend/src/components/OrderPage.js index f4bee0a2..5a1820c9 100644 --- a/frontend/src/components/OrderPage.js +++ b/frontend/src/components/OrderPage.js @@ -1,8 +1,15 @@ import React, { Component } from "react"; -import { Alert, Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress} from "@mui/material" +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; @@ -75,6 +82,13 @@ export default class OrderPage extends Component { 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 }) }); } @@ -106,15 +120,15 @@ export default class OrderPage extends Component { if (completed) { // Render a completed state this.getOrderDetails(); + return null; } else { var col = 'black' var fraction_left = (total/1000) / this.state.total_secs_expiry - console.log(fraction_left) - // Make orange at -25% of time left + // 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 + // 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 @@ -226,6 +240,9 @@ export default class OrderPage extends Component { "" } + + + @@ -234,28 +251,49 @@ export default class OrderPage extends Component { } + + + + + + + + {/* If there is live Price and Premium data, show it. Otherwise show the order maker settings */} - {this.state.isExplicit ? - - : - - } + + + + {this.state.priceNow? + + : + (this.state.isExplicit ? + + : + + ) + } - + + + + - + + + + diff --git a/frontend/src/components/TradeBox.js b/frontend/src/components/TradeBox.js index 450bb0a3..972d3dfe 100644 --- a/frontend/src/components/TradeBox.js +++ b/frontend/src/components/TradeBox.js @@ -163,7 +163,7 @@ export default class TradeBox extends Component { - + diff --git a/setup.md b/setup.md index caca25f6..366747dc 100644 --- a/setup.md +++ b/setup.md @@ -115,6 +115,7 @@ npm install @mui/material npm install react-markdown npm install websocket npm install react-countdown +npm install @mui/icons-material ``` Note we are using mostly MaterialUI V5 (@mui/material) but Image loading from V4 (@material-ui/core) extentions (so both V4 and V5 are needed)