mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 20:21:35 +00:00
Enhance UI for Swaps (#346)
* Add better fiat/swap UI switches * Add swap controls to booktable * Enhance order details and take button for swaps * Add swap specific order summary strings * Add specific bond commitment descriptions for swap orders * Fix cosmetics
This commit is contained in:
parent
237c9fd951
commit
965bbb0765
@ -69,15 +69,6 @@ const BookPage = ({
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleCurrencyChange = function (e) {
|
||||
const currency = e.target.value;
|
||||
setFav({ ...fav, currency });
|
||||
};
|
||||
|
||||
const handleTypeChange = function (mouseEvent, val) {
|
||||
setFav({ ...fav, type: val });
|
||||
};
|
||||
|
||||
const onOrderClicked = function (id: number) {
|
||||
if (hasRobot) {
|
||||
history.push('/order/' + id);
|
||||
@ -159,13 +150,12 @@ const BookPage = ({
|
||||
clickRefresh={() => fetchBook()}
|
||||
book={book}
|
||||
fav={fav}
|
||||
setFav={setFav}
|
||||
maxWidth={maxBookTableWidth} // EM units
|
||||
maxHeight={windowSize.height * 0.825 - 5} // EM units
|
||||
fullWidth={windowSize.width} // EM units
|
||||
fullHeight={windowSize.height} // EM units
|
||||
defaultFullscreen={false}
|
||||
onCurrencyChange={handleCurrencyChange}
|
||||
onTypeChange={handleTypeChange}
|
||||
onOrderClicked={onOrderClicked}
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
@ -199,13 +189,12 @@ const BookPage = ({
|
||||
book={book}
|
||||
clickRefresh={() => fetchBook()}
|
||||
fav={fav}
|
||||
setFav={setFav}
|
||||
maxWidth={windowSize.width * 0.97} // EM units
|
||||
maxHeight={windowSize.height * 0.825 - 5} // EM units
|
||||
fullWidth={windowSize.width} // EM units
|
||||
fullHeight={windowSize.height} // EM units
|
||||
defaultFullscreen={false}
|
||||
onCurrencyChange={handleCurrencyChange}
|
||||
onTypeChange={handleTypeChange}
|
||||
onOrderClicked={onOrderClicked}
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
|
@ -89,7 +89,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
const [info, setInfo] = useState<Info>(defaultInfo);
|
||||
const [coordinators, setCoordinators] = useState<Coordinator[]>(defaultCoordinators);
|
||||
const [baseUrl, setBaseUrl] = useState<string>('');
|
||||
const [fav, setFav] = useState<Favorites>({ type: null, currency: 0 });
|
||||
const [fav, setFav] = useState<Favorites>({ type: null, mode: 'fiat', currency: 0 });
|
||||
|
||||
const [delay, setDelay] = useState<number>(60000);
|
||||
const [timer, setTimer] = useState<NodeJS.Timer | undefined>(setInterval(() => null, delay));
|
||||
@ -456,6 +456,8 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
>
|
||||
<div>
|
||||
<SettingsPage
|
||||
fav={fav}
|
||||
setFav={setFav}
|
||||
settings={settings}
|
||||
setSettings={setSettings}
|
||||
windowSize={{ ...windowSize, height: windowSize.height - navbarHeight }}
|
||||
|
@ -2,15 +2,23 @@ import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Grid, Paper, useTheme } from '@mui/material';
|
||||
import SettingsForm from '../../components/SettingsForm';
|
||||
import { Settings } from '../../models';
|
||||
import { Settings, Favorites } from '../../models';
|
||||
|
||||
interface SettingsPageProps {
|
||||
fav: Favorites;
|
||||
setFav: (state: Favorites) => void;
|
||||
settings: Settings;
|
||||
setSettings: (state: Settings) => void;
|
||||
windowSize: { width: number; height: number };
|
||||
}
|
||||
|
||||
const SettingsPage = ({ settings, setSettings, windowSize }: SettingsPageProps): JSX.Element => {
|
||||
const SettingsPage = ({
|
||||
fav,
|
||||
setFav,
|
||||
settings,
|
||||
setSettings,
|
||||
windowSize,
|
||||
}: SettingsPageProps): JSX.Element => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const maxHeight = windowSize.height * 0.85 - 3;
|
||||
@ -23,6 +31,8 @@ const SettingsPage = ({ settings, setSettings, windowSize }: SettingsPageProps):
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<SettingsForm
|
||||
fav={fav}
|
||||
setFav={setFav}
|
||||
settings={settings}
|
||||
setSettings={setSettings}
|
||||
showNetwork={!(window.NativeRobosats === undefined)}
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
Divider,
|
||||
MenuItem,
|
||||
Box,
|
||||
Tooltip,
|
||||
} from '@mui/material';
|
||||
import currencyDict from '../../../static/assets/currencies.json';
|
||||
import { useTheme } from '@mui/system';
|
||||
@ -17,34 +18,50 @@ import { fiatMethods, swapMethods, PaymentIcon } from '../PaymentMethods';
|
||||
import { FlagWithProps } from '../Icons';
|
||||
|
||||
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
||||
import { Favorites } from '../../models';
|
||||
import SwapCalls from '@mui/icons-material/SwapCalls';
|
||||
|
||||
interface BookControlProps {
|
||||
width: number;
|
||||
type: number;
|
||||
currency: number;
|
||||
fav: Favorites;
|
||||
setFav: (state: Favorites) => void;
|
||||
paymentMethod: string[];
|
||||
onCurrencyChange: () => void;
|
||||
onTypeChange: () => void;
|
||||
setPaymentMethods: () => void;
|
||||
}
|
||||
|
||||
const BookControl = ({
|
||||
width,
|
||||
type,
|
||||
currency,
|
||||
onCurrencyChange,
|
||||
onTypeChange,
|
||||
fav,
|
||||
setFav,
|
||||
paymentMethod,
|
||||
setPaymentMethods,
|
||||
}: BookControlProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
const smallestToolbarWidth = (t('Buy').length + t('Sell').length) * 0.7 + 12;
|
||||
const typeZeroText = fav.mode === 'fiat' ? 'Buy' : 'Swap In';
|
||||
const typeOneText = fav.mode === 'fiat' ? 'Sell' : 'Swap Out';
|
||||
|
||||
const smallestToolbarWidth = (typeZeroText.length + typeOneText.length) * 0.7 + 12;
|
||||
const mediumToolbarWidth = smallestToolbarWidth + 12;
|
||||
const verboseToolbarWidth =
|
||||
mediumToolbarWidth + (t('and use').length + t('pay with').length) * 0.6;
|
||||
|
||||
const handleCurrencyChange = function (e) {
|
||||
const currency = e.target.value;
|
||||
setFav({ ...fav, currency, mode: currency === 1000 ? 'swap' : 'fiat' });
|
||||
};
|
||||
|
||||
const handleTypeChange = function (mouseEvent, val) {
|
||||
setFav({ ...fav, type: val });
|
||||
};
|
||||
|
||||
const handleModeChange = function (mouseEvent, val) {
|
||||
const mode = fav.mode === 'fiat' ? 'swap' : 'fiat';
|
||||
const currency = fav.mode === 'fiat' ? 1000 : 0;
|
||||
setFav({ ...fav, mode, currency });
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid
|
||||
@ -63,6 +80,37 @@ const BookControl = ({
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
<Grid item>
|
||||
<Tooltip
|
||||
placement='bottom'
|
||||
enterTouchDelay={200}
|
||||
enterDelay={700}
|
||||
enterNextDelay={2000}
|
||||
title={t('Show Lightning swaps')}
|
||||
>
|
||||
<ToggleButtonGroup
|
||||
sx={{
|
||||
height: '2.6em',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: '0.5px solid',
|
||||
borderColor: 'text.disabled',
|
||||
'&:hover': {
|
||||
borderColor: 'text.primary',
|
||||
border: '1px solid',
|
||||
},
|
||||
}}
|
||||
size='small'
|
||||
exclusive={true}
|
||||
value={fav.mode}
|
||||
onChange={handleModeChange}
|
||||
>
|
||||
<ToggleButton value={'swap'} color={'secondary'}>
|
||||
<SwapCalls />
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
<ToggleButtonGroup
|
||||
sx={{
|
||||
@ -77,19 +125,19 @@ const BookControl = ({
|
||||
}}
|
||||
size='small'
|
||||
exclusive={true}
|
||||
value={type}
|
||||
onChange={onTypeChange}
|
||||
value={fav.type}
|
||||
onChange={handleTypeChange}
|
||||
>
|
||||
<ToggleButton value={1} color={'primary'}>
|
||||
{t('Buy')}
|
||||
{typeZeroText}
|
||||
</ToggleButton>
|
||||
<ToggleButton value={0} color={'secondary'}>
|
||||
{t('Sell')}
|
||||
{typeOneText}
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
</Grid>
|
||||
|
||||
{width > verboseToolbarWidth ? (
|
||||
{width > verboseToolbarWidth && fav.mode === 'fiat' ? (
|
||||
<Grid item sx={{ position: 'relative', top: '0.5em' }}>
|
||||
<Typography variant='caption' color='text.secondary'>
|
||||
{t('and use')}
|
||||
@ -97,53 +145,55 @@ const BookControl = ({
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
<Grid item>
|
||||
<Select
|
||||
autoWidth
|
||||
sx={{
|
||||
height: '2.3em',
|
||||
border: '0.5px solid',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: '4px',
|
||||
borderColor: 'text.disabled',
|
||||
'&:hover': {
|
||||
borderColor: 'text.primary',
|
||||
},
|
||||
}}
|
||||
size='small'
|
||||
label={t('Select Payment Currency')}
|
||||
required={true}
|
||||
value={currency}
|
||||
inputProps={{
|
||||
style: { textAlign: 'center' },
|
||||
}}
|
||||
onChange={onCurrencyChange}
|
||||
>
|
||||
<MenuItem value={0}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
<FlagWithProps code='ANY' />
|
||||
<Typography sx={{ width: '2em' }} align='right' color='text.secondary'>
|
||||
{' ' + t('ANY')}
|
||||
</Typography>
|
||||
</div>
|
||||
</MenuItem>
|
||||
{Object.entries(currencyDict).map(([key, value]) => (
|
||||
<MenuItem key={key} value={parseInt(key)} color='text.secondary'>
|
||||
{fav.mode === 'fiat' ? (
|
||||
<Grid item>
|
||||
<Select
|
||||
autoWidth
|
||||
sx={{
|
||||
height: '2.3em',
|
||||
border: '0.5px solid',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: '4px',
|
||||
borderColor: 'text.disabled',
|
||||
'&:hover': {
|
||||
borderColor: 'text.primary',
|
||||
},
|
||||
}}
|
||||
size='small'
|
||||
label={t('Select Payment Currency')}
|
||||
required={true}
|
||||
value={fav.currency}
|
||||
inputProps={{
|
||||
style: { textAlign: 'center' },
|
||||
}}
|
||||
onChange={handleCurrencyChange}
|
||||
>
|
||||
<MenuItem value={0}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
<FlagWithProps code={value} />
|
||||
<FlagWithProps code='ANY' />
|
||||
<Typography sx={{ width: '2em' }} align='right' color='text.secondary'>
|
||||
{' ' + value}
|
||||
{' ' + t('ANY')}
|
||||
</Typography>
|
||||
</div>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Grid>
|
||||
{Object.entries(currencyDict).map(([key, value]) => (
|
||||
<MenuItem key={key} value={parseInt(key)} color='text.secondary'>
|
||||
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
<FlagWithProps code={value} />
|
||||
<Typography sx={{ width: '2em' }} align='right' color='text.secondary'>
|
||||
{' ' + value}
|
||||
</Typography>
|
||||
</div>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
{width > verboseToolbarWidth ? (
|
||||
<Grid item sx={{ position: 'relative', top: '0.5em' }}>
|
||||
<Typography variant='caption' color='text.secondary'>
|
||||
{currency == 1000 ? t('swap to') : t('pay with')}
|
||||
{fav.currency == 1000 ? t(fav.type === 0 ? 'to' : 'from') : t('pay with')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
) : null}
|
||||
@ -164,10 +214,10 @@ const BookControl = ({
|
||||
listBoxProps={{ sx: { width: '13em' } }}
|
||||
onAutocompleteChange={setPaymentMethods}
|
||||
value={paymentMethod}
|
||||
optionsType={currency == 1000 ? 'swap' : 'fiat'}
|
||||
optionsType={fav.currency == 1000 ? 'swap' : 'fiat'}
|
||||
error={false}
|
||||
helperText={''}
|
||||
label={currency == 1000 ? t('DESTINATION') : t('METHOD')}
|
||||
label={fav.currency == 1000 ? t('DESTINATION') : t('METHOD')}
|
||||
tooltipTitle=''
|
||||
listHeaderText=''
|
||||
addNewButtonText=''
|
||||
@ -216,7 +266,7 @@ const BookControl = ({
|
||||
</Typography>
|
||||
</div>
|
||||
</MenuItem>
|
||||
{currency === 1000
|
||||
{fav.currency === 1000
|
||||
? swapMethods.map((method, index) => (
|
||||
<MenuItem
|
||||
style={{ width: '10em' }}
|
||||
|
@ -43,8 +43,7 @@ interface BookTableProps {
|
||||
showControls?: boolean;
|
||||
showFooter?: boolean;
|
||||
showNoResults?: boolean;
|
||||
onCurrencyChange?: (e: any) => void;
|
||||
onTypeChange?: (mouseEvent: any, val: number) => void;
|
||||
setFav?: (state: Favorites) => void;
|
||||
onOrderClicked?: (id: number) => void;
|
||||
baseUrl: string;
|
||||
}
|
||||
@ -52,7 +51,8 @@ interface BookTableProps {
|
||||
const BookTable = ({
|
||||
clickRefresh,
|
||||
book,
|
||||
fav = { currency: 1, type: 0 },
|
||||
fav = { currency: 1, type: 0, mode: 'fiat' },
|
||||
setFav,
|
||||
maxWidth = 100,
|
||||
maxHeight = 70,
|
||||
fullWidth = 100,
|
||||
@ -63,8 +63,6 @@ const BookTable = ({
|
||||
showControls = true,
|
||||
showFooter = true,
|
||||
showNoResults = true,
|
||||
onCurrencyChange,
|
||||
onTypeChange,
|
||||
onOrderClicked = () => null,
|
||||
baseUrl,
|
||||
}: BookTableProps): JSX.Element => {
|
||||
@ -218,7 +216,10 @@ const BookTable = ({
|
||||
field: 'type',
|
||||
headerName: t('Is'),
|
||||
width: width * fontSize,
|
||||
renderCell: (params: any) => (params.row.type ? t('Seller') : t('Buyer')),
|
||||
renderCell: (params: any) =>
|
||||
params.row.type
|
||||
? t(fav.mode === 'fiat' ? 'Seller' : 'Swapping Out')
|
||||
: t(fav.mode === 'fiat' ? 'Buyer' : 'Swapping In'),
|
||||
};
|
||||
};
|
||||
|
||||
@ -230,14 +231,15 @@ const BookTable = ({
|
||||
type: 'number',
|
||||
width: width * fontSize,
|
||||
renderCell: (params: any) => {
|
||||
const amount = fav.mode === 'swap' ? params.row.amount * 100000 : params.row.amount;
|
||||
const minAmount =
|
||||
fav.mode === 'swap' ? params.row.min_amount * 100000 : params.row.min_amount;
|
||||
const maxAmount =
|
||||
fav.mode === 'swap' ? params.row.max_amount * 100000 : params.row.max_amount;
|
||||
return (
|
||||
<div style={{ cursor: 'pointer' }}>
|
||||
{amountToString(
|
||||
params.row.amount,
|
||||
params.row.has_range,
|
||||
params.row.min_amount,
|
||||
params.row.max_amount,
|
||||
)}
|
||||
{amountToString(amount, params.row.has_range, minAmount, maxAmount) +
|
||||
(fav.mode === 'swap' ? 'K Sats' : '')}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@ -246,7 +248,7 @@ const BookTable = ({
|
||||
|
||||
const currencyObj = function (width: number, hide: boolean) {
|
||||
return {
|
||||
hide,
|
||||
hide: fav.mode === 'swap' ? true : hide,
|
||||
field: 'currency',
|
||||
headerName: t('Currency'),
|
||||
width: width * fontSize,
|
||||
@ -274,7 +276,7 @@ const BookTable = ({
|
||||
return {
|
||||
hide,
|
||||
field: 'payment_method',
|
||||
headerName: t('Payment Method'),
|
||||
headerName: fav.mode === 'fiat' ? t('Payment Method') : t('Destination'),
|
||||
width: width * fontSize,
|
||||
renderCell: (params: any) => {
|
||||
return (
|
||||
@ -497,7 +499,7 @@ const BookTable = ({
|
||||
priority: 1,
|
||||
order: 4,
|
||||
normal: {
|
||||
width: 6.5,
|
||||
width: fav.mode === 'swap' ? 9.5 : 6.5,
|
||||
object: amountObj,
|
||||
},
|
||||
},
|
||||
@ -505,7 +507,7 @@ const BookTable = ({
|
||||
priority: 2,
|
||||
order: 5,
|
||||
normal: {
|
||||
width: 5.9,
|
||||
width: fav.mode === 'swap' ? 0 : 5.9,
|
||||
object: currencyObj,
|
||||
},
|
||||
},
|
||||
@ -577,7 +579,7 @@ const BookTable = ({
|
||||
priority: 10,
|
||||
order: 2,
|
||||
normal: {
|
||||
width: 4.3,
|
||||
width: fav.mode === 'swap' ? 7 : 4.3,
|
||||
object: typeObj,
|
||||
},
|
||||
},
|
||||
@ -742,10 +744,8 @@ const BookTable = ({
|
||||
componentsProps={{
|
||||
toolbar: {
|
||||
width,
|
||||
type: fav.type,
|
||||
currency: fav.currency,
|
||||
onCurrencyChange,
|
||||
onTypeChange,
|
||||
fav,
|
||||
setFav,
|
||||
paymentMethod: paymentMethods,
|
||||
setPaymentMethods,
|
||||
},
|
||||
|
@ -148,7 +148,7 @@ function AmountRange({
|
||||
<Grid
|
||||
item
|
||||
sx={{
|
||||
width: `calc(100% - ${Math.log10(amountLimits[1] * 0.65) + 2}em)`,
|
||||
width: `calc(100% - ${Math.abs(Math.log10(amountLimits[1]) * 0.65) + 2}em)`,
|
||||
}}
|
||||
>
|
||||
<RangeSlider
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
Switch,
|
||||
Tooltip,
|
||||
Button,
|
||||
Checkbox,
|
||||
Grid,
|
||||
Typography,
|
||||
TextField,
|
||||
@ -36,7 +37,7 @@ import { FlagWithProps } from '../Icons';
|
||||
import AutocompletePayments from './AutocompletePayments';
|
||||
import AmountRange from './AmountRange';
|
||||
import currencyDict from '../../../static/assets/currencies.json';
|
||||
import { pn } from '../../utils';
|
||||
import { amountToString, pn } from '../../utils';
|
||||
|
||||
import { SelfImprovement, Lock, HourglassTop, DeleteSweep, Edit } from '@mui/icons-material';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
@ -146,6 +147,7 @@ const MakerForm = ({
|
||||
setFav({
|
||||
...fav,
|
||||
currency: newCurrency,
|
||||
mode: newCurrency === 1000 ? 'swap' : 'fiat',
|
||||
});
|
||||
updateAmountLimits(limits.list, newCurrency, maker.premium);
|
||||
updateCurrentPrice(limits.list, newCurrency, maker.premium);
|
||||
@ -409,18 +411,23 @@ const MakerForm = ({
|
||||
color={disableSubmit() ? 'text.secondary' : 'text.primary'}
|
||||
>
|
||||
{fav.type == null
|
||||
? t('Order for ')
|
||||
? t(fav.mode === 'fiat' ? 'Order for ' : 'Swap of ')
|
||||
: fav.type == 1
|
||||
? t('Buy order for ')
|
||||
: t('Sell order for ')}
|
||||
{maker.advancedOptions && maker.minAmount != ''
|
||||
? pn(maker.minAmount) + '-' + pn(maker.maxAmount)
|
||||
: pn(maker.amount)}
|
||||
{' ' + currencyCode}
|
||||
? t(fav.mode === 'fiat' ? 'Buy BTC for ' : 'Swap into LN ')
|
||||
: t(fav.mode === 'fiat' ? 'Sell BTC for ' : 'Swap out of LN ')}
|
||||
{fav.mode === 'fiat'
|
||||
? amountToString(maker.amount, maker.advancedOptions, maker.minAmount, maker.maxAmount)
|
||||
: amountToString(
|
||||
maker.amount * 100000000,
|
||||
maker.advancedOptions,
|
||||
maker.minAmount * 100000000,
|
||||
maker.maxAmount * 100000000,
|
||||
)}
|
||||
{' ' + (fav.mode === 'fiat' ? currencyCode : 'Sats')}
|
||||
{maker.isExplicit
|
||||
? t(' of {{satoshis}} Satoshis', { satoshis: pn(maker.satoshis) })
|
||||
: maker.premium == 0
|
||||
? t(' at market price')
|
||||
? t(fav.mode === 'fiat' ? ' at market price' : '')
|
||||
: maker.premium > 0
|
||||
? t(' at a {{premium}}% premium', { premium: maker.premium })
|
||||
: t(' at a {{discount}}% discount', { discount: -maker.premium })}
|
||||
@ -492,56 +499,73 @@ const MakerForm = ({
|
||||
<Collapse in={!collapseAll}>
|
||||
<Grid container spacing={1} justifyContent='center' alignItems='center'>
|
||||
<Grid item>
|
||||
<FormControl component='fieldset'>
|
||||
<FormHelperText sx={{ textAlign: 'center' }}>
|
||||
{t('Buy or Sell Bitcoin?')}
|
||||
</FormHelperText>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
size={maker.advancedOptions ? 'small' : 'large'}
|
||||
variant='contained'
|
||||
onClick={() =>
|
||||
setFav({
|
||||
...fav,
|
||||
type: 1,
|
||||
})
|
||||
}
|
||||
disableElevation={fav.type == 1}
|
||||
sx={{
|
||||
backgroundColor: fav.type == 1 ? 'primary.main' : 'background.paper',
|
||||
color: fav.type == 1 ? 'background.paper' : 'text.secondary',
|
||||
':hover': {
|
||||
color: 'background.paper',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{t('Buy')}
|
||||
</Button>
|
||||
<Button
|
||||
size={maker.advancedOptions ? 'small' : 'large'}
|
||||
variant='contained'
|
||||
onClick={() =>
|
||||
setFav({
|
||||
...fav,
|
||||
type: 0,
|
||||
})
|
||||
}
|
||||
disableElevation={fav.type == 0}
|
||||
color='secondary'
|
||||
sx={{
|
||||
backgroundColor: fav.type == 0 ? 'secondary.main' : 'background.paper',
|
||||
color: fav.type == 0 ? 'background.secondary' : 'text.secondary',
|
||||
':hover': {
|
||||
color: 'background.paper',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{t('Sell')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</FormControl>
|
||||
<Grid container direction='row' justifyContent='center' alignItems='stretch'>
|
||||
<Collapse in={maker.advancedOptions} orientation='horizontal'>
|
||||
<Grid item>
|
||||
<FormControl>
|
||||
<FormHelperText sx={{ textAlign: 'center' }}>{t('Swap?')}</FormHelperText>
|
||||
<Checkbox
|
||||
sx={{ position: 'relative', bottom: '0.3em' }}
|
||||
checked={fav.mode == 'swap'}
|
||||
onClick={() => handleCurrencyChange(fav.mode == 'swap' ? 1 : 1000)}
|
||||
/>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Collapse>
|
||||
|
||||
<Grid item>
|
||||
<FormControl component='fieldset'>
|
||||
<FormHelperText sx={{ textAlign: 'center' }}>
|
||||
{fav.mode === 'fiat' ? t('Buy or Sell Bitcoin?') : t('In or Out of Lightning?')}
|
||||
</FormHelperText>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
size={maker.advancedOptions ? 'small' : 'large'}
|
||||
variant='contained'
|
||||
onClick={() =>
|
||||
setFav({
|
||||
...fav,
|
||||
type: 1,
|
||||
})
|
||||
}
|
||||
disableElevation={fav.type == 1}
|
||||
sx={{
|
||||
backgroundColor: fav.type == 1 ? 'primary.main' : 'background.paper',
|
||||
color: fav.type == 1 ? 'background.paper' : 'text.secondary',
|
||||
':hover': {
|
||||
color: 'background.paper',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{fav.mode === 'fiat' ? t('Buy') : t('Swap In')}
|
||||
</Button>
|
||||
<Button
|
||||
size={maker.advancedOptions ? 'small' : 'large'}
|
||||
variant='contained'
|
||||
onClick={() =>
|
||||
setFav({
|
||||
...fav,
|
||||
type: 0,
|
||||
})
|
||||
}
|
||||
disableElevation={fav.type == 0}
|
||||
color='secondary'
|
||||
sx={{
|
||||
backgroundColor: fav.type == 0 ? 'secondary.main' : 'background.paper',
|
||||
color: fav.type == 0 ? 'background.secondary' : 'text.secondary',
|
||||
':hover': {
|
||||
color: 'background.paper',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{fav.mode === 'fiat' ? t('Sell') : t('Swap Out')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
@ -637,10 +661,10 @@ const MakerForm = ({
|
||||
<AutocompletePayments
|
||||
onAutocompleteChange={handlePaymentMethodChange}
|
||||
// listBoxProps={{ sx: { width: '15.3em', maxHeight: '20em' } }}
|
||||
optionsType={fav.currency == 1000 ? 'swap' : 'fiat'}
|
||||
optionsType={fav.mode}
|
||||
error={maker.badPaymentMethod}
|
||||
helperText={maker.badPaymentMethod ? t('Must be shorter than 65 characters') : ''}
|
||||
label={fav.currency == 1000 ? t('Swap Destination(s)') : t('Fiat Payment Method(s)')}
|
||||
label={fav.mode == 'swap' ? t('Swap Destination(s)') : t('Fiat Payment Method(s)')}
|
||||
tooltipTitle={t(
|
||||
'Enter your preferred fiat payment methods. Fast methods are highly recommended.',
|
||||
)}
|
||||
|
@ -54,7 +54,7 @@ const TakeButton = ({
|
||||
const [loadingTake, setLoadingTake] = useState<boolean>(false);
|
||||
const [open, setOpen] = useState<OpenDialogsProps>(closeAll);
|
||||
|
||||
const currencyCode: string = currencies[`${order.currency}`];
|
||||
const currencyCode: string = order.currency == 1000 ? 'Sats' : currencies[`${order.currency}`];
|
||||
|
||||
const InactiveMakerDialog = function () {
|
||||
return (
|
||||
@ -104,9 +104,10 @@ const TakeButton = ({
|
||||
};
|
||||
|
||||
const amountHelperText = function () {
|
||||
if (Number(takeAmount) < Number(order.min_amount) && takeAmount != '') {
|
||||
const amount = order.currency == 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
if (amount < Number(order.min_amount) && takeAmount != '') {
|
||||
return t('Too low');
|
||||
} else if (Number(takeAmount) > Number(order.max_amount) && takeAmount != '') {
|
||||
} else if (amount > Number(order.max_amount) && takeAmount != '') {
|
||||
return t('Too high');
|
||||
} else {
|
||||
return null;
|
||||
@ -122,9 +123,10 @@ const TakeButton = ({
|
||||
};
|
||||
|
||||
const invalidTakeAmount = function () {
|
||||
const amount = order.currency == 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
return (
|
||||
Number(takeAmount) < Number(order.min_amount) ||
|
||||
Number(takeAmount) > Number(order.max_amount) ||
|
||||
amount < Number(order.min_amount) ||
|
||||
amount > Number(order.max_amount) ||
|
||||
takeAmount == '' ||
|
||||
takeAmount == null
|
||||
);
|
||||
@ -146,7 +148,7 @@ const TakeButton = ({
|
||||
}}
|
||||
>
|
||||
<Grid container direction='row' alignItems='flex-start' justifyContent='space-evenly'>
|
||||
<Grid item>
|
||||
<Grid item sx={{ width: '12em' }}>
|
||||
<Tooltip
|
||||
placement='top'
|
||||
enterTouchDelay={500}
|
||||
@ -155,11 +157,7 @@ const TakeButton = ({
|
||||
title={t('Enter amount of fiat to exchange for bitcoin')}
|
||||
>
|
||||
<TextField
|
||||
error={
|
||||
(Number(takeAmount) < Number(order.min_amount) ||
|
||||
Number(takeAmount) > Number(order.max_amount)) &&
|
||||
takeAmount != ''
|
||||
}
|
||||
error={takeAmount === '' ? false : invalidTakeAmount()}
|
||||
helperText={amountHelperText()}
|
||||
label={t('Amount {{currencyCode}}', { currencyCode })}
|
||||
size='small'
|
||||
@ -249,7 +247,7 @@ const TakeButton = ({
|
||||
apiClient
|
||||
.post(baseUrl, '/api/order/?order_id=' + order.id, {
|
||||
action: 'take',
|
||||
amount: takeAmount,
|
||||
amount: order.currency == 1000 ? takeAmount / 100000000 : takeAmount,
|
||||
})
|
||||
.then((data) => {
|
||||
setLoadingTake(false);
|
||||
|
@ -32,7 +32,7 @@ import { FlagWithProps } from '../Icons';
|
||||
import LinearDeterminate from './LinearDeterminate';
|
||||
|
||||
import { Order } from '../../models';
|
||||
import { statusBadgeColor, pn } from '../../utils';
|
||||
import { statusBadgeColor, pn, amountToString } from '../../utils';
|
||||
import { Page } from '../../basic/NavBar';
|
||||
import TakeButton from './TakeButton';
|
||||
|
||||
@ -58,21 +58,23 @@ const OrderDetails = ({
|
||||
|
||||
const AmountString = function () {
|
||||
// precision to 8 decimal if currency is BTC otherwise 4 decimals
|
||||
const precision = order.currency == 1000 ? 8 : 4;
|
||||
|
||||
let primary = '';
|
||||
let secondary = '';
|
||||
if (order.has_range && order.amount == null) {
|
||||
const minAmount = pn(parseFloat(Number(order.min_amount).toPrecision(precision)));
|
||||
const maxAmount = pn(parseFloat(Number(order.max_amount).toPrecision(precision)));
|
||||
primary = `${minAmount}-${maxAmount} ${currencyCode}`;
|
||||
secondary = t('Amount range');
|
||||
if (order.currency == 1000) {
|
||||
return (
|
||||
amountToString(
|
||||
order.amount * 100000000,
|
||||
order.amount ? false : order.has_range,
|
||||
order.min_amount * 100000000,
|
||||
order.max_amount * 100000000,
|
||||
) + ' Sats'
|
||||
);
|
||||
} else {
|
||||
const amount = pn(parseFloat(Number(order.amount).toPrecision(precision)));
|
||||
primary = `${amount} ${currencyCode}`;
|
||||
secondary = t('Amount');
|
||||
return amountToString(
|
||||
order.amount,
|
||||
order.amount ? false : order.has_range,
|
||||
order.min_amount,
|
||||
order.max_amount,
|
||||
);
|
||||
}
|
||||
return { primary, secondary };
|
||||
};
|
||||
|
||||
// Countdown Renderer callback with condition
|
||||
@ -151,7 +153,11 @@ const OrderDetails = ({
|
||||
/>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={order.maker_nick + (order.type ? ' ' + t('(Seller)') : ' ' + t('(Buyer)'))}
|
||||
primary={`${order.maker_nick} (${
|
||||
order.type
|
||||
? t(order.currency == 1000 ? 'Swapping Out' : 'Seller')
|
||||
: t(order.currency == 1000 ? 'Swapping In' : 'Buyer')
|
||||
})`}
|
||||
secondary={t('Order maker')}
|
||||
/>
|
||||
</ListItem>
|
||||
@ -160,7 +166,11 @@ const OrderDetails = ({
|
||||
<Divider />
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary={`${order.taker_nick} ${order.type ? t('(Buyer)') : t('(Seller)')}`}
|
||||
primary={`${order.taker_nick} (${
|
||||
order.type
|
||||
? t(order.currency == 1000 ? 'Swapping In' : 'Buyer')
|
||||
: t(order.currency == 1000 ? 'Swapping Out' : 'Seller')
|
||||
})`}
|
||||
secondary={t('Order taker')}
|
||||
/>
|
||||
<ListItemAvatar>
|
||||
@ -205,7 +215,10 @@ const OrderDetails = ({
|
||||
<FlagWithProps code={currencyCode} width='1.2em' height='1.2em' />
|
||||
</div>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={AmountString().primary} secondary={AmountString().secondary} />
|
||||
<ListItemText
|
||||
primary={AmountString()}
|
||||
secondary={order.amount && !order.has_range ? 'Amount' : 'Amount Range'}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
ToggleButtonGroup,
|
||||
ToggleButton,
|
||||
} from '@mui/material';
|
||||
import { Settings } from '../../models';
|
||||
import { Favorites, Settings } from '../../models';
|
||||
import SelectLanguage from './SelectLanguage';
|
||||
import {
|
||||
Translate,
|
||||
@ -23,11 +23,16 @@ import {
|
||||
DarkMode,
|
||||
SettingsOverscan,
|
||||
Link,
|
||||
AccountBalance,
|
||||
AttachMoney,
|
||||
} from '@mui/icons-material';
|
||||
import { systemClient } from '../../services/System';
|
||||
import SwapCalls from '@mui/icons-material/SwapCalls';
|
||||
|
||||
interface SettingsFormProps {
|
||||
dense?: boolean;
|
||||
fav: Favorites;
|
||||
setFav: (state: Favorites) => void;
|
||||
settings: Settings;
|
||||
setSettings: (state: Settings) => void;
|
||||
showNetwork?: boolean;
|
||||
@ -35,6 +40,8 @@ interface SettingsFormProps {
|
||||
|
||||
const SettingsForm = ({
|
||||
dense = false,
|
||||
fav,
|
||||
setFav,
|
||||
settings,
|
||||
setSettings,
|
||||
showNetwork = false,
|
||||
@ -139,6 +146,29 @@ const SettingsForm = ({
|
||||
track={false}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<AccountBalance />
|
||||
</ListItemIcon>
|
||||
<ToggleButtonGroup
|
||||
exclusive={true}
|
||||
value={fav.mode}
|
||||
onChange={(e, mode) => {
|
||||
setFav({ ...fav, mode, currency: mode === 'fiat' ? 0 : 1000 });
|
||||
}}
|
||||
>
|
||||
<ToggleButton value='fiat' color='primary'>
|
||||
<AttachMoney />
|
||||
{t('Fiat')}
|
||||
</ToggleButton>
|
||||
<ToggleButton value='swap' color='secondary'>
|
||||
<SwapCalls />
|
||||
{t('Swaps')}
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
</ListItem>
|
||||
|
||||
{showNetwork ? (
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
|
@ -56,18 +56,22 @@ export const LockInvoicePrompt = ({ order, concept }: LockInvoicePromptProps): J
|
||||
alignItems='center'
|
||||
spacing={0.5}
|
||||
>
|
||||
<Grid item xs={12}>
|
||||
{concept === 'bond' ? <WalletsButton /> : <ExpirationWarning />}
|
||||
</Grid>
|
||||
|
||||
{concept == 'bond' ? (
|
||||
<Typography color='secondary'>
|
||||
<b>{t(`You are ${order.is_buyer ? 'BUYING' : 'SELLING'} BTC`)}</b>
|
||||
<Typography color='secondary' variant='h6' align='center'>
|
||||
<b>
|
||||
{order.currency == 1000
|
||||
? t(`${order.is_buyer ? 'SWAPPING INTO' : 'SWAPPING OUT of'} Lightning`)
|
||||
: t(`You are ${order.is_buyer ? 'BUYING' : 'SELLING'} BTC`)}
|
||||
</b>
|
||||
</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
<Grid item xs={12}>
|
||||
{concept === 'bond' ? <WalletsButton /> : <ExpirationWarning />}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
|
||||
<Box
|
||||
|
@ -54,9 +54,13 @@ export const PayoutPrompt = ({
|
||||
'Before letting you send {{amountFiat}} {{currencyCode}}, we want to make sure you are able to receive the BTC.',
|
||||
{
|
||||
amountFiat: pn(
|
||||
parseFloat(parseFloat(order.amount).toFixed(order.currency == 1000 ? 8 : 4)),
|
||||
parseFloat(
|
||||
parseFloat(
|
||||
order.currency == 1000 ? order.amount * 100000000 : order.amount,
|
||||
).toFixed(4),
|
||||
),
|
||||
),
|
||||
currencyCode,
|
||||
currencyCode: order.currency == 1000 ? 'Sats' : currencyCode,
|
||||
},
|
||||
)}
|
||||
</Typography>
|
||||
|
@ -1,5 +1,6 @@
|
||||
export interface Favorites {
|
||||
type: number | null;
|
||||
mode: 'swap' | 'fiat';
|
||||
currency: number;
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,12 @@ const filterOrders = function ({
|
||||
}: FilterOrders) {
|
||||
const filteredOrders = orders.filter((order) => {
|
||||
const typeChecks = order.type == baseFilter.type || baseFilter.type == null;
|
||||
const modeChecks = baseFilter.mode === 'fiat' ? !(order.currency === 1000) : true;
|
||||
const currencyChecks = order.currency == baseFilter.currency || baseFilter.currency == 0;
|
||||
const paymentMethodChecks =
|
||||
paymentMethods.length > 0 ? filterByPayment(order, paymentMethods) : true;
|
||||
const amountChecks = amountFilter != null ? filterByAmount(order, amountFilter) : true;
|
||||
return typeChecks && currencyChecks && paymentMethodChecks && amountChecks;
|
||||
return typeChecks && modeChecks && currencyChecks && paymentMethodChecks && amountChecks;
|
||||
});
|
||||
return filteredOrders;
|
||||
};
|
||||
|
@ -15,15 +15,16 @@ export const amountToString: (
|
||||
has_range: boolean,
|
||||
min_amount: number,
|
||||
max_amount: number,
|
||||
) => string = (amount, has_range, min_amount, max_amount) => {
|
||||
precision?: number,
|
||||
) => string = (amount, has_range, min_amount, max_amount, precision = 4) => {
|
||||
if (has_range) {
|
||||
return (
|
||||
pn(parseFloat(Number(min_amount).toPrecision(4))) +
|
||||
pn(parseFloat(Number(min_amount).toPrecision(precision))) +
|
||||
'-' +
|
||||
pn(parseFloat(Number(max_amount).toPrecision(4)))
|
||||
pn(parseFloat(Number(max_amount).toPrecision(precision)))
|
||||
);
|
||||
}
|
||||
return pn(parseFloat(Number(amount).toPrecision(4))) || '';
|
||||
return pn(parseFloat(Number(amount).toPrecision(precision))) || '';
|
||||
};
|
||||
|
||||
export default pn;
|
||||
|
Loading…
Reference in New Issue
Block a user