mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-31 02:21:35 +00:00
Add UI info and icons on order pager
This commit is contained in:
parent
abb1bdd0be
commit
135c4c59e5
@ -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)]}')
|
||||
|
31
api/views.py
31
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)
|
||||
|
||||
|
8
frontend/package-lock.json
generated
8
frontend/package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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 ? <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>
|
||||
@ -226,6 +240,9 @@ export default class OrderPage extends Component {
|
||||
""
|
||||
}
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<ArticleIcon/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={this.state.statusText} secondary="Order status"/>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
@ -234,28 +251,49 @@ export default class OrderPage extends Component {
|
||||
}
|
||||
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<MoneyIcon/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={parseFloat(parseFloat(this.state.amount).toFixed(4))+" "+this.state.currencyCode} secondary="Amount"/>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<PaymentsIcon/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={this.state.paymentMethod} secondary="Accepted payment methods"/>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
|
||||
{/* If there is live Price and Premium data, show it. Otherwise show the order maker settings */}
|
||||
<ListItem>
|
||||
{this.state.isExplicit ?
|
||||
<ListItemText primary={pn(this.state.satoshis)} secondary="Amount of Satoshis"/>
|
||||
:
|
||||
<ListItemText primary={parseFloat(parseFloat(this.state.premium).toFixed(2))+"%"} secondary="Premium over market price"/>
|
||||
}
|
||||
<ListItemIcon>
|
||||
<PriceChangeIcon/>
|
||||
</ListItemIcon>
|
||||
{this.state.priceNow?
|
||||
<ListItemText primary={pn(this.state.priceNow)+" "+this.state.currencyCode+"/BTC - Premium: "+this.state.premiumNow+"%"} secondary="Price and Premium"/>
|
||||
:
|
||||
(this.state.isExplicit ?
|
||||
<ListItemText primary={pn(this.state.satoshis)} secondary="Amount of Satoshis"/>
|
||||
:
|
||||
<ListItemText primary={parseFloat(parseFloat(this.state.premium).toFixed(2))+"%"} secondary="Premium over market price"/>
|
||||
)
|
||||
}
|
||||
</ListItem>
|
||||
<Divider />
|
||||
|
||||
<ListItem>
|
||||
<ListItemText primary={'#'+this.orderId} secondary="Order ID"/>
|
||||
<ListItemIcon>
|
||||
<NumbersIcon/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={this.orderId} secondary="Order ID"/>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem>
|
||||
<ListItemText secondary="Expires">
|
||||
<ListItemIcon>
|
||||
<AccessTimeIcon/>
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Expires in">
|
||||
<Countdown onTick={console.log(this.seconds)} date={new Date(this.state.expiresAt)} renderer={this.countdownRenderer} />
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
@ -163,7 +163,7 @@ export default class TradeBox extends Component {
|
||||
|
||||
<Divider/>
|
||||
<ListItem>
|
||||
<ListItemText primary={999} secondary={"Active orders for " + this.props.data.currencyCode}/>
|
||||
<ListItemText primary={this.props.data.numSimilarOrders} secondary={"Public orders for " + this.props.data.currencyCode}/>
|
||||
</ListItem>
|
||||
|
||||
<Divider/>
|
||||
|
1
setup.md
1
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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user