mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-31 10:31:35 +00:00
Fix order page
This commit is contained in:
parent
8d8e3a5688
commit
7c06c229b4
@ -18,7 +18,7 @@ import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageCon
|
||||
const BookPage = (): JSX.Element => {
|
||||
const { windowSize } = useContext<UseAppStoreType>(AppContext);
|
||||
const { setDelay } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage, clearOrder } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const [view, setView] = useState<'list' | 'depth' | 'map'>('list');
|
||||
@ -32,7 +32,6 @@ const BookPage = (): JSX.Element => {
|
||||
|
||||
const onOrderClicked = function (id: number, shortAlias: string): void {
|
||||
if (garage.getRobot().avatarLoaded) {
|
||||
clearOrder();
|
||||
setDelay(10000);
|
||||
navigate(`/order/${shortAlias}/${id}`);
|
||||
} else {
|
||||
|
@ -14,7 +14,7 @@ import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageCon
|
||||
|
||||
const MakerPage = (): JSX.Element => {
|
||||
const { fav, windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
|
||||
const { setDelay, federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage, maker } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
@ -50,15 +50,9 @@ const MakerPage = (): JSX.Element => {
|
||||
maker.paymentMethods,
|
||||
]);
|
||||
|
||||
const onViewOrder = function (): void {
|
||||
garage.updateOrder(null);
|
||||
setDelay(10000);
|
||||
};
|
||||
|
||||
const onOrderClicked = function (id: number): void {
|
||||
if (garage.getRobot().avatarLoaded) {
|
||||
navigate(`/order/${id}`);
|
||||
onViewOrder();
|
||||
} else {
|
||||
setOpenNoRobot(true);
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import {
|
||||
} from '@mui/icons-material';
|
||||
import RobotAvatar from '../../components/RobotAvatar';
|
||||
import { AppContext, type UseAppStoreType, closeAll } from '../../contexts/AppContext';
|
||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
|
||||
const NavBar = (): JSX.Element => {
|
||||
@ -33,8 +32,7 @@ const NavBar = (): JSX.Element => {
|
||||
navbarHeight,
|
||||
hostUrl,
|
||||
} = useContext<UseAppStoreType>(AppContext);
|
||||
const { currentOrder } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { garage, orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
@ -67,7 +65,7 @@ const NavBar = (): JSX.Element => {
|
||||
if (isPage(pathPage)) {
|
||||
setPage(pathPage);
|
||||
}
|
||||
}, [location, navigate, setPage]);
|
||||
}, [location, navigate, setPage, orderUpdatedAt]);
|
||||
|
||||
const handleSlideDirection = function (oldPage: Page, newPage: Page): void {
|
||||
const oldPos: number = pagesPosition[oldPage];
|
||||
@ -79,10 +77,15 @@ const NavBar = (): JSX.Element => {
|
||||
|
||||
const changePage = function (mouseEvent: any, newPage: Page): void {
|
||||
if (newPage !== 'none') {
|
||||
const slot = garage.getSlot();
|
||||
handleSlideDirection(page, newPage);
|
||||
setPage(newPage);
|
||||
const param =
|
||||
newPage === 'order' ? `${String(currentOrder.shortAlias)}/${String(currentOrder.id)}` : '';
|
||||
newPage === 'order'
|
||||
? `${String(slot.activeOrderShortAlias)}/${String(
|
||||
slot.activeOrderId ?? slot.lastOrderId,
|
||||
)}`
|
||||
: '';
|
||||
setTimeout(() => {
|
||||
navigate(`/${newPage}/${param}`);
|
||||
}, theme.transitions.duration.leavingScreen * 3);
|
||||
@ -159,7 +162,7 @@ const NavBar = (): JSX.Element => {
|
||||
sx={tabSx}
|
||||
label={smallBar ? undefined : t('Order')}
|
||||
value='order'
|
||||
disabled={!garage.getRobot().avatarLoaded || currentOrder.id == null}
|
||||
disabled={!garage.getRobot().avatarLoaded || !garage.getSlot().activeOrderId}
|
||||
icon={<Assignment />}
|
||||
iconPosition='start'
|
||||
/>
|
||||
|
@ -10,11 +10,12 @@ import { apiClient } from '../../services/api';
|
||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
import { type Order } from '../../models';
|
||||
|
||||
const OrderPage = (): JSX.Element => {
|
||||
const { windowSize, setOpen, settings, navbarHeight, hostUrl, origin } =
|
||||
useContext<UseAppStoreType>(AppContext);
|
||||
const { setFocusedCoordinator, federation, currentOrder, setCurrentOrder, focusedCoordinator } =
|
||||
const { setFocusedCoordinator, federation, focusedCoordinator } =
|
||||
useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage, badOrder, setBadOrder } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { t } = useTranslation();
|
||||
@ -26,26 +27,47 @@ const OrderPage = (): JSX.Element => {
|
||||
|
||||
const [tab, setTab] = useState<'order' | 'contract'>('contract');
|
||||
const [baseUrl, setBaseUrl] = useState<string>(hostUrl);
|
||||
const [currentOrder, setCurrentOrder] = useState<Order | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const newOrder = {
|
||||
shortAlias: params.shortAlias ?? '',
|
||||
id: Number(params.orderId) ?? null,
|
||||
order: null,
|
||||
};
|
||||
const coordinator = federation.getCoordinator(params.shortAlias ?? '');
|
||||
const { url, basePath } = coordinator.getEndpoint(
|
||||
settings.network,
|
||||
origin,
|
||||
settings.selfhostedClient,
|
||||
hostUrl,
|
||||
);
|
||||
|
||||
const { url, basePath } = federation
|
||||
.getCoordinator(newOrder.shortAlias)
|
||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||
setBaseUrl(`${url}${basePath}`);
|
||||
|
||||
if (currentOrder.id !== newOrder.id || currentOrder.shortAlias !== newOrder.shortAlias) {
|
||||
setCurrentOrder(newOrder);
|
||||
if (garage.getSlot().activeOrderId === Number(params.orderId)) {
|
||||
if (garage.getSlot().order != null) {
|
||||
setCurrentOrder(garage.getSlot().order);
|
||||
} else {
|
||||
coordinator
|
||||
.fetchOrder(Number(params.orderId) ?? null, garage.getRobot())
|
||||
.then((response) => {
|
||||
setCurrentOrder(response);
|
||||
garage.updateOrder(response as Order);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
coordinator
|
||||
.fetchOrder(Number(params.orderId) ?? null, garage.getRobot())
|
||||
.then((response) => {
|
||||
setCurrentOrder(response);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
}, [params]);
|
||||
|
||||
const onClickCoordinator = function (): void {
|
||||
if (currentOrder.shortAlias != null) {
|
||||
if (currentOrder?.shortAlias != null) {
|
||||
setFocusedCoordinator(currentOrder.shortAlias);
|
||||
}
|
||||
setOpen((open) => {
|
||||
@ -54,7 +76,7 @@ const OrderPage = (): JSX.Element => {
|
||||
};
|
||||
|
||||
const renewOrder = function (): void {
|
||||
const order = currentOrder.order;
|
||||
const order = currentOrder;
|
||||
if (order !== null && focusedCoordinator != null) {
|
||||
const body = {
|
||||
type: order.type,
|
||||
@ -73,16 +95,16 @@ const OrderPage = (): JSX.Element => {
|
||||
latitude: order.latitude,
|
||||
longitude: order.longitude,
|
||||
};
|
||||
const { url } = federation
|
||||
.getCoordinator(focusedCoordinator)
|
||||
const { url, basePath } = federation
|
||||
.getCoordinator(order.shortAlias)
|
||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||
apiClient
|
||||
.post(url, '/api/make/', body, { tokenSHA256: garage.getRobot().tokenSHA256 })
|
||||
.post(url + basePath, '/api/make/', body, { tokenSHA256: garage.getRobot().tokenSHA256 })
|
||||
.then((data: any) => {
|
||||
if (data.bad_request !== undefined) {
|
||||
setBadOrder(data.bad_request);
|
||||
} else if (data.id !== undefined) {
|
||||
navigate(`/order/${String(currentOrder.shortAlias)}/${String(data.id)}`);
|
||||
navigate(`/order/${String(currentOrder?.shortAlias)}/${String(data.id)}`);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@ -97,14 +119,14 @@ const OrderPage = (): JSX.Element => {
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{currentOrder.order === null && badOrder === undefined && <CircularProgress />}
|
||||
{currentOrder === null && badOrder === undefined && <CircularProgress />}
|
||||
{badOrder !== undefined ? (
|
||||
<Typography align='center' variant='subtitle2' color='secondary'>
|
||||
{t(badOrder)}
|
||||
</Typography>
|
||||
) : null}
|
||||
{currentOrder.order !== null && badOrder === undefined ? (
|
||||
currentOrder.order.is_participant ? (
|
||||
{currentOrder !== null && badOrder === undefined ? (
|
||||
currentOrder.is_participant ? (
|
||||
windowSize.width > doublePageWidth ? (
|
||||
// DOUBLE PAPER VIEW
|
||||
<Grid
|
||||
@ -125,7 +147,8 @@ const OrderPage = (): JSX.Element => {
|
||||
}}
|
||||
>
|
||||
<OrderDetails
|
||||
coordinator={federation.getCoordinator(String(currentOrder.shortAlias))}
|
||||
shortAlias={String(currentOrder.shortAlias)}
|
||||
currentOrder={currentOrder}
|
||||
onClickCoordinator={onClickCoordinator}
|
||||
baseUrl={baseUrl}
|
||||
onClickGenerateRobot={() => {
|
||||
@ -145,6 +168,7 @@ const OrderPage = (): JSX.Element => {
|
||||
>
|
||||
<TradeBox
|
||||
robot={garage.getRobot()}
|
||||
currentOrder={currentOrder}
|
||||
settings={settings}
|
||||
setBadOrder={setBadOrder}
|
||||
baseUrl={baseUrl}
|
||||
@ -179,7 +203,8 @@ const OrderPage = (): JSX.Element => {
|
||||
>
|
||||
<div style={{ display: tab === 'order' ? '' : 'none' }}>
|
||||
<OrderDetails
|
||||
coordinator={federation.getCoordinator(String(currentOrder.shortAlias))}
|
||||
shortAlias={String(currentOrder.shortAlias)}
|
||||
currentOrder={currentOrder}
|
||||
onClickCoordinator={onClickCoordinator}
|
||||
baseUrl={baseUrl}
|
||||
onClickGenerateRobot={() => {
|
||||
@ -190,6 +215,7 @@ const OrderPage = (): JSX.Element => {
|
||||
<div style={{ display: tab === 'contract' ? '' : 'none' }}>
|
||||
<TradeBox
|
||||
robot={garage.getRobot()}
|
||||
currentOrder={currentOrder}
|
||||
settings={settings}
|
||||
setBadOrder={setBadOrder}
|
||||
baseUrl={baseUrl}
|
||||
@ -210,7 +236,8 @@ const OrderPage = (): JSX.Element => {
|
||||
}}
|
||||
>
|
||||
<OrderDetails
|
||||
coordinator={federation.getCoordinator(String(currentOrder.shortAlias))}
|
||||
shortAlias={String(currentOrder.shortAlias)}
|
||||
currentOrder={currentOrder}
|
||||
onClickCoordinator={onClickCoordinator}
|
||||
baseUrl={hostUrl}
|
||||
onClickGenerateRobot={() => {
|
||||
|
@ -22,7 +22,6 @@ import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
import { genBase62Token } from '../../utils';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
|
||||
interface RobotProfileProps {
|
||||
robot: Robot;
|
||||
@ -45,7 +44,6 @@ const RobotProfile = ({
|
||||
width,
|
||||
}: RobotProfileProps): JSX.Element => {
|
||||
const { windowSize, hostUrl } = useContext<UseAppStoreType>(AppContext);
|
||||
const { currentOrder } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage, robotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
||||
|
||||
const { t } = useTranslation();
|
||||
@ -146,28 +144,36 @@ const RobotProfile = ({
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
{Boolean(garage.getRobot().activeOrderId) &&
|
||||
{Boolean(garage.getSlot().activeOrderId) &&
|
||||
garage.getRobot().avatarLoaded &&
|
||||
Boolean(garage.getRobot().nickname) ? (
|
||||
<Grid item>
|
||||
<Button
|
||||
onClick={() => {
|
||||
navigate(`/order/${String(currentOrder.shortAlias)}/${String(currentOrder.id)}`);
|
||||
navigate(
|
||||
`/order/${String(garage.getSlot().activeOrderShortAlias)}/${String(
|
||||
garage.getSlot().activeOrderId,
|
||||
)}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('Active order #{{orderID}}', { orderID: garage.getRobot().activeOrderId })}
|
||||
{t('Active order #{{orderID}}', { orderID: garage.getSlot().activeOrderId })}
|
||||
</Button>
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
{Boolean(garage.getRobot().lastOrderId) &&
|
||||
{Boolean(garage.getSlot().lastOrderId) &&
|
||||
garage.getRobot().avatarLoaded &&
|
||||
Boolean(garage.getRobot().nickname) ? (
|
||||
<Grid item container direction='column' alignItems='center'>
|
||||
<Grid item>
|
||||
<Button
|
||||
onClick={() => {
|
||||
navigate(`/order/${String(currentOrder.shortAlias)}/${String(currentOrder.id)}`);
|
||||
navigate(
|
||||
`/order/${String(garage.getRobot()?.shortAlias)}/${String(
|
||||
garage.getRobot()?.lastOrderId,
|
||||
)}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('Last order #{{orderID}}', { orderID: garage.getRobot().lastOrderId })}
|
||||
|
@ -30,7 +30,7 @@ import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
|
||||
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
||||
|
||||
interface TakeButtonProps {
|
||||
baseUrl: string;
|
||||
currentOrder: Order;
|
||||
info?: Info;
|
||||
onClickGenerateRobot?: () => void;
|
||||
}
|
||||
@ -42,7 +42,7 @@ interface OpenDialogsProps {
|
||||
const closeAll = { inactiveMaker: false, confirmation: false };
|
||||
|
||||
const TakeButton = ({
|
||||
baseUrl,
|
||||
currentOrder,
|
||||
info,
|
||||
onClickGenerateRobot = () => null,
|
||||
}: TakeButtonProps): JSX.Element => {
|
||||
@ -50,7 +50,7 @@ const TakeButton = ({
|
||||
const theme = useTheme();
|
||||
const { settings, origin, hostUrl } = useContext<UseAppStoreType>(AppContext);
|
||||
const { garage, orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { federation, focusedCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
|
||||
const [takeAmount, setTakeAmount] = useState<string>('');
|
||||
const [badRequest, setBadRequest] = useState<string>('');
|
||||
@ -59,18 +59,18 @@ const TakeButton = ({
|
||||
const [satoshis, setSatoshis] = useState<string>('');
|
||||
|
||||
const satoshisNow = (): string | undefined => {
|
||||
const order = garage.getOrder();
|
||||
|
||||
if (order === null) return;
|
||||
if (currentOrder === null) return;
|
||||
|
||||
const tradeFee = info?.taker_fee ?? 0;
|
||||
const defaultRoutingBudget = 0.001;
|
||||
const btcNow = order.satoshis_now / 100000000;
|
||||
const rate = order.amount != null ? order.amount / btcNow : order.max_amount / btcNow;
|
||||
const amount = order.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
const btcNow = currentOrder.satoshis_now / 100000000;
|
||||
const rate =
|
||||
currentOrder.amount != null ? currentOrder.amount / btcNow : currentOrder.max_amount / btcNow;
|
||||
const amount =
|
||||
currentOrder.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
const satoshis = computeSats({
|
||||
amount,
|
||||
routingBudget: order.is_buyer ? defaultRoutingBudget : 0,
|
||||
routingBudget: currentOrder.is_buyer ? defaultRoutingBudget : 0,
|
||||
fee: tradeFee,
|
||||
rate,
|
||||
});
|
||||
@ -82,9 +82,7 @@ const TakeButton = ({
|
||||
}, [orderUpdatedAt, takeAmount, info]);
|
||||
|
||||
const currencyCode: string =
|
||||
garage.getOrder()?.currency === 1000
|
||||
? 'Sats'
|
||||
: currencies[`${Number(garage.getOrder()?.currency)}`];
|
||||
currentOrder?.currency === 1000 ? 'Sats' : currencies[`${Number(currentOrder?.currency)}`];
|
||||
|
||||
const InactiveMakerDialog = function (): JSX.Element {
|
||||
return (
|
||||
@ -156,14 +154,13 @@ const TakeButton = ({
|
||||
};
|
||||
|
||||
const amountHelperText = useMemo(() => {
|
||||
const order = garage.getOrder();
|
||||
if (currentOrder === null) return;
|
||||
|
||||
if (order === null) return;
|
||||
|
||||
const amount = order.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
if (amount < Number(order.min_amount) && takeAmount !== '') {
|
||||
const amount =
|
||||
currentOrder.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
if (amount < Number(currentOrder.min_amount) && takeAmount !== '') {
|
||||
return t('Too low');
|
||||
} else if (amount > Number(order.max_amount) && takeAmount !== '') {
|
||||
} else if (amount > Number(currentOrder.max_amount) && takeAmount !== '') {
|
||||
return t('Too high');
|
||||
} else {
|
||||
return null;
|
||||
@ -171,7 +168,7 @@ const TakeButton = ({
|
||||
}, [orderUpdatedAt, takeAmount]);
|
||||
|
||||
const onTakeOrderClicked = function (): void {
|
||||
if (garage.getOrder()?.maker_status === 'Inactive') {
|
||||
if (currentOrder?.maker_status === 'Inactive') {
|
||||
setOpen({ inactiveMaker: true, confirmation: false });
|
||||
} else {
|
||||
setOpen({ inactiveMaker: false, confirmation: true });
|
||||
@ -179,18 +176,18 @@ const TakeButton = ({
|
||||
};
|
||||
|
||||
const invalidTakeAmount = useMemo(() => {
|
||||
const order = garage.getOrder();
|
||||
const amount = order?.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
const amount =
|
||||
currentOrder?.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
|
||||
return (
|
||||
amount < Number(order?.min_amount) ||
|
||||
amount > Number(order?.max_amount) ||
|
||||
amount < Number(currentOrder?.min_amount) ||
|
||||
amount > Number(currentOrder?.max_amount) ||
|
||||
takeAmount === '' ||
|
||||
takeAmount == null
|
||||
);
|
||||
}, [takeAmount, orderUpdatedAt]);
|
||||
|
||||
const takeOrderButton = function (): JSX.Element {
|
||||
if (garage.getOrder()?.has_range === true) {
|
||||
if (currentOrder?.has_range === true) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@ -229,8 +226,8 @@ const TakeButton = ({
|
||||
required={true}
|
||||
value={takeAmount}
|
||||
inputProps={{
|
||||
min: garage.getOrder()?.min_amount,
|
||||
max: garage.getOrder()?.max_amount,
|
||||
min: currentOrder?.min_amount,
|
||||
max: currentOrder?.max_amount,
|
||||
style: { textAlign: 'center' },
|
||||
}}
|
||||
onChange={handleTakeAmountChange}
|
||||
@ -283,7 +280,7 @@ const TakeButton = ({
|
||||
{satoshis !== '0' && satoshis !== '' && !invalidTakeAmount ? (
|
||||
<Grid item>
|
||||
<FormHelperText sx={{ position: 'relative', top: '0.15em' }}>
|
||||
{garage.getOrder()?.type === 1
|
||||
{currentOrder?.type === 1
|
||||
? t('You will receive {{satoshis}} Sats (Approx)', { satoshis })
|
||||
: t('You will send {{satoshis}} Sats (Approx)', { satoshis })}
|
||||
</FormHelperText>
|
||||
@ -317,19 +314,19 @@ const TakeButton = ({
|
||||
};
|
||||
|
||||
const takeOrder = function (): void {
|
||||
if (!(focusedCoordinator != null)) return;
|
||||
if (currentOrder === null) return;
|
||||
|
||||
setLoadingTake(true);
|
||||
const { url } = federation
|
||||
.getCoordinator(focusedCoordinator)
|
||||
const { url, basePath } = federation
|
||||
.getCoordinator(currentOrder.shortAlias)
|
||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||
apiClient
|
||||
.post(
|
||||
url,
|
||||
`/api/order/?order_id=${String(garage.getOrder()?.id)}`,
|
||||
url + basePath,
|
||||
`/api/order/?order_id=${String(currentOrder?.id)}`,
|
||||
{
|
||||
action: 'take',
|
||||
amount: garage.getOrder()?.currency === 1000 ? takeAmount / 100000000 : takeAmount,
|
||||
amount: currentOrder?.currency === 1000 ? takeAmount / 100000000 : takeAmount,
|
||||
},
|
||||
{ tokenSHA256: garage.getRobot().tokenSHA256 },
|
||||
)
|
||||
@ -350,7 +347,7 @@ const TakeButton = ({
|
||||
return (
|
||||
<Box>
|
||||
<Countdown
|
||||
date={new Date(garage.getOrder()?.penalty ?? '')}
|
||||
date={new Date(currentOrder?.penalty ?? '')}
|
||||
renderer={countdownTakeOrderRenderer}
|
||||
/>
|
||||
{badRequest !== '' ? (
|
||||
|
@ -43,52 +43,52 @@ import { F2fMapDialog } from '../Dialogs';
|
||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
||||
import { type Order } from '../../models';
|
||||
|
||||
interface OrderDetailsProps {
|
||||
coordinator: Coordinator;
|
||||
shortAlias: string;
|
||||
currentOrder: Order;
|
||||
onClickCoordinator?: () => void;
|
||||
baseUrl: string;
|
||||
onClickGenerateRobot?: () => void;
|
||||
}
|
||||
|
||||
const OrderDetails = ({
|
||||
coordinator,
|
||||
shortAlias,
|
||||
currentOrder,
|
||||
onClickCoordinator = () => null,
|
||||
baseUrl,
|
||||
onClickGenerateRobot = () => null,
|
||||
}: OrderDetailsProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const { hostUrl } = useContext<UseAppStoreType>(AppContext);
|
||||
const theme = useTheme();
|
||||
const { hostUrl } = useContext<UseAppStoreType>(AppContext);
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { currentOrder } = useContext<UseFederationStoreType>(FederationContext);
|
||||
|
||||
const currencyCode: string = currencies[(currentOrder.order?.currency ?? 1).toString()];
|
||||
const [coordinator] = useState<Coordinator | null>(federation.getCoordinator(shortAlias));
|
||||
const currencyCode: string = currencies[(currentOrder?.currency ?? 1).toString()];
|
||||
const [showSatsDetails, setShowSatsDetails] = useState<boolean>(false);
|
||||
const [openWorldmap, setOpenWorldmap] = useState<boolean>(false);
|
||||
|
||||
const amountString = useMemo(() => {
|
||||
// precision to 8 decimal if currency is BTC otherwise 4 decimals
|
||||
const order = currentOrder.order;
|
||||
if (currentOrder === null || currentOrder.amount === null) return;
|
||||
|
||||
if (order === null) return;
|
||||
|
||||
if (order.currency === 1000) {
|
||||
if (currentOrder.currency === 1000) {
|
||||
return (
|
||||
amountToString(
|
||||
(order.amount * 100000000).toString(),
|
||||
order.amount > 0 ? false : order.has_range,
|
||||
order.min_amount * 100000000,
|
||||
order.max_amount * 100000000,
|
||||
(currentOrder.amount * 100000000).toString(),
|
||||
currentOrder.amount > 0 ? false : currentOrder.has_range,
|
||||
currentOrder.min_amount * 100000000,
|
||||
currentOrder.max_amount * 100000000,
|
||||
) + ' Sats'
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
amountToString(
|
||||
order.amount.toString(),
|
||||
order.amount > 0 ? false : order.has_range,
|
||||
order.min_amount,
|
||||
order.max_amount,
|
||||
currentOrder.amount.toString(),
|
||||
currentOrder.amount > 0 ? false : currentOrder.has_range,
|
||||
currentOrder.min_amount,
|
||||
currentOrder.max_amount,
|
||||
) + ` ${currencyCode}`
|
||||
);
|
||||
}
|
||||
@ -107,7 +107,7 @@ const OrderDetails = ({
|
||||
return <span> {t('The order has expired')}</span>;
|
||||
} else {
|
||||
let color = 'inherit';
|
||||
const fraction_left = total / 1000 / (currentOrder.order?.total_secs_exp ?? 1);
|
||||
const fraction_left = total / 1000 / (currentOrder?.total_secs_exp ?? 1);
|
||||
// Make orange at 25% of time left
|
||||
if (fraction_left < 0.25) {
|
||||
color = theme.palette.warning.main;
|
||||
@ -167,7 +167,7 @@ const OrderDetails = ({
|
||||
let send: string = '';
|
||||
let receive: string = '';
|
||||
let sats: string = '';
|
||||
const order = currentOrder.order;
|
||||
const order = currentOrder;
|
||||
|
||||
if (order === null) return {};
|
||||
|
||||
@ -242,10 +242,10 @@ const OrderDetails = ({
|
||||
return (
|
||||
<Grid container spacing={0}>
|
||||
<F2fMapDialog
|
||||
latitude={currentOrder.order?.latitude}
|
||||
longitude={currentOrder.order?.longitude}
|
||||
latitude={currentOrder?.latitude}
|
||||
longitude={currentOrder?.longitude}
|
||||
open={openWorldmap}
|
||||
orderType={currentOrder.order?.type ?? 0}
|
||||
orderType={currentOrder?.type ?? 0}
|
||||
zoom={6}
|
||||
message={t(
|
||||
'The pinned location is approximate. The exact location for the meeting place must be exchanged in the encrypted chat.',
|
||||
@ -282,51 +282,44 @@ const OrderDetails = ({
|
||||
<ListItem>
|
||||
<ListItemAvatar sx={{ width: '4em', height: '4em' }}>
|
||||
<RobotAvatar
|
||||
statusColor={statusBadgeColor(currentOrder.order?.maker_status ?? '')}
|
||||
nickname={currentOrder.order?.maker_nick}
|
||||
tooltip={t(currentOrder.order?.maker_status ?? '')}
|
||||
orderType={currentOrder.order?.type}
|
||||
statusColor={statusBadgeColor(currentOrder?.maker_status ?? '')}
|
||||
nickname={currentOrder?.maker_nick}
|
||||
tooltip={t(currentOrder?.maker_status ?? '')}
|
||||
orderType={currentOrder?.type}
|
||||
baseUrl={baseUrl}
|
||||
small={true}
|
||||
/>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={`${String(currentOrder.order?.maker_nick)} (${
|
||||
currentOrder.order?.type === 1
|
||||
? t(currentOrder.order?.currency === 1000 ? 'Swapping Out' : 'Seller')
|
||||
: t(currentOrder.order?.currency === 1000 ? 'Swapping In' : 'Buyer')
|
||||
primary={`${String(currentOrder?.maker_nick)} (${
|
||||
currentOrder?.type === 1
|
||||
? t(currentOrder?.currency === 1000 ? 'Swapping Out' : 'Seller')
|
||||
: t(currentOrder?.currency === 1000 ? 'Swapping In' : 'Buyer')
|
||||
})`}
|
||||
secondary={t('Order maker')}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<Collapse
|
||||
in={
|
||||
currentOrder.order?.is_participant === true &&
|
||||
currentOrder.order?.taker_nick !== 'None'
|
||||
}
|
||||
>
|
||||
<Collapse in={currentOrder?.is_participant && currentOrder?.taker_nick !== 'None'}>
|
||||
<Divider />
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary={`${String(currentOrder.order?.taker_nick)} (${
|
||||
currentOrder.order?.type === 1
|
||||
? t(currentOrder.order?.currency === 1000 ? 'Swapping In' : 'Buyer')
|
||||
: t(currentOrder.order?.currency === 1000 ? 'Swapping Out' : 'Seller')
|
||||
primary={`${String(currentOrder?.taker_nick)} (${
|
||||
currentOrder?.type === 1
|
||||
? t(currentOrder?.currency === 1000 ? 'Swapping In' : 'Buyer')
|
||||
: t(currentOrder?.currency === 1000 ? 'Swapping Out' : 'Seller')
|
||||
})`}
|
||||
secondary={t('Order taker')}
|
||||
/>
|
||||
<ListItemAvatar>
|
||||
<RobotAvatar
|
||||
avatarClass='smallAvatar'
|
||||
statusColor={statusBadgeColor(currentOrder.order?.taker_status ?? '')}
|
||||
statusColor={statusBadgeColor(currentOrder?.taker_status ?? '')}
|
||||
nickname={
|
||||
currentOrder.order?.taker_nick === 'None'
|
||||
? undefined
|
||||
: currentOrder.order?.taker_nick
|
||||
currentOrder?.taker_nick === 'None' ? undefined : currentOrder?.taker_nick
|
||||
}
|
||||
tooltip={t(currentOrder.order?.taker_status ?? '')}
|
||||
orderType={currentOrder.order?.type === 0 ? 1 : 0}
|
||||
tooltip={t(currentOrder?.taker_status ?? '')}
|
||||
orderType={currentOrder?.type === 0 ? 1 : 0}
|
||||
baseUrl={baseUrl}
|
||||
small={true}
|
||||
/>
|
||||
@ -337,13 +330,13 @@ const OrderDetails = ({
|
||||
<Chip label={t('Order Details')} />
|
||||
</Divider>
|
||||
|
||||
<Collapse in={currentOrder.order?.is_participant}>
|
||||
<Collapse in={currentOrder?.is_participant}>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<Article />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t(currentOrder.order?.status_message ?? '')}
|
||||
primary={t(currentOrder?.status_message ?? '')}
|
||||
secondary={t('Order status')}
|
||||
/>
|
||||
</ListItem>
|
||||
@ -367,7 +360,7 @@ const OrderDetails = ({
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={amountString}
|
||||
secondary={(currentOrder.order?.amount ?? 0) > 0 ? 'Amount' : 'Amount Range'}
|
||||
secondary={(currentOrder?.amount ?? 0) > 0 ? 'Amount' : 'Amount Range'}
|
||||
/>
|
||||
<ListItemIcon>
|
||||
<IconButton
|
||||
@ -416,16 +409,16 @@ const OrderDetails = ({
|
||||
size={1.42 * theme.typography.fontSize}
|
||||
othersText={t('Others')}
|
||||
verbose={true}
|
||||
text={currentOrder.order?.payment_method}
|
||||
text={currentOrder?.payment_method}
|
||||
/>
|
||||
}
|
||||
secondary={
|
||||
currentOrder.order?.currency === 1000
|
||||
currentOrder?.currency === 1000
|
||||
? t('Swap destination')
|
||||
: t('Accepted payment methods')
|
||||
}
|
||||
/>
|
||||
{currentOrder.order?.payment_method.includes('Cash F2F') === true && (
|
||||
{currentOrder?.payment_method.includes('Cash F2F') && (
|
||||
<ListItemIcon>
|
||||
<Tooltip enterTouchDelay={0} title={t('F2F location')}>
|
||||
<div>
|
||||
@ -449,29 +442,27 @@ const OrderDetails = ({
|
||||
<PriceChange />
|
||||
</ListItemIcon>
|
||||
|
||||
{currentOrder.order?.price_now !== undefined ? (
|
||||
{currentOrder?.price_now !== undefined ? (
|
||||
<ListItemText
|
||||
primary={t('{{price}} {{currencyCode}}/BTC - Premium: {{premium}}%', {
|
||||
price: pn(currentOrder.order?.price_now),
|
||||
price: pn(currentOrder?.price_now),
|
||||
currencyCode,
|
||||
premium: currentOrder.order?.premium_now,
|
||||
premium: currentOrder?.premium_now,
|
||||
})}
|
||||
secondary={t('Price and Premium')}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{currentOrder.order?.price_now === undefined &&
|
||||
currentOrder.order?.is_explicit === true ? (
|
||||
{currentOrder?.price_now === undefined && currentOrder?.is_explicit ? (
|
||||
<ListItemText
|
||||
primary={pn(currentOrder.order?.satoshis)}
|
||||
primary={pn(currentOrder?.satoshis)}
|
||||
secondary={t('Amount of Satoshis')}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{currentOrder.order?.price_now === undefined &&
|
||||
!(currentOrder.order?.is_explicit === true) ? (
|
||||
{currentOrder?.price_now === undefined && !currentOrder?.is_explicit ? (
|
||||
<ListItemText
|
||||
primary={`${parseFloat(Number(currentOrder.order?.premium).toFixed(2))}%`}
|
||||
primary={`${parseFloat(Number(currentOrder?.premium).toFixed(2))}%`}
|
||||
secondary={t('Premium over market price')}
|
||||
/>
|
||||
) : null}
|
||||
@ -485,7 +476,7 @@ const OrderDetails = ({
|
||||
</ListItemIcon>
|
||||
<Grid container>
|
||||
<Grid item xs={4.5}>
|
||||
<ListItemText primary={currentOrder.order?.id} secondary={t('Order ID')} />
|
||||
<ListItemText primary={currentOrder?.id} secondary={t('Order ID')} />
|
||||
</Grid>
|
||||
<Grid item xs={7.5}>
|
||||
<Grid container>
|
||||
@ -496,7 +487,7 @@ const OrderDetails = ({
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<ListItemText
|
||||
primary={timerRenderer(currentOrder.order?.escrow_duration)}
|
||||
primary={timerRenderer(currentOrder?.escrow_duration)}
|
||||
secondary={t('Deposit timer')}
|
||||
></ListItemText>
|
||||
</Grid>
|
||||
@ -506,9 +497,7 @@ const OrderDetails = ({
|
||||
</ListItem>
|
||||
|
||||
{/* if order is in a status that does not expire, do not show countdown */}
|
||||
<Collapse
|
||||
in={![4, 5, 12, 13, 14, 15, 16, 17, 18].includes(currentOrder.order?.status ?? 0)}
|
||||
>
|
||||
<Collapse in={![4, 5, 12, 13, 14, 15, 16, 17, 18].includes(currentOrder?.status ?? 0)}>
|
||||
<Divider />
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
@ -516,24 +505,24 @@ const OrderDetails = ({
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary={t('Expires in')}>
|
||||
<Countdown
|
||||
date={new Date(currentOrder.order?.expires_at ?? '')}
|
||||
date={new Date(currentOrder?.expires_at ?? '')}
|
||||
renderer={countdownRenderer}
|
||||
/>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
<LinearDeterminate
|
||||
totalSecsExp={currentOrder.order?.total_secs_exp ?? 0}
|
||||
expiresAt={currentOrder.order?.expires_at ?? ''}
|
||||
totalSecsExp={currentOrder?.total_secs_exp ?? 0}
|
||||
expiresAt={currentOrder?.expires_at ?? ''}
|
||||
/>
|
||||
</Collapse>
|
||||
</List>
|
||||
|
||||
{/* If the user has a penalty/limit */}
|
||||
{currentOrder.order?.penalty !== undefined ? (
|
||||
{currentOrder?.penalty !== undefined ? (
|
||||
<Grid item xs={12}>
|
||||
<Alert severity='warning' sx={{ borderRadius: '0' }}>
|
||||
<Countdown
|
||||
date={new Date(currentOrder.order?.penalty ?? '')}
|
||||
date={new Date(currentOrder?.penalty ?? '')}
|
||||
renderer={countdownPenaltyRenderer}
|
||||
/>
|
||||
</Alert>
|
||||
@ -542,10 +531,10 @@ const OrderDetails = ({
|
||||
<></>
|
||||
)}
|
||||
|
||||
{!(currentOrder.order?.is_participant === true) ? (
|
||||
{!currentOrder?.is_participant ? (
|
||||
<Grid item xs={12}>
|
||||
<TakeButton
|
||||
baseUrl={baseUrl}
|
||||
currentOrder={currentOrder}
|
||||
info={coordinator.info}
|
||||
onClickGenerateRobot={onClickGenerateRobot}
|
||||
/>
|
||||
|
@ -102,6 +102,7 @@ const closeAll: OpenDialogProps = {
|
||||
|
||||
interface TradeBoxProps {
|
||||
robot: Robot;
|
||||
currentOrder: Order;
|
||||
setBadOrder: (state: string | undefined) => void;
|
||||
onRenewOrder: () => void;
|
||||
onStartAgain: () => void;
|
||||
@ -111,16 +112,17 @@ interface TradeBoxProps {
|
||||
|
||||
const TradeBox = ({
|
||||
robot,
|
||||
currentOrder,
|
||||
settings,
|
||||
baseUrl,
|
||||
setBadOrder,
|
||||
onRenewOrder,
|
||||
onStartAgain,
|
||||
}: TradeBoxProps): JSX.Element => {
|
||||
const { currentOrder, setCurrentOrder, federation, focusedCoordinator } =
|
||||
useContext<UseFederationStoreType>(FederationContext);
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage, orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { origin, hostUrl } = useContext<UseAppStoreType>(AppContext);
|
||||
|
||||
// Buttons and Dialogs
|
||||
const [loadingButtons, setLoadingButtons] = useState<loadingButtonsProps>(noLoadingButtons);
|
||||
const [open, setOpen] = useState<OpenDialogProps>(closeAll);
|
||||
@ -164,7 +166,7 @@ const TradeBox = ({
|
||||
rating,
|
||||
}: SubmitActionProps): void {
|
||||
const { url } = federation
|
||||
.getCoordinator(focusedCoordinator)
|
||||
.getCoordinator(currentOrder.shortAlias)
|
||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||
void apiClient
|
||||
.post(
|
||||
@ -193,12 +195,7 @@ const TradeBox = ({
|
||||
} else if (data.bad_statement !== undefined) {
|
||||
setDispute({ ...dispute, badStatement: data.bad_statement });
|
||||
} else {
|
||||
setCurrentOrder((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
order: { ...prev.order, ...data },
|
||||
};
|
||||
});
|
||||
garage.updateOrder(data);
|
||||
setBadOrder(undefined);
|
||||
}
|
||||
})
|
||||
@ -325,9 +322,9 @@ const TradeBox = ({
|
||||
|
||||
// Effect on Order Status change (used for WebLN)
|
||||
useEffect(() => {
|
||||
if (currentOrder.order !== null && currentOrder.order.status !== lastOrderStatus) {
|
||||
setLastOrderStatus(currentOrder.order.status);
|
||||
void handleWebln(currentOrder.order);
|
||||
if (currentOrder !== null && currentOrder.status !== lastOrderStatus) {
|
||||
setLastOrderStatus(currentOrder.status);
|
||||
void handleWebln(currentOrder);
|
||||
}
|
||||
// FIXME this should trigger with current order, not garage order
|
||||
}, [orderUpdatedAt]);
|
||||
@ -698,7 +695,7 @@ const TradeBox = ({
|
||||
return { title, titleVariables, titleColor, prompt, bondStatus, titleIcon };
|
||||
};
|
||||
|
||||
const contract = currentOrder.order != null ? statusToContract(currentOrder.order) : null;
|
||||
const contract = currentOrder != null ? statusToContract(currentOrder) : null;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@ -708,7 +705,7 @@ const TradeBox = ({
|
||||
setOpen(closeAll);
|
||||
}}
|
||||
waitingWebln={waitingWebln}
|
||||
isBuyer={currentOrder.order?.is_buyer ?? false}
|
||||
isBuyer={currentOrder?.is_buyer ?? false}
|
||||
/>
|
||||
<ConfirmDisputeDialog
|
||||
open={open.confirmDispute}
|
||||
@ -731,11 +728,11 @@ const TradeBox = ({
|
||||
}}
|
||||
onCollabCancelClick={cancel}
|
||||
loading={loadingButtons.cancel}
|
||||
peerAskedCancel={currentOrder.order?.pending_cancel ?? false}
|
||||
peerAskedCancel={currentOrder?.pending_cancel ?? false}
|
||||
/>
|
||||
<ConfirmFiatSentDialog
|
||||
open={open.confirmFiatSent}
|
||||
order={currentOrder.order}
|
||||
order={currentOrder}
|
||||
loadingButton={loadingButtons.fiatSent}
|
||||
onClose={() => {
|
||||
setOpen(closeAll);
|
||||
@ -752,14 +749,14 @@ const TradeBox = ({
|
||||
/>
|
||||
<ConfirmFiatReceivedDialog
|
||||
open={open.confirmFiatReceived}
|
||||
order={currentOrder.order}
|
||||
order={currentOrder}
|
||||
loadingButton={loadingButtons.fiatReceived}
|
||||
onClose={() => {
|
||||
setOpen(closeAll);
|
||||
}}
|
||||
onConfirmClick={confirmFiatReceived}
|
||||
/>
|
||||
<CollabCancelAlert order={currentOrder.order} />
|
||||
<CollabCancelAlert order={currentOrder} />
|
||||
<Grid
|
||||
container
|
||||
padding={1}
|
||||
@ -770,7 +767,7 @@ const TradeBox = ({
|
||||
>
|
||||
<Grid item>
|
||||
<Title
|
||||
order={currentOrder.order}
|
||||
order={currentOrder}
|
||||
text={contract?.title}
|
||||
color={contract?.titleColor}
|
||||
icon={contract?.titleIcon}
|
||||
@ -784,10 +781,7 @@ const TradeBox = ({
|
||||
{contract?.bondStatus !== 'hide' ? (
|
||||
<Grid item sx={{ width: '100%' }}>
|
||||
<Divider />
|
||||
<BondStatus
|
||||
status={contract?.bondStatus}
|
||||
isMaker={currentOrder.order?.is_maker ?? false}
|
||||
/>
|
||||
<BondStatus status={contract?.bondStatus} isMaker={currentOrder?.is_maker ?? false} />
|
||||
</Grid>
|
||||
) : (
|
||||
<></>
|
||||
@ -795,7 +789,7 @@ const TradeBox = ({
|
||||
|
||||
<Grid item>
|
||||
<CancelButton
|
||||
order={currentOrder.order}
|
||||
order={currentOrder}
|
||||
onClickCancel={cancel}
|
||||
openCancelDialog={() => {
|
||||
setOpen({ ...closeAll, confirmCancel: true });
|
||||
|
@ -48,19 +48,13 @@ export interface fetchRobotProps {
|
||||
isRefresh?: boolean;
|
||||
}
|
||||
|
||||
export interface CurrentOrder {
|
||||
shortAlias: string | null;
|
||||
id: number | null;
|
||||
order: Order | null;
|
||||
}
|
||||
|
||||
export interface UseFederationStoreType {
|
||||
federation: Federation;
|
||||
sortedCoordinators: string[];
|
||||
focusedCoordinator: string | null;
|
||||
setFocusedCoordinator: Dispatch<SetStateAction<string>>;
|
||||
currentOrder: CurrentOrder;
|
||||
setCurrentOrder: Dispatch<SetStateAction<CurrentOrder>>;
|
||||
currentOrder: Order | null;
|
||||
setCurrentOrder: Dispatch<SetStateAction<Order | null>>;
|
||||
setDelay: Dispatch<SetStateAction<number>>;
|
||||
coordinatorUpdatedAt: string;
|
||||
federationUpdatedAt: string;
|
||||
@ -70,8 +64,8 @@ export const initialFederationContext: UseFederationStoreType = {
|
||||
federation: new Federation(),
|
||||
sortedCoordinators: [],
|
||||
focusedCoordinator: '',
|
||||
currentOrder: null,
|
||||
setFocusedCoordinator: () => {},
|
||||
currentOrder: { shortAlias: null, id: null, order: null },
|
||||
setCurrentOrder: () => {},
|
||||
setDelay: () => {},
|
||||
coordinatorUpdatedAt: '',
|
||||
@ -83,7 +77,7 @@ export const FederationContext = createContext<UseFederationStoreType>(initialFe
|
||||
export const useFederationStore = (): UseFederationStoreType => {
|
||||
const { settings, page, origin, hostUrl, open, torStatus } =
|
||||
useContext<UseAppStoreType>(AppContext);
|
||||
const { setMaker, garage, robotUpdatedAt, badOrder } =
|
||||
const { setMaker, garage, orderUpdatedAt, robotUpdatedAt, badOrder } =
|
||||
useContext<UseGarageStoreType>(GarageContext);
|
||||
const [federation, setFederation] = useState(initialFederationContext.federation);
|
||||
const sortedCoordinators = useMemo(() => {
|
||||
@ -104,9 +98,7 @@ export const useFederationStore = (): UseFederationStoreType => {
|
||||
const [timer, setTimer] = useState<NodeJS.Timer | undefined>(() =>
|
||||
setInterval(() => null, delay),
|
||||
);
|
||||
const [currentOrder, setCurrentOrder] = useState<CurrentOrder>(
|
||||
initialFederationContext.currentOrder,
|
||||
);
|
||||
const [currentOrder, setCurrentOrder] = useState<Order | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// On bitcoin network change we reset book, limits and federation info and fetch everything again
|
||||
@ -124,8 +116,8 @@ export const useFederationStore = (): UseFederationStoreType => {
|
||||
}, [settings.network, torStatus]);
|
||||
|
||||
const fetchCurrentOrder = (): void => {
|
||||
if (currentOrder.id != null && (page === 'order' || badOrder === undefined)) {
|
||||
void federation.fetchOrder(currentOrder, garage.getRobot());
|
||||
if (currentOrder?.id != null && (page === 'order' || badOrder === undefined)) {
|
||||
void federation.fetchOrder(currentOrder, garage);
|
||||
}
|
||||
};
|
||||
|
||||
@ -134,6 +126,10 @@ export const useFederationStore = (): UseFederationStoreType => {
|
||||
fetchCurrentOrder();
|
||||
}, [currentOrder, page]);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentOrder(garage.getOrder());
|
||||
}, [orderUpdatedAt]);
|
||||
|
||||
useEffect(() => {
|
||||
clearInterval(timer);
|
||||
setTimer(setInterval(fetchCurrentOrder, delay));
|
||||
|
@ -10,7 +10,6 @@ export interface UseGarageStoreType {
|
||||
setBadOrder: Dispatch<SetStateAction<string | undefined>>;
|
||||
robotUpdatedAt: string;
|
||||
orderUpdatedAt: string;
|
||||
clearOrder: () => void;
|
||||
}
|
||||
|
||||
export const initialGarageContext: UseGarageStoreType = {
|
||||
@ -21,7 +20,6 @@ export const initialGarageContext: UseGarageStoreType = {
|
||||
setBadOrder: () => {},
|
||||
robotUpdatedAt: '',
|
||||
orderUpdatedAt: '',
|
||||
clearOrder: () => {},
|
||||
};
|
||||
|
||||
export const GarageContext = createContext<UseGarageStoreType>(initialGarageContext);
|
||||
@ -47,11 +45,6 @@ export const useGarageStore = (): UseGarageStoreType => {
|
||||
garage.registerHook('onOrderUpdate', onOrderUpdate);
|
||||
}, []);
|
||||
|
||||
const clearOrder = function (): void {
|
||||
garage.updateOrder(null);
|
||||
setBadOrder(undefined);
|
||||
};
|
||||
|
||||
return {
|
||||
garage,
|
||||
maker,
|
||||
@ -60,6 +53,5 @@ export const useGarageStore = (): UseGarageStoreType => {
|
||||
setBadOrder,
|
||||
robotUpdatedAt,
|
||||
orderUpdatedAt,
|
||||
clearOrder,
|
||||
};
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
import { apiClient } from '../services/api';
|
||||
import { validateTokenEntropy } from '../utils';
|
||||
import { compareUpdateLimit } from './Limit.model';
|
||||
import { defaultOrder } from './Order.model';
|
||||
|
||||
export interface Contact {
|
||||
nostr?: string | undefined;
|
||||
@ -122,7 +123,6 @@ export class Coordinator {
|
||||
public loadingInfo: boolean = false;
|
||||
public limits: LimitList = {};
|
||||
public loadingLimits: boolean = false;
|
||||
public robot?: Robot | undefined = undefined;
|
||||
public loadingRobot: boolean = true;
|
||||
|
||||
start = async (
|
||||
@ -297,10 +297,6 @@ export class Coordinator {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
if (
|
||||
newAttributes?.activeOrderId !== null ||
|
||||
(garage.getRobot(index).activeOrderId === null && newAttributes?.lastOrderId !== null)
|
||||
) {
|
||||
garage.updateRobot(
|
||||
{
|
||||
...newAttributes,
|
||||
@ -308,10 +304,10 @@ export class Coordinator {
|
||||
loading: false,
|
||||
bitsEntropy,
|
||||
shannonEntropy,
|
||||
shortAlias: this.shortAlias,
|
||||
},
|
||||
index,
|
||||
);
|
||||
}
|
||||
|
||||
return garage.getRobot(index);
|
||||
};
|
||||
@ -326,7 +322,12 @@ export class Coordinator {
|
||||
return await apiClient
|
||||
.get(this.url, `${this.basePath}/api/order/?order_id=${orderId}`, authHeaders)
|
||||
.then((data) => {
|
||||
return data as Order;
|
||||
const order: Order = {
|
||||
...defaultOrder,
|
||||
...data,
|
||||
shortAlias: this.shortAlias,
|
||||
};
|
||||
return order;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
|
@ -4,12 +4,11 @@ import {
|
||||
type Garage,
|
||||
type Origin,
|
||||
type PublicOrder,
|
||||
type Robot,
|
||||
type Settings,
|
||||
defaultExchange,
|
||||
type Order,
|
||||
} from '.';
|
||||
import defaultFederation from '../../static/federation.json';
|
||||
import { type CurrentOrder } from '../contexts/FederationContext';
|
||||
import { updateExchangeInfo } from './Exchange.model';
|
||||
|
||||
type FederationHooks = 'onCoordinatorUpdate' | 'onFederationReady';
|
||||
@ -97,20 +96,18 @@ export class Federation {
|
||||
});
|
||||
};
|
||||
|
||||
fetchOrder = async (currentOrder: CurrentOrder, robot: Robot): Promise<CurrentOrder | null> => {
|
||||
if (currentOrder.shortAlias !== null) {
|
||||
const coordinator = this.coordinators[currentOrder.shortAlias];
|
||||
if (coordinator != null && currentOrder.id !== null) {
|
||||
const newOrder = await coordinator.fetchOrder(currentOrder.id, robot);
|
||||
if (newOrder) {
|
||||
return {
|
||||
...currentOrder,
|
||||
order: newOrder,
|
||||
};
|
||||
fetchOrder = async (order: Order, garage: Garage): Promise<Order | null> => {
|
||||
if (order.shortAlias !== null) {
|
||||
const coordinator = this.coordinators[order.shortAlias];
|
||||
if (coordinator != null && order.id !== null) {
|
||||
const newOrder = await coordinator.fetchOrder(order.id, garage.getRobot());
|
||||
if (newOrder != null) {
|
||||
garage.updateOrder(newOrder);
|
||||
return newOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
return currentOrder;
|
||||
return order;
|
||||
};
|
||||
|
||||
// Coordinators
|
||||
|
@ -3,9 +3,22 @@ import { systemClient } from '../services/System';
|
||||
import { saveAsJson } from '../utils';
|
||||
export interface Slot {
|
||||
robot: Robot;
|
||||
lastOrderId: number | null;
|
||||
lastOrderShortAlias: string | null;
|
||||
activeOrderId: number | null;
|
||||
activeOrderShortAlias: string | null;
|
||||
order: Order | null;
|
||||
}
|
||||
|
||||
const defaultSlot = {
|
||||
robot: new Robot(),
|
||||
lastOrderId: null,
|
||||
lastOrderShortAlias: null,
|
||||
activeOrderId: null,
|
||||
activeOrderShortAlias: null,
|
||||
order: null,
|
||||
};
|
||||
|
||||
type GarageHooks = 'onRobotUpdate' | 'onOrderUpdate';
|
||||
|
||||
class Garage {
|
||||
@ -19,13 +32,17 @@ class Garage {
|
||||
.map((raw: any) => {
|
||||
const robot = new Robot(raw.robot);
|
||||
robot.update(raw.robot);
|
||||
return { robot, order: raw.order as Order };
|
||||
return {
|
||||
...defaultSlot,
|
||||
...raw,
|
||||
robot,
|
||||
};
|
||||
});
|
||||
console.log('Robot Garage was loaded from local storage');
|
||||
}
|
||||
|
||||
if (this.slots.length < 1) {
|
||||
this.slots = [{ robot: new Robot(), order: null }];
|
||||
this.slots = [defaultSlot];
|
||||
}
|
||||
|
||||
this.currentSlot = 0;
|
||||
@ -64,7 +81,7 @@ class Garage {
|
||||
|
||||
// Slots
|
||||
delete = (): void => {
|
||||
this.slots = [{ robot: new Robot(), order: null }];
|
||||
this.slots = [defaultSlot];
|
||||
systemClient.deleteItem('garage');
|
||||
this.triggerHook('onRobotUpdate');
|
||||
this.triggerHook('onOrderUpdate');
|
||||
@ -79,9 +96,9 @@ class Garage {
|
||||
this.save();
|
||||
};
|
||||
|
||||
getSlot: (index: number) => Slot = (index) => {
|
||||
getSlot: (index?: number) => Slot = (index = this.currentSlot) => {
|
||||
if (this.slots[index] === undefined) {
|
||||
this.slots[index] = { robot: new Robot(), order: null };
|
||||
this.slots[index] = defaultSlot;
|
||||
}
|
||||
|
||||
return this.slots[index];
|
||||
@ -95,6 +112,14 @@ class Garage {
|
||||
const robot = this.getSlot(index).robot;
|
||||
if (robot != null) {
|
||||
robot.update(attributes);
|
||||
if (attributes.activeOrderId != null) {
|
||||
this.slots[index].activeOrderId = attributes.activeOrderId;
|
||||
this.slots[index].activeOrderShortAlias = attributes.shortAlias;
|
||||
}
|
||||
if (attributes.lastOrderId != null) {
|
||||
this.slots[index].lastOrderId = attributes.lastOrderId;
|
||||
this.slots[index].lastOrderShortAlias = attributes.shortAlias;
|
||||
}
|
||||
this.triggerHook('onRobotUpdate');
|
||||
this.save();
|
||||
}
|
||||
@ -105,29 +130,32 @@ class Garage {
|
||||
};
|
||||
|
||||
createRobot = (attributes: Record<any, any>): void => {
|
||||
const newSlot = { robot: new Robot(), order: null };
|
||||
const newSlot = defaultSlot;
|
||||
newSlot.robot.update(attributes);
|
||||
this.slots.push(newSlot);
|
||||
this.currentSlot = this.slots.length - 1;
|
||||
this.save();
|
||||
};
|
||||
|
||||
// Orders
|
||||
updateOrder: (order: Order | null, index?: number) => void = (
|
||||
order,
|
||||
index = this.currentSlot,
|
||||
) => {
|
||||
const slot = this.getSlot(index);
|
||||
this.slots[index] = {
|
||||
...slot,
|
||||
order,
|
||||
getActiveOrderId: (index?: number) => number | null = (index = this.currentSlot) => {
|
||||
return this.getSlot(index)?.robot?.activeOrderId ?? null;
|
||||
};
|
||||
|
||||
// Orders
|
||||
updateOrder: (order: Order, index?: number) => void = (order, index = this.currentSlot) => {
|
||||
this.slots[index].order = order;
|
||||
this.triggerHook('onOrderUpdate');
|
||||
this.save();
|
||||
};
|
||||
|
||||
getOrder = (): Order | null => {
|
||||
return this.getSlot(this.currentSlot).order;
|
||||
deleteOrder: (index?: number) => void = (index = this.currentSlot) => {
|
||||
this.slots[index].order = null;
|
||||
this.triggerHook('onOrderUpdate');
|
||||
this.save();
|
||||
};
|
||||
|
||||
getOrder: (index?: number) => Order | null = (index = this.currentSlot) => {
|
||||
return this.getSlot(index)?.order;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -104,6 +104,120 @@ export interface Order {
|
||||
tx_queued: boolean;
|
||||
address: string;
|
||||
network: 'mainnet' | 'testnet';
|
||||
shortAlias: string;
|
||||
}
|
||||
|
||||
export const defaultOrder: Order = {
|
||||
shortAlias: '',
|
||||
id: 0,
|
||||
status: 0,
|
||||
created_at: new Date(),
|
||||
expires_at: new Date(),
|
||||
type: 0,
|
||||
currency: 0,
|
||||
amount: 0,
|
||||
has_range: false,
|
||||
min_amount: 0,
|
||||
max_amount: 0,
|
||||
payment_method: '',
|
||||
is_explicit: false,
|
||||
premium: 0,
|
||||
satoshis: 0,
|
||||
maker: 0,
|
||||
taker: 0,
|
||||
escrow_duration: 0,
|
||||
total_secs_exp: 0,
|
||||
penalty: undefined,
|
||||
is_maker: false,
|
||||
is_taker: false,
|
||||
is_participant: false,
|
||||
maker_status: 'Active',
|
||||
taker_status: 'Active',
|
||||
price_now: undefined,
|
||||
satoshis_now: 0,
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
premium_now: undefined,
|
||||
premium_percentile: 0,
|
||||
num_similar_orders: 0,
|
||||
tg_enabled: false,
|
||||
tg_token: '',
|
||||
tg_bot_name: '',
|
||||
is_buyer: false,
|
||||
is_seller: false,
|
||||
maker_nick: '',
|
||||
taker_nick: '',
|
||||
status_message: '',
|
||||
is_fiat_sent: false,
|
||||
is_disputed: false,
|
||||
ur_nick: '',
|
||||
maker_locked: false,
|
||||
taker_locked: false,
|
||||
escrow_locked: false,
|
||||
trade_satoshis: 0,
|
||||
bond_invoice: '',
|
||||
bond_satoshis: 0,
|
||||
escrow_invoice: '',
|
||||
escrow_satoshis: 0,
|
||||
invoice_amount: 0,
|
||||
swap_allowed: false,
|
||||
swap_failure_reason: '',
|
||||
suggested_mining_fee_rate: 0,
|
||||
swap_fee_rate: 0,
|
||||
pending_cancel: false,
|
||||
asked_for_cancel: false,
|
||||
statement_submitted: false,
|
||||
retries: 0,
|
||||
next_retry_time: new Date(),
|
||||
failure_reason: '',
|
||||
invoice_expired: false,
|
||||
public_duration: 0,
|
||||
bond_size: '',
|
||||
trade_fee_percent: 0,
|
||||
bond_size_sats: 0,
|
||||
bond_size_percent: 0,
|
||||
chat_last_index: 0,
|
||||
maker_summary: {
|
||||
is_buyer: false,
|
||||
sent_fiat: 0,
|
||||
received_sats: 0,
|
||||
is_swap: false,
|
||||
received_onchain_sats: 0,
|
||||
mining_fee_sats: 0,
|
||||
swap_fee_sats: 0,
|
||||
swap_fee_percent: 0,
|
||||
sent_sats: 0,
|
||||
received_fiat: 0,
|
||||
trade_fee_sats: 0,
|
||||
},
|
||||
taker_summary: {
|
||||
is_buyer: false,
|
||||
sent_fiat: 0,
|
||||
received_sats: 0,
|
||||
is_swap: false,
|
||||
received_onchain_sats: 0,
|
||||
mining_fee_sats: 0,
|
||||
swap_fee_sats: 0,
|
||||
swap_fee_percent: 0,
|
||||
sent_sats: 0,
|
||||
received_fiat: 0,
|
||||
trade_fee_sats: 0,
|
||||
},
|
||||
platform_summary: {
|
||||
contract_timestamp: new Date(),
|
||||
contract_total_time: 0,
|
||||
contract_exchange_rate: 0,
|
||||
routing_budget_sats: 0,
|
||||
trade_revenue_sats: 0,
|
||||
},
|
||||
expiry_reason: 0,
|
||||
expiry_message: '',
|
||||
num_satoshis: 0,
|
||||
sent_satoshis: 0,
|
||||
txid: '',
|
||||
tx_queued: false,
|
||||
address: '',
|
||||
network: 'mainnet',
|
||||
};
|
||||
|
||||
export default Order;
|
||||
|
@ -39,6 +39,7 @@ class Robot {
|
||||
public last_login: string = '';
|
||||
public copiedToken: boolean = false;
|
||||
public avatarLoaded: boolean = false;
|
||||
public shortAlias: string = '';
|
||||
|
||||
update = (attributes: Record<string, any>): void => {
|
||||
Object.assign(this, attributes);
|
||||
|
Loading…
Reference in New Issue
Block a user