mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 20:21:35 +00:00
parent
937ac62c5d
commit
eb840c5b14
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useContext, useEffect } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import {
|
import {
|
||||||
CommunityDialog,
|
CommunityDialog,
|
||||||
ExchangeDialog,
|
ExchangeDialog,
|
||||||
@ -9,16 +9,16 @@ import {
|
|||||||
ClientDialog,
|
ClientDialog,
|
||||||
UpdateDialog,
|
UpdateDialog,
|
||||||
} from '../../components/Dialogs';
|
} from '../../components/Dialogs';
|
||||||
import { pn } from '../../utils';
|
|
||||||
import { AppContext, type UseAppStoreType, closeAll } from '../../contexts/AppContext';
|
import { AppContext, type UseAppStoreType, closeAll } from '../../contexts/AppContext';
|
||||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||||
|
import { UseGarageStoreType, GarageContext } from '../../contexts/GarageContext';
|
||||||
|
|
||||||
export interface OpenDialogs {
|
export interface OpenDialogs {
|
||||||
more: boolean;
|
more: boolean;
|
||||||
learn: boolean;
|
learn: boolean;
|
||||||
community: boolean;
|
community: boolean;
|
||||||
info: boolean;
|
info: boolean;
|
||||||
coordinator: boolean;
|
coordinator: string;
|
||||||
exchange: boolean;
|
exchange: boolean;
|
||||||
client: boolean;
|
client: boolean;
|
||||||
update: boolean;
|
update: boolean;
|
||||||
@ -29,19 +29,8 @@ export interface OpenDialogs {
|
|||||||
const MainDialogs = (): JSX.Element => {
|
const MainDialogs = (): JSX.Element => {
|
||||||
const { open, setOpen, settings, clientVersion, hostUrl } =
|
const { open, setOpen, settings, clientVersion, hostUrl } =
|
||||||
useContext<UseAppStoreType>(AppContext);
|
useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation, focusedCoordinator, coordinatorUpdatedAt } =
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
|
|
||||||
const [maxAmount, setMaxAmount] = useState<string>('...loading...');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (focusedCoordinator !== null && focusedCoordinator !== '') {
|
|
||||||
const limits = federation.getCoordinator(focusedCoordinator).limits;
|
|
||||||
if (limits[1000] !== undefined) {
|
|
||||||
setMaxAmount(pn(limits[1000].max_amount * 100000000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [coordinatorUpdatedAt]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -56,7 +45,7 @@ const MainDialogs = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
<AboutDialog
|
<AboutDialog
|
||||||
open={open.info}
|
open={open.info}
|
||||||
maxAmount={maxAmount}
|
maxAmount={'100000'} //FIXME About dialog shoul allow to change coordinator
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen((open) => {
|
setOpen((open) => {
|
||||||
return { ...open, info: false };
|
return { ...open, info: false };
|
||||||
@ -103,16 +92,12 @@ const MainDialogs = (): JSX.Element => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CoordinatorDialog
|
<CoordinatorDialog
|
||||||
open={open.coordinator}
|
open={Boolean(open.coordinator)}
|
||||||
network={settings.network}
|
network={settings.network}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen(closeAll);
|
setOpen(closeAll);
|
||||||
}}
|
}}
|
||||||
coordinator={
|
shortAlias={open.coordinator}
|
||||||
focusedCoordinator !== null && focusedCoordinator !== ''
|
|
||||||
? federation.getCoordinator(focusedCoordinator)
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -6,7 +6,6 @@ import { useNavigate, useParams } from 'react-router-dom';
|
|||||||
import TradeBox from '../../components/TradeBox';
|
import TradeBox from '../../components/TradeBox';
|
||||||
import OrderDetails from '../../components/OrderDetails';
|
import OrderDetails from '../../components/OrderDetails';
|
||||||
|
|
||||||
import { apiClient } from '../../services/api';
|
|
||||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||||
@ -15,8 +14,7 @@ import { type Order } from '../../models';
|
|||||||
const OrderPage = (): JSX.Element => {
|
const OrderPage = (): JSX.Element => {
|
||||||
const { windowSize, setOpen, settings, navbarHeight, hostUrl, origin } =
|
const { windowSize, setOpen, settings, navbarHeight, hostUrl, origin } =
|
||||||
useContext<UseAppStoreType>(AppContext);
|
useContext<UseAppStoreType>(AppContext);
|
||||||
const { setFocusedCoordinator, federation, focusedCoordinator } =
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
|
||||||
const { garage, badOrder, setBadOrder } = useContext<UseGarageStoreType>(GarageContext);
|
const { garage, badOrder, setBadOrder } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@ -40,32 +38,18 @@ const OrderPage = (): JSX.Element => {
|
|||||||
|
|
||||||
setBaseUrl(`${url}${basePath}`);
|
setBaseUrl(`${url}${basePath}`);
|
||||||
|
|
||||||
if (garage.getSlot().activeOrderId === Number(params.orderId)) {
|
if (currentOrder?.id !== Number(params.orderId)) {
|
||||||
if (garage.getSlot().order != null) {
|
const coordinator = federation.getCoordinator(params.shortAlias ?? '');
|
||||||
setCurrentOrder(garage.getSlot().order);
|
|
||||||
} else {
|
|
||||||
coordinator
|
|
||||||
.fetchOrder(Number(params.orderId) ?? null, garage.getSlot().robot)
|
|
||||||
.then((order) => {
|
|
||||||
if (order?.bad_request !== undefined) {
|
|
||||||
setBadOrder(order.bad_request);
|
|
||||||
} else {
|
|
||||||
setCurrentOrder(order);
|
|
||||||
garage.updateOrder(order as Order);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
coordinator
|
coordinator
|
||||||
.fetchOrder(Number(params.orderId) ?? null, garage.getSlot().robot)
|
.fetchOrder(Number(params.orderId) ?? null, garage.getSlot().robot)
|
||||||
.then((order) => {
|
.then((order) => {
|
||||||
if (order?.bad_request !== undefined) {
|
if (order?.bad_request !== undefined) {
|
||||||
setBadOrder(order.bad_request);
|
setBadOrder(order.bad_request);
|
||||||
} else {
|
} else if (order !== null && order?.id !== null) {
|
||||||
setCurrentOrder(order);
|
setCurrentOrder(order);
|
||||||
|
if (order.is_participant) {
|
||||||
|
garage.updateOrder(order as Order);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
@ -76,50 +60,9 @@ const OrderPage = (): JSX.Element => {
|
|||||||
|
|
||||||
const onClickCoordinator = function (): void {
|
const onClickCoordinator = function (): void {
|
||||||
if (currentOrder?.shortAlias != null) {
|
if (currentOrder?.shortAlias != null) {
|
||||||
setFocusedCoordinator(currentOrder.shortAlias);
|
setOpen((open) => {
|
||||||
}
|
return { ...open, coordinator: shortAlias };
|
||||||
setOpen((open) => {
|
});
|
||||||
return { ...open, coordinator: true };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const renewOrder = function (): void {
|
|
||||||
const order = currentOrder;
|
|
||||||
if (order !== null && focusedCoordinator != null) {
|
|
||||||
const body = {
|
|
||||||
type: order.type,
|
|
||||||
currency: order.currency,
|
|
||||||
amount: order.has_range ? null : order.amount,
|
|
||||||
has_range: order.has_range,
|
|
||||||
min_amount: order.min_amount,
|
|
||||||
max_amount: order.max_amount,
|
|
||||||
payment_method: order.payment_method,
|
|
||||||
is_explicit: order.is_explicit,
|
|
||||||
premium: order.is_explicit ? null : order.premium,
|
|
||||||
satoshis: order.is_explicit ? order.satoshis : null,
|
|
||||||
public_duration: order.public_duration,
|
|
||||||
escrow_duration: order.escrow_duration,
|
|
||||||
bond_size: order.bond_size,
|
|
||||||
latitude: order.latitude,
|
|
||||||
longitude: order.longitude,
|
|
||||||
};
|
|
||||||
const { url, basePath } = federation
|
|
||||||
.getCoordinator(order.shortAlias)
|
|
||||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
|
||||||
apiClient
|
|
||||||
.post(url + basePath, '/api/make/', body, {
|
|
||||||
tokenSHA256: garage.getSlot().robot.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)}`);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setBadOrder('Request error');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -127,6 +70,26 @@ const OrderPage = (): JSX.Element => {
|
|||||||
navigate('/robot');
|
navigate('/robot');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const orderDetailsSpace = currentOrder ? (
|
||||||
|
<OrderDetails
|
||||||
|
shortAlias={String(currentOrder.shortAlias)}
|
||||||
|
currentOrder={currentOrder}
|
||||||
|
onClickCoordinator={onClickCoordinator}
|
||||||
|
baseUrl={baseUrl}
|
||||||
|
onClickGenerateRobot={() => {
|
||||||
|
navigate('/robot');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
|
|
||||||
|
const tradeBoxSpace = currentOrder ? (
|
||||||
|
<TradeBox baseUrl={baseUrl} onStartAgain={startAgain} />
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{currentOrder === null && badOrder === undefined && <CircularProgress />}
|
{currentOrder === null && badOrder === undefined && <CircularProgress />}
|
||||||
@ -156,15 +119,7 @@ const OrderPage = (): JSX.Element => {
|
|||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<OrderDetails
|
{orderDetailsSpace}
|
||||||
shortAlias={String(currentOrder.shortAlias)}
|
|
||||||
currentOrder={currentOrder}
|
|
||||||
onClickCoordinator={onClickCoordinator}
|
|
||||||
baseUrl={baseUrl}
|
|
||||||
onClickGenerateRobot={() => {
|
|
||||||
navigate('/robot');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6} style={{ width: '21em' }}>
|
<Grid item xs={6} style={{ width: '21em' }}>
|
||||||
@ -176,15 +131,7 @@ const OrderPage = (): JSX.Element => {
|
|||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TradeBox
|
{tradeBoxSpace}
|
||||||
robot={garage.getSlot().robot}
|
|
||||||
currentOrder={currentOrder}
|
|
||||||
settings={settings}
|
|
||||||
setBadOrder={setBadOrder}
|
|
||||||
baseUrl={baseUrl}
|
|
||||||
onRenewOrder={renewOrder}
|
|
||||||
onStartAgain={startAgain}
|
|
||||||
/>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -194,7 +141,7 @@ const OrderPage = (): JSX.Element => {
|
|||||||
<Box sx={{ borderBottom: 1, borderColor: 'divider', width: '21em' }}>
|
<Box sx={{ borderBottom: 1, borderColor: 'divider', width: '21em' }}>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={tab}
|
value={tab}
|
||||||
onChange={(mouseEvent, value) => {
|
onChange={(_mouseEvent, value) => {
|
||||||
setTab(value);
|
setTab(value);
|
||||||
}}
|
}}
|
||||||
variant='fullWidth'
|
variant='fullWidth'
|
||||||
@ -211,28 +158,8 @@ const OrderPage = (): JSX.Element => {
|
|||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: tab === 'order' ? '' : 'none' }}>
|
<div style={{ display: tab === 'order' ? '' : 'none' }}>{orderDetailsSpace}</div>
|
||||||
<OrderDetails
|
<div style={{ display: tab === 'contract' ? '' : 'none' }}>{tradeBoxSpace}</div>
|
||||||
shortAlias={String(currentOrder.shortAlias)}
|
|
||||||
currentOrder={currentOrder}
|
|
||||||
onClickCoordinator={onClickCoordinator}
|
|
||||||
baseUrl={baseUrl}
|
|
||||||
onClickGenerateRobot={() => {
|
|
||||||
navigate('/robot');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: tab === 'contract' ? '' : 'none' }}>
|
|
||||||
<TradeBox
|
|
||||||
robot={garage.getSlot().robot}
|
|
||||||
currentOrder={currentOrder}
|
|
||||||
settings={settings}
|
|
||||||
setBadOrder={setBadOrder}
|
|
||||||
baseUrl={baseUrl}
|
|
||||||
onRenewOrder={renewOrder}
|
|
||||||
onStartAgain={startAgain}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
@ -245,15 +172,7 @@ const OrderPage = (): JSX.Element => {
|
|||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<OrderDetails
|
{orderDetailsSpace}
|
||||||
shortAlias={String(currentOrder.shortAlias)}
|
|
||||||
currentOrder={currentOrder}
|
|
||||||
onClickCoordinator={onClickCoordinator}
|
|
||||||
baseUrl={hostUrl}
|
|
||||||
onClickGenerateRobot={() => {
|
|
||||||
navigate('/robot');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
|
@ -25,14 +25,7 @@ const SettingsPage = (): JSX.Element => {
|
|||||||
<SettingsForm showNetwork={!(window.NativeRobosats === undefined)} />
|
<SettingsForm showNetwork={!(window.NativeRobosats === undefined)} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<FederationTable
|
<FederationTable baseUrl={hostUrl} maxHeight={14} network={settings.network} />
|
||||||
openCoordinator={() => {
|
|
||||||
setOpen({ ...open, coordinator: true });
|
|
||||||
}}
|
|
||||||
baseUrl={hostUrl}
|
|
||||||
maxHeight={14}
|
|
||||||
network={settings.network}
|
|
||||||
/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
@ -108,7 +108,7 @@ const BookTable = ({
|
|||||||
}: BookTableProps): JSX.Element => {
|
}: BookTableProps): JSX.Element => {
|
||||||
const { fav, setFav, settings, setOpen, hostUrl, origin } =
|
const { fav, setFav, settings, setOpen, hostUrl, origin } =
|
||||||
useContext<UseAppStoreType>(AppContext);
|
useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation, setFocusedCoordinator, coordinatorUpdatedAt } =
|
const { federation, coordinatorUpdatedAt } =
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
useContext<UseFederationStoreType>(FederationContext);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -273,9 +273,8 @@ const BookTable = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onClickCoordinator = function (shortAlias: string): void {
|
const onClickCoordinator = function (shortAlias: string): void {
|
||||||
setFocusedCoordinator(shortAlias);
|
|
||||||
setOpen((open) => {
|
setOpen((open) => {
|
||||||
return { ...open, coordinator: true };
|
return { ...open, coordinator: shortAlias };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,11 +62,12 @@ import {
|
|||||||
import { AppContext } from '../../contexts/AppContext';
|
import { AppContext } from '../../contexts/AppContext';
|
||||||
import { systemClient } from '../../services/System';
|
import { systemClient } from '../../services/System';
|
||||||
import { type Badges } from '../../models/Coordinator.model';
|
import { type Badges } from '../../models/Coordinator.model';
|
||||||
|
import { UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
coordinator: Coordinator | null;
|
shortAlias: string | null;
|
||||||
network: 'mainnet' | 'testnet' | undefined;
|
network: 'mainnet' | 'testnet' | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,9 +336,11 @@ const BadgesHall = ({ badges }: BadgesProps): JSX.Element => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CoordinatorDialog = ({ open = false, onClose, coordinator, network }: Props): JSX.Element => {
|
const CoordinatorDialog = ({ open = false, onClose, network, shortAlias }: Props): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { clientVersion, page, hostUrl } = useContext(AppContext);
|
const { clientVersion, page, hostUrl } = useContext(AppContext);
|
||||||
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
|
const coordinator = federation.getCoordinator(shortAlias);
|
||||||
|
|
||||||
const [expanded, setExpanded] = useState<'summary' | 'stats' | 'policies' | undefined>(undefined);
|
const [expanded, setExpanded] = useState<'summary' | 'stats' | 'policies' | undefined>(undefined);
|
||||||
|
|
||||||
|
@ -9,22 +9,20 @@ import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
|||||||
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
||||||
|
|
||||||
interface FederationTableProps {
|
interface FederationTableProps {
|
||||||
openCoordinator: () => void;
|
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
fillContainer?: boolean;
|
fillContainer?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FederationTable = ({
|
const FederationTable = ({
|
||||||
openCoordinator,
|
|
||||||
maxWidth = 90,
|
maxWidth = 90,
|
||||||
maxHeight = 50,
|
maxHeight = 50,
|
||||||
fillContainer = false,
|
fillContainer = false,
|
||||||
}: FederationTableProps): JSX.Element => {
|
}: FederationTableProps): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { federation, sortedCoordinators, setFocusedCoordinator, coordinatorUpdatedAt } =
|
const { federation, sortedCoordinators, coordinatorUpdatedAt } =
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
useContext<UseFederationStoreType>(FederationContext);
|
||||||
const { hostUrl } = useContext<UseAppStoreType>(AppContext);
|
const { hostUrl, setOpen } = useContext<UseAppStoreType>(AppContext);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [pageSize, setPageSize] = useState<number>(0);
|
const [pageSize, setPageSize] = useState<number>(0);
|
||||||
|
|
||||||
@ -52,8 +50,9 @@ const FederationTable = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onClickCoordinator = function (shortAlias: string): void {
|
const onClickCoordinator = function (shortAlias: string): void {
|
||||||
setFocusedCoordinator(shortAlias);
|
setOpen((open) => {
|
||||||
openCoordinator();
|
return { ...open, coordinator: shortAlias };
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const aliasObj = useCallback((width: number) => {
|
const aliasObj = useCallback((width: number) => {
|
||||||
|
@ -68,7 +68,7 @@ const MakerForm = ({
|
|||||||
onClickGenerateRobot = () => null,
|
onClickGenerateRobot = () => null,
|
||||||
}: MakerFormProps): JSX.Element => {
|
}: MakerFormProps): JSX.Element => {
|
||||||
const { fav, setFav, settings, hostUrl, origin } = useContext<UseAppStoreType>(AppContext);
|
const { fav, setFav, settings, hostUrl, origin } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation, focusedCoordinator, coordinatorUpdatedAt, federationUpdatedAt } =
|
const { federation, coordinatorUpdatedAt, federationUpdatedAt } =
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
useContext<UseFederationStoreType>(FederationContext);
|
||||||
const { maker, setMaker, garage } = useContext<UseGarageStoreType>(GarageContext);
|
const { maker, setMaker, garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
|
|
||||||
@ -93,8 +93,8 @@ const MakerForm = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrencyCode(currencyDict[fav.currency === 0 ? 1 : fav.currency]);
|
setCurrencyCode(currencyDict[fav.currency === 0 ? 1 : fav.currency]);
|
||||||
if (focusedCoordinator != null) {
|
if (maker.coordinator != null) {
|
||||||
const newLimits = federation.getCoordinator(focusedCoordinator).limits;
|
const newLimits = federation.getCoordinator(maker.coordinator).limits;
|
||||||
if (Object.keys(newLimits).length !== 0) {
|
if (Object.keys(newLimits).length !== 0) {
|
||||||
updateAmountLimits(newLimits, fav.currency, maker.premium);
|
updateAmountLimits(newLimits, fav.currency, maker.premium);
|
||||||
updateCurrentPrice(newLimits, fav.currency, maker.premium);
|
updateCurrentPrice(newLimits, fav.currency, maker.premium);
|
||||||
@ -285,15 +285,9 @@ const MakerForm = ({
|
|||||||
.getCoordinator(maker.coordinator)
|
.getCoordinator(maker.coordinator)
|
||||||
?.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl) ?? {};
|
?.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl) ?? {};
|
||||||
|
|
||||||
const auth = {
|
const auth = garage.getSlot().robot.getAuthHeaders();
|
||||||
tokenSHA256: garage.getSlot().robot.tokenSHA256,
|
|
||||||
keys: {
|
|
||||||
pubKey: garage.getSlot().robot.pubKey?.split('\n').join('\\'),
|
|
||||||
encPrivKey: garage.getSlot().robot.encPrivKey?.split('\n').join('\\'),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!disableRequest && focusedCoordinator != null) {
|
if (!disableRequest && maker.coordinator != null && auth !== null) {
|
||||||
setSubmittingRequest(true);
|
setSubmittingRequest(true);
|
||||||
const body = {
|
const body = {
|
||||||
type: fav.type === 0 ? 1 : 0,
|
type: fav.type === 0 ? 1 : 0,
|
||||||
@ -320,6 +314,7 @@ const MakerForm = ({
|
|||||||
setBadRequest(data.bad_request);
|
setBadRequest(data.bad_request);
|
||||||
if (data.id !== undefined) {
|
if (data.id !== undefined) {
|
||||||
onOrderCreated(maker.coordinator, data.id);
|
onOrderCreated(maker.coordinator, data.id);
|
||||||
|
garage.updateOrder(data);
|
||||||
}
|
}
|
||||||
setSubmittingRequest(false);
|
setSubmittingRequest(false);
|
||||||
})
|
})
|
||||||
@ -446,9 +441,9 @@ const MakerForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const amountLabel = useMemo(() => {
|
const amountLabel = useMemo(() => {
|
||||||
if (!(focusedCoordinator != null)) return;
|
if (!(maker.coordinator != null)) return;
|
||||||
|
|
||||||
const info = federation.getCoordinator(focusedCoordinator)?.info;
|
const info = federation.getCoordinator(maker.coordinator)?.info;
|
||||||
const defaultRoutingBudget = 0.001;
|
const defaultRoutingBudget = 0.001;
|
||||||
let label = t('Amount');
|
let label = t('Amount');
|
||||||
let helper = '';
|
let helper = '';
|
||||||
|
@ -22,15 +22,13 @@ interface SelectCoordinatorProps {
|
|||||||
|
|
||||||
const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({ coordinator, setCoordinator }) => {
|
const SelectCoordinator: React.FC<SelectCoordinatorProps> = ({ coordinator, setCoordinator }) => {
|
||||||
const { setOpen, hostUrl } = useContext<UseAppStoreType>(AppContext);
|
const { setOpen, hostUrl } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation, setFocusedCoordinator, sortedCoordinators } =
|
const { federation, sortedCoordinators } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const onClickCurrentCoordinator = function (shortAlias: string): void {
|
const onClickCurrentCoordinator = function (shortAlias: string): void {
|
||||||
setFocusedCoordinator(shortAlias);
|
|
||||||
setOpen((open) => {
|
setOpen((open) => {
|
||||||
return { ...open, coordinator: true };
|
return { ...open, coordinator: shortAlias };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,9 +47,6 @@ const RobotAvatar: React.FC<Props> = ({
|
|||||||
coordinator = false,
|
coordinator = false,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
}) => {
|
}) => {
|
||||||
const { settings, origin, hostUrl } = useContext<UseAppStoreType>(AppContext);
|
|
||||||
const { federation, focusedCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
|
||||||
|
|
||||||
const [avatarSrc, setAvatarSrc] = useState<string>();
|
const [avatarSrc, setAvatarSrc] = useState<string>();
|
||||||
const [nicknameReady, setNicknameReady] = useState<boolean>(false);
|
const [nicknameReady, setNicknameReady] = useState<boolean>(false);
|
||||||
const [activeBackground, setActiveBackground] = useState<boolean>(true);
|
const [activeBackground, setActiveBackground] = useState<boolean>(true);
|
||||||
@ -66,13 +63,10 @@ const RobotAvatar: React.FC<Props> = ({
|
|||||||
if (window.NativeRobosats === undefined) {
|
if (window.NativeRobosats === undefined) {
|
||||||
setAvatarSrc(`${baseUrl}${path}${nickname}${small ? '.small' : ''}.webp`);
|
setAvatarSrc(`${baseUrl}${path}${nickname}${small ? '.small' : ''}.webp`);
|
||||||
setNicknameReady(true);
|
setNicknameReady(true);
|
||||||
} else if (focusedCoordinator != null) {
|
} else if (baseUrl != null && apiClient.fileImageUrl !== undefined) {
|
||||||
setNicknameReady(true);
|
setNicknameReady(true);
|
||||||
const { url, basePath } = federation
|
|
||||||
.getCoordinator(focusedCoordinator)
|
|
||||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
|
||||||
void apiClient
|
void apiClient
|
||||||
.fileImageUrl(url + basePath, `${path}${nickname}${small ? '.small' : ''}.webp`)
|
.fileImageUrl(baseUrl, `${path}${nickname}${small ? '.small' : ''}.webp`)
|
||||||
.then(setAvatarSrc);
|
.then(setAvatarSrc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,7 +25,6 @@ const audioPath =
|
|||||||
interface Props {
|
interface Props {
|
||||||
orderId: number;
|
orderId: number;
|
||||||
status: number;
|
status: number;
|
||||||
robot: Robot;
|
|
||||||
userNick: string;
|
userNick: string;
|
||||||
takerNick: string;
|
takerNick: string;
|
||||||
messages: EncryptedChatMessage[];
|
messages: EncryptedChatMessage[];
|
||||||
@ -38,7 +37,6 @@ interface Props {
|
|||||||
const EncryptedSocketChat: React.FC<Props> = ({
|
const EncryptedSocketChat: React.FC<Props> = ({
|
||||||
orderId,
|
orderId,
|
||||||
status,
|
status,
|
||||||
robot,
|
|
||||||
userNick,
|
userNick,
|
||||||
takerNick,
|
takerNick,
|
||||||
messages,
|
messages,
|
||||||
@ -110,7 +108,7 @@ const EncryptedSocketChat: React.FC<Props> = ({
|
|||||||
setConnected(true);
|
setConnected(true);
|
||||||
|
|
||||||
connection.send({
|
connection.send({
|
||||||
message: robot.pubKey,
|
message: garage.getSlot().robot.pubKey,
|
||||||
nick: userNick,
|
nick: userNick,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -132,10 +130,10 @@ const EncryptedSocketChat: React.FC<Props> = ({
|
|||||||
const createJsonFile: () => object = () => {
|
const createJsonFile: () => object = () => {
|
||||||
return {
|
return {
|
||||||
credentials: {
|
credentials: {
|
||||||
own_public_key: robot.pubKey,
|
own_public_key: garage.getSlot().robot.pubKey,
|
||||||
peer_public_key: peerPubKey,
|
peer_public_key: peerPubKey,
|
||||||
encrypted_private_key: robot.encPrivKey,
|
encrypted_private_key: garage.getSlot().robot.encPrivKey,
|
||||||
passphrase: robot.token,
|
passphrase: garage.getSlot().robot.token,
|
||||||
},
|
},
|
||||||
messages,
|
messages,
|
||||||
};
|
};
|
||||||
@ -143,7 +141,7 @@ const EncryptedSocketChat: React.FC<Props> = ({
|
|||||||
|
|
||||||
const onMessage: (message: any) => void = (message) => {
|
const onMessage: (message: any) => void = (message) => {
|
||||||
const dataFromServer = JSON.parse(message.data);
|
const dataFromServer = JSON.parse(message.data);
|
||||||
|
const robot = garage.getSlot().robot;
|
||||||
if (dataFromServer != null && !receivedIndexes.includes(dataFromServer.index)) {
|
if (dataFromServer != null && !receivedIndexes.includes(dataFromServer.index)) {
|
||||||
setReceivedIndexes((prev) => [...prev, dataFromServer.index]);
|
setReceivedIndexes((prev) => [...prev, dataFromServer.index]);
|
||||||
setPeerConnected(dataFromServer.peer_connected);
|
setPeerConnected(dataFromServer.peer_connected);
|
||||||
@ -213,6 +211,7 @@ const EncryptedSocketChat: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onButtonClicked = (e: React.FormEvent<HTMLFormElement>): void => {
|
const onButtonClicked = (e: React.FormEvent<HTMLFormElement>): void => {
|
||||||
|
const robot = garage.getSlot().robot;
|
||||||
if (robot.token !== undefined && value.includes(robot.token)) {
|
if (robot.token !== undefined && value.includes(robot.token)) {
|
||||||
alert(
|
alert(
|
||||||
`Aye! You just sent your own robot robot.token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`,
|
`Aye! You just sent your own robot robot.token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`,
|
||||||
@ -264,10 +263,10 @@ const EncryptedSocketChat: React.FC<Props> = ({
|
|||||||
}}
|
}}
|
||||||
orderId={Number(orderId)}
|
orderId={Number(orderId)}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
ownPubKey={robot.pubKey ?? ''}
|
ownPubKey={garage.getSlot().robot.pubKey ?? ''}
|
||||||
ownEncPrivKey={robot.encPrivKey ?? ''}
|
ownEncPrivKey={garage.getSlot().robot.encPrivKey ?? ''}
|
||||||
peerPubKey={peerPubKey ?? 'Not received yet'}
|
peerPubKey={peerPubKey ?? 'Not received yet'}
|
||||||
passphrase={robot.token ?? ''}
|
passphrase={garage.getSlot().robot.token ?? ''}
|
||||||
onClickBack={() => {
|
onClickBack={() => {
|
||||||
setAudit(false);
|
setAudit(false);
|
||||||
}}
|
}}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button, TextField, Grid, Paper, Typography } from '@mui/material';
|
import { Button, TextField, Grid, Paper, Typography } from '@mui/material';
|
||||||
import { encryptMessage, decryptMessage } from '../../../../pgp';
|
import { encryptMessage, decryptMessage } from '../../../../pgp';
|
||||||
@ -14,10 +14,12 @@ import ChatHeader from '../ChatHeader';
|
|||||||
import { type EncryptedChatMessage, type ServerMessage } from '..';
|
import { type EncryptedChatMessage, type ServerMessage } from '..';
|
||||||
import { apiClient } from '../../../../services/api';
|
import { apiClient } from '../../../../services/api';
|
||||||
import ChatBottom from '../ChatBottom';
|
import ChatBottom from '../ChatBottom';
|
||||||
|
import { UseAppStoreType, AppContext } from '../../../../contexts/AppContext';
|
||||||
|
import { UseFederationStoreType, FederationContext } from '../../../../contexts/FederationContext';
|
||||||
|
import { UseGarageStoreType, GarageContext } from '../../../../contexts/GarageContext';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
orderId: number;
|
orderId: number;
|
||||||
robot: Robot;
|
|
||||||
userNick: string;
|
userNick: string;
|
||||||
takerNick: string;
|
takerNick: string;
|
||||||
chatOffset: number;
|
chatOffset: number;
|
||||||
@ -35,7 +37,6 @@ const audioPath =
|
|||||||
|
|
||||||
const EncryptedTurtleChat: React.FC<Props> = ({
|
const EncryptedTurtleChat: React.FC<Props> = ({
|
||||||
orderId,
|
orderId,
|
||||||
robot,
|
|
||||||
userNick,
|
userNick,
|
||||||
takerNick,
|
takerNick,
|
||||||
chatOffset,
|
chatOffset,
|
||||||
@ -48,7 +49,8 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { origin, hostUrl, settings } = useContext<UseAppStoreType>(AppContext);
|
const { origin, hostUrl, settings } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation, focusedCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
|
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
|
|
||||||
const [audio] = useState(() => new Audio(`${audioPath}/chat-open.mp3`));
|
const [audio] = useState(() => new Audio(`${audioPath}/chat-open.mp3`));
|
||||||
const [peerConnected, setPeerConnected] = useState<boolean>(false);
|
const [peerConnected, setPeerConnected] = useState<boolean>(false);
|
||||||
@ -83,11 +85,11 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
|||||||
|
|
||||||
const loadMessages: () => void = () => {
|
const loadMessages: () => void = () => {
|
||||||
const { url, basePath } = federation
|
const { url, basePath } = federation
|
||||||
.getCoordinator(focusedCoordinator)
|
.getCoordinator(garage.getSlot().activeOrderShortAlias)
|
||||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||||
apiClient
|
apiClient
|
||||||
.get(url + basePath, `/api/chat/?order_id=${orderId}&offset=${lastIndex}`, {
|
.get(url + basePath, `/api/chat/?order_id=${orderId}&offset=${lastIndex}`, {
|
||||||
tokenSHA256: robot.tokenSHA256,
|
tokenSHA256: garage.getSlot().robot.tokenSHA256,
|
||||||
})
|
})
|
||||||
.then((results: any) => {
|
.then((results: any) => {
|
||||||
if (results != null) {
|
if (results != null) {
|
||||||
@ -104,16 +106,17 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
|||||||
const createJsonFile = (): object => {
|
const createJsonFile = (): object => {
|
||||||
return {
|
return {
|
||||||
credentials: {
|
credentials: {
|
||||||
own_public_key: robot.pubKey,
|
own_public_key: garage.getSlot().robot.pubKey,
|
||||||
peer_public_key: peerPubKey,
|
peer_public_key: peerPubKey,
|
||||||
encrypted_private_key: robot.encPrivKey,
|
encrypted_private_key: garage.getSlot().robot.encPrivKey,
|
||||||
passphrase: robot.token,
|
passphrase: garage.getSlot().robot.token,
|
||||||
},
|
},
|
||||||
messages,
|
messages,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMessage = (dataFromServer: ServerMessage): void => {
|
const onMessage = (dataFromServer: ServerMessage): void => {
|
||||||
|
const robot = garage.getSlot().robot;
|
||||||
if (dataFromServer != null) {
|
if (dataFromServer != null) {
|
||||||
// If we receive an encrypted message
|
// If we receive an encrypted message
|
||||||
if (dataFromServer.message.substring(0, 27) === `-----BEGIN PGP MESSAGE-----`) {
|
if (dataFromServer.message.substring(0, 27) === `-----BEGIN PGP MESSAGE-----`) {
|
||||||
@ -169,6 +172,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onButtonClicked = (e: React.FormEvent<HTMLFormElement>): void => {
|
const onButtonClicked = (e: React.FormEvent<HTMLFormElement>): void => {
|
||||||
|
const robot = garage.getSlot().robot;
|
||||||
if (robot.token !== undefined && value.includes(robot.token)) {
|
if (robot.token !== undefined && value.includes(robot.token)) {
|
||||||
alert(
|
alert(
|
||||||
`Aye! You just sent your own robot robot.token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`,
|
`Aye! You just sent your own robot robot.token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`,
|
||||||
@ -178,7 +182,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
|||||||
// If input string contains '#' send unencrypted and unlogged message
|
// If input string contains '#' send unencrypted and unlogged message
|
||||||
else if (value.substring(0, 1) === '#') {
|
else if (value.substring(0, 1) === '#') {
|
||||||
const { url, basePath } = federation
|
const { url, basePath } = federation
|
||||||
.getCoordinator(focusedCoordinator)
|
.getCoordinator(garage.getSlot().activeOrderShortAlias ?? '')
|
||||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||||
apiClient
|
apiClient
|
||||||
.post(
|
.post(
|
||||||
@ -211,7 +215,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
|||||||
encryptMessage(value, robot.pubKey, peerPubKey, robot.encPrivKey, robot.token)
|
encryptMessage(value, robot.pubKey, peerPubKey, robot.encPrivKey, robot.token)
|
||||||
.then((encryptedMessage) => {
|
.then((encryptedMessage) => {
|
||||||
const { url, basePath } = federation
|
const { url, basePath } = federation
|
||||||
.getCoordinator(focusedCoordinator)
|
.getCoordinator(garage.getSlot().activeOrderShortAlias ?? '')
|
||||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||||
apiClient
|
apiClient
|
||||||
.post(
|
.post(
|
||||||
@ -259,10 +263,10 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
|||||||
}}
|
}}
|
||||||
orderId={Number(orderId)}
|
orderId={Number(orderId)}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
ownPubKey={robot.pubKey ?? ''}
|
ownPubKey={garage.getSlot().robot.pubKey ?? ''}
|
||||||
ownEncPrivKey={robot.encPrivKey ?? ''}
|
ownEncPrivKey={garage.getSlot().robot.encPrivKey ?? ''}
|
||||||
peerPubKey={peerPubKey ?? 'Not received yet'}
|
peerPubKey={peerPubKey ?? 'Not received yet'}
|
||||||
passphrase={robot.token ?? ''}
|
passphrase={garage.getSlot().robot.token ?? ''}
|
||||||
onClickBack={() => {
|
onClickBack={() => {
|
||||||
setAudit(false);
|
setAudit(false);
|
||||||
}}
|
}}
|
||||||
|
@ -35,7 +35,6 @@ export interface ServerMessage {
|
|||||||
const EncryptedChat: React.FC<Props> = ({
|
const EncryptedChat: React.FC<Props> = ({
|
||||||
orderId,
|
orderId,
|
||||||
takerNick,
|
takerNick,
|
||||||
robot,
|
|
||||||
userNick,
|
userNick,
|
||||||
chatOffset,
|
chatOffset,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
@ -48,7 +47,6 @@ const EncryptedChat: React.FC<Props> = ({
|
|||||||
return turtleMode ? (
|
return turtleMode ? (
|
||||||
<EncryptedTurtleChat
|
<EncryptedTurtleChat
|
||||||
messages={messages}
|
messages={messages}
|
||||||
robot={robot}
|
|
||||||
setMessages={setMessages}
|
setMessages={setMessages}
|
||||||
orderId={orderId}
|
orderId={orderId}
|
||||||
takerNick={takerNick}
|
takerNick={takerNick}
|
||||||
@ -62,7 +60,6 @@ const EncryptedChat: React.FC<Props> = ({
|
|||||||
<EncryptedSocketChat
|
<EncryptedSocketChat
|
||||||
status={status}
|
status={status}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
robot={robot}
|
|
||||||
setMessages={setMessages}
|
setMessages={setMessages}
|
||||||
orderId={orderId}
|
orderId={orderId}
|
||||||
takerNick={takerNick}
|
takerNick={takerNick}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Grid, Typography, Tooltip, Collapse } from '@mui/material';
|
import { Grid, Typography, Tooltip, Collapse } from '@mui/material';
|
||||||
import currencies from '../../../../static/assets/currencies.json';
|
import currencies from '../../../../static/assets/currencies.json';
|
||||||
@ -8,10 +8,10 @@ import { pn } from '../../../utils';
|
|||||||
import EncryptedChat, { type EncryptedChatMessage } from '../EncryptedChat';
|
import EncryptedChat, { type EncryptedChatMessage } from '../EncryptedChat';
|
||||||
import Countdown, { zeroPad } from 'react-countdown';
|
import Countdown, { zeroPad } from 'react-countdown';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
|
import { UseGarageStoreType, GarageContext } from '../../../contexts/GarageContext';
|
||||||
|
|
||||||
interface ChatPromptProps {
|
interface ChatPromptProps {
|
||||||
order: Order;
|
order: Order;
|
||||||
robot: Robot;
|
|
||||||
onClickConfirmSent: () => void;
|
onClickConfirmSent: () => void;
|
||||||
onClickUndoConfirmSent: () => void;
|
onClickUndoConfirmSent: () => void;
|
||||||
loadingSent: boolean;
|
loadingSent: boolean;
|
||||||
@ -27,7 +27,6 @@ interface ChatPromptProps {
|
|||||||
|
|
||||||
export const ChatPrompt = ({
|
export const ChatPrompt = ({
|
||||||
order,
|
order,
|
||||||
robot,
|
|
||||||
onClickConfirmSent,
|
onClickConfirmSent,
|
||||||
onClickUndoConfirmSent,
|
onClickUndoConfirmSent,
|
||||||
onClickConfirmReceived,
|
onClickConfirmReceived,
|
||||||
@ -41,6 +40,7 @@ export const ChatPrompt = ({
|
|||||||
setMessages,
|
setMessages,
|
||||||
}: ChatPromptProps): JSX.Element => {
|
}: ChatPromptProps): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
|
|
||||||
const [sentButton, setSentButton] = useState<boolean>(false);
|
const [sentButton, setSentButton] = useState<boolean>(false);
|
||||||
const [receivedButton, setReceivedButton] = useState<boolean>(false);
|
const [receivedButton, setReceivedButton] = useState<boolean>(false);
|
||||||
@ -49,9 +49,9 @@ export const ChatPrompt = ({
|
|||||||
const [enableDisputeTime, setEnableDisputeTime] = useState<Date>(new Date(order.expires_at));
|
const [enableDisputeTime, setEnableDisputeTime] = useState<Date>(new Date(order.expires_at));
|
||||||
const [text, setText] = useState<string>('');
|
const [text, setText] = useState<string>('');
|
||||||
|
|
||||||
const currencyCode: string = currencies[`${order.currency}`];
|
const currencyCode: string = currencies[`${garage.getSlot().order.currency}`];
|
||||||
const amount: string = pn(
|
const amount: string = pn(
|
||||||
parseFloat(parseFloat(order.amount).toFixed(order.currency === 1000 ? 8 : 4)),
|
parseFloat(parseFloat(garage.getSlot().order.amount).toFixed(order.currency === 1000 ? 8 : 4)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const disputeCountdownRenderer = function ({
|
const disputeCountdownRenderer = function ({
|
||||||
@ -133,7 +133,6 @@ export const ChatPrompt = ({
|
|||||||
<Grid item>
|
<Grid item>
|
||||||
<EncryptedChat
|
<EncryptedChat
|
||||||
status={order.status}
|
status={order.status}
|
||||||
robot={robot}
|
|
||||||
chatOffset={order.chat_last_index}
|
chatOffset={order.chat_last_index}
|
||||||
orderId={order.id}
|
orderId={order.id}
|
||||||
takerNick={order.taker_nick}
|
takerNick={order.taker_nick}
|
||||||
|
@ -45,14 +45,15 @@ import {
|
|||||||
defaultDispute,
|
defaultDispute,
|
||||||
} from './Forms';
|
} from './Forms';
|
||||||
|
|
||||||
import { type Order, type Robot, type Settings } from '../../models';
|
import { type Order } from '../../models';
|
||||||
import { type EncryptedChatMessage } from './EncryptedChat';
|
import { type EncryptedChatMessage } from './EncryptedChat';
|
||||||
import CollabCancelAlert from './CollabCancelAlert';
|
import CollabCancelAlert from './CollabCancelAlert';
|
||||||
import { Bolt } from '@mui/icons-material';
|
import { Bolt } from '@mui/icons-material';
|
||||||
import { signCleartextMessage } from '../../pgp';
|
import { signCleartextMessage } from '../../pgp';
|
||||||
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
|
||||||
import { type UseGarageStoreType, GarageContext } from '../../contexts/GarageContext';
|
import { type UseGarageStoreType, GarageContext } from '../../contexts/GarageContext';
|
||||||
import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
|
import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
|
||||||
|
import { FederationContext, UseFederationStoreType } from '../../contexts/FederationContext';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
interface loadingButtonsProps {
|
interface loadingButtonsProps {
|
||||||
cancel: boolean;
|
cancel: boolean;
|
||||||
@ -101,27 +102,24 @@ const closeAll: OpenDialogProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface TradeBoxProps {
|
interface TradeBoxProps {
|
||||||
robot: Robot;
|
|
||||||
currentOrder: Order;
|
|
||||||
setBadOrder: (state: string | undefined) => void;
|
|
||||||
onRenewOrder: () => void;
|
|
||||||
onStartAgain: () => void;
|
|
||||||
settings: Settings;
|
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
onStartAgain: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TradeBox = ({
|
interface Contract {
|
||||||
robot,
|
title: string;
|
||||||
currentOrder,
|
titleVariables: object;
|
||||||
settings,
|
titleColor: string;
|
||||||
baseUrl,
|
prompt: () => JSX.Element;
|
||||||
setBadOrder,
|
bondStatus: 'hide' | 'locked' | 'unlocked' | 'settled';
|
||||||
onRenewOrder,
|
titleIcon: () => JSX.Element;
|
||||||
onStartAgain,
|
}
|
||||||
}: TradeBoxProps): JSX.Element => {
|
|
||||||
|
const TradeBox = ({ baseUrl, onStartAgain }: TradeBoxProps): JSX.Element => {
|
||||||
|
const { garage, orderUpdatedAt, setBadOrder } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
|
const { settings, hostUrl, origin } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
const { garage, orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
const navigate = useNavigate();
|
||||||
const { origin, hostUrl } = useContext<UseAppStoreType>(AppContext);
|
|
||||||
|
|
||||||
// Buttons and Dialogs
|
// Buttons and Dialogs
|
||||||
const [loadingButtons, setLoadingButtons] = useState<loadingButtonsProps>(noLoadingButtons);
|
const [loadingButtons, setLoadingButtons] = useState<loadingButtonsProps>(noLoadingButtons);
|
||||||
@ -156,6 +154,46 @@ const TradeBox = ({
|
|||||||
rating?: number;
|
rating?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renewOrder = function (): void {
|
||||||
|
const currentOrder = garage.getSlot().order;
|
||||||
|
if (currentOrder !== null) {
|
||||||
|
const body = {
|
||||||
|
type: currentOrder.type,
|
||||||
|
currency: currentOrder.currency,
|
||||||
|
amount: currentOrder.has_range ? null : currentOrder.amount,
|
||||||
|
has_range: currentOrder.has_range,
|
||||||
|
min_amount: currentOrder.min_amount,
|
||||||
|
max_amount: currentOrder.max_amount,
|
||||||
|
payment_method: currentOrder.payment_method,
|
||||||
|
is_explicit: currentOrder.is_explicit,
|
||||||
|
premium: currentOrder.is_explicit ? null : currentOrder.premium,
|
||||||
|
satoshis: currentOrder.is_explicit ? currentOrder.satoshis : null,
|
||||||
|
public_duration: currentOrder.public_duration,
|
||||||
|
escrow_duration: currentOrder.escrow_duration,
|
||||||
|
bond_size: currentOrder.bond_size,
|
||||||
|
latitude: currentOrder.latitude,
|
||||||
|
longitude: currentOrder.longitude,
|
||||||
|
};
|
||||||
|
const { url, basePath } = federation
|
||||||
|
.getCoordinator(currentOrder.shortAlias)
|
||||||
|
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||||
|
apiClient
|
||||||
|
.post(url + basePath, '/api/make/', body, {
|
||||||
|
tokenSHA256: garage.getSlot().robot.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)}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setBadOrder('Request error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const submitAction = function ({
|
const submitAction = function ({
|
||||||
action,
|
action,
|
||||||
invoice,
|
invoice,
|
||||||
@ -165,13 +203,13 @@ const TradeBox = ({
|
|||||||
statement,
|
statement,
|
||||||
rating,
|
rating,
|
||||||
}: SubmitActionProps): void {
|
}: SubmitActionProps): void {
|
||||||
const { url, basePath } = federation
|
const robot = garage.getSlot().robot;
|
||||||
.getCoordinator(currentOrder.shortAlias)
|
const currentOrder = garage.getSlot().order;
|
||||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
|
||||||
void apiClient
|
void apiClient
|
||||||
.post(
|
.post(
|
||||||
url + basePath,
|
baseUrl,
|
||||||
`/api/order/?order_id=${Number(currentOrder.id)}`,
|
`/api/order/?order_id=${Number(currentOrder?.id)}`,
|
||||||
{
|
{
|
||||||
action,
|
action,
|
||||||
invoice,
|
invoice,
|
||||||
@ -268,6 +306,7 @@ const TradeBox = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const submitStatement = function (): void {
|
const submitStatement = function (): void {
|
||||||
|
const robot = garage.getSlot().robot;
|
||||||
let statement = dispute.statement;
|
let statement = dispute.statement;
|
||||||
if (dispute.attachLogs) {
|
if (dispute.attachLogs) {
|
||||||
const payload = { statement, messages, token: robot.token };
|
const payload = { statement, messages, token: robot.token };
|
||||||
@ -322,44 +361,48 @@ const TradeBox = ({
|
|||||||
|
|
||||||
// Effect on Order Status change (used for WebLN)
|
// Effect on Order Status change (used for WebLN)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const currentOrder = garage.getSlot().order;
|
||||||
if (currentOrder !== null && currentOrder.status !== lastOrderStatus) {
|
if (currentOrder !== null && currentOrder.status !== lastOrderStatus) {
|
||||||
setLastOrderStatus(currentOrder.status);
|
setLastOrderStatus(currentOrder.status);
|
||||||
void handleWebln(currentOrder);
|
void handleWebln(currentOrder);
|
||||||
}
|
}
|
||||||
// FIXME this should trigger with current order, not garage order
|
|
||||||
}, [orderUpdatedAt]);
|
}, [orderUpdatedAt]);
|
||||||
|
|
||||||
const statusToContract = function (order: Order): JSX.Element {
|
const statusToContract = function (): Contract {
|
||||||
|
const order = garage.getSlot().order;
|
||||||
|
|
||||||
|
const baseContract: Contract = {
|
||||||
|
title: 'Unknown Order Status',
|
||||||
|
titleVariables: {},
|
||||||
|
titleColor: 'primary',
|
||||||
|
prompt: () => <span>Wops!</span>,
|
||||||
|
bondStatus: 'hide',
|
||||||
|
titleIcon: () => <></>,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (order === null) return baseContract;
|
||||||
|
|
||||||
const status = order.status;
|
const status = order.status;
|
||||||
const isBuyer = order.is_buyer;
|
const isBuyer = order.is_buyer;
|
||||||
const isMaker = order.is_maker;
|
const isMaker = order.is_maker;
|
||||||
|
|
||||||
let title: string = 'Unknown Order Status';
|
|
||||||
let titleVariables: object = {};
|
|
||||||
let titleColor: string = 'primary';
|
|
||||||
let titleIcon: () => JSX.Element = function () {
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
let prompt = (): JSX.Element => <span>Wops!</span>;
|
|
||||||
let bondStatus: 'hide' | 'locked' | 'unlocked' | 'settled' = 'hide';
|
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
// 0: 'Waiting for maker bond'
|
// 0: 'Waiting for maker bond'
|
||||||
case 0:
|
case 0:
|
||||||
if (isMaker) {
|
if (isMaker) {
|
||||||
title = 'Lock {{amountSats}} Sats to PUBLISH order';
|
baseContract.title = 'Lock {{amountSats}} Sats to PUBLISH order';
|
||||||
titleVariables = { amountSats: pn(order.bond_satoshis) };
|
baseContract.titleVariables = { amountSats: pn(order.bond_satoshis) };
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return <LockInvoicePrompt order={order} concept={'bond'} />;
|
return <LockInvoicePrompt order={order} concept={'bond'} />;
|
||||||
};
|
};
|
||||||
bondStatus = 'hide';
|
baseContract.bondStatus = 'hide';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// 1: 'Public'
|
// 1: 'Public'
|
||||||
case 1:
|
case 1:
|
||||||
if (isMaker) {
|
if (isMaker) {
|
||||||
title = 'Your order is public';
|
baseContract.title = 'Your order is public';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return (
|
return (
|
||||||
<PublicWaitPrompt
|
<PublicWaitPrompt
|
||||||
order={order}
|
order={order}
|
||||||
@ -368,14 +411,14 @@ const TradeBox = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
bondStatus = 'locked';
|
baseContract.bondStatus = 'locked';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// 2: 'Paused'
|
// 2: 'Paused'
|
||||||
case 2:
|
case 2:
|
||||||
if (isMaker) {
|
if (isMaker) {
|
||||||
title = 'Your order is paused';
|
baseContract.title = 'Your order is paused';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return (
|
return (
|
||||||
<PausedPrompt
|
<PausedPrompt
|
||||||
pauseLoading={loadingButtons.pauseOrder}
|
pauseLoading={loadingButtons.pauseOrder}
|
||||||
@ -383,53 +426,53 @@ const TradeBox = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
bondStatus = 'locked';
|
baseContract.bondStatus = 'locked';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 3: 'Waiting for taker bond'
|
// 3: 'Waiting for taker bond'
|
||||||
case 3:
|
case 3:
|
||||||
if (isMaker) {
|
if (isMaker) {
|
||||||
title = 'A taker has been found!';
|
baseContract.title = 'A taker has been found!';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return <TakerFoundPrompt />;
|
return <TakerFoundPrompt />;
|
||||||
};
|
};
|
||||||
bondStatus = 'locked';
|
baseContract.bondStatus = 'locked';
|
||||||
} else {
|
} else {
|
||||||
title = 'Lock {{amountSats}} Sats to TAKE order';
|
baseContract.title = 'Lock {{amountSats}} Sats to TAKE order';
|
||||||
titleVariables = { amountSats: pn(order.bond_satoshis) };
|
baseContract.titleVariables = { amountSats: pn(order.bond_satoshis) };
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return <LockInvoicePrompt order={order} concept={'bond'} />;
|
return <LockInvoicePrompt order={order} concept={'bond'} />;
|
||||||
};
|
};
|
||||||
bondStatus = 'hide';
|
baseContract.bondStatus = 'hide';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 5: 'Expired'
|
// 5: 'Expired'
|
||||||
case 5:
|
case 5:
|
||||||
title = 'The order has expired';
|
baseContract.title = 'The order has expired';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return (
|
return (
|
||||||
<ExpiredPrompt
|
<ExpiredPrompt
|
||||||
loadingRenew={loadingButtons.renewOrder}
|
loadingRenew={loadingButtons.renewOrder}
|
||||||
order={order}
|
order={order}
|
||||||
onClickRenew={() => {
|
onClickRenew={() => {
|
||||||
onRenewOrder();
|
renewOrder();
|
||||||
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
bondStatus = 'hide'; // To do: show bond status according to expiry message.
|
baseContract.bondStatus = 'hide'; // To do: show bond status according to expiry message.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 6: 'Waiting for trade collateral and buyer invoice'
|
// 6: 'Waiting for trade collateral and buyer invoice'
|
||||||
case 6:
|
case 6:
|
||||||
bondStatus = 'locked';
|
baseContract.bondStatus = 'locked';
|
||||||
if (isBuyer) {
|
if (isBuyer) {
|
||||||
title = 'Submit payout info';
|
baseContract.title = 'Submit payout info';
|
||||||
titleVariables = { amountSats: pn(order.invoice_amount) };
|
baseContract.titleVariables = { amountSats: pn(order.invoice_amount) };
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return (
|
return (
|
||||||
<PayoutPrompt
|
<PayoutPrompt
|
||||||
order={order}
|
order={order}
|
||||||
@ -446,10 +489,10 @@ const TradeBox = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
title = 'Lock {{amountSats}} Sats as collateral';
|
baseContract.title = 'Lock {{amountSats}} Sats as collateral';
|
||||||
titleVariables = { amountSats: pn(order.escrow_satoshis) };
|
baseContract.titleVariables = { amountSats: pn(order.escrow_satoshis) };
|
||||||
titleColor = 'warning';
|
baseContract.titleColor = 'warning';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return <LockInvoicePrompt order={order} concept={'escrow'} />;
|
return <LockInvoicePrompt order={order} concept={'escrow'} />;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -457,17 +500,17 @@ const TradeBox = ({
|
|||||||
|
|
||||||
// 7: 'Waiting only for seller trade collateral'
|
// 7: 'Waiting only for seller trade collateral'
|
||||||
case 7:
|
case 7:
|
||||||
bondStatus = 'locked';
|
baseContract.bondStatus = 'locked';
|
||||||
if (isBuyer) {
|
if (isBuyer) {
|
||||||
title = 'Your info looks good!';
|
baseContract.title = 'Your info looks good!';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return <EscrowWaitPrompt />;
|
return <EscrowWaitPrompt />;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
title = 'Lock {{amountSats}} Sats as collateral';
|
baseContract.title = 'Lock {{amountSats}} Sats as collateral';
|
||||||
titleVariables = { amountSats: pn(order.escrow_satoshis) };
|
baseContract.titleVariables = { amountSats: pn(order.escrow_satoshis) };
|
||||||
titleColor = 'warning';
|
baseContract.titleColor = 'warning';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return <LockInvoicePrompt order={order} concept={'escrow'} />;
|
return <LockInvoicePrompt order={order} concept={'escrow'} />;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -475,11 +518,11 @@ const TradeBox = ({
|
|||||||
|
|
||||||
// 8: 'Waiting only for buyer invoice'
|
// 8: 'Waiting only for buyer invoice'
|
||||||
case 8:
|
case 8:
|
||||||
bondStatus = 'locked';
|
baseContract.bondStatus = 'locked';
|
||||||
if (isBuyer) {
|
if (isBuyer) {
|
||||||
title = 'Submit payout info';
|
baseContract.title = 'Submit payout info';
|
||||||
titleVariables = { amountSats: pn(order.invoice_amount) };
|
baseContract.titleVariables = { amountSats: pn(order.invoice_amount) };
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return (
|
return (
|
||||||
<PayoutPrompt
|
<PayoutPrompt
|
||||||
order={order}
|
order={order}
|
||||||
@ -496,8 +539,8 @@ const TradeBox = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
title = 'The trade collateral is locked!';
|
baseContract.title = 'The trade collateral is locked!';
|
||||||
prompt = () => {
|
baseContract.prompt = () => {
|
||||||
return <PayoutWaitPrompt />;
|
return <PayoutWaitPrompt />;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -507,12 +550,11 @@ const TradeBox = ({
|
|||||||
// 10: 'Fiat sent - In chatroom'
|
// 10: 'Fiat sent - In chatroom'
|
||||||
case 9:
|
case 9:
|
||||||
case 10:
|
case 10:
|
||||||
title = isBuyer ? 'Chat with the seller' : 'Chat with the buyer';
|
baseContract.title = isBuyer ? 'Chat with the seller' : 'Chat with the buyer';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return (
|
return (
|
||||||
<ChatPrompt
|
<ChatPrompt
|
||||||
order={order}
|
order={order}
|
||||||
robot={robot}
|
|
||||||
onClickConfirmSent={() => {
|
onClickConfirmSent={() => {
|
||||||
setOpen({ ...open, confirmFiatSent: true });
|
setOpen({ ...open, confirmFiatSent: true });
|
||||||
}}
|
}}
|
||||||
@ -535,20 +577,20 @@ const TradeBox = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
bondStatus = 'locked';
|
baseContract.bondStatus = 'locked';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 11: 'In dispute'
|
// 11: 'In dispute'
|
||||||
case 11:
|
case 11:
|
||||||
bondStatus = 'settled';
|
baseContract.bondStatus = 'settled';
|
||||||
if (order.statement_submitted) {
|
if (order.statement_submitted) {
|
||||||
title = 'We have received your statement';
|
baseContract.title = 'We have received your statement';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return <DisputeWaitPeerPrompt />;
|
return <DisputeWaitPeerPrompt />;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
title = 'A dispute has been opened';
|
baseContract.title = 'A dispute has been opened';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return (
|
return (
|
||||||
<DisputePrompt
|
<DisputePrompt
|
||||||
loading={loadingButtons.submitStatement}
|
loading={loadingButtons.submitStatement}
|
||||||
@ -567,18 +609,18 @@ const TradeBox = ({
|
|||||||
// 13: 'Sending satoshis to buyer'
|
// 13: 'Sending satoshis to buyer'
|
||||||
case 13:
|
case 13:
|
||||||
if (isBuyer) {
|
if (isBuyer) {
|
||||||
bondStatus = 'unlocked';
|
baseContract.bondStatus = 'unlocked';
|
||||||
title = 'Attempting Lightning Payment';
|
baseContract.title = 'Attempting Lightning Payment';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return <SendingSatsPrompt />;
|
return <SendingSatsPrompt />;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
title = 'Trade finished!';
|
baseContract.title = 'Trade finished!';
|
||||||
titleColor = 'success';
|
baseContract.titleColor = 'success';
|
||||||
titleIcon = function () {
|
baseContract.titleIcon = function () {
|
||||||
return <Bolt xs={{ width: '1em', height: '1em' }} color='warning' />;
|
return <Bolt xs={{ width: '1em', height: '1em' }} color='warning' />;
|
||||||
};
|
};
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return (
|
return (
|
||||||
<SuccessfulPrompt
|
<SuccessfulPrompt
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
@ -587,7 +629,7 @@ const TradeBox = ({
|
|||||||
onClickStartAgain={onStartAgain}
|
onClickStartAgain={onStartAgain}
|
||||||
loadingRenew={loadingButtons.renewOrder}
|
loadingRenew={loadingButtons.renewOrder}
|
||||||
onClickRenew={() => {
|
onClickRenew={() => {
|
||||||
onRenewOrder();
|
renewOrder();
|
||||||
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -598,12 +640,12 @@ const TradeBox = ({
|
|||||||
|
|
||||||
// 14: 'Sucessful trade'
|
// 14: 'Sucessful trade'
|
||||||
case 14:
|
case 14:
|
||||||
title = 'Trade finished!';
|
baseContract.title = 'Trade finished!';
|
||||||
titleColor = 'success';
|
baseContract.titleColor = 'success';
|
||||||
titleIcon = function () {
|
baseContract.titleIcon = function () {
|
||||||
return <Bolt xs={{ width: '1em', height: '1em' }} color='warning' />;
|
return <Bolt xs={{ width: '1em', height: '1em' }} color='warning' />;
|
||||||
};
|
};
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return (
|
return (
|
||||||
<SuccessfulPrompt
|
<SuccessfulPrompt
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
@ -612,7 +654,7 @@ const TradeBox = ({
|
|||||||
onClickStartAgain={onStartAgain}
|
onClickStartAgain={onStartAgain}
|
||||||
loadingRenew={loadingButtons.renewOrder}
|
loadingRenew={loadingButtons.renewOrder}
|
||||||
onClickRenew={() => {
|
onClickRenew={() => {
|
||||||
onRenewOrder();
|
renewOrder();
|
||||||
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -623,9 +665,9 @@ const TradeBox = ({
|
|||||||
// 15: 'Failed lightning network routing'
|
// 15: 'Failed lightning network routing'
|
||||||
case 15:
|
case 15:
|
||||||
if (isBuyer) {
|
if (isBuyer) {
|
||||||
bondStatus = 'unlocked';
|
baseContract.bondStatus = 'unlocked';
|
||||||
title = 'Lightning Routing Failed';
|
baseContract.title = 'Lightning Routing Failed';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return (
|
return (
|
||||||
<RoutingFailedPrompt
|
<RoutingFailedPrompt
|
||||||
order={order}
|
order={order}
|
||||||
@ -638,12 +680,12 @@ const TradeBox = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
title = 'Trade finished!';
|
baseContract.title = 'Trade finished!';
|
||||||
titleColor = 'success';
|
baseContract.titleColor = 'success';
|
||||||
titleIcon = function () {
|
baseContract.titleIcon = function () {
|
||||||
return <Bolt xs={{ width: '1em', height: '1em' }} color='warning' />;
|
return <Bolt xs={{ width: '1em', height: '1em' }} color='warning' />;
|
||||||
};
|
};
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return (
|
return (
|
||||||
<SuccessfulPrompt
|
<SuccessfulPrompt
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
@ -652,7 +694,7 @@ const TradeBox = ({
|
|||||||
onClickStartAgain={onStartAgain}
|
onClickStartAgain={onStartAgain}
|
||||||
loadingRenew={loadingButtons.renewOrder}
|
loadingRenew={loadingButtons.renewOrder}
|
||||||
onClickRenew={() => {
|
onClickRenew={() => {
|
||||||
onRenewOrder();
|
renewOrder();
|
||||||
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
setLoadingButtons({ ...noLoadingButtons, renewOrder: true });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -663,9 +705,9 @@ const TradeBox = ({
|
|||||||
|
|
||||||
// 16: 'Wait for dispute resolution'
|
// 16: 'Wait for dispute resolution'
|
||||||
case 16:
|
case 16:
|
||||||
bondStatus = 'settled';
|
baseContract.bondStatus = 'settled';
|
||||||
title = 'We have the statements';
|
baseContract.title = 'We have the statements';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return <DisputeWaitResolutionPrompt />;
|
return <DisputeWaitResolutionPrompt />;
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
@ -675,14 +717,14 @@ const TradeBox = ({
|
|||||||
case 17:
|
case 17:
|
||||||
case 18:
|
case 18:
|
||||||
if ((status === 17 && isMaker) || (status === 18 && !isMaker)) {
|
if ((status === 17 && isMaker) || (status === 18 && !isMaker)) {
|
||||||
title = 'You have lost the dispute';
|
baseContract.title = 'You have lost the dispute';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return <DisputeLoserPrompt />;
|
return <DisputeLoserPrompt />;
|
||||||
};
|
};
|
||||||
bondStatus = 'settled';
|
baseContract.bondStatus = 'settled';
|
||||||
} else if ((status === 17 && !isMaker) || (status === 18 && isMaker)) {
|
} else if ((status === 17 && !isMaker) || (status === 18 && isMaker)) {
|
||||||
title = 'You have won the dispute';
|
baseContract.title = 'You have won the dispute';
|
||||||
prompt = function () {
|
baseContract.prompt = function () {
|
||||||
return <DisputeWinnerPrompt />;
|
return <DisputeWinnerPrompt />;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -692,10 +734,10 @@ const TradeBox = ({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { title, titleVariables, titleColor, prompt, bondStatus, titleIcon };
|
return baseContract;
|
||||||
};
|
};
|
||||||
|
|
||||||
const contract = currentOrder != null ? statusToContract(currentOrder) : null;
|
const contract = statusToContract();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
@ -705,7 +747,7 @@ const TradeBox = ({
|
|||||||
setOpen(closeAll);
|
setOpen(closeAll);
|
||||||
}}
|
}}
|
||||||
waitingWebln={waitingWebln}
|
waitingWebln={waitingWebln}
|
||||||
isBuyer={currentOrder?.is_buyer ?? false}
|
isBuyer={garage.getSlot().order?.is_buyer ?? false}
|
||||||
/>
|
/>
|
||||||
<ConfirmDisputeDialog
|
<ConfirmDisputeDialog
|
||||||
open={open.confirmDispute}
|
open={open.confirmDispute}
|
||||||
@ -728,11 +770,11 @@ const TradeBox = ({
|
|||||||
}}
|
}}
|
||||||
onCollabCancelClick={cancel}
|
onCollabCancelClick={cancel}
|
||||||
loading={loadingButtons.cancel}
|
loading={loadingButtons.cancel}
|
||||||
peerAskedCancel={currentOrder?.pending_cancel ?? false}
|
peerAskedCancel={garage.getSlot().order?.pending_cancel ?? false}
|
||||||
/>
|
/>
|
||||||
<ConfirmFiatSentDialog
|
<ConfirmFiatSentDialog
|
||||||
open={open.confirmFiatSent}
|
open={open.confirmFiatSent}
|
||||||
order={currentOrder}
|
order={garage.getSlot().order}
|
||||||
loadingButton={loadingButtons.fiatSent}
|
loadingButton={loadingButtons.fiatSent}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen(closeAll);
|
setOpen(closeAll);
|
||||||
@ -749,14 +791,14 @@ const TradeBox = ({
|
|||||||
/>
|
/>
|
||||||
<ConfirmFiatReceivedDialog
|
<ConfirmFiatReceivedDialog
|
||||||
open={open.confirmFiatReceived}
|
open={open.confirmFiatReceived}
|
||||||
order={currentOrder}
|
order={garage.getSlot().order}
|
||||||
loadingButton={loadingButtons.fiatReceived}
|
loadingButton={loadingButtons.fiatReceived}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen(closeAll);
|
setOpen(closeAll);
|
||||||
}}
|
}}
|
||||||
onConfirmClick={confirmFiatReceived}
|
onConfirmClick={confirmFiatReceived}
|
||||||
/>
|
/>
|
||||||
<CollabCancelAlert order={currentOrder} />
|
<CollabCancelAlert order={garage.getSlot().order} />
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
padding={1}
|
padding={1}
|
||||||
@ -767,7 +809,7 @@ const TradeBox = ({
|
|||||||
>
|
>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Title
|
<Title
|
||||||
order={currentOrder}
|
order={garage.getSlot().order}
|
||||||
text={contract?.title}
|
text={contract?.title}
|
||||||
color={contract?.titleColor}
|
color={contract?.titleColor}
|
||||||
icon={contract?.titleIcon}
|
icon={contract?.titleIcon}
|
||||||
@ -781,7 +823,10 @@ const TradeBox = ({
|
|||||||
{contract?.bondStatus !== 'hide' ? (
|
{contract?.bondStatus !== 'hide' ? (
|
||||||
<Grid item sx={{ width: '100%' }}>
|
<Grid item sx={{ width: '100%' }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<BondStatus status={contract?.bondStatus} isMaker={currentOrder?.is_maker ?? false} />
|
<BondStatus
|
||||||
|
status={contract?.bondStatus}
|
||||||
|
isMaker={garage.getSlot().order?.is_maker ?? false}
|
||||||
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
@ -789,7 +834,7 @@ const TradeBox = ({
|
|||||||
|
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<CancelButton
|
<CancelButton
|
||||||
order={currentOrder}
|
order={garage.getSlot().order}
|
||||||
onClickCancel={cancel}
|
onClickCancel={cancel}
|
||||||
openCancelDialog={() => {
|
openCancelDialog={() => {
|
||||||
setOpen({ ...closeAll, confirmCancel: true });
|
setOpen({ ...closeAll, confirmCancel: true });
|
||||||
|
@ -51,8 +51,6 @@ export interface fetchRobotProps {
|
|||||||
export interface UseFederationStoreType {
|
export interface UseFederationStoreType {
|
||||||
federation: Federation;
|
federation: Federation;
|
||||||
sortedCoordinators: string[];
|
sortedCoordinators: string[];
|
||||||
focusedCoordinator: string | null;
|
|
||||||
setFocusedCoordinator: Dispatch<SetStateAction<string>>;
|
|
||||||
setDelay: Dispatch<SetStateAction<number>>;
|
setDelay: Dispatch<SetStateAction<number>>;
|
||||||
coordinatorUpdatedAt: string;
|
coordinatorUpdatedAt: string;
|
||||||
federationUpdatedAt: string;
|
federationUpdatedAt: string;
|
||||||
@ -61,8 +59,6 @@ export interface UseFederationStoreType {
|
|||||||
export const initialFederationContext: UseFederationStoreType = {
|
export const initialFederationContext: UseFederationStoreType = {
|
||||||
federation: new Federation(),
|
federation: new Federation(),
|
||||||
sortedCoordinators: [],
|
sortedCoordinators: [],
|
||||||
focusedCoordinator: '',
|
|
||||||
setFocusedCoordinator: () => {},
|
|
||||||
setDelay: () => {},
|
setDelay: () => {},
|
||||||
coordinatorUpdatedAt: '',
|
coordinatorUpdatedAt: '',
|
||||||
federationUpdatedAt: '',
|
federationUpdatedAt: '',
|
||||||
@ -73,7 +69,7 @@ export const FederationContext = createContext<UseFederationStoreType>(initialFe
|
|||||||
export const useFederationStore = (): UseFederationStoreType => {
|
export const useFederationStore = (): UseFederationStoreType => {
|
||||||
const { settings, page, origin, hostUrl, open, torStatus } =
|
const { settings, page, origin, hostUrl, open, torStatus } =
|
||||||
useContext<UseAppStoreType>(AppContext);
|
useContext<UseAppStoreType>(AppContext);
|
||||||
const { setMaker, garage, orderUpdatedAt, robotUpdatedAt, badOrder } =
|
const { setMaker, garage, setBadOrder, robotUpdatedAt, badOrder, orderUpdatedAt } =
|
||||||
useContext<UseGarageStoreType>(GarageContext);
|
useContext<UseGarageStoreType>(GarageContext);
|
||||||
const [federation, setFederation] = useState(initialFederationContext.federation);
|
const [federation, setFederation] = useState(initialFederationContext.federation);
|
||||||
const sortedCoordinators = useMemo(() => {
|
const sortedCoordinators = useMemo(() => {
|
||||||
@ -88,13 +84,10 @@ export const useFederationStore = (): UseFederationStoreType => {
|
|||||||
);
|
);
|
||||||
const [federationUpdatedAt, setFederationUpdatedAt] = useState<string>(new Date().toISOString());
|
const [federationUpdatedAt, setFederationUpdatedAt] = useState<string>(new Date().toISOString());
|
||||||
|
|
||||||
const [focusedCoordinator, setFocusedCoordinator] = useState<string>(sortedCoordinators[0]);
|
const [delay, setDelay] = useState<number>(5000);
|
||||||
|
|
||||||
const [delay, setDelay] = useState<number>(60000);
|
|
||||||
const [timer, setTimer] = useState<NodeJS.Timer | undefined>(() =>
|
const [timer, setTimer] = useState<NodeJS.Timer | undefined>(() =>
|
||||||
setInterval(() => null, delay),
|
setInterval(() => null, delay),
|
||||||
);
|
);
|
||||||
const [currentOrder, setCurrentOrder] = useState<Order | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// On bitcoin network change we reset book, limits and federation info and fetch everything again
|
// On bitcoin network change we reset book, limits and federation info and fetch everything again
|
||||||
@ -112,27 +105,34 @@ export const useFederationStore = (): UseFederationStoreType => {
|
|||||||
}, [settings.network, torStatus]);
|
}, [settings.network, torStatus]);
|
||||||
|
|
||||||
const fetchCurrentOrder = (): void => {
|
const fetchCurrentOrder = (): void => {
|
||||||
if (currentOrder?.id != null && (page === 'order' || badOrder === undefined)) {
|
const activeSlot = garage.getSlot();
|
||||||
void federation.fetchOrder(currentOrder, garage);
|
if (activeSlot.activeOrderShortAlias !== null && activeSlot.activeOrderId !== null) {
|
||||||
|
const coordinator = federation.getCoordinator(activeSlot.activeOrderShortAlias);
|
||||||
|
coordinator
|
||||||
|
.fetchOrder(activeSlot.activeOrderId, activeSlot.robot)
|
||||||
|
.then((order) => {
|
||||||
|
if (order?.bad_request !== undefined) {
|
||||||
|
setBadOrder(order.bad_request);
|
||||||
|
}
|
||||||
|
if (order?.id !== null) {
|
||||||
|
garage.updateOrder(order as Order);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setTimer(setTimeout(fetchCurrentOrder, delay));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setTimer(setTimeout(fetchCurrentOrder, delay));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch current order at load and in a loop
|
|
||||||
useEffect(() => {
|
|
||||||
fetchCurrentOrder();
|
|
||||||
}, [currentOrder, page]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCurrentOrder(garage.getOrder());
|
|
||||||
}, [orderUpdatedAt]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
setTimer(setInterval(fetchCurrentOrder, delay));
|
fetchCurrentOrder();
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
};
|
};
|
||||||
}, [delay, currentOrder, page, badOrder]);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const robot = garage.getSlot().robot;
|
const robot = garage.getSlot().robot;
|
||||||
@ -154,8 +154,6 @@ export const useFederationStore = (): UseFederationStoreType => {
|
|||||||
return {
|
return {
|
||||||
federation,
|
federation,
|
||||||
sortedCoordinators,
|
sortedCoordinators,
|
||||||
focusedCoordinator,
|
|
||||||
setFocusedCoordinator,
|
|
||||||
setDelay,
|
setDelay,
|
||||||
coordinatorUpdatedAt,
|
coordinatorUpdatedAt,
|
||||||
federationUpdatedAt,
|
federationUpdatedAt,
|
||||||
|
@ -188,7 +188,7 @@ export class Coordinator {
|
|||||||
apiClient
|
apiClient
|
||||||
.get(this.url, `${this.basePath}/api/limits/`)
|
.get(this.url, `${this.basePath}/api/limits/`)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data != null) {
|
if (data !== null) {
|
||||||
const newLimits = data as LimitList;
|
const newLimits = data as LimitList;
|
||||||
|
|
||||||
for (const currency in this.limits) {
|
for (const currency in this.limits) {
|
||||||
@ -215,8 +215,10 @@ export class Coordinator {
|
|||||||
apiClient
|
apiClient
|
||||||
.get(this.url, `${this.basePath}/api/info/`)
|
.get(this.url, `${this.basePath}/api/info/`)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.info = data as Info;
|
if (data !== null) {
|
||||||
onDataLoad();
|
this.info = data as Info;
|
||||||
|
onDataLoad();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
@ -96,20 +96,6 @@ export class Federation {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
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.getSlot().robot);
|
|
||||||
if (newOrder != null) {
|
|
||||||
garage.updateOrder(newOrder);
|
|
||||||
return newOrder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return order;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Coordinators
|
// Coordinators
|
||||||
getCoordinator = (shortAlias: string): Coordinator => {
|
getCoordinator = (shortAlias: string): Coordinator => {
|
||||||
return this.coordinators[shortAlias];
|
return this.coordinators[shortAlias];
|
||||||
|
@ -146,7 +146,17 @@ class Garage {
|
|||||||
|
|
||||||
// Orders
|
// Orders
|
||||||
updateOrder: (order: Order, index?: number) => void = (order, index = this.currentSlot) => {
|
updateOrder: (order: Order, index?: number) => void = (order, index = this.currentSlot) => {
|
||||||
this.slots[index].order = order;
|
const updatedOrder = this.slots[index].order;
|
||||||
|
if (updatedOrder !== null && updatedOrder.id === order.id) {
|
||||||
|
Object.assign(updatedOrder, order);
|
||||||
|
this.slots[index].order = updatedOrder;
|
||||||
|
} else {
|
||||||
|
this.slots[index].order = order;
|
||||||
|
}
|
||||||
|
if (this.slots[index].order?.is_participant) {
|
||||||
|
this.slots[index].activeOrderId = this.slots[index].order?.id ?? null;
|
||||||
|
this.slots[index].activeOrderShortAlias = this.slots[index].order?.shortAlias ?? null;
|
||||||
|
}
|
||||||
this.triggerHook('onOrderUpdate');
|
this.triggerHook('onOrderUpdate');
|
||||||
this.save();
|
this.save();
|
||||||
};
|
};
|
||||||
|
@ -106,6 +106,9 @@ export interface Order {
|
|||||||
network: 'mainnet' | 'testnet';
|
network: 'mainnet' | 'testnet';
|
||||||
shortAlias: string;
|
shortAlias: string;
|
||||||
bad_request?: string;
|
bad_request?: string;
|
||||||
|
bad_address?: string;
|
||||||
|
bad_invoice?: string;
|
||||||
|
bad_statement?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultOrder: Order = {
|
export const defaultOrder: Order = {
|
||||||
|
@ -35,7 +35,6 @@ const FederationWidget = React.forwardRef(function Component(
|
|||||||
return (
|
return (
|
||||||
<Paper elevation={3} style={{ width: '100%', height: '100%' }}>
|
<Paper elevation={3} style={{ width: '100%', height: '100%' }}>
|
||||||
<FederationTable
|
<FederationTable
|
||||||
openCoordinator={() => setOpen({ ...open, coordinator: true })}
|
|
||||||
maxWidth={layout.w * gridCellSize} // EM units
|
maxWidth={layout.w * gridCellSize} // EM units
|
||||||
maxHeight={layout.h * gridCellSize} // EM units
|
maxHeight={layout.h * gridCellSize} // EM units
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user