mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 20:21:35 +00:00
Implement backend handle range amounts, order take amount input and order book ranges
This commit is contained in:
parent
bf80986005
commit
8ae2406275
10
api/admin.py
10
api/admin.py
@ -46,7 +46,7 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
|
|||||||
"maker_link",
|
"maker_link",
|
||||||
"taker_link",
|
"taker_link",
|
||||||
"status",
|
"status",
|
||||||
"amount",
|
"amt",
|
||||||
"currency_link",
|
"currency_link",
|
||||||
"t0_satoshis",
|
"t0_satoshis",
|
||||||
"is_disputed",
|
"is_disputed",
|
||||||
@ -69,7 +69,13 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
|
|||||||
"trade_escrow",
|
"trade_escrow",
|
||||||
)
|
)
|
||||||
list_filter = ("is_disputed", "is_fiat_sent", "type", "currency", "status")
|
list_filter = ("is_disputed", "is_fiat_sent", "type", "currency", "status")
|
||||||
search_fields = ["id","amount"]
|
search_fields = ["id","amount","min_amount","max_amount"]
|
||||||
|
|
||||||
|
def amt(self, obj):
|
||||||
|
if obj.has_range and obj.amount == None:
|
||||||
|
return str(float(obj.min_amount))+"-"+ str(float(obj.max_amount))
|
||||||
|
else:
|
||||||
|
return float(obj.amount)
|
||||||
|
|
||||||
@admin.register(LNPayment)
|
@admin.register(LNPayment)
|
||||||
class LNPaymentAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
|
class LNPaymentAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
|
||||||
|
@ -118,16 +118,16 @@ class Logics:
|
|||||||
elif max_sats > MAX_TRADE:
|
elif max_sats > MAX_TRADE:
|
||||||
return False, {
|
return False, {
|
||||||
"bad_request":
|
"bad_request":
|
||||||
"Your order upper range value (max_amount) is too big. It is worth " +
|
"Your order maximum amount is too big. It is worth " +
|
||||||
"{:,}".format(max_sats) +
|
"{:,}".format(int(max_sats)) +
|
||||||
" Sats now, but the limit is " + "{:,}".format(MAX_TRADE) +
|
" Sats now, but the limit is " + "{:,}".format(MAX_TRADE) +
|
||||||
" Sats"
|
" Sats"
|
||||||
}
|
}
|
||||||
elif min_sats < MIN_TRADE:
|
elif min_sats < MIN_TRADE:
|
||||||
return False, {
|
return False, {
|
||||||
"bad_request":
|
"bad_request":
|
||||||
"Your order lower range value (min_mount) is too small. It is worth " +
|
"Your order minimum amount is too small. It is worth " +
|
||||||
"{:,}".format(min_sats) +
|
"{:,}".format(int(min_sats)) +
|
||||||
" Sats now, but the limit is " + "{:,}".format(MAX_TRADE) +
|
" Sats now, but the limit is " + "{:,}".format(MAX_TRADE) +
|
||||||
" Sats"
|
" Sats"
|
||||||
}
|
}
|
||||||
@ -139,6 +139,15 @@ class Logics:
|
|||||||
|
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
|
def validate_amount_within_range(order, amount):
|
||||||
|
if amount > float(order.max_amount) or amount < float(order.min_amount):
|
||||||
|
return False, {
|
||||||
|
"bad_request":
|
||||||
|
"The amount specified is outside the range specified by the maker"
|
||||||
|
}
|
||||||
|
|
||||||
|
return True, None
|
||||||
|
|
||||||
def user_activity_status(last_seen):
|
def user_activity_status(last_seen):
|
||||||
if last_seen > (timezone.now() - timedelta(minutes=2)):
|
if last_seen > (timezone.now() - timedelta(minutes=2)):
|
||||||
return "Active"
|
return "Active"
|
||||||
@ -148,7 +157,7 @@ class Logics:
|
|||||||
return "Inactive"
|
return "Inactive"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def take(cls, order, user):
|
def take(cls, order, user, amount=None):
|
||||||
is_penalized, time_out = cls.is_penalized(user)
|
is_penalized, time_out = cls.is_penalized(user)
|
||||||
if is_penalized:
|
if is_penalized:
|
||||||
return False, {
|
return False, {
|
||||||
@ -156,6 +165,8 @@ class Logics:
|
|||||||
f"You need to wait {time_out} seconds to take an order",
|
f"You need to wait {time_out} seconds to take an order",
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
|
if order.has_range:
|
||||||
|
order.amount= amount
|
||||||
order.taker = user
|
order.taker = user
|
||||||
order.status = Order.Status.TAK
|
order.status = Order.Status.TAK
|
||||||
order.expires_at = timezone.now() + timedelta(
|
order.expires_at = timezone.now() + timedelta(
|
||||||
@ -702,6 +713,8 @@ class Logics:
|
|||||||
order.status = Order.Status.PUB
|
order.status = Order.Status.PUB
|
||||||
order.expires_at = order.created_at + timedelta(
|
order.expires_at = order.created_at + timedelta(
|
||||||
seconds=order.t_to_expire(Order.Status.PUB))
|
seconds=order.t_to_expire(Order.Status.PUB))
|
||||||
|
if order.has_range:
|
||||||
|
order.amount = None
|
||||||
order.save()
|
order.save()
|
||||||
# send_message.delay(order.id,'order_published') # too spammy
|
# send_message.delay(order.id,'order_published') # too spammy
|
||||||
return
|
return
|
||||||
|
@ -339,7 +339,11 @@ class Order(models.Model):
|
|||||||
taker_platform_rated = models.BooleanField(default=False, null=False)
|
taker_platform_rated = models.BooleanField(default=False, null=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Order {self.id}: {self.Types(self.type).label} BTC for {float(self.amount)} {self.currency}"
|
if self.has_range and self.amount == None:
|
||||||
|
amt = str(float(self.min_amount))+"-"+ str(float(self.max_amount))
|
||||||
|
else:
|
||||||
|
amt = float(self.amount)
|
||||||
|
return f"Order {self.id}: {self.Types(self.type).label} BTC for {amt} {self.currency}"
|
||||||
|
|
||||||
def t_to_expire(self, status):
|
def t_to_expire(self, status):
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class ListOrderSerializer(serializers.ModelSerializer):
|
|||||||
"is_explicit",
|
"is_explicit",
|
||||||
"premium",
|
"premium",
|
||||||
"satoshis",
|
"satoshis",
|
||||||
"bondless_taker"
|
"bondless_taker",
|
||||||
"maker",
|
"maker",
|
||||||
"taker",
|
"taker",
|
||||||
)
|
)
|
||||||
@ -75,6 +75,7 @@ class UpdateOrderSerializer(serializers.Serializer):
|
|||||||
allow_blank=True,
|
allow_blank=True,
|
||||||
default=None,
|
default=None,
|
||||||
)
|
)
|
||||||
|
amount = serializers.DecimalField(max_digits=18, decimal_places=8, allow_null=True, required=False, default=None)
|
||||||
|
|
||||||
class ClaimRewardSerializer(serializers.Serializer):
|
class ClaimRewardSerializer(serializers.Serializer):
|
||||||
invoice = serializers.CharField(max_length=2000,
|
invoice = serializers.CharField(max_length=2000,
|
||||||
|
14
api/views.py
14
api/views.py
@ -390,6 +390,10 @@ class OrderView(viewsets.ViewSet):
|
|||||||
"""
|
"""
|
||||||
order_id = request.GET.get(self.lookup_url_kwarg)
|
order_id = request.GET.get(self.lookup_url_kwarg)
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.stdout.write('AAAAAA')
|
||||||
|
print('BBBBB1')
|
||||||
|
|
||||||
serializer = UpdateOrderSerializer(data=request.data)
|
serializer = UpdateOrderSerializer(data=request.data)
|
||||||
if not serializer.is_valid():
|
if not serializer.is_valid():
|
||||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||||
@ -410,6 +414,16 @@ class OrderView(viewsets.ViewSet):
|
|||||||
request.user)
|
request.user)
|
||||||
if not valid:
|
if not valid:
|
||||||
return Response(context, status=status.HTTP_409_CONFLICT)
|
return Response(context, status=status.HTTP_409_CONFLICT)
|
||||||
|
|
||||||
|
# For order with amount range, set the amount now.
|
||||||
|
if order.has_range:
|
||||||
|
amount = float(serializer.data.get("amount"))
|
||||||
|
valid, context = Logics.validate_amount_within_range(order, amount)
|
||||||
|
if not valid:
|
||||||
|
return Response(context, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
valid, context = Logics.take(order, request.user, amount)
|
||||||
|
else:
|
||||||
valid, context = Logics.take(order, request.user)
|
valid, context = Logics.take(order, request.user)
|
||||||
if not valid:
|
if not valid:
|
||||||
return Response(context, status=status.HTTP_403_FORBIDDEN)
|
return Response(context, status=status.HTTP_403_FORBIDDEN)
|
||||||
|
@ -78,6 +78,15 @@ export default class BookPage extends Component {
|
|||||||
if(status=='Seen recently'){return("warning")}
|
if(status=='Seen recently'){return("warning")}
|
||||||
if(status=='Inactive'){return('error')}
|
if(status=='Inactive'){return('error')}
|
||||||
}
|
}
|
||||||
|
amountToString = (amount,has_range,min_amount,max_amount) => {
|
||||||
|
if (has_range){
|
||||||
|
console.log(this.pn(parseFloat(Number(min_amount).toPrecision(2))))
|
||||||
|
console.log(this.pn(parseFloat(Number(min_amount).toPrecision(2)))+'-'+this.pn(parseFloat(Number(max_amount).toPrecision(2))))
|
||||||
|
return this.pn(parseFloat(Number(min_amount).toPrecision(2)))+'-'+this.pn(parseFloat(Number(max_amount).toPrecision(2)))
|
||||||
|
}else{
|
||||||
|
return this.pn(parseFloat(Number(amount).toPrecision(3)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bookListTableDesktop=()=>{
|
bookListTableDesktop=()=>{
|
||||||
return (
|
return (
|
||||||
@ -90,7 +99,10 @@ export default class BookPage extends Component {
|
|||||||
robot: order.maker_nick,
|
robot: order.maker_nick,
|
||||||
robot_status: order.maker_status,
|
robot_status: order.maker_status,
|
||||||
type: order.type ? "Seller": "Buyer",
|
type: order.type ? "Seller": "Buyer",
|
||||||
amount: parseFloat(parseFloat(order.amount).toFixed(5)),
|
amount: order.amount,
|
||||||
|
has_range: order.has_range,
|
||||||
|
min_amount: order.min_amount,
|
||||||
|
max_amount: order.max_amount,
|
||||||
currency: this.getCurrencyCode(order.currency),
|
currency: this.getCurrencyCode(order.currency),
|
||||||
payment_method: order.payment_method,
|
payment_method: order.payment_method,
|
||||||
price: order.price,
|
price: order.price,
|
||||||
@ -123,9 +135,9 @@ export default class BookPage extends Component {
|
|||||||
);
|
);
|
||||||
} },
|
} },
|
||||||
{ field: 'type', headerName: 'Is', width: 60 },
|
{ field: 'type', headerName: 'Is', width: 60 },
|
||||||
{ field: 'amount', headerName: 'Amount', type: 'number', width: 80,
|
{ field: 'amount', headerName: 'Amount', type: 'number', width: 90,
|
||||||
renderCell: (params) => {return (
|
renderCell: (params) => {return (
|
||||||
<div style={{ cursor: "pointer" }}>{this.pn(params.row.amount)}</div>
|
<div style={{ cursor: "pointer" }}>{this.amountToString(params.row.amount,params.row.has_range, params.row.min_amount, params.row.max_amount)}</div>
|
||||||
)}},
|
)}},
|
||||||
{ field: 'currency', headerName: 'Currency', width: 100,
|
{ field: 'currency', headerName: 'Currency', width: 100,
|
||||||
renderCell: (params) => {return (
|
renderCell: (params) => {return (
|
||||||
@ -163,7 +175,10 @@ export default class BookPage extends Component {
|
|||||||
robot: order.maker_nick,
|
robot: order.maker_nick,
|
||||||
robot_status: order.maker_status,
|
robot_status: order.maker_status,
|
||||||
type: order.type ? "Seller": "Buyer",
|
type: order.type ? "Seller": "Buyer",
|
||||||
amount: parseFloat(parseFloat(order.amount).toFixed(4)),
|
amount: order.amount,
|
||||||
|
has_range: order.has_range,
|
||||||
|
min_amount: order.min_amount,
|
||||||
|
max_amount: order.max_amount,
|
||||||
currency: this.getCurrencyCode(order.currency),
|
currency: this.getCurrencyCode(order.currency),
|
||||||
payment_method: order.payment_method,
|
payment_method: order.payment_method,
|
||||||
price: order.price,
|
price: order.price,
|
||||||
@ -191,10 +206,10 @@ export default class BookPage extends Component {
|
|||||||
);
|
);
|
||||||
} },
|
} },
|
||||||
{ field: 'type', headerName: 'Is', width: 60, hide:'true'},
|
{ field: 'type', headerName: 'Is', width: 60, hide:'true'},
|
||||||
{ field: 'amount', headerName: 'Amount', type: 'number', width: 80,
|
{ field: 'amount', headerName: 'Amount', type: 'number', width: 90,
|
||||||
renderCell: (params) => {return (
|
renderCell: (params) => {return (
|
||||||
<Tooltip placement="right" enterTouchDelay="0" title={params.row.type}>
|
<Tooltip placement="right" enterTouchDelay="0" title={params.row.type}>
|
||||||
<div style={{ cursor: "pointer" }}>{this.pn(params.row.amount)}</div>
|
<div style={{ cursor: "pointer" }}>{this.amountToString(params.row.amount,params.row.has_range, params.row.min_amount, params.row.max_amount)}</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)} },
|
)} },
|
||||||
{ field: 'currency', headerName: 'Currency', width: 100,
|
{ field: 'currency', headerName: 'Currency', width: 100,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { LinearProgress, Checkbox, Slider, Switch, Tooltip, Paper, Button , Grid, Typography, TextField, Select, FormHelperText, MenuItem, FormControl, Radio, FormControlLabel, RadioGroup} from "@mui/material"
|
import { LinearProgress, Checkbox, Slider, SliderThumb, Switch, Tooltip, Paper, Button , Grid, Typography, TextField, Select, FormHelperText, MenuItem, FormControl, Radio, FormControlLabel, RadioGroup} from "@mui/material"
|
||||||
import { LocalizationProvider, TimePicker} from '@mui/lab';
|
import { LocalizationProvider, TimePicker} from '@mui/lab';
|
||||||
import DateFnsUtils from "@date-io/date-fns";
|
import DateFnsUtils from "@date-io/date-fns";
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
import getFlags from './getFlags'
|
import getFlags from './getFlags'
|
||||||
|
|
||||||
import LockIcon from '@mui/icons-material/Lock';
|
import LockIcon from '@mui/icons-material/Lock';
|
||||||
import SelfImprovementIcon from '@mui/icons-material/SelfImprovement';
|
|
||||||
|
|
||||||
function getCookie(name) {
|
function getCookie(name) {
|
||||||
let cookieValue = null;
|
let cookieValue = null;
|
||||||
@ -43,8 +43,8 @@ export default class MakerPage extends Component {
|
|||||||
minTradeSats = 20000;
|
minTradeSats = 20000;
|
||||||
maxTradeSats = 800000;
|
maxTradeSats = 800000;
|
||||||
maxBondlessSats = 50000;
|
maxBondlessSats = 50000;
|
||||||
maxRangeAmountMultiple = 5;
|
maxRangeAmountMultiple = 4.9;
|
||||||
minRangeAmountMultiple = 1.5;
|
minRangeAmountMultiple = 1.6;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -79,9 +79,8 @@ export default class MakerPage extends Component {
|
|||||||
limits:data,
|
limits:data,
|
||||||
loadingLimits:false,
|
loadingLimits:false,
|
||||||
minAmount: parseFloat(Number(data[this.state.currency]['max_amount']*0.25).toPrecision(2)),
|
minAmount: parseFloat(Number(data[this.state.currency]['max_amount']*0.25).toPrecision(2)),
|
||||||
maxAmount: parseFloat(Number(data[this.state.currency]['max_amount']*0.75).toPrecision(2))
|
maxAmount: parseFloat(Number(data[this.state.currency]['max_amount']*0.75).toPrecision(2)),
|
||||||
})
|
}));
|
||||||
& console.log(this.state.limits));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTypeChange=(e)=>{
|
handleTypeChange=(e)=>{
|
||||||
@ -94,6 +93,12 @@ export default class MakerPage extends Component {
|
|||||||
currency: e.target.value,
|
currency: e.target.value,
|
||||||
currencyCode: this.getCurrencyCode(e.target.value),
|
currencyCode: this.getCurrencyCode(e.target.value),
|
||||||
});
|
});
|
||||||
|
if(this.state.enableAmountRange){
|
||||||
|
this.setState({
|
||||||
|
minAmount: parseFloat(Number(this.state.limits[e.target.value]['max_amount']*0.25).toPrecision(2)),
|
||||||
|
maxAmount: parseFloat(Number(this.state.limits[e.target.value]['max_amount']*0.75).toPrecision(2)),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
handleAmountChange=(e)=>{
|
handleAmountChange=(e)=>{
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -101,7 +106,7 @@ export default class MakerPage extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRangeAmountChange = (e, activeThumb) => {
|
handleRangeAmountChange = (e, newValue, activeThumb) => {
|
||||||
var maxAmount = this.getMaxAmount();
|
var maxAmount = this.getMaxAmount();
|
||||||
var minAmount = this.getMinAmount();
|
var minAmount = this.getMinAmount();
|
||||||
var lowerValue = e.target.value[0];
|
var lowerValue = e.target.value[0];
|
||||||
@ -379,7 +384,6 @@ export default class MakerPage extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChangePublicDuration = (date) => {
|
handleChangePublicDuration = (date) => {
|
||||||
console.log(date)
|
|
||||||
let d = new Date(date),
|
let d = new Date(date),
|
||||||
hours = d.getHours(),
|
hours = d.getHours(),
|
||||||
minutes = d.getMinutes();
|
minutes = d.getMinutes();
|
||||||
@ -401,7 +405,8 @@ export default class MakerPage extends Component {
|
|||||||
}else{
|
}else{
|
||||||
var max_amount = this.state.limits[this.state.currency]['max_amount']
|
var max_amount = this.state.limits[this.state.currency]['max_amount']
|
||||||
}
|
}
|
||||||
return parseFloat(Number(max_amount).toPrecision(2))
|
// times 0.98 to allow a bit of margin with respect to the backend minimum
|
||||||
|
return parseFloat(Number(max_amount*0.98).toPrecision(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
getMinAmount = () => {
|
getMinAmount = () => {
|
||||||
@ -410,9 +415,51 @@ export default class MakerPage extends Component {
|
|||||||
}else{
|
}else{
|
||||||
var min_amount = this.state.limits[this.state.currency]['min_amount']
|
var min_amount = this.state.limits[this.state.currency]['min_amount']
|
||||||
}
|
}
|
||||||
return parseFloat(Number(min_amount).toPrecision(2))
|
// times 1.1 to allow a bit of margin with respect to the backend minimum
|
||||||
|
return parseFloat(Number(min_amount*1.1).toPrecision(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RangeSlider = styled(Slider)(({ theme }) => ({
|
||||||
|
color: 'primary',
|
||||||
|
height: 3,
|
||||||
|
padding: '13px 0',
|
||||||
|
'& .MuiSlider-thumb': {
|
||||||
|
height: 27,
|
||||||
|
width: 27,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
border: '1px solid currentColor',
|
||||||
|
'&:hover': {
|
||||||
|
boxShadow: '0 0 0 8px rgba(58, 133, 137, 0.16)',
|
||||||
|
},
|
||||||
|
'& .range-bar': {
|
||||||
|
height: 9,
|
||||||
|
width: 1,
|
||||||
|
backgroundColor: 'currentColor',
|
||||||
|
marginLeft: 1,
|
||||||
|
marginRight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'& .MuiSlider-track': {
|
||||||
|
height: 3,
|
||||||
|
},
|
||||||
|
'& .MuiSlider-rail': {
|
||||||
|
color: theme.palette.mode === 'dark' ? '#bfbfbf' : '#d8d8d8',
|
||||||
|
opacity: theme.palette.mode === 'dark' ? undefined : 1,
|
||||||
|
height: 3,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
RangeThumbComponent(props) {
|
||||||
|
const { children, ...other } = props;
|
||||||
|
return (
|
||||||
|
<SliderThumb {...other}>
|
||||||
|
{children}
|
||||||
|
<span className="range-bar" />
|
||||||
|
<span className="range-bar" />
|
||||||
|
<span className="range-bar" />
|
||||||
|
</SliderThumb>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
AdvancedMakerOptions = () => {
|
AdvancedMakerOptions = () => {
|
||||||
return(
|
return(
|
||||||
@ -422,26 +469,38 @@ export default class MakerPage extends Component {
|
|||||||
|
|
||||||
<Grid item xs={12} align="center" spacing={1}>
|
<Grid item xs={12} align="center" spacing={1}>
|
||||||
<FormControl align="center">
|
<FormControl align="center">
|
||||||
<Tooltip enterDelay="800" enterTouchDelay="0" placement="top" title={"Set the skin-in-the-game, increase for higher safety assurance"}>
|
|
||||||
<FormHelperText>
|
<FormHelperText>
|
||||||
<div align="center" style={{display:'flex',flexWrap:'wrap', transform: 'translate(20%, 0)'}}>
|
<Tooltip enterTouchDelay="0" placement="top" align="center"title={"Let the taker chose an amount within the range"}>
|
||||||
Fidelity Bond Size <LockIcon sx={{height:20,width:20}}/>
|
<div align="center" style={{display:'flex',alignItems:'center', flexWrap:'wrap'}}>
|
||||||
|
<Checkbox onChange={(e)=>this.setState({enableAmountRange:e.target.checked}) & (e.target.checked ? this.getLimits() : null)}/>
|
||||||
|
{this.state.enableAmountRange & this.state.minAmount != null?
|
||||||
|
"From "+this.state.minAmount+" to "+this.state.maxAmount +" "+this.state.currencyCode: "Enable Amount Range"}
|
||||||
</div>
|
</div>
|
||||||
</FormHelperText>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Slider
|
</FormHelperText>
|
||||||
sx={{width:220, align:"center"}}
|
<div style={{ display: this.state.loadingLimits == true ? '':'none'}}>
|
||||||
aria-label="Bond Size (%)"
|
<LinearProgress />
|
||||||
defaultValue={1}
|
</div>
|
||||||
|
<div style={{ display: this.state.loadingLimits == false ? '':'none'}}>
|
||||||
|
<this.RangeSlider
|
||||||
|
disableSwap={true}
|
||||||
|
sx={{width:200, align:"center"}}
|
||||||
|
disabled={!this.state.enableAmountRange || this.state.loadingLimits}
|
||||||
|
value={[this.state.minAmount, this.state.maxAmount]}
|
||||||
|
step={(this.getMaxAmount()-this.getMinAmount())/100}
|
||||||
valueLabelDisplay="auto"
|
valueLabelDisplay="auto"
|
||||||
valueLabelFormat={(x) => (x+'%')}
|
components={{ Thumb: this.RangeThumbComponent }}
|
||||||
step={0.25}
|
valueLabelFormat={(x) => (parseFloat(Number(x).toPrecision(2))+" "+this.state.currencyCode)}
|
||||||
marks={[{value: 1,label: '1%'},{value: 5,label: '5%'},{value: 10,label: '10%'},{value: 15,label: '15%'}]}
|
marks={this.state.limits == null?
|
||||||
min={1}
|
null
|
||||||
max={15}
|
:
|
||||||
onChange={(e) => this.setState({bondSize: e.target.value})}
|
[{value: this.getMinAmount(),label: this.getMinAmount()+" "+ this.state.currencyCode},
|
||||||
|
{value: this.getMaxAmount(),label: this.getMaxAmount()+" "+this.state.currencyCode}]}
|
||||||
|
min={this.getMinAmount()}
|
||||||
|
max={this.getMaxAmount()}
|
||||||
|
onChange={this.handleRangeAmountChange}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@ -465,36 +524,26 @@ export default class MakerPage extends Component {
|
|||||||
|
|
||||||
<Grid item xs={12} align="center" spacing={1}>
|
<Grid item xs={12} align="center" spacing={1}>
|
||||||
<FormControl align="center">
|
<FormControl align="center">
|
||||||
|
<Tooltip enterDelay="800" enterTouchDelay="0" placement="top" title={"Set the skin-in-the-game, increase for higher safety assurance"}>
|
||||||
<FormHelperText>
|
<FormHelperText>
|
||||||
<Tooltip enterTouchDelay="0" placement="top" align="center"title={"Let the taker chose an amount within the range"}>
|
<div align="center" style={{display:'flex',flexWrap:'wrap', transform: 'translate(20%, 0)'}}>
|
||||||
<div align="center" style={{display:'flex',alignItems:'center', flexWrap:'wrap'}}>
|
Fidelity Bond Size <LockIcon sx={{height:20,width:20}}/>
|
||||||
<Checkbox onChange={(e)=>this.setState({enableAmountRange:e.target.checked}) & (e.target.checked ? this.getLimits() : null)}/>
|
|
||||||
Amount Range
|
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
<div style={{ display: this.state.loadingLimits == true ? '':'none'}}>
|
</Tooltip>
|
||||||
<LinearProgress />
|
|
||||||
</div>
|
|
||||||
<div style={{ display: this.state.loadingLimits == false ? '':'none'}}>
|
|
||||||
<Slider
|
<Slider
|
||||||
disableSwap={true}
|
sx={{width:220, align:"center"}}
|
||||||
sx={{width:190, align:"center"}}
|
aria-label="Bond Size (%)"
|
||||||
disabled={!this.state.enableAmountRange || this.state.loadingLimits}
|
defaultValue={1}
|
||||||
value={[this.state.minAmount, this.state.maxAmount]}
|
|
||||||
step={(this.getMaxAmount()-this.getMinAmount())/100}
|
|
||||||
valueLabelDisplay="auto"
|
valueLabelDisplay="auto"
|
||||||
valueLabelFormat={(x) => (parseFloat(Number(x).toPrecision(2))+" "+this.state.currencyCode)}
|
valueLabelFormat={(x) => (x+'%')}
|
||||||
marks={this.state.limits == null?
|
step={0.25}
|
||||||
null
|
marks={[{value: 1,label: '1%'},{value: 5,label: '5%'},{value: 10,label: '10%'},{value: 15,label: '15%'}]}
|
||||||
:
|
min={1}
|
||||||
[{value: this.getMinAmount(),label: this.getMinAmount()+" "+ this.state.currencyCode},
|
max={15}
|
||||||
{value: this.getMaxAmount(),label: this.getMaxAmount()+" "+this.state.currencyCode}]}
|
onChange={(e) => this.setState({bondSize: e.target.value})}
|
||||||
min={this.getMinAmount()}
|
|
||||||
max={this.getMaxAmount()}
|
|
||||||
onChange={this.handleRangeAmountChange}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@ -554,8 +603,8 @@ export default class MakerPage extends Component {
|
|||||||
|
|
||||||
<Grid item xs={12} align="center">
|
<Grid item xs={12} align="center">
|
||||||
{/* conditions to disable the make button */}
|
{/* conditions to disable the make button */}
|
||||||
{(this.state.amount == null ||
|
{(this.state.amount == null & (this.state.enableAmountRange == false & this.state.minAmount != null) ||
|
||||||
this.state.amount <= 0 ||
|
this.state.amount <= 0 & !this.state.enableAmountRange ||
|
||||||
(this.state.is_explicit & (this.state.badSatoshis != null || this.state.satoshis == null)) ||
|
(this.state.is_explicit & (this.state.badSatoshis != null || this.state.satoshis == null)) ||
|
||||||
(!this.state.is_explicit & this.state.badPremium != null))
|
(!this.state.is_explicit & this.state.badPremium != null))
|
||||||
?
|
?
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
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"
|
import {TextField,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"
|
||||||
import Countdown, { zeroPad, calcTimeDelta } from 'react-countdown';
|
import Countdown, { zeroPad, calcTimeDelta } from 'react-countdown';
|
||||||
import MediaQuery from 'react-responsive'
|
import MediaQuery from 'react-responsive'
|
||||||
|
|
||||||
@ -89,6 +89,7 @@ export default class OrderPage extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var otherStateVars = {
|
var otherStateVars = {
|
||||||
|
amount: newStateVars.amount ? newStateVars.amount : null,
|
||||||
loading: false,
|
loading: false,
|
||||||
delay: this.setDelay(newStateVars.status),
|
delay: this.setDelay(newStateVars.status),
|
||||||
currencyCode: this.getCurrencyCode(newStateVars.currency),
|
currencyCode: this.getCurrencyCode(newStateVars.currency),
|
||||||
@ -157,19 +158,60 @@ export default class OrderPage extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
countdownTakeOrderRenderer = ({ seconds, completed }) => {
|
handleTakeAmountChange = (e) => {
|
||||||
if(isNaN(seconds)){
|
if (e.target.value != "" & e.target.value != null){
|
||||||
|
this.setState({takeAmount: parseFloat(e.target.value)})
|
||||||
|
}else{
|
||||||
|
this.setState({takeAmount: e.target.value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
amountHelperText=()=>{
|
||||||
|
if(this.state.takeAmount < this.state.min_amount & this.state.takeAmount != ""){
|
||||||
|
return "Too low"
|
||||||
|
}else if (this.state.takeAmount > this.state.max_amount & this.state.takeAmount != ""){
|
||||||
|
return "Too high"
|
||||||
|
}else{
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
takeOrderButton = () => {
|
||||||
|
if(this.state.has_range){
|
||||||
return(
|
return(
|
||||||
<>
|
<Grid containter xs={12} align="center" alignItems="stretch" justifyContent="center" style={{ display: "flex"}}>
|
||||||
<this.InactiveMakerDialog/>
|
<this.InactiveMakerDialog/>
|
||||||
<Button variant='contained' color='primary'
|
<div style={{maxWidth:120}}>
|
||||||
onClick={this.state.maker_status=='Inactive' ? this.handleClickOpenInactiveMakerDialog : this.takeOrder}>
|
<Tooltip placement="top" enterTouchDelay="500" enterDelay="700" enterNextDelay="2000" title="Amount of fiat to exchange for bitcoin">
|
||||||
|
<Paper sx={{maxHeight:40}}>
|
||||||
|
<TextField
|
||||||
|
error={(this.state.takeAmount < this.state.min_amount || this.state.takeAmount > this.state.max_amount) & this.state.takeAmount != "" }
|
||||||
|
helperText={this.amountHelperText()}
|
||||||
|
label={"Amount "+this.state.currencyCode}
|
||||||
|
size="small"
|
||||||
|
type="number"
|
||||||
|
required="true"
|
||||||
|
value={this.state.takeAmount}
|
||||||
|
inputProps={{
|
||||||
|
min:this.state.min_amount ,
|
||||||
|
max:this.state.max_amount ,
|
||||||
|
style: {textAlign:"center"}
|
||||||
|
}}
|
||||||
|
onChange={this.handleTakeAmountChange}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div style={{height:38, top:'1px', position:'relative'}}>
|
||||||
|
<Button sx={{height:38}} variant='contained' color='primary'
|
||||||
|
onClick={this.state.maker_status=='Inactive' ? this.handleClickOpenInactiveMakerDialog : this.takeOrder}
|
||||||
|
disabled={this.state.takeAmount < this.state.min_amount || this.state.takeAmount > this.state.max_amount || this.state.takeAmount == "" || this.state.takeAmount == null } >
|
||||||
Take Order
|
Take Order
|
||||||
</Button>
|
</Button>
|
||||||
</>)
|
</div>
|
||||||
}
|
</Grid>
|
||||||
if (completed) {
|
)
|
||||||
// Render a completed state
|
}else{
|
||||||
return(
|
return(
|
||||||
<>
|
<>
|
||||||
<this.InactiveMakerDialog/>
|
<this.InactiveMakerDialog/>
|
||||||
@ -178,11 +220,19 @@ export default class OrderPage extends Component {
|
|||||||
Take Order
|
Take Order
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countdownTakeOrderRenderer = ({ seconds, completed }) => {
|
||||||
|
if(isNaN(seconds)){return (<this.takeOrderButton/>)}
|
||||||
|
if (completed) {
|
||||||
|
// Render a completed state
|
||||||
|
return ( <this.takeOrderButton/>);
|
||||||
} else{
|
} else{
|
||||||
return(
|
return(
|
||||||
<Tooltip enterTouchDelay="0" title="Wait until you can take an order"><div>
|
<Tooltip enterTouchDelay="0" title="Wait until you can take an order"><div>
|
||||||
<Button disabled={true} variant='contained' color='primary' onClick={this.takeOrder}>Take Order</Button>
|
<Button disabled={true} variant='contained' color='primary'>Take Order</Button>
|
||||||
</div></Tooltip>)
|
</div></Tooltip>)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -212,12 +262,13 @@ export default class OrderPage extends Component {
|
|||||||
|
|
||||||
takeOrder=()=>{
|
takeOrder=()=>{
|
||||||
this.setState({loading:true})
|
this.setState({loading:true})
|
||||||
|
console.log(this.state.takeAmount)
|
||||||
const requestOptions = {
|
const requestOptions = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),},
|
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
'action':'take',
|
'action':'take',
|
||||||
|
'amount':this.state.takeAmount,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
fetch('/api/order/' + '?order_id=' + this.orderId, requestOptions)
|
fetch('/api/order/' + '?order_id=' + this.orderId, requestOptions)
|
||||||
@ -483,10 +534,17 @@ export default class OrderPage extends Component {
|
|||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
{getFlags(this.state.currencyCode)}
|
{getFlags(this.state.currencyCode)}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
{this.state.has_range & this.state.amount == null ?
|
||||||
|
<ListItemText primary={parseFloat(Number(this.state.min_amount).toPrecision(2))
|
||||||
|
+"-" + parseFloat(Number(this.state.max_amount).toPrecision(2)) +" "+this.state.currencyCode} secondary="Amount range"/>
|
||||||
|
:
|
||||||
<ListItemText primary={parseFloat(parseFloat(this.state.amount).toFixed(4))
|
<ListItemText primary={parseFloat(parseFloat(this.state.amount).toFixed(4))
|
||||||
+" "+this.state.currencyCode} secondary="Amount"/>
|
+" "+this.state.currencyCode} secondary="Amount"/>
|
||||||
|
}
|
||||||
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<PaymentsIcon/>
|
<PaymentsIcon/>
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user