Small fixes, fix reconnecting websockets, fix rewards webln

This commit is contained in:
Reckless_Satoshi 2023-05-08 17:37:23 -07:00
parent 3b77a473f8
commit 0d180ee7c9
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
84 changed files with 656 additions and 308 deletions

View File

@ -10,7 +10,7 @@ import BookTable from '../../components/BookTable';
// Icons // Icons
import { BarChart, FormatListBulleted } from '@mui/icons-material'; import { BarChart, FormatListBulleted } from '@mui/icons-material';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
const BookPage = (): JSX.Element => { const BookPage = (): JSX.Element => {
const { robot, fetchBook, windowSize, setDelay, setOrder } = const { robot, fetchBook, windowSize, setDelay, setOrder } =
@ -47,13 +47,22 @@ const BookPage = (): JSX.Element => {
const NavButtons = function () { const NavButtons = function () {
return ( return (
<ButtonGroup variant='contained' color='inherit'> <ButtonGroup variant='contained' color='inherit'>
<Button color='primary' onClick={() => setOpenMaker(true)}> <Button
color='primary'
onClick={() => {
setOpenMaker(true);
}}
>
{t('Create')} {t('Create')}
</Button> </Button>
{doubleView ? ( {doubleView ? (
<></> <></>
) : ( ) : (
<Button onClick={() => setView(view === 'depth' ? 'list' : 'depth')}> <Button
onClick={() => {
setView(view === 'depth' ? 'list' : 'depth');
}}
>
{view == 'depth' ? ( {view == 'depth' ? (
<> <>
<FormatListBulleted /> {t('List')} <FormatListBulleted /> {t('List')}
@ -71,9 +80,19 @@ const BookPage = (): JSX.Element => {
return ( return (
<Grid container direction='column' alignItems='center' spacing={1} sx={{ minWidth: 400 }}> <Grid container direction='column' alignItems='center' spacing={1} sx={{ minWidth: 400 }}>
<NoRobotDialog open={openNoRobot} onClose={() => setOpenNoRobot(false)} /> <NoRobotDialog
open={openNoRobot}
onClose={() => {
setOpenNoRobot(false);
}}
/>
{openMaker ? ( {openMaker ? (
<Dialog open={openMaker} onClose={() => setOpenMaker(false)}> <Dialog
open={openMaker}
onClose={() => {
setOpenMaker(false);
}}
>
<Box sx={{ maxWidth: '18em', padding: '0.5em' }}> <Box sx={{ maxWidth: '18em', padding: '0.5em' }}>
<MakerForm <MakerForm
onOrderCreated={(id) => { onOrderCreated={(id) => {

View File

@ -14,7 +14,7 @@ import RobotAvatar from '../components/RobotAvatar';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Notifications from '../components/Notifications'; import Notifications from '../components/Notifications';
import { UseAppStoreType, AppContext, closeAll } from '../contexts/AppContext'; import { type UseAppStoreType, AppContext, closeAll } from '../contexts/AppContext';
const Router = window.NativeRobosats === undefined ? BrowserRouter : MemoryRouter; const Router = window.NativeRobosats === undefined ? BrowserRouter : MemoryRouter;
@ -54,16 +54,18 @@ const Main: React.FC = () => {
style={{ display: 'none' }} style={{ display: 'none' }}
nickname={robot.nickname} nickname={robot.nickname}
baseUrl={baseUrl} baseUrl={baseUrl}
onLoad={() => onLoad={() => {
setRobot((robot) => { setRobot((robot) => {
return { ...robot, avatarLoaded: true }; return { ...robot, avatarLoaded: true };
}) });
} }}
/> />
<Notifications <Notifications
order={order} order={order}
page={page} page={page}
openProfile={() => setOpen({ ...closeAll, profile: true })} openProfile={() => {
setOpen({ ...closeAll, profile: true });
}}
rewards={robot.earnedRewards} rewards={robot.earnedRewards}
windowWidth={windowSize.width} windowWidth={windowSize.width}
/> />

View File

@ -9,7 +9,7 @@ import {
UpdateClientDialog, UpdateClientDialog,
} from '../../components/Dialogs'; } from '../../components/Dialogs';
import { pn } from '../../utils'; import { pn } from '../../utils';
import { AppContext, UseAppStoreType, closeAll } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType, closeAll } from '../../contexts/AppContext';
export interface OpenDialogs { export interface OpenDialogs {
more: boolean; more: boolean;
@ -46,32 +46,49 @@ const MainDialogs = (): JSX.Element => {
open={open.update} open={open.update}
coordinatorVersion={info.coordinatorVersion} coordinatorVersion={info.coordinatorVersion}
clientVersion={info.clientVersion} clientVersion={info.clientVersion}
onClose={() => setOpen({ ...open, update: false })} onClose={() => {
setOpen({ ...open, update: false });
}}
/> />
<InfoDialog <InfoDialog
open={open.info} open={open.info}
maxAmount={maxAmount} maxAmount={maxAmount}
onClose={() => setOpen({ ...open, info: false })} onClose={() => {
setOpen({ ...open, info: false });
}}
/>
<LearnDialog
open={open.learn}
onClose={() => {
setOpen({ ...open, learn: false });
}}
/> />
<LearnDialog open={open.learn} onClose={() => setOpen({ ...open, learn: false })} />
<CommunityDialog <CommunityDialog
open={open.community} open={open.community}
onClose={() => setOpen({ ...open, community: false })} onClose={() => {
setOpen({ ...open, community: false });
}}
/> />
<CoordinatorSummaryDialog <CoordinatorSummaryDialog
open={open.coordinator} open={open.coordinator}
onClose={() => setOpen({ ...open, coordinator: false })} onClose={() => {
setOpen({ ...open, coordinator: false });
}}
info={info} info={info}
/> />
<StatsDialog <StatsDialog
open={open.stats} open={open.stats}
onClose={() => setOpen({ ...open, stats: false })} onClose={() => {
setOpen({ ...open, stats: false });
}}
info={info} info={info}
/> />
<ProfileDialog <ProfileDialog
open={open.profile} open={open.profile}
baseUrl={baseUrl} baseUrl={baseUrl}
onClose={() => setOpen({ ...open, profile: false })} onClose={() => {
setOpen({ ...open, profile: false });
}}
robot={robot} robot={robot}
setRobot={setRobot} setRobot={setRobot}
setCurrentOrder={setCurrentOrder} setCurrentOrder={setCurrentOrder}

View File

@ -8,7 +8,7 @@ import { filterOrders } from '../../utils';
import MakerForm from '../../components/MakerForm'; import MakerForm from '../../components/MakerForm';
import BookTable from '../../components/BookTable'; import BookTable from '../../components/BookTable';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import { NoRobotDialog } from '../../components/Dialogs'; import { NoRobotDialog } from '../../components/Dialogs';
const MakerPage = (): JSX.Element => { const MakerPage = (): JSX.Element => {
@ -64,7 +64,12 @@ const MakerPage = (): JSX.Element => {
return ( return (
<Grid container direction='column' alignItems='center' spacing={1}> <Grid container direction='column' alignItems='center' spacing={1}>
<NoRobotDialog open={openNoRobot} onClose={() => setOpenNoRobot(false)} /> <NoRobotDialog
open={openNoRobot}
onClose={() => {
setOpenNoRobot(false);
}}
/>
<Grid item> <Grid item>
<Collapse in={matches.length > 0 && showMatches}> <Collapse in={matches.length > 0 && showMatches}>
<Grid container direction='column' alignItems='center' spacing={1}> <Grid container direction='column' alignItems='center' spacing={1}>
@ -102,8 +107,12 @@ const MakerPage = (): JSX.Element => {
}} }}
disableRequest={matches.length > 0 && !showMatches} disableRequest={matches.length > 0 && !showMatches}
collapseAll={showMatches} collapseAll={showMatches}
onSubmit={() => setShowMatches(matches.length > 0)} onSubmit={() => {
onReset={() => setShowMatches(false)} setShowMatches(matches.length > 0);
}}
onReset={() => {
setShowMatches(false);
}}
submitButtonLabel={matches.length > 0 && !showMatches ? 'Submit' : 'Create order'} submitButtonLabel={matches.length > 0 && !showMatches ? 'Submit' : 'Create order'}
/> />
</Paper> </Paper>

View File

@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useTheme, styled, Grid, IconButton } from '@mui/material'; import { useTheme, styled, Grid, IconButton } from '@mui/material';
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip'; import Tooltip, { type TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
import { closeAll } from '../../contexts/AppContext'; import { closeAll } from '../../contexts/AppContext';
import { OpenDialogs } from '../MainDialogs'; import { type OpenDialogs } from '../MainDialogs';
import { BubbleChart, Info, People, PriceChange, School } from '@mui/icons-material'; import { BubbleChart, Info, People, PriceChange, School } from '@mui/icons-material';
@ -45,7 +45,9 @@ const MoreTooltip = ({ open, setOpen, children }: MoreTooltipProps): JSX.Element
sx={{ sx={{
color: open.info ? theme.palette.primary.main : theme.palette.text.secondary, color: open.info ? theme.palette.primary.main : theme.palette.text.secondary,
}} }}
onClick={() => setOpen({ ...closeAll, info: !open.info })} onClick={() => {
setOpen({ ...closeAll, info: !open.info });
}}
> >
<Info /> <Info />
</IconButton> </IconButton>
@ -58,7 +60,9 @@ const MoreTooltip = ({ open, setOpen, children }: MoreTooltipProps): JSX.Element
sx={{ sx={{
color: open.learn ? theme.palette.primary.main : theme.palette.text.secondary, color: open.learn ? theme.palette.primary.main : theme.palette.text.secondary,
}} }}
onClick={() => setOpen({ ...closeAll, learn: !open.learn })} onClick={() => {
setOpen({ ...closeAll, learn: !open.learn });
}}
> >
<School /> <School />
</IconButton> </IconButton>
@ -75,7 +79,9 @@ const MoreTooltip = ({ open, setOpen, children }: MoreTooltipProps): JSX.Element
sx={{ sx={{
color: open.community ? theme.palette.primary.main : theme.palette.text.secondary, color: open.community ? theme.palette.primary.main : theme.palette.text.secondary,
}} }}
onClick={() => setOpen({ ...closeAll, community: !open.community })} onClick={() => {
setOpen({ ...closeAll, community: !open.community });
}}
> >
<People /> <People />
</IconButton> </IconButton>
@ -90,7 +96,9 @@ const MoreTooltip = ({ open, setOpen, children }: MoreTooltipProps): JSX.Element
? theme.palette.primary.main ? theme.palette.primary.main
: theme.palette.text.secondary, : theme.palette.text.secondary,
}} }}
onClick={() => setOpen({ ...closeAll, coordinator: !open.coordinator })} onClick={() => {
setOpen({ ...closeAll, coordinator: !open.coordinator });
}}
> >
<PriceChange /> <PriceChange />
</IconButton> </IconButton>
@ -103,7 +111,9 @@ const MoreTooltip = ({ open, setOpen, children }: MoreTooltipProps): JSX.Element
sx={{ sx={{
color: open.stats ? theme.palette.primary.main : theme.palette.text.secondary, color: open.stats ? theme.palette.primary.main : theme.palette.text.secondary,
}} }}
onClick={() => setOpen({ ...closeAll, stats: !open.stats })} onClick={() => {
setOpen({ ...closeAll, stats: !open.stats });
}}
> >
<BubbleChart /> <BubbleChart />
</IconButton> </IconButton>

View File

@ -4,7 +4,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
import { Tabs, Tab, Paper, useTheme } from '@mui/material'; import { Tabs, Tab, Paper, useTheme } from '@mui/material';
import MoreTooltip from './MoreTooltip'; import MoreTooltip from './MoreTooltip';
import { Page } from '.'; import { type Page } from '.';
import { import {
SettingsApplications, SettingsApplications,
@ -15,7 +15,7 @@ import {
MoreHoriz, MoreHoriz,
} from '@mui/icons-material'; } from '@mui/icons-material';
import RobotAvatar from '../../components/RobotAvatar'; import RobotAvatar from '../../components/RobotAvatar';
import { AppContext, UseAppStoreType, closeAll } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType, closeAll } from '../../contexts/AppContext';
interface NavBarProps { interface NavBarProps {
width: number; width: number;
@ -76,10 +76,9 @@ const NavBar = ({ width, height }: NavBarProps): JSX.Element => {
handleSlideDirection(page, newPage); handleSlideDirection(page, newPage);
setPage(newPage); setPage(newPage);
const param = newPage === 'order' ? currentOrder ?? '' : ''; const param = newPage === 'order' ? currentOrder ?? '' : '';
setTimeout( setTimeout(() => {
() => navigate(`/${newPage}/${param}`), navigate(`/${newPage}/${param}`);
theme.transitions.duration.leavingScreen * 3, }, theme.transitions.duration.leavingScreen * 3);
);
} }
}; };
@ -104,7 +103,9 @@ const NavBar = ({ width, height }: NavBarProps): JSX.Element => {
sx={{ ...tabSx, minWidth: '2.5em', width: '2.5em', maxWidth: '4em' }} sx={{ ...tabSx, minWidth: '2.5em', width: '2.5em', maxWidth: '4em' }}
value='none' value='none'
disabled={robot.nickname === null} disabled={robot.nickname === null}
onClick={() => setOpen({ ...closeAll, profile: !open.profile })} onClick={() => {
setOpen({ ...closeAll, profile: !open.profile });
}}
icon={ icon={
robot.nickname && robot.avatarLoaded ? ( robot.nickname && robot.avatarLoaded ? (
<RobotAvatar <RobotAvatar

View File

@ -7,7 +7,7 @@ import TradeBox from '../../components/TradeBox';
import OrderDetails from '../../components/OrderDetails'; import OrderDetails from '../../components/OrderDetails';
import { apiClient } from '../../services/api'; import { apiClient } from '../../services/api';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
const OrderPage = (): JSX.Element => { const OrderPage = (): JSX.Element => {
const { const {
@ -70,7 +70,9 @@ const OrderPage = (): JSX.Element => {
} }
}; };
const startAgain = () => navigate('/robot'); const startAgain = () => {
navigate('/robot');
};
return ( return (
<Box> <Box>
@ -138,7 +140,9 @@ 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) => setTab(value)} onChange={(mouseEvent, value) => {
setTab(value);
}}
variant='fullWidth' variant='fullWidth'
> >
<Tab label={t('Order')} value='order' /> <Tab label={t('Order')} value='order' />

View File

@ -15,7 +15,7 @@ import {
AccordionSummary, AccordionSummary,
AccordionDetails, AccordionDetails,
} from '@mui/material'; } from '@mui/material';
import { Robot } from '../../models'; import { type Robot } from '../../models';
import { Casino, Bolt, Check, Storefront, AddBox, School } from '@mui/icons-material'; import { Casino, Bolt, Check, Storefront, AddBox, School } from '@mui/icons-material';
import RobotAvatar from '../../components/RobotAvatar'; import RobotAvatar from '../../components/RobotAvatar';
import TokenInput from './TokenInput'; import TokenInput from './TokenInput';
@ -54,7 +54,9 @@ const Onboarding = ({
setGeneratedToken(true); setGeneratedToken(true);
setInputToken(genBase62Token(36)); setInputToken(genBase62Token(36));
setLoading(true); setLoading(true);
setTimeout(() => setLoading(false), 1000); setTimeout(() => {
setLoading(false);
}, 1000);
}; };
return ( return (
@ -209,7 +211,13 @@ const Onboarding = ({
) : null} ) : null}
<Grid item> <Grid item>
<Collapse in={!!(robot.avatarLoaded && robot.nickname)}> <Collapse in={!!(robot.avatarLoaded && robot.nickname)}>
<Button onClick={() => setStep('3')} variant='contained' size='large'> <Button
onClick={() => {
setStep('3');
}}
variant='contained'
size='large'
>
<Check /> <Check />
{t('Continue')} {t('Continue')}
</Button> </Button>
@ -237,11 +245,21 @@ const Onboarding = ({
<Grid item> <Grid item>
<ButtonGroup variant='contained'> <ButtonGroup variant='contained'>
<Button color='primary' onClick={() => navigate('/offers')}> <Button
color='primary'
onClick={() => {
navigate('/offers');
}}
>
<Storefront /> <div style={{ width: '0.5em' }} /> <Storefront /> <div style={{ width: '0.5em' }} />
{t('Offers')} {t('Offers')}
</Button> </Button>
<Button color='secondary' onClick={() => navigate('/create')}> <Button
color='secondary'
onClick={() => {
navigate('/create');
}}
>
<AddBox /> <div style={{ width: '0.5em' }} /> <AddBox /> <div style={{ width: '0.5em' }} />
{t('Create')} {t('Create')}
</Button> </Button>
@ -273,7 +291,12 @@ const Onboarding = ({
</Button> </Button>
</Grid> </Grid>
<Grid item sx={{ position: 'relative', top: '0.6em' }}> <Grid item sx={{ position: 'relative', top: '0.6em' }}>
<Button color='inherit' onClick={() => setView('profile')}> <Button
color='inherit'
onClick={() => {
setView('profile');
}}
>
{t('See profile')} {t('See profile')}
</Button> </Button>
</Grid> </Grid>

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button, Grid, Typography } from '@mui/material'; import { Button, Grid, Typography } from '@mui/material';
import { Robot } from '../../models'; import { type Robot } from '../../models';
import TokenInput from './TokenInput'; import TokenInput from './TokenInput';
import Key from '@mui/icons-material/Key'; import Key from '@mui/icons-material/Key';

View File

@ -16,8 +16,8 @@ import {
import { Bolt, Add, DeleteSweep, Logout, Download } from '@mui/icons-material'; import { Bolt, Add, DeleteSweep, Logout, Download } from '@mui/icons-material';
import RobotAvatar from '../../components/RobotAvatar'; import RobotAvatar from '../../components/RobotAvatar';
import TokenInput from './TokenInput'; import TokenInput from './TokenInput';
import { Slot, Robot } from '../../models'; import { type Slot, type Robot } from '../../models';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import { genBase62Token } from '../../utils'; import { genBase62Token } from '../../utils';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
@ -298,7 +298,12 @@ const RobotProfile = ({
{window.NativeRobosats === undefined ? ( {window.NativeRobosats === undefined ? (
<Grid item> <Grid item>
<Button color='primary' onClick={() => garage.download()}> <Button
color='primary'
onClick={() => {
garage.download();
}}
>
<Download /> <Download />
</Button> </Button>
</Grid> </Grid>

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { IconButton, LinearProgress, TextField, Tooltip } from '@mui/material'; import { IconButton, LinearProgress, TextField, Tooltip } from '@mui/material';
import { Robot } from '../../models'; import { type Robot } from '../../models';
import { ContentCopy } from '@mui/icons-material'; import { ContentCopy } from '@mui/icons-material';
import { systemClient } from '../../services/System'; import { systemClient } from '../../services/System';
@ -57,7 +57,9 @@ const TokenInput = ({
variant={editable ? 'outlined' : 'filled'} variant={editable ? 'outlined' : 'filled'}
helperText={badToken} helperText={badToken}
size='medium' size='medium'
onChange={(e) => setInputToken(e.target.value)} onChange={(e) => {
setInputToken(e.target.value);
}}
onKeyPress={(e) => { onKeyPress={(e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
onPressEnter(); onPressEnter();
@ -72,7 +74,9 @@ const TokenInput = ({
onClick={() => { onClick={() => {
systemClient.copyToClipboard(inputToken); systemClient.copyToClipboard(inputToken);
setShowCopied(true); setShowCopied(true);
setTimeout(() => setShowCopied(false), 1000); setTimeout(() => {
setShowCopied(false);
}, 1000);
setRobot((robot) => { setRobot((robot) => {
return { ...robot, copiedToken: true }; return { ...robot, copiedToken: true };
}); });

View File

@ -73,7 +73,9 @@ const Welcome = ({ setView, width, getGenerateRobot }: WelcomeProps): JSX.Elemen
size='large' size='large'
color='primary' color='primary'
variant='contained' variant='contained'
onClick={() => setView('onboarding')} onClick={() => {
setView('onboarding');
}}
> >
<RocketLaunch /> <RocketLaunch />
<div style={{ width: '0.5em' }} /> <div style={{ width: '0.5em' }} />
@ -91,7 +93,9 @@ const Welcome = ({ setView, width, getGenerateRobot }: WelcomeProps): JSX.Elemen
size='small' size='small'
color='secondary' color='secondary'
variant='contained' variant='contained'
onClick={() => setView('recovery')} onClick={() => {
setView('recovery');
}}
> >
<Key /> <div style={{ width: '0.5em' }} /> <Key /> <div style={{ width: '0.5em' }} />
{t('Recovery')} {t('Recovery')}

View File

@ -19,7 +19,7 @@ import RobotProfile from './RobotProfile';
import Recovery from './Recovery'; import Recovery from './Recovery';
import { TorIcon } from '../../components/Icons'; import { TorIcon } from '../../components/Icons';
import { genKey } from '../../pgp'; import { genKey } from '../../pgp';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import { validateTokenEntropy } from '../../utils'; import { validateTokenEntropy } from '../../utils';
const RobotPage = (): JSX.Element => { const RobotPage = (): JSX.Element => {

View File

@ -1,7 +1,7 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { Grid, Paper } from '@mui/material'; import { Grid, Paper } from '@mui/material';
import SettingsForm from '../../components/SettingsForm'; import SettingsForm from '../../components/SettingsForm';
import { UseAppStoreType, AppContext } from '../../contexts/AppContext'; import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
const SettingsPage = (): JSX.Element => { const SettingsPage = (): JSX.Element => {
const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext); const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);

View File

@ -18,7 +18,7 @@ import { fiatMethods, swapMethods, PaymentIcon } from '../PaymentMethods';
import { FlagWithProps } from '../Icons'; import { FlagWithProps } from '../Icons';
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import { Favorites } from '../../models'; import { type Favorites } from '../../models';
import SwapCalls from '@mui/icons-material/SwapCalls'; import SwapCalls from '@mui/icons-material/SwapCalls';
interface BookControlProps { interface BookControlProps {
@ -259,7 +259,9 @@ const BookControl = ({
style: { textAlign: 'center' }, style: { textAlign: 'center' },
}} }}
value={paymentMethod[0] ? paymentMethod[0] : 'ANY'} value={paymentMethod[0] ? paymentMethod[0] : 'ANY'}
onChange={(e) => setPaymentMethods(e.target.value == 'ANY' ? [] : [e.target.value])} onChange={(e) => {
setPaymentMethods(e.target.value == 'ANY' ? [] : [e.target.value]);
}}
> >
<MenuItem value={'ANY'}> <MenuItem value={'ANY'}>
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}> <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>

View File

@ -14,17 +14,17 @@ import {
LinearProgress, LinearProgress,
IconButton, IconButton,
Tooltip, Tooltip,
LinearProgressProps, type LinearProgressProps,
styled, styled,
} from '@mui/material'; } from '@mui/material';
import { import {
DataGrid, DataGrid,
GridColumnVisibilityModel, type GridColumnVisibilityModel,
GridPagination, GridPagination,
GridPaginationModel, type GridPaginationModel,
} from '@mui/x-data-grid'; } from '@mui/x-data-grid';
import currencyDict from '../../../static/assets/currencies.json'; import currencyDict from '../../../static/assets/currencies.json';
import { PublicOrder } from '../../models'; import { type PublicOrder } from '../../models';
import { filterOrders, hexToRgb, statusBadgeColor, pn, amountToString } from '../../utils'; import { filterOrders, hexToRgb, statusBadgeColor, pn, amountToString } from '../../utils';
import BookControl from './BookControl'; import BookControl from './BookControl';
@ -34,7 +34,7 @@ import RobotAvatar from '../RobotAvatar';
// Icons // Icons
import { Fullscreen, FullscreenExit, Refresh } from '@mui/icons-material'; import { Fullscreen, FullscreenExit, Refresh } from '@mui/icons-material';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
const ClickThroughDataGrid = styled(DataGrid)({ const ClickThroughDataGrid = styled(DataGrid)({
'& .MuiDataGrid-overlayWrapperInner': { '& .MuiDataGrid-overlayWrapperInner': {
@ -609,7 +609,7 @@ const BookTable = ({
const filteredColumns = function (maxWidth: number) { const filteredColumns = function (maxWidth: number) {
const useSmall = maxWidth < 70; const useSmall = maxWidth < 70;
const selectedColumns: object[] = []; const selectedColumns: object[] = [];
let columnVisibilityModel: GridColumnVisibilityModel = {}; const columnVisibilityModel: GridColumnVisibilityModel = {};
let width: number = 0; let width: number = 0;
for (const [key, value] of Object.entries(columnSpecs)) { for (const [key, value] of Object.entries(columnSpecs)) {
@ -654,12 +654,20 @@ const BookTable = ({
<Grid item> <Grid item>
<Grid container alignItems='center' direction='row'> <Grid container alignItems='center' direction='row'>
<Grid item xs={6}> <Grid item xs={6}>
<IconButton onClick={() => setFullscreen(!fullscreen)}> <IconButton
onClick={() => {
setFullscreen(!fullscreen);
}}
>
{fullscreen ? <FullscreenExit /> : <Fullscreen />} {fullscreen ? <FullscreenExit /> : <Fullscreen />}
</IconButton> </IconButton>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<IconButton onClick={() => fetchBook()}> <IconButton
onClick={() => {
fetchBook();
}}
>
<Refresh /> <Refresh />
</IconButton> </IconButton>
</Grid> </Grid>
@ -758,9 +766,9 @@ const BookTable = ({
loading={book.loading} loading={book.loading}
columns={columns} columns={columns}
columnVisibilityModel={columnVisibilityModel} columnVisibilityModel={columnVisibilityModel}
onColumnVisibilityModelChange={(newColumnVisibilityModel) => onColumnVisibilityModelChange={(newColumnVisibilityModel) => {
setColumnVisibilityModel(newColumnVisibilityModel) setColumnVisibilityModel(newColumnVisibilityModel);
} }}
hideFooter={!showFooter} hideFooter={!showFooter}
components={gridComponents} components={gridComponents}
componentsProps={{ componentsProps={{
@ -777,7 +785,9 @@ const BookTable = ({
onPaginationModelChange={(newPaginationModel) => { onPaginationModelChange={(newPaginationModel) => {
setPaginationModel(newPaginationModel); setPaginationModel(newPaginationModel);
}} }}
onRowClick={(params: any) => onOrderClicked(params.row.id)} onRowClick={(params: any) => {
onOrderClicked(params.row.id);
}}
/> />
</Paper> </Paper>
); );
@ -795,9 +805,9 @@ const BookTable = ({
hideFooter={!showFooter} hideFooter={!showFooter}
components={gridComponents} components={gridComponents}
columnVisibilityModel={columnVisibilityModel} columnVisibilityModel={columnVisibilityModel}
onColumnVisibilityModelChange={(newColumnVisibilityModel) => onColumnVisibilityModelChange={(newColumnVisibilityModel) => {
setColumnVisibilityModel(newColumnVisibilityModel) setColumnVisibilityModel(newColumnVisibilityModel);
} }}
componentsProps={{ componentsProps={{
toolbar: { toolbar: {
width, width,
@ -812,7 +822,9 @@ const BookTable = ({
onPaginationModelChange={(newPaginationModel) => { onPaginationModelChange={(newPaginationModel) => {
setPaginationModel(newPaginationModel); setPaginationModel(newPaginationModel);
}} }}
onRowClick={(params: any) => onOrderClicked(params.row.id)} onRowClick={(params: any) => {
onOrderClicked(params.row.id);
}}
/> />
</Paper> </Paper>
</Dialog> </Dialog>

View File

@ -1,12 +1,12 @@
import React, { useEffect, useState, useContext } from 'react'; import React, { useEffect, useState, useContext } from 'react';
import { import {
ResponsiveLine, ResponsiveLine,
Serie, type Serie,
Datum, type Datum,
PointTooltipProps, type PointTooltipProps,
PointMouseHandler, type PointMouseHandler,
Point, type Point,
CustomLayer, type CustomLayer,
} from '@nivo/line'; } from '@nivo/line';
import { import {
Box, Box,
@ -20,13 +20,13 @@ import {
} from '@mui/material'; } from '@mui/material';
import { AddCircleOutline, RemoveCircleOutline } from '@mui/icons-material'; import { AddCircleOutline, RemoveCircleOutline } from '@mui/icons-material';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PublicOrder, LimitList, Order } from '../../../models'; import { type PublicOrder, LimitList, type Order } from '../../../models';
import RobotAvatar from '../../RobotAvatar'; import RobotAvatar from '../../RobotAvatar';
import { amountToString, matchMedian, statusBadgeColor } from '../../../utils'; import { amountToString, matchMedian, statusBadgeColor } from '../../../utils';
import currencyDict from '../../../../static/assets/currencies.json'; import currencyDict from '../../../../static/assets/currencies.json';
import { PaymentStringAsIcons } from '../../PaymentMethods'; import { PaymentStringAsIcons } from '../../PaymentMethods';
import getNivoScheme from '../NivoScheme'; import getNivoScheme from '../NivoScheme';
import { UseAppStoreType, AppContext } from '../../../contexts/AppContext'; import { type UseAppStoreType, AppContext } from '../../../contexts/AppContext';
interface DepthChartProps { interface DepthChartProps {
maxWidth: number; maxWidth: number;
@ -316,7 +316,13 @@ const DepthChart: React.FC<DepthChartProps> = ({
alignItems='flex-start' alignItems='flex-start'
style={{ paddingLeft: '1em' }} style={{ paddingLeft: '1em' }}
> >
<Select variant='standard' value={xType} onChange={(e) => setXType(e.target.value)}> <Select
variant='standard'
value={xType}
onChange={(e) => {
setXType(e.target.value);
}}
>
<MenuItem value={'premium'}> <MenuItem value={'premium'}>
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}> <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
{t('Premium')} {t('Premium')}
@ -333,7 +339,11 @@ const DepthChart: React.FC<DepthChartProps> = ({
<Grid container direction='row' justifyContent='center' alignItems='center'> <Grid container direction='row' justifyContent='center' alignItems='center'>
<Grid container justifyContent='center' alignItems='center'> <Grid container justifyContent='center' alignItems='center'>
<Grid item> <Grid item>
<IconButton onClick={() => setXRange(xRange + rangeSteps)}> <IconButton
onClick={() => {
setXRange(xRange + rangeSteps);
}}
>
<RemoveCircleOutline /> <RemoveCircleOutline />
</IconButton> </IconButton>
</Grid> </Grid>
@ -345,7 +355,12 @@ const DepthChart: React.FC<DepthChartProps> = ({
</Box> </Box>
</Grid> </Grid>
<Grid item> <Grid item>
<IconButton onClick={() => setXRange(xRange - rangeSteps)} disabled={xRange <= 1}> <IconButton
onClick={() => {
setXRange(xRange - rangeSteps);
}}
disabled={xRange <= 1}
>
<AddCircleOutline /> <AddCircleOutline />
</IconButton> </IconButton>
</Grid> </Grid>

View File

@ -1,5 +1,5 @@
import { Theme as NivoTheme } from '@nivo/core'; import { type Theme as NivoTheme } from '@nivo/core';
import { Theme as MuiTheme } from '@mui/material/styles'; import { type Theme as MuiTheme } from '@mui/material/styles';
export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => { export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => {
const lightMode = { const lightMode = {

View File

@ -37,7 +37,11 @@ function CredentialTextfield(props) {
InputProps={{ InputProps={{
endAdornment: ( endAdornment: (
<Tooltip disableHoverListener enterTouchDelay={0} title={props.copiedTitle}> <Tooltip disableHoverListener enterTouchDelay={0} title={props.copiedTitle}>
<IconButton onClick={() => systemClient.copyToClipboard(props.value)}> <IconButton
onClick={() => {
systemClient.copyToClipboard(props.value);
}}
>
<ContentCopy /> <ContentCopy />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
@ -144,14 +148,14 @@ const AuditPGPDialog = ({
size='small' size='small'
color='primary' color='primary'
variant='contained' variant='contained'
onClick={() => onClick={() => {
saveAsJson('keys_' + orderId + '.json', { saveAsJson('keys_' + orderId + '.json', {
own_public_key: own_pub_key, own_public_key: own_pub_key,
peer_public_key: peer_pub_key, peer_public_key: peer_pub_key,
encrypted_private_key: own_enc_priv_key, encrypted_private_key: own_enc_priv_key,
passphrase, passphrase,
}) });
} }}
> >
<div style={{ width: 26, height: 18 }}> <div style={{ width: 26, height: 18 }}>
<ExportIcon sx={{ width: 18, height: 18 }} /> <ExportIcon sx={{ width: 18, height: 18 }} />
@ -176,7 +180,9 @@ const AuditPGPDialog = ({
size='small' size='small'
color='primary' color='primary'
variant='contained' variant='contained'
onClick={() => saveAsJson('messages_' + orderId + '.json', messages)} onClick={() => {
saveAsJson('messages_' + orderId + '.json', messages);
}}
> >
<div style={{ width: 28, height: 20 }}> <div style={{ width: 28, height: 20 }}>
<ExportIcon sx={{ width: 18, height: 18 }} /> <ExportIcon sx={{ width: 18, height: 18 }} />

View File

@ -23,7 +23,7 @@ import BookIcon from '@mui/icons-material/Book';
import LinkIcon from '@mui/icons-material/Link'; import LinkIcon from '@mui/icons-material/Link';
import { pn } from '../../utils'; import { pn } from '../../utils';
import { Info } from '../../models'; import { type Info } from '../../models';
interface Props { interface Props {
open: boolean; open: boolean;

View File

@ -13,7 +13,7 @@ import {
Grid, Grid,
} from '@mui/material'; } from '@mui/material';
import { NewTabIcon } from '../Icons'; import { NewTabIcon } from '../Icons';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
interface Props { interface Props {
open: boolean; open: boolean;

View File

@ -33,10 +33,10 @@ import NumbersIcon from '@mui/icons-material/Numbers';
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
import { UserNinjaIcon } from '../Icons'; import { UserNinjaIcon } from '../Icons';
import { getHost, getWebln } from '../../utils'; import { getWebln } from '../../utils';
import RobotAvatar from '../RobotAvatar'; import RobotAvatar from '../RobotAvatar';
import { apiClient } from '../../services/api'; import { apiClient } from '../../services/api';
import { Robot } from '../../models'; import { type Robot } from '../../models';
interface Props { interface Props {
open: boolean; open: boolean;
@ -50,7 +50,6 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const theme = useTheme(); const theme = useTheme();
const host = getHost();
const [rewardInvoice, setRewardInvoice] = useState<string>(''); const [rewardInvoice, setRewardInvoice] = useState<string>('');
const [showRewardsSpinner, setShowRewardsSpinner] = useState<boolean>(false); const [showRewardsSpinner, setShowRewardsSpinner] = useState<boolean>(false);
@ -60,13 +59,20 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
const [weblnEnabled, setWeblnEnabled] = useState<boolean>(false); const [weblnEnabled, setWeblnEnabled] = useState<boolean>(false);
const [openEnableTelegram, setOpenEnableTelegram] = useState<boolean>(false); const [openEnableTelegram, setOpenEnableTelegram] = useState<boolean>(false);
useEffect(() => { const handleWebln = async () => {
const handleWebln = async (order: Order) => { const webln = await getWebln()
const webln = await getWebln().catch(() => console.log('WebLN not available')); .then(() => {
setWeblnEnabled(true);
})
.catch(() => {
setWeblnEnabled(false);
console.log('WebLN not available');
});
return webln; return webln;
}; };
const webln = handleWebln();
setWeblnEnabled(webln !== undefined); useEffect(() => {
handleWebln();
}, []); }, []);
const handleWeblnInvoiceClicked = async (e: any) => { const handleWeblnInvoiceClicked = async (e: any) => {
@ -107,7 +113,9 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
const setStealthInvoice = (wantsStealth: boolean) => { const setStealthInvoice = (wantsStealth: boolean) => {
apiClient apiClient
.post(baseUrl, '/api/stealth/', { wantsStealth }, { tokenSHA256: robot.tokenSHA256 }) .post(baseUrl, '/api/stealth/', { wantsStealth }, { tokenSHA256: robot.tokenSHA256 })
.then((data) => setRobot({ ...robot, stealthInvoices: data?.wantsStealth })); .then((data) => {
setRobot({ ...robot, stealthInvoices: data?.wantsStealth });
});
}; };
return ( return (
@ -213,7 +221,9 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
<EnableTelegramDialog <EnableTelegramDialog
open={openEnableTelegram} open={openEnableTelegram}
onClose={() => setOpenEnableTelegram(false)} onClose={() => {
setOpenEnableTelegram(false);
}}
tgBotName={robot.tgBotName} tgBotName={robot.tgBotName}
tgToken={robot.tgToken} tgToken={robot.tgToken}
/> />
@ -229,7 +239,12 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
<b>{t('Telegram enabled')}</b> <b>{t('Telegram enabled')}</b>
</Typography> </Typography>
) : ( ) : (
<Button color='primary' onClick={() => setOpenEnableTelegram(true)}> <Button
color='primary'
onClick={() => {
setOpenEnableTelegram(true);
}}
>
{t('Enable Telegram Notifications')} {t('Enable Telegram Notifications')}
</Button> </Button>
)} )}
@ -256,7 +271,9 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
control={ control={
<Switch <Switch
checked={robot.stealthInvoices} checked={robot.stealthInvoices}
onChange={() => setStealthInvoice(!robot.stealthInvoices)} onChange={() => {
setStealthInvoice(!robot.stealthInvoices);
}}
/> />
} }
/> />
@ -280,7 +297,9 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
<Grid item xs={3}> <Grid item xs={3}>
<Button <Button
disabled={robot.earnedRewards === 0} disabled={robot.earnedRewards === 0}
onClick={() => setOpenClaimRewards(true)} onClick={() => {
setOpenClaimRewards(true);
}}
variant='contained' variant='contained'
size='small' size='small'
> >
@ -309,7 +328,9 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
<Grid item alignItems='stretch' style={{ display: 'flex', maxWidth: 80 }}> <Grid item alignItems='stretch' style={{ display: 'flex', maxWidth: 80 }}>
<Button <Button
sx={{ maxHeight: 38 }} sx={{ maxHeight: 38 }}
onClick={(e) => handleSubmitInvoiceClicked(e, rewardInvoice)} onClick={(e) => {
handleSubmitInvoiceClicked(e, rewardInvoice);
}}
variant='contained' variant='contained'
color='primary' color='primary'
size='small' size='small'
@ -319,12 +340,14 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
{weblnEnabled && ( {weblnEnabled ? (
<Grid container style={{ display: 'flex', alignItems: 'stretch' }}> <Grid container style={{ display: 'flex', alignItems: 'stretch' }}>
<Grid item alignItems='stretch' style={{ display: 'flex', maxWidth: 240 }}> <Grid item alignItems='stretch' style={{ display: 'flex', maxWidth: 240 }}>
<Button <Button
sx={{ maxHeight: 38, minWidth: 230 }} sx={{ maxHeight: 38, minWidth: 230 }}
onClick={async (e) => await handleWeblnInvoiceClicked(e)} onClick={async (e) => {
await handleWeblnInvoiceClicked(e);
}}
variant='contained' variant='contained'
color='primary' color='primary'
size='small' size='small'
@ -334,6 +357,8 @@ const ProfileDialog = ({ open = false, baseUrl, onClose, robot, setRobot }: Prop
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
) : (
<></>
)} )}
</form> </form>
)} )}

View File

@ -25,7 +25,7 @@ import EqualizerIcon from '@mui/icons-material/Equalizer';
import { AmbossIcon, BitcoinSignIcon, RoboSatsNoTextIcon } from '../Icons'; import { AmbossIcon, BitcoinSignIcon, RoboSatsNoTextIcon } from '../Icons';
import { pn } from '../../utils'; import { pn } from '../../utils';
import { Info } from '../../models'; import { type Info } from '../../models';
interface Props { interface Props {
open: boolean; open: boolean;

View File

@ -14,7 +14,7 @@ import {
} from '@mui/material'; } from '@mui/material';
import { systemClient } from '../../services/System'; import { systemClient } from '../../services/System';
import ContentCopy from '@mui/icons-material/ContentCopy'; import ContentCopy from '@mui/icons-material/ContentCopy';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
interface Props { interface Props {
open: boolean; open: boolean;
@ -49,7 +49,11 @@ const StoreTokenDialog = ({ open, onClose, onClickBack, onClickDone }: Props): J
InputProps={{ InputProps={{
endAdornment: ( endAdornment: (
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}> <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
<IconButton onClick={() => systemClient.copyToClipboard(robot.token)}> <IconButton
onClick={() => {
systemClient.copyToClipboard(robot.token);
}}
>
<ContentCopy color='primary' /> <ContentCopy color='primary' />
</IconButton> </IconButton>
</Tooltip> </Tooltip>

View File

@ -88,7 +88,12 @@ const UpdateClientDialog = ({
<Divider /> <Divider />
<ListItemButton component='a' onClick={() => location.reload(true)}> <ListItemButton
component='a'
onClick={() => {
location.reload(true);
}}
>
<ListItemIcon> <ListItemIcon>
<WebIcon color='primary' sx={{ height: 32, width: 32 }} /> <WebIcon color='primary' sx={{ height: 32, width: 32 }} />
</ListItemIcon> </ListItemIcon>

View File

@ -29,6 +29,7 @@ export default class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBo
window.location.reload(); window.location.reload();
}, 30000); }, 30000);
} }
render() { render() {
if (this.state.hasError) { if (this.state.hasError) {
return ( return (

View File

@ -132,7 +132,9 @@ function AmountRange({
}} }}
value={currency == 0 ? 1 : currency} value={currency == 0 ? 1 : currency}
renderValue={() => currencyCode} renderValue={() => currencyCode}
onChange={(e) => handleCurrencyChange(e.target.value)} onChange={(e) => {
handleCurrencyChange(e.target.value);
}}
> >
{Object.entries(currencyDict).map(([key, value]) => ( {Object.entries(currencyDict).map(([key, value]) => (
<MenuItem key={key} value={parseInt(key)}> <MenuItem key={key} value={parseInt(key)}>

View File

@ -226,9 +226,13 @@ export default function AutocompletePayments(props) {
value: props.value, value: props.value,
options: props.optionsType == 'fiat' ? fiatMethods : swapMethods, options: props.optionsType == 'fiat' ? fiatMethods : swapMethods,
getOptionLabel: (option) => option.name, getOptionLabel: (option) => option.name,
onInputChange: (e) => setVal(e ? (e.target.value ? e.target.value : '') : ''), onInputChange: (e) => {
setVal(e ? (e.target.value ? e.target.value : '') : '');
},
onChange: (event, value) => props.onAutocompleteChange(value), onChange: (event, value) => props.onAutocompleteChange(value),
onClose: () => setVal(() => ''), onClose: () => {
setVal(() => '');
},
}); });
const [val, setVal] = useState(''); const [val, setVal] = useState('');

View File

@ -25,7 +25,7 @@ import {
IconButton, IconButton,
} from '@mui/material'; } from '@mui/material';
import { LimitList, defaultMaker } from '../../models'; import { type LimitList, defaultMaker } from '../../models';
import { LocalizationProvider, MobileTimePicker } from '@mui/x-date-pickers'; import { LocalizationProvider, MobileTimePicker } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
@ -40,7 +40,7 @@ import { amountToString, computeSats, pn } from '../../utils';
import { SelfImprovement, Lock, HourglassTop, DeleteSweep, Edit } from '@mui/icons-material'; import { SelfImprovement, Lock, HourglassTop, DeleteSweep, Edit } from '@mui/icons-material';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
interface MakerFormProps { interface MakerFormProps {
disableRequest?: boolean; disableRequest?: boolean;
@ -464,7 +464,9 @@ const MakerForm = ({
<Box> <Box>
<ConfirmationDialog <ConfirmationDialog
open={openDialogs} open={openDialogs}
onClose={() => setOpenDialogs(false)} onClose={() => {
setOpenDialogs(false);
}}
onClickDone={handleCreateOrder} onClickDone={handleCreateOrder}
hasRobot={robot.avatarLoaded} hasRobot={robot.avatarLoaded}
/> />
@ -531,7 +533,9 @@ const MakerForm = ({
<Checkbox <Checkbox
sx={{ position: 'relative', bottom: '0.3em' }} sx={{ position: 'relative', bottom: '0.3em' }}
checked={fav.mode == 'swap'} checked={fav.mode == 'swap'}
onClick={() => handleCurrencyChange(fav.mode == 'swap' ? 1 : 1000)} onClick={() => {
handleCurrencyChange(fav.mode == 'swap' ? 1 : 1000);
}}
/> />
</FormControl> </FormControl>
</Grid> </Grid>
@ -547,12 +551,12 @@ const MakerForm = ({
<Button <Button
size={maker.advancedOptions ? 'small' : 'large'} size={maker.advancedOptions ? 'small' : 'large'}
variant='contained' variant='contained'
onClick={() => onClick={() => {
setFav({ setFav({
...fav, ...fav,
type: 1, type: 1,
}) });
} }}
disableElevation={fav.type == 1} disableElevation={fav.type == 1}
sx={{ sx={{
backgroundColor: fav.type == 1 ? 'primary.main' : 'background.paper', backgroundColor: fav.type == 1 ? 'primary.main' : 'background.paper',
@ -567,12 +571,12 @@ const MakerForm = ({
<Button <Button
size={maker.advancedOptions ? 'small' : 'large'} size={maker.advancedOptions ? 'small' : 'large'}
variant='contained' variant='contained'
onClick={() => onClick={() => {
setFav({ setFav({
...fav, ...fav,
type: 0, type: 0,
}) });
} }}
disableElevation={fav.type == 0} disableElevation={fav.type == 0}
color='secondary' color='secondary'
sx={{ sx={{
@ -654,7 +658,9 @@ const MakerForm = ({
borderRadius: '4px', borderRadius: '4px',
}, },
}} }}
onChange={(e) => setMaker({ ...maker, amount: e.target.value })} onChange={(e) => {
setMaker({ ...maker, amount: e.target.value });
}}
/> />
</Tooltip> </Tooltip>
{fav.mode === 'swap' && maker.amount != '' ? ( {fav.mode === 'swap' && maker.amount != '' ? (
@ -677,7 +683,9 @@ const MakerForm = ({
style: { textAlign: 'center' }, style: { textAlign: 'center' },
}} }}
value={fav.currency == 0 ? 1 : fav.currency} value={fav.currency == 0 ? 1 : fav.currency}
onChange={(e) => handleCurrencyChange(e.target.value)} onChange={(e) => {
handleCurrencyChange(e.target.value);
}}
> >
{Object.entries(currencyDict).map(([key, value]) => ( {Object.entries(currencyDict).map(([key, value]) => (
<MenuItem key={key} value={parseInt(key)}> <MenuItem key={key} value={parseInt(key)}>
@ -946,7 +954,9 @@ const MakerForm = ({
]} ]}
min={2} min={2}
max={15} max={15}
onChange={(e) => setMaker({ ...maker, bondSize: e.target.value })} onChange={(e) => {
setMaker({ ...maker, bondSize: e.target.value });
}}
/> />
</Grid> </Grid>
</Grid> </Grid>

View File

@ -5,14 +5,14 @@ import {
Alert, Alert,
useTheme, useTheme,
IconButton, IconButton,
TooltipProps, type TooltipProps,
styled, styled,
tooltipClasses, tooltipClasses,
} from '@mui/material'; } from '@mui/material';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Order } from '../../models'; import { type Order } from '../../models';
import Close from '@mui/icons-material/Close'; import Close from '@mui/icons-material/Close';
import { Page } from '../../basic/NavBar'; import { type Page } from '../../basic/NavBar';
interface NotificationsProps { interface NotificationsProps {
order: Order | undefined; order: Order | undefined;
@ -28,7 +28,7 @@ interface NotificationMessage {
onClick: () => void; onClick: () => void;
sound: HTMLAudioElement | undefined; sound: HTMLAudioElement | undefined;
timeout: number; timeout: number;
pageTitle: String; pageTitle: string;
} }
const audio = { const audio = {
@ -207,7 +207,9 @@ const Notifications = ({
if (message.title != '') { if (message.title != '') {
setMessage(message); setMessage(message);
setShow(true); setShow(true);
setTimeout(() => setShow(false), message.timeout); setTimeout(() => {
setShow(false);
}, message.timeout);
if (message.sound != null) { if (message.sound != null) {
message.sound.play(); message.sound.play();
} }

View File

@ -21,11 +21,11 @@ import Countdown from 'react-countdown';
import currencies from '../../../static/assets/currencies.json'; import currencies from '../../../static/assets/currencies.json';
import { apiClient } from '../../services/api'; import { apiClient } from '../../services/api';
import { Order, Info } from '../../models'; import { type Order, type Info } from '../../models';
import { ConfirmationDialog } from '../Dialogs'; import { ConfirmationDialog } from '../Dialogs';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import { computeSats } from '../../utils'; import { computeSats } from '../../utils';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
interface TakeButtonProps { interface TakeButtonProps {
order: Order; order: Order;
@ -58,10 +58,10 @@ const TakeButton = ({ order, setOrder, baseUrl, info }: TakeButtonProps): JSX.El
const rate = order.amount ? order.amount / btc_now : order.max_amount / btc_now; const rate = order.amount ? order.amount / btc_now : order.max_amount / btc_now;
const amount = order.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount); const amount = order.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount);
const satoshis = computeSats({ const satoshis = computeSats({
amount: amount, amount,
routingBudget: order.is_buyer ? defaultRoutingBudget : 0, routingBudget: order.is_buyer ? defaultRoutingBudget : 0,
fee: tradeFee, fee: tradeFee,
rate: rate, rate,
}); });
return satoshis; return satoshis;
}; };
@ -74,7 +74,12 @@ const TakeButton = ({ order, setOrder, baseUrl, info }: TakeButtonProps): JSX.El
const InactiveMakerDialog = function () { const InactiveMakerDialog = function () {
return ( return (
<Dialog open={open.inactiveMaker} onClose={() => setOpen({ ...open, inactiveMaker: false })}> <Dialog
open={open.inactiveMaker}
onClose={() => {
setOpen({ ...open, inactiveMaker: false });
}}
>
<DialogTitle>{t('The maker is away')}</DialogTitle> <DialogTitle>{t('The maker is away')}</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText> <DialogContentText>
@ -84,10 +89,19 @@ const TakeButton = ({ order, setOrder, baseUrl, info }: TakeButtonProps): JSX.El
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={() => setOpen(closeAll)} autoFocus> <Button
onClick={() => {
setOpen(closeAll);
}}
autoFocus
>
{t('Go back')} {t('Go back')}
</Button> </Button>
<Button onClick={() => setOpen({ inactiveMaker: false, confirmation: true })}> <Button
onClick={() => {
setOpen({ inactiveMaker: false, confirmation: true });
}}
>
{t('Sounds fine')} {t('Sounds fine')}
</Button> </Button>
</DialogActions> </DialogActions>
@ -313,7 +327,9 @@ const TakeButton = ({ order, setOrder, baseUrl, info }: TakeButtonProps): JSX.El
<ConfirmationDialog <ConfirmationDialog
open={open.confirmation} open={open.confirmation}
onClose={() => setOpen({ ...open, confirmation: false })} onClose={() => {
setOpen({ ...open, confirmation: false });
}}
onClickDone={() => { onClickDone={() => {
takeOrder(); takeOrder();
setLoadingTake(true); setLoadingTake(true);

View File

@ -16,7 +16,7 @@ import {
IconButton, IconButton,
} from '@mui/material'; } from '@mui/material';
import Countdown, { CountdownRenderProps, zeroPad } from 'react-countdown'; import Countdown, { type CountdownRenderProps, zeroPad } from 'react-countdown';
import RobotAvatar from '../../components/RobotAvatar'; import RobotAvatar from '../../components/RobotAvatar';
import currencies from '../../../static/assets/currencies.json'; import currencies from '../../../static/assets/currencies.json';
@ -34,7 +34,7 @@ import { PaymentStringAsIcons } from '../../components/PaymentMethods';
import { FlagWithProps, SendReceiveIcon } from '../Icons'; import { FlagWithProps, SendReceiveIcon } from '../Icons';
import LinearDeterminate from './LinearDeterminate'; import LinearDeterminate from './LinearDeterminate';
import { Order, Info } from '../../models'; import { type Order, type Info } from '../../models';
import { statusBadgeColor, pn, amountToString, computeSats } from '../../utils'; import { statusBadgeColor, pn, amountToString, computeSats } from '../../utils';
import TakeButton from './TakeButton'; import TakeButton from './TakeButton';
@ -160,20 +160,20 @@ const OrderDetails = ({
amount: order.amount, amount: order.amount,
fee: -tradeFee, fee: -tradeFee,
routingBudget: defaultRoutingBudget, routingBudget: defaultRoutingBudget,
rate: rate, rate,
}); });
} else { } else {
const min = computeSats({ const min = computeSats({
amount: Number(order.min_amount), amount: Number(order.min_amount),
fee: -tradeFee, fee: -tradeFee,
routingBudget: defaultRoutingBudget, routingBudget: defaultRoutingBudget,
rate: rate, rate,
}); });
const max = computeSats({ const max = computeSats({
amount: Number(order.max_amount), amount: Number(order.max_amount),
fee: -tradeFee, fee: -tradeFee,
routingBudget: defaultRoutingBudget, routingBudget: defaultRoutingBudget,
rate: rate, rate,
}); });
sats = `${min}-${max}`; sats = `${min}-${max}`;
} }
@ -190,18 +190,18 @@ const OrderDetails = ({
sats = computeSats({ sats = computeSats({
amount: order.amount, amount: order.amount,
fee: tradeFee, fee: tradeFee,
rate: rate, rate,
}); });
} else { } else {
const min = computeSats({ const min = computeSats({
amount: order.min_amount, amount: order.min_amount,
fee: tradeFee, fee: tradeFee,
rate: rate, rate,
}); });
const max = computeSats({ const max = computeSats({
amount: order.max_amount, amount: order.max_amount,
fee: tradeFee, fee: tradeFee,
rate: rate, rate,
}); });
sats = `${min}-${max}`; sats = `${min}-${max}`;
} }
@ -297,7 +297,11 @@ const OrderDetails = ({
secondary={order.amount ? 'Amount' : 'Amount Range'} secondary={order.amount ? 'Amount' : 'Amount Range'}
/> />
<ListItemIcon> <ListItemIcon>
<IconButton onClick={() => setShowSatsDetails(!showSatsDetails)}> <IconButton
onClick={() => {
setShowSatsDetails(!showSatsDetails);
}}
>
{showSatsDetails ? <ExpandLess /> : <ExpandMore color='primary' />} {showSatsDetails ? <ExpandLess /> : <ExpandMore color='primary' />}
</IconButton> </IconButton>
</ListItemIcon> </ListItemIcon>

View File

@ -105,7 +105,9 @@ const RobotAvatar: React.FC<Props> = ({
border: '0.3px solid #55555', border: '0.3px solid #55555',
filter: 'dropShadow(0.5px 0.5px 0.5px #000000)', filter: 'dropShadow(0.5px 0.5px 0.5px #000000)',
...imageStyle, ...imageStyle,
onLoad: setTimeout(() => setActiveBackground(false), 1000), onLoad: setTimeout(() => {
setActiveBackground(false);
}, 1000),
}} }}
/> />
</div> </div>

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Select, MenuItem, useTheme, Grid, Typography } from '@mui/material'; import { Select, MenuItem, useTheme, Grid, Typography } from '@mui/material';
import Language from '../../models/Language.model'; import type Language from '../../models/Language.model';
import Flags from 'country-flag-icons/react/3x2'; import Flags from 'country-flag-icons/react/3x2';
import { CataloniaFlag, BasqueCountryFlag } from '../Icons'; import { CataloniaFlag, BasqueCountryFlag } from '../Icons';

View File

@ -1,6 +1,6 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { UseAppStoreType, AppContext } from '../../contexts/AppContext'; import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
import { import {
Grid, Grid,
Paper, Paper,

View File

@ -2,7 +2,7 @@ import React, { useContext } from 'react';
import { Box, CircularProgress, Tooltip } from '@mui/material'; import { Box, CircularProgress, Tooltip } from '@mui/material';
import { TorIcon } from './Icons'; import { TorIcon } from './Icons';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { AppContext, UseAppStoreType } from '../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../contexts/AppContext';
interface TorIndicatorProps { interface TorIndicatorProps {
color: 'inherit' | 'error' | 'warning' | 'success' | 'primary' | 'secondary' | 'info' | undefined; color: 'inherit' | 'error' | 'warning' | 'success' | 'primary' | 'secondary' | 'info' | undefined;

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Box, Tooltip } from '@mui/material'; import { Box, Tooltip } from '@mui/material';
import { Order } from '../../models'; import { type Order } from '../../models';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
interface CancelButtonProps { interface CancelButtonProps {

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Alert } from '@mui/material'; import { Alert } from '@mui/material';
import { Order } from '../../models'; import { type Order } from '../../models';
interface CollabCancelAlertProps { interface CollabCancelAlertProps {
order: Order; order: Order;

View File

@ -12,7 +12,7 @@ import { LoadingButton } from '@mui/lab';
interface ConfirmCollabCancelDialogProps { interface ConfirmCollabCancelDialogProps {
open: boolean; open: boolean;
loading: Boolean; loading: boolean;
onClose: () => void; onClose: () => void;
onCollabCancelClick: () => void; onCollabCancelClick: () => void;
peerAskedCancel: boolean; peerAskedCancel: boolean;

View File

@ -8,7 +8,7 @@ import {
DialogContentText, DialogContentText,
Button, Button,
} from '@mui/material'; } from '@mui/material';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import currencies from '../../../../static/assets/currencies.json'; import currencies from '../../../../static/assets/currencies.json';
import { pn } from '../../../utils'; import { pn } from '../../../utils';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';

View File

@ -8,7 +8,7 @@ import {
DialogContentText, DialogContentText,
Button, Button,
} from '@mui/material'; } from '@mui/material';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import currencies from '../../../../static/assets/currencies.json'; import currencies from '../../../../static/assets/currencies.json';
import { pn } from '../../../utils'; import { pn } from '../../../utils';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';

View File

@ -8,7 +8,7 @@ import {
DialogContentText, DialogContentText,
Button, Button,
} from '@mui/material'; } from '@mui/material';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
interface ConfirmUndoFiatSentDialogProps { interface ConfirmUndoFiatSentDialogProps {
@ -30,7 +30,9 @@ export const ConfirmUndoFiatSentDialog = ({
useEffect(() => { useEffect(() => {
if (time > 0 && open) { if (time > 0 && open) {
setTimeout(() => setTime(time - 1), 1000); setTimeout(() => {
setTime(time - 1);
}, 1000);
} }
}, [time, open]); }, [time, open]);

View File

@ -34,7 +34,14 @@ const ChatBottom: React.FC<Props> = ({ orderId, setAudit, audit, createJsonFile
enterNextDelay={2000} enterNextDelay={2000}
title={t('Verify your privacy')} title={t('Verify your privacy')}
> >
<Button size='small' color='primary' variant='outlined' onClick={() => setAudit(!audit)}> <Button
size='small'
color='primary'
variant='outlined'
onClick={() => {
setAudit(!audit);
}}
>
<KeyIcon sx={{ width: '0.8em', height: '0.8em' }} /> <KeyIcon sx={{ width: '0.8em', height: '0.8em' }} />
{t('Audit PGP')}{' '} {t('Audit PGP')}{' '}
</Button> </Button>
@ -54,7 +61,9 @@ const ChatBottom: React.FC<Props> = ({ orderId, setAudit, audit, createJsonFile
size='small' size='small'
color='primary' color='primary'
variant='outlined' variant='outlined'
onClick={() => saveAsJson('complete_log_chat_' + orderId + '.json', createJsonFile())} onClick={() => {
saveAsJson('complete_log_chat_' + orderId + '.json', createJsonFile());
}}
> >
<div style={{ width: '1.4em', height: '1.4em' }}> <div style={{ width: '1.4em', height: '1.4em' }}>
<ExportIcon sx={{ width: '0.8em', height: '0.8em' }} /> <ExportIcon sx={{ width: '0.8em', height: '0.8em' }} />
@ -68,7 +77,9 @@ const ChatBottom: React.FC<Props> = ({ orderId, setAudit, audit, createJsonFile
size='small' size='small'
color='primary' color='primary'
variant='outlined' variant='outlined'
onClick={() => systemClient.copyToClipboard(JSON.stringify(createJsonFile()))} onClick={() => {
systemClient.copyToClipboard(JSON.stringify(createJsonFile()));
}}
> >
<div style={{ width: '1.4em', height: '1.4em' }}> <div style={{ width: '1.4em', height: '1.4em' }}>
<ExportIcon sx={{ width: '0.8em', height: '0.8em' }} /> <ExportIcon sx={{ width: '0.8em', height: '0.8em' }} />

View File

@ -53,7 +53,9 @@ const ChatHeader: React.FC<Props> = ({ connected, peerConnected, turtleMode, set
<IconButton <IconButton
size='small' size='small'
color={turtleMode ? 'primary' : 'inherit'} color={turtleMode ? 'primary' : 'inherit'}
onClick={() => setTurtleMode(!turtleMode)} onClick={() => {
setTurtleMode(!turtleMode);
}}
> >
<WifiTetheringError /> <WifiTetheringError />
</IconButton> </IconButton>

View File

@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next';
import { Button, Tooltip, TextField, Grid, Paper, Typography } from '@mui/material'; import { Button, Tooltip, TextField, Grid, Paper, Typography } from '@mui/material';
import { encryptMessage, decryptMessage } from '../../../../pgp'; import { encryptMessage, decryptMessage } from '../../../../pgp';
import { AuditPGPDialog } from '../../../Dialogs'; import { AuditPGPDialog } from '../../../Dialogs';
import { websocketClient, WebsocketConnection } from '../../../../services/Websocket'; import { websocketClient, type WebsocketConnection } from '../../../../services/Websocket';
import { Robot } from '../../../../models'; import { type Robot } from '../../../../models';
// Icons // Icons
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
@ -12,7 +12,7 @@ import KeyIcon from '@mui/icons-material/Key';
import { useTheme } from '@mui/system'; import { useTheme } from '@mui/system';
import MessageCard from '../MessageCard'; import MessageCard from '../MessageCard';
import ChatHeader from '../ChatHeader'; import ChatHeader from '../ChatHeader';
import { EncryptedChatMessage, ServerMessage } from '..'; import { type EncryptedChatMessage, type ServerMessage } from '..';
import ChatBottom from '../ChatBottom'; import ChatBottom from '../ChatBottom';
import { sha256 } from 'js-sha256'; import { sha256 } from 'js-sha256';
@ -107,9 +107,15 @@ const EncryptedSocketChat: React.FC<Props> = ({
nick: userNick, nick: userNick,
}); });
connection.onMessage((message) => setServerMessages((prev) => [...prev, message])); connection.onMessage((message) => {
connection.onClose(() => setConnected(false)); setServerMessages((prev) => [...prev, message]);
connection.onError(() => setConnected(false)); });
connection.onClose(() => {
setConnected(false);
});
connection.onError(() => {
setConnected(false);
});
}); });
}; };
@ -230,7 +236,9 @@ const EncryptedSocketChat: React.FC<Props> = ({
}); });
} }
}) })
.catch((error) => setError(error.toString())); .catch((error) => {
setError(error.toString());
});
} }
e.preventDefault(); e.preventDefault();
}; };
@ -245,14 +253,18 @@ const EncryptedSocketChat: React.FC<Props> = ({
> >
<AuditPGPDialog <AuditPGPDialog
open={audit} open={audit}
onClose={() => setAudit(false)} onClose={() => {
setAudit(false);
}}
orderId={Number(orderId)} orderId={Number(orderId)}
messages={messages} messages={messages}
own_pub_key={robot.pubKey || ''} own_pub_key={robot.pubKey || ''}
own_enc_priv_key={robot.encPrivKey || ''} own_enc_priv_key={robot.encPrivKey || ''}
peer_pub_key={peerPubKey || 'Not received yet'} peer_pub_key={peerPubKey || 'Not received yet'}
passphrase={robot.token || ''} passphrase={robot.token || ''}
onClickBack={() => setAudit(false)} onClickBack={() => {
setAudit(false);
}}
/> />
<Grid item> <Grid item>
<ChatHeader <ChatHeader

View File

@ -3,7 +3,7 @@ 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';
import { AuditPGPDialog } from '../../../Dialogs'; import { AuditPGPDialog } from '../../../Dialogs';
import { Robot } from '../../../../models'; import { type Robot } from '../../../../models';
// Icons // Icons
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
@ -11,7 +11,7 @@ import KeyIcon from '@mui/icons-material/Key';
import { useTheme } from '@mui/system'; import { useTheme } from '@mui/system';
import MessageCard from '../MessageCard'; import MessageCard from '../MessageCard';
import ChatHeader from '../ChatHeader'; import ChatHeader from '../ChatHeader';
import { EncryptedChatMessage, 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';
@ -222,7 +222,9 @@ const EncryptedTurtleChat: React.FC<Props> = ({
setValue(''); setValue('');
}); });
}) })
.catch((error) => setError(error.toString())); .catch((error) => {
setError(error.toString());
});
} }
e.preventDefault(); e.preventDefault();
}; };
@ -237,14 +239,18 @@ const EncryptedTurtleChat: React.FC<Props> = ({
> >
<AuditPGPDialog <AuditPGPDialog
open={audit} open={audit}
onClose={() => setAudit(false)} onClose={() => {
setAudit(false);
}}
orderId={Number(orderId)} orderId={Number(orderId)}
messages={messages} messages={messages}
own_pub_key={robot.pubKey || ''} own_pub_key={robot.pubKey || ''}
own_enc_priv_key={robot.encPrivKey || ''} own_enc_priv_key={robot.encPrivKey || ''}
peer_pub_key={peerPubKey || 'Not received yet'} peer_pub_key={peerPubKey || 'Not received yet'}
passphrase={robot.token || ''} passphrase={robot.token || ''}
onClickBack={() => setAudit(false)} onClickBack={() => {
setAudit(false);
}}
/> />
<Grid item> <Grid item>

View File

@ -9,7 +9,7 @@ import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import ContentCopy from '@mui/icons-material/ContentCopy'; import ContentCopy from '@mui/icons-material/ContentCopy';
import VisibilityIcon from '@mui/icons-material/Visibility'; import VisibilityIcon from '@mui/icons-material/Visibility';
import { EncryptedChatMessage } from '..'; import { type EncryptedChatMessage } from '..';
interface Props { interface Props {
message: EncryptedChatMessage; message: EncryptedChatMessage;
@ -81,7 +81,9 @@ const MessageCard: React.FC<Props> = ({ message, isTaker, userConnected, baseUrl
<div style={{ width: '1.4em' }}> <div style={{ width: '1.4em' }}>
<IconButton <IconButton
sx={{ height: '1.2em', width: '1.2em', position: 'relative', right: '0.15em' }} sx={{ height: '1.2em', width: '1.2em', position: 'relative', right: '0.15em' }}
onClick={() => setShowPGP(!showPGP)} onClick={() => {
setShowPGP(!showPGP);
}}
> >
<VisibilityIcon <VisibilityIcon
color={showPGP ? 'primary' : 'inherit'} color={showPGP ? 'primary' : 'inherit'}
@ -97,11 +99,11 @@ const MessageCard: React.FC<Props> = ({ message, isTaker, userConnected, baseUrl
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}> <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
<IconButton <IconButton
sx={{ height: '0.8em', width: '0.8em' }} sx={{ height: '0.8em', width: '0.8em' }}
onClick={() => onClick={() => {
systemClient.copyToClipboard( systemClient.copyToClipboard(
showPGP ? message.encryptedMessage : message.plainTextMessage, showPGP ? message.encryptedMessage : message.plainTextMessage,
) );
} }}
> >
<ContentCopy <ContentCopy
sx={{ sx={{

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Robot } from '../../../models'; import { type Robot } from '../../../models';
import EncryptedSocketChat from './EncryptedSocketChat'; import EncryptedSocketChat from './EncryptedSocketChat';
import EncryptedTurtleChat from './EncryptedTurtleChat'; import EncryptedTurtleChat from './EncryptedTurtleChat';

View File

@ -52,7 +52,9 @@ export const DisputeStatementForm = ({
}} }}
multiline multiline
rows={4} rows={4}
onChange={(e) => setDispute({ ...dispute, statement: e.target.value })} onChange={(e) => {
setDispute({ ...dispute, statement: e.target.value });
}}
/> />
</Grid> </Grid>
<Grid item> <Grid item>
@ -67,7 +69,9 @@ export const DisputeStatementForm = ({
control={ control={
<Checkbox <Checkbox
checked={dispute.attachLogs} checked={dispute.attachLogs}
onChange={() => setDispute({ ...dispute, attachLogs: !dispute.attachLogs })} onChange={() => {
setDispute({ ...dispute, attachLogs: !dispute.attachLogs });
}}
/> />
} }
label={t('Attach chat logs')} label={t('Attach chat logs')}

View File

@ -21,7 +21,7 @@ import {
FormHelperText, FormHelperText,
} from '@mui/material'; } from '@mui/material';
import { Order, Settings } from '../../../models'; import { type Order, type Settings } from '../../../models';
import { decode } from 'light-bolt11-decoder'; import { decode } from 'light-bolt11-decoder';
import WalletsButton from '../WalletsButton'; import WalletsButton from '../WalletsButton';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
@ -195,7 +195,9 @@ export const LightningPayoutForm = ({
.catch(() => { .catch(() => {
setLightning({ ...lightning, badLnproxy: 'Lnproxy server uncaught error' }); setLightning({ ...lightning, badLnproxy: 'Lnproxy server uncaught error' });
}) })
.finally(() => setLoadingLnproxy(false)); .finally(() => {
setLoadingLnproxy(false);
});
}; };
const handleAdvancedOptions = function (checked: boolean) { const handleAdvancedOptions = function (checked: boolean) {
@ -291,7 +293,9 @@ export const LightningPayoutForm = ({
<Switch <Switch
size='small' size='small'
checked={lightning.advancedOptions} checked={lightning.advancedOptions}
onChange={(e) => handleAdvancedOptions(e.target.checked)} onChange={(e) => {
handleAdvancedOptions(e.target.checked);
}}
/> />
<SelfImprovement sx={{ color: 'text.primary' }} /> <SelfImprovement sx={{ color: 'text.primary' }} />
</Grid> </Grid>
@ -375,13 +379,13 @@ export const LightningPayoutForm = ({
> >
<div> <div>
<FormControlLabel <FormControlLabel
onChange={(e) => onChange={(e) => {
setLightning({ setLightning({
...lightning, ...lightning,
useLnproxy: e.target.checked, useLnproxy: e.target.checked,
invoice: e.target.checked ? '' : lightning.invoice, invoice: e.target.checked ? '' : lightning.invoice,
}) });
} }}
checked={lightning.useLnproxy} checked={lightning.useLnproxy}
control={<Checkbox />} control={<Checkbox />}
label={ label={
@ -419,9 +423,9 @@ export const LightningPayoutForm = ({
label={t('Server')} label={t('Server')}
labelId='select-label' labelId='select-label'
value={lightning.lnproxyServer} value={lightning.lnproxyServer}
onChange={(e) => onChange={(e) => {
setLightning({ ...lightning, lnproxyServer: Number(e.target.value) }) setLightning({ ...lightning, lnproxyServer: Number(e.target.value) });
} }}
> >
{lnproxies.map((lnproxyServer, index) => ( {lnproxies.map((lnproxyServer, index) => (
<MenuItem key={index} value={index}> <MenuItem key={index} value={index}>
@ -494,13 +498,13 @@ export const LightningPayoutForm = ({
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}> <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
<IconButton <IconButton
sx={{ height: '0.5em' }} sx={{ height: '0.5em' }}
onClick={() => onClick={() => {
systemClient.copyToClipboard( systemClient.copyToClipboard(
lightning.useLnproxy lightning.useLnproxy
? String(lightning.lnproxyAmount) ? String(lightning.lnproxyAmount)
: String(lightning.amount), : String(lightning.amount),
) );
} }}
> >
<ContentCopy sx={{ width: '0.8em' }} /> <ContentCopy sx={{ width: '0.8em' }} />
</IconButton> </IconButton>
@ -523,9 +527,9 @@ export const LightningPayoutForm = ({
style: { textAlign: 'center' }, style: { textAlign: 'center' },
}} }}
variant='outlined' variant='outlined'
onChange={(e) => onChange={(e) => {
setLightning({ ...lightning, lnproxyInvoice: e.target.value ?? '' }) setLightning({ ...lightning, lnproxyInvoice: e.target.value ?? '' });
} }}
/> />
) : ( ) : (
<></> <></>
@ -547,7 +551,9 @@ export const LightningPayoutForm = ({
multiline={!lightning.useLnproxy} multiline={!lightning.useLnproxy}
minRows={3} minRows={3}
maxRows={5} maxRows={5}
onChange={(e) => setLightning({ ...lightning, invoice: e.target.value ?? '' })} onChange={(e) => {
setLightning({ ...lightning, invoice: e.target.value ?? '' });
}}
/> />
</Grid> </Grid>
@ -572,7 +578,9 @@ export const LightningPayoutForm = ({
<LoadingButton <LoadingButton
loading={loading} loading={loading}
disabled={lightning.invoice.length < 20 || lightning.badInvoice != ''} disabled={lightning.invoice.length < 20 || lightning.badInvoice != ''}
onClick={() => onClickSubmit(lightning.invoice)} onClick={() => {
onClickSubmit(lightning.invoice);
}}
variant='outlined' variant='outlined'
color='primary' color='primary'
> >

View File

@ -1,7 +1,7 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Grid, Typography, TextField, List, Divider, ListItemText, ListItem } from '@mui/material'; import { Grid, Typography, TextField, List, Divider, ListItemText, ListItem } from '@mui/material';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import { pn } from '../../../utils'; import { pn } from '../../../utils';
@ -124,7 +124,9 @@ export const OnchainPayoutForm = ({
inputProps={{ inputProps={{
style: { textAlign: 'center' }, style: { textAlign: 'center' },
}} }}
onChange={(e) => setOnchain({ ...onchain, address: e.target.value })} onChange={(e) => {
setOnchain({ ...onchain, address: e.target.value });
}}
/> />
</Grid> </Grid>
<Grid item xs={5}> <Grid item xs={5}>

View File

@ -3,9 +3,9 @@ import { useTranslation } from 'react-i18next';
import { Grid, Typography, Tooltip, Collapse, IconButton } from '@mui/material'; import { Grid, Typography, Tooltip, Collapse, IconButton } from '@mui/material';
import currencies from '../../../../static/assets/currencies.json'; import currencies from '../../../../static/assets/currencies.json';
import { Order, Robot } from '../../../models'; import { type Order, type Robot } from '../../../models';
import { pn } from '../../../utils'; import { pn } from '../../../utils';
import EncryptedChat, { 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';

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Grid, Typography } from '@mui/material'; import { Grid, Typography } from '@mui/material';
import { DisputeForm, DisputeStatementForm } from '../Forms'; import { type DisputeForm, DisputeStatementForm } from '../Forms';
interface DisputePromptProps { interface DisputePromptProps {
loading: boolean; loading: boolean;

View File

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Grid, Typography } from '@mui/material'; import { Grid, Typography } from '@mui/material';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import { Order } from '../../../models'; import { type Order } from '../../../models';
interface ExpiredPromptProps { interface ExpiredPromptProps {
order: Order; order: Order;

View File

@ -3,11 +3,11 @@ import { useTranslation } from 'react-i18next';
import { Button, Box, Grid, Typography, TextField, Tooltip, useTheme } from '@mui/material'; import { Button, Box, Grid, Typography, TextField, Tooltip, useTheme } from '@mui/material';
import { ContentCopy } from '@mui/icons-material'; import { ContentCopy } from '@mui/icons-material';
import QRCode from 'react-qr-code'; import QRCode from 'react-qr-code';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import { systemClient } from '../../../services/System'; import { systemClient } from '../../../services/System';
import currencies from '../../../../static/assets/currencies.json'; import currencies from '../../../../static/assets/currencies.json';
import WalletsButton from '../WalletsButton'; import WalletsButton from '../WalletsButton';
import { AppContext, UseAppStoreType } from '../../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../../contexts/AppContext';
interface LockInvoicePromptProps { interface LockInvoicePromptProps {
order: Order; order: Order;

View File

@ -4,10 +4,15 @@ import { Grid, Typography, ToggleButtonGroup, ToggleButton } from '@mui/material
import currencies from '../../../../static/assets/currencies.json'; import currencies from '../../../../static/assets/currencies.json';
import { Order, Settings } from '../../../models'; import { type Order, type Settings } from '../../../models';
import { pn } from '../../../utils'; import { pn } from '../../../utils';
import { Bolt, Link } from '@mui/icons-material'; import { Bolt, Link } from '@mui/icons-material';
import { LightningPayoutForm, LightningForm, OnchainPayoutForm, OnchainForm } from '../Forms'; import {
LightningPayoutForm,
type LightningForm,
OnchainPayoutForm,
type OnchainForm,
} from '../Forms';
interface PayoutPrompProps { interface PayoutPrompProps {
order: Order; order: Order;
@ -71,7 +76,9 @@ export const PayoutPrompt = ({
size='small' size='small'
value={tab} value={tab}
exclusive exclusive
onChange={(mouseEvent, value) => setTab(value == null ? tab : value)} onChange={(mouseEvent, value) => {
setTab(value == null ? tab : value);
}}
> >
<ToggleButton value='lightning'> <ToggleButton value='lightning'>
<div <div

View File

@ -14,7 +14,7 @@ import { LoadingButton } from '@mui/lab';
import currencies from '../../../../static/assets/currencies.json'; import currencies from '../../../../static/assets/currencies.json';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import { PauseCircle, Storefront, Percent } from '@mui/icons-material'; import { PauseCircle, Storefront, Percent } from '@mui/icons-material';
interface PublicWaitPrompProps { interface PublicWaitPrompProps {

View File

@ -1,10 +1,10 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Box, CircularProgress, Grid, Typography, useTheme } from '@mui/material'; import { Box, CircularProgress, Grid, Typography, useTheme } from '@mui/material';
import Countdown, { CountdownRenderProps, zeroPad } from 'react-countdown'; import Countdown, { type CountdownRenderProps, zeroPad } from 'react-countdown';
import { Order, Settings } from '../../../models'; import { type Order, type Settings } from '../../../models';
import { LightningForm, LightningPayoutForm } from '../Forms'; import { type LightningForm, LightningPayoutForm } from '../Forms';
interface RoutingFailedPromptProps { interface RoutingFailedPromptProps {
order: Order; order: Order;

View File

@ -18,7 +18,7 @@ import TradeSummary from '../TradeSummary';
import { Favorite, RocketLaunch, ContentCopy, Refresh } from '@mui/icons-material'; import { Favorite, RocketLaunch, ContentCopy, Refresh } from '@mui/icons-material';
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import { systemClient } from '../../../services/System'; import { systemClient } from '../../../services/System';
interface SuccessfulPromptProps { interface SuccessfulPromptProps {

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Typography, useTheme } from '@mui/material'; import { Typography, useTheme } from '@mui/material';
import { Order } from '../../../models'; import { type Order } from '../../../models';
import stepXofY from '../stepXofY'; import stepXofY from '../stepXofY';
interface TakerFoundPrompProps { interface TakerFoundPrompProps {

View File

@ -30,7 +30,7 @@ import {
Link, Link,
} from '@mui/icons-material'; } from '@mui/icons-material';
import { RoboSatsNoTextIcon, SendReceiveIcon, BitcoinIcon } from '../Icons'; import { RoboSatsNoTextIcon, SendReceiveIcon, BitcoinIcon } from '../Icons';
import { TradeCoordinatorSummary, TradeRobotSummary } from '../../models/Order.model'; import { type TradeCoordinatorSummary, type TradeRobotSummary } from '../../models/Order.model';
import { systemClient } from '../../services/System'; import { systemClient } from '../../services/System';
interface Props { interface Props {
@ -110,7 +110,13 @@ const TradeSummary = ({
}} }}
> >
<ToggleButtonGroup size='small' value={buttonValue} exclusive> <ToggleButtonGroup size='small' value={buttonValue} exclusive>
<ToggleButton value={0} disableRipple={true} onClick={() => setButtonValue(0)}> <ToggleButton
value={0}
disableRipple={true}
onClick={() => {
setButtonValue(0);
}}
>
<RobotAvatar <RobotAvatar
baseUrl={baseUrl} baseUrl={baseUrl}
style={{ height: '1.5em', width: '1.5em' }} style={{ height: '1.5em', width: '1.5em' }}
@ -120,10 +126,22 @@ const TradeSummary = ({
&nbsp; &nbsp;
{t('Maker')} {t('Maker')}
</ToggleButton> </ToggleButton>
<ToggleButton value={1} disableRipple={true} onClick={() => setButtonValue(1)}> <ToggleButton
value={1}
disableRipple={true}
onClick={() => {
setButtonValue(1);
}}
>
<RoboSatsNoTextIcon /> <RoboSatsNoTextIcon />
</ToggleButton> </ToggleButton>
<ToggleButton value={2} disableRipple={true} onClick={() => setButtonValue(2)}> <ToggleButton
value={2}
disableRipple={true}
onClick={() => {
setButtonValue(2);
}}
>
{t('Taker')} {t('Taker')}
&nbsp; &nbsp;
<RobotAvatar <RobotAvatar

View File

@ -39,15 +39,15 @@ import BondStatus from './BondStatus';
import CancelButton from './CancelButton'; import CancelButton from './CancelButton';
import { import {
defaultLightning, defaultLightning,
LightningForm, type LightningForm,
defaultOnchain, defaultOnchain,
OnchainForm, type OnchainForm,
DisputeForm, type DisputeForm,
defaultDispute, defaultDispute,
} from './Forms'; } from './Forms';
import { Order, Robot, Settings } from '../../models'; import { type Order, type Robot, type Settings } from '../../models';
import { 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';
@ -259,7 +259,9 @@ const TradeBox = ({
}; };
const handleWebln = async (order: Order) => { const handleWebln = async (order: Order) => {
const webln = await getWebln().catch(() => console.log('WebLN not available')); const webln = await getWebln().catch(() => {
console.log('WebLN not available');
});
// If Webln implements locked payments compatibility, this logic might be simplier // If Webln implements locked payments compatibility, this logic might be simplier
if (webln == undefined) { if (webln == undefined) {
return null; return null;
@ -488,13 +490,21 @@ const TradeBox = ({
<ChatPrompt <ChatPrompt
order={order} order={order}
robot={robot} robot={robot}
onClickConfirmSent={() => setOpen({ ...open, confirmFiatSent: true })} onClickConfirmSent={() => {
onClickUndoConfirmSent={() => setOpen({ ...open, confirmUndoFiatSent: true })} setOpen({ ...open, confirmFiatSent: true });
onClickConfirmReceived={() => setOpen({ ...open, confirmFiatReceived: true })} }}
onClickUndoConfirmSent={() => {
setOpen({ ...open, confirmUndoFiatSent: true });
}}
onClickConfirmReceived={() => {
setOpen({ ...open, confirmFiatReceived: true });
}}
loadingSent={loadingButtons.fiatSent} loadingSent={loadingButtons.fiatSent}
loadingUndoSent={loadingButtons.undoFiatSent} loadingUndoSent={loadingButtons.undoFiatSent}
loadingReceived={loadingButtons.fiatReceived} loadingReceived={loadingButtons.fiatReceived}
onClickDispute={() => setOpen({ ...open, confirmDispute: true })} onClickDispute={() => {
setOpen({ ...open, confirmDispute: true });
}}
loadingDispute={loadingButtons.openDispute} loadingDispute={loadingButtons.openDispute}
baseUrl={baseUrl} baseUrl={baseUrl}
messages={messages} messages={messages}
@ -668,23 +678,31 @@ const TradeBox = ({
<Box> <Box>
<WebLNDialog <WebLNDialog
open={open.webln} open={open.webln}
onClose={() => setOpen(closeAll)} onClose={() => {
setOpen(closeAll);
}}
waitingWebln={waitingWebln} waitingWebln={waitingWebln}
isBuyer={order.is_buyer} isBuyer={order.is_buyer}
/> />
<ConfirmDisputeDialog <ConfirmDisputeDialog
open={open.confirmDispute} open={open.confirmDispute}
onClose={() => setOpen(closeAll)} onClose={() => {
setOpen(closeAll);
}}
onAgreeClick={openDispute} onAgreeClick={openDispute}
/> />
<ConfirmCancelDialog <ConfirmCancelDialog
open={open.confirmCancel} open={open.confirmCancel}
onClose={() => setOpen(closeAll)} onClose={() => {
setOpen(closeAll);
}}
onCancelClick={cancel} onCancelClick={cancel}
/> />
<ConfirmCollabCancelDialog <ConfirmCollabCancelDialog
open={open.confirmCollabCancel} open={open.confirmCollabCancel}
onClose={() => setOpen(closeAll)} onClose={() => {
setOpen(closeAll);
}}
onCollabCancelClick={cancel} onCollabCancelClick={cancel}
loading={loadingButtons.cancel} loading={loadingButtons.cancel}
peerAskedCancel={order.pending_cancel} peerAskedCancel={order.pending_cancel}
@ -693,21 +711,27 @@ const TradeBox = ({
open={open.confirmFiatSent} open={open.confirmFiatSent}
order={order} order={order}
loadingButton={loadingButtons.fiatSent} loadingButton={loadingButtons.fiatSent}
onClose={() => setOpen(closeAll)} onClose={() => {
setOpen(closeAll);
}}
onConfirmClick={confirmFiatSent} onConfirmClick={confirmFiatSent}
/> />
<ConfirmUndoFiatSentDialog <ConfirmUndoFiatSentDialog
open={open.confirmUndoFiatSent} open={open.confirmUndoFiatSent}
order={order} order={order}
loadingButton={loadingButtons.undoFiatSent} loadingButton={loadingButtons.undoFiatSent}
onClose={() => setOpen(closeAll)} onClose={() => {
setOpen(closeAll);
}}
onConfirmClick={confirmUndoFiatSent} onConfirmClick={confirmUndoFiatSent}
/> />
<ConfirmFiatReceivedDialog <ConfirmFiatReceivedDialog
open={open.confirmFiatReceived} open={open.confirmFiatReceived}
order={order} order={order}
loadingButton={loadingButtons.fiatReceived} loadingButton={loadingButtons.fiatReceived}
onClose={() => setOpen(closeAll)} onClose={() => {
setOpen(closeAll);
}}
onConfirmClick={confirmFiatReceived} onConfirmClick={confirmFiatReceived}
/> />
<CollabCancelAlert order={order} /> <CollabCancelAlert order={order} />
@ -745,8 +769,12 @@ const TradeBox = ({
<CancelButton <CancelButton
order={order} order={order}
onClickCancel={cancel} onClickCancel={cancel}
openCancelDialog={() => setOpen({ ...closeAll, confirmCancel: true })} openCancelDialog={() => {
openCollabCancelDialog={() => setOpen({ ...closeAll, confirmCollabCancel: true })} setOpen({ ...closeAll, confirmCancel: true });
}}
openCollabCancelDialog={() => {
setOpen({ ...closeAll, confirmCollabCancel: true });
}}
loading={loadingButtons.cancel} loading={loadingButtons.cancel}
/> />
</Grid> </Grid>

View File

@ -1,4 +1,4 @@
import { Order } from '../../models'; import { type Order } from '../../models';
const stepXofY = function (order: Order): string { const stepXofY = function (order: Order): string {
// set y value // set y value

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect, useContext } from 'react'; import React, { useState, useEffect, useContext } from 'react';
import { AppContext, UseAppStoreType } from '../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../contexts/AppContext';
import { useTranslation, Trans } from 'react-i18next'; import { useTranslation, Trans } from 'react-i18next';
import { Paper, Alert, AlertTitle, Button, Link } from '@mui/material'; import { Paper, Alert, AlertTitle, Button, Link } from '@mui/material';
import { getHost } from '../utils'; import { getHost } from '../utils';
@ -57,7 +57,12 @@ const UnsafeAlert = (): JSX.Element => {
severity='success' severity='success'
sx={{ maxHeight: '8em' }} sx={{ maxHeight: '8em' }}
action={ action={
<Button color='success' onClick={() => setShow(false)}> <Button
color='success'
onClick={() => {
setShow(false);
}}
>
{t('Hide')} {t('Hide')}
</Button> </Button>
} }
@ -80,7 +85,15 @@ const UnsafeAlert = (): JSX.Element => {
<Alert <Alert
severity='warning' severity='warning'
sx={{ maxHeight: '7em' }} sx={{ maxHeight: '7em' }}
action={<Button onClick={() => setShow(false)}>{t('Hide')}</Button>} action={
<Button
onClick={() => {
setShow(false);
}}
>
{t('Hide')}
</Button>
}
> >
<AlertTitle>{t('You are not using RoboSats privately')}</AlertTitle> <AlertTitle>{t('You are not using RoboSats privately')}</AlertTitle>
<Trans i18nKey='desktop_unsafe_alert'> <Trans i18nKey='desktop_unsafe_alert'>
@ -120,7 +133,12 @@ const UnsafeAlert = (): JSX.Element => {
<a> site.</a> <a> site.</a>
</Trans> </Trans>
<div style={{ display: 'flex', justifyContent: 'center', width: '100%' }}> <div style={{ display: 'flex', justifyContent: 'center', width: '100%' }}>
<Button className='hideAlertButton' onClick={() => setShow(false)}> <Button
className='hideAlertButton'
onClick={() => {
setShow(false);
}}
>
{t('Hide')} {t('Hide')}
</Button> </Button>
</div> </div>

View File

@ -1,20 +1,20 @@
import React, { createContext, useEffect, useState } from 'react'; import React, { createContext, useEffect, useState } from 'react';
import { Page } from '../basic/NavBar'; import { type Page } from '../basic/NavBar';
import { OpenDialogs } from '../basic/MainDialogs'; import { type OpenDialogs } from '../basic/MainDialogs';
import { import {
Book, type Book,
LimitList, type LimitList,
Maker, type Maker,
Robot, Robot,
Garage, Garage,
Info, type Info,
Settings, Settings,
Favorites, type Favorites,
defaultMaker, defaultMaker,
defaultInfo, defaultInfo,
Coordinator, type Coordinator,
Order, type Order,
} from '../models'; } from '../models';
import { apiClient } from '../services/api'; import { apiClient } from '../services/api';
@ -22,7 +22,7 @@ import { checkVer, getHost, hexToBase91, validateTokenEntropy } from '../utils';
import { sha256 } from 'js-sha256'; import { sha256 } from 'js-sha256';
import defaultCoordinators from '../../static/federation.json'; import defaultCoordinators from '../../static/federation.json';
import { createTheme, Theme } from '@mui/material/styles'; import { createTheme, type Theme } from '@mui/material/styles';
import i18n from '../i18n/Web'; import i18n from '../i18n/Web';
import { systemClient } from '../services/System'; import { systemClient } from '../services/System';
@ -163,7 +163,12 @@ export const useAppStore = () => {
useEffect(() => { useEffect(() => {
window.addEventListener('torStatus', (event) => { window.addEventListener('torStatus', (event) => {
// Trick to improve UX on Android webview: delay the "Connected to TOR" status by 5 secs to avoid long waits on the first request. // Trick to improve UX on Android webview: delay the "Connected to TOR" status by 5 secs to avoid long waits on the first request.
setTimeout(() => setTorStatus(event?.detail), event?.detail === '"Done"' ? 5000 : 0); setTimeout(
() => {
setTorStatus(event?.detail);
},
event?.detail === '"Done"' ? 5000 : 0,
);
}); });
}, []); }, []);
@ -213,12 +218,12 @@ export const useAppStore = () => {
setBook((book) => { setBook((book) => {
return { ...book, loading: true }; return { ...book, loading: true };
}); });
apiClient.get(baseUrl, '/api/book/').then((data: any) => apiClient.get(baseUrl, '/api/book/').then((data: any) => {
setBook({ setBook({
loading: false, loading: false,
orders: data.not_found ? [] : data, orders: data.not_found ? [] : data,
}), });
); });
}; };
const fetchLimits = async () => { const fetchLimits = async () => {
@ -272,7 +277,9 @@ export const useAppStore = () => {
useEffect(() => { useEffect(() => {
clearInterval(timer); clearInterval(timer);
setTimer(setInterval(fetchOrder, delay)); setTimer(setInterval(fetchOrder, delay));
return () => clearInterval(timer); return () => {
clearInterval(timer);
};
}, [delay, currentOrder, page, badOrder]); }, [delay, currentOrder, page, badOrder]);
const orderReceived = function (data: any) { const orderReceived = function (data: any) {

View File

@ -1,4 +1,4 @@
import { Robot, Order } from '.'; import { Robot, type Order } from '.';
import { systemClient } from '../services/System'; import { systemClient } from '../services/System';
import { saveAsJson } from '../utils'; import { saveAsJson } from '../utils';
export interface Slot { export interface Slot {

View File

@ -6,8 +6,6 @@ export interface Limit {
max_bondless_amount: number; max_bondless_amount: number;
} }
export interface LimitList { export type LimitList = Record<string, Limit>;
[currencyCode: string]: Limit;
}
export default Limit; export default Limit;

View File

@ -1,5 +1,5 @@
import React, { useEffect, useContext, useState } from 'react'; import React, { useEffect, useContext, useState } from 'react';
import GridLayout, { Layout } from 'react-grid-layout'; import GridLayout, { type Layout } from 'react-grid-layout';
import { Grid, styled, useTheme } from '@mui/material'; import { Grid, styled, useTheme } from '@mui/material';
import { import {
@ -12,7 +12,7 @@ import {
import ToolBar from '../pro/ToolBar'; import ToolBar from '../pro/ToolBar';
import LandingDialog from '../pro/LandingDialog'; import LandingDialog from '../pro/LandingDialog';
import { AppContext, UseAppStoreType } from '../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../contexts/AppContext';
// To Do. Add dotted grid when layout is not frozen // To Do. Add dotted grid when layout is not frozen
// ${freeze ? // ${freeze ?
@ -83,7 +83,12 @@ const Main = (): JSX.Element => {
<Grid container direction='column' sx={{ width: `${windowSize.width}em` }}> <Grid container direction='column' sx={{ width: `${windowSize.width}em` }}>
<Grid item> <Grid item>
<ToolBar height={`${toolbarHeight}em`} settings={settings} setSettings={setSettings} /> <ToolBar height={`${toolbarHeight}em`} settings={settings} setSettings={setSettings} />
<LandingDialog open={openLanding} onClose={() => setOpenLanding(!openLanding)} /> <LandingDialog
open={openLanding}
onClose={() => {
setOpenLanding(!openLanding);
}}
/>
</Grid> </Grid>
<Grid item> <Grid item>
@ -101,7 +106,9 @@ const Main = (): JSX.Element => {
isResizable={!settings.freezeViewports} isResizable={!settings.freezeViewports}
rowHeight={gridCellSize * em} // rows are 2em high rowHeight={gridCellSize * em} // rows are 2em high
autoSize={true} autoSize={true}
onLayoutChange={(layout: Layout) => setLayout(layout)} onLayoutChange={(layout: Layout) => {
setLayout(layout);
}}
> >
<div key='Maker'> <div key='Maker'>
<MakerWidget /> <MakerWidget />

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Paper, Grid, IconButton, Tooltip, Typography } from '@mui/material'; import { Paper, Grid, IconButton, Tooltip, Typography } from '@mui/material';
import { Lock, LockOpen } from '@mui/icons-material'; import { Lock, LockOpen } from '@mui/icons-material';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Settings } from '../../models'; import { type Settings } from '../../models';
interface ToolBarProps { interface ToolBarProps {
settings: Settings; settings: Settings;
@ -39,9 +39,9 @@ const ToolBar = ({ height = '3em', settings, setSettings }: ToolBarProps): JSX.E
enterNextDelay={2000} enterNextDelay={2000}
> >
<IconButton <IconButton
onClick={() => onClick={() => {
setSettings({ ...settings, freezeViewports: !settings.freezeViewports }) setSettings({ ...settings, freezeViewports: !settings.freezeViewports });
} }}
sx={{ position: 'fixed', right: '1em', top: '0em', color: 'text.secondary' }} sx={{ position: 'fixed', right: '1em', top: '0em', color: 'text.secondary' }}
> >
{settings.freezeViewports ? <Lock color='primary' /> : <LockOpen color='secondary' />} {settings.freezeViewports ? <Lock color='primary' /> : <LockOpen color='secondary' />}

View File

@ -1,7 +1,7 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import { Book, Favorites } from '../../models'; import { type Book, type Favorites } from '../../models';
import { Paper } from '@mui/material'; import { Paper } from '@mui/material';
import BookTable from '../../components/BookTable'; import BookTable from '../../components/BookTable';

View File

@ -1,5 +1,5 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import { Paper, useTheme } from '@mui/material'; import { Paper, useTheme } from '@mui/material';
import DepthChart from '../../components/Charts/DepthChart'; import DepthChart from '../../components/Charts/DepthChart';

View File

@ -1,5 +1,5 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
import MakerForm from '../../components/MakerForm'; import MakerForm from '../../components/MakerForm';
import { LimitList, Maker, Favorites } from '../../models'; import { LimitList, Maker, Favorites } from '../../models';

View File

@ -1,5 +1,5 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { UseAppStoreType, AppContext } from '../../contexts/AppContext'; import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
import { Settings } from '../../models'; import { Settings } from '../../models';
import { Paper } from '@mui/material'; import { Paper } from '@mui/material';
import SettingsForm from '../../components/SettingsForm'; import SettingsForm from '../../components/SettingsForm';

View File

@ -1,4 +1,4 @@
import NativeRobosats from './index'; import type NativeRobosats from './index';
declare global { declare global {
interface Window { interface Window {

View File

@ -1,13 +1,17 @@
import { NativeRobosatsPromise, NativeWebViewMessage, NativeWebViewMessageSystem } from './index.d'; import {
type NativeRobosatsPromise,
type NativeWebViewMessage,
type NativeWebViewMessageSystem,
} from './index.d';
class NativeRobosats { class NativeRobosats {
public torDaemonStatus = 'NOTINIT'; public torDaemonStatus = 'NOTINIT';
private messageCounter: number = 0; private messageCounter: number = 0;
private pendingMessages: { [id: number]: NativeRobosatsPromise } = {}; private pendingMessages: Record<number, NativeRobosatsPromise> = {};
public cookies: { [key: string]: string } = {}; public cookies: Record<string, string> = {};
public loadCookie = (cookie: { key: string; value: string }) => { public loadCookie = (cookie: { key: string; value: string }) => {
this.cookies[cookie.key] = cookie.value; this.cookies[cookie.key] = cookie.value;
@ -44,7 +48,7 @@ class NativeRobosats {
} }
}; };
public postMessage: (message: NativeWebViewMessage) => Promise<{ [key: string]: any }> = async ( public postMessage: (message: NativeWebViewMessage) => Promise<Record<string, any>> = async (
message, message,
) => { ) => {
this.messageCounter += 1; this.messageCounter += 1;

View File

@ -1,4 +1,4 @@
import { SystemClient } from '..'; import { type SystemClient } from '..';
import NativeRobosats from '../../Native'; import NativeRobosats from '../../Native';
class SystemNativeClient implements SystemClient { class SystemNativeClient implements SystemClient {

View File

@ -1,4 +1,4 @@
import { SystemClient } from '..'; import { type SystemClient } from '..';
class SystemWebClient implements SystemClient { class SystemWebClient implements SystemClient {
public loading = false; public loading = false;

View File

@ -1,12 +1,14 @@
import ReconnectingWebSocket from 'reconnecting-websocket'; import ReconnectingWebSocket from 'reconnecting-websocket';
import { WebsocketConnection } from '..'; import { type WebsocketConnection } from '..';
class WebsocketConnectionWeb implements WebsocketConnection { class WebsocketConnectionWeb implements WebsocketConnection {
constructor(path: string) { constructor(path: string) {
this.rws = new ReconnectingWebSocket(path, [], { this.rws = new ReconnectingWebSocket(path, [], {
WebSocket,
minReconnectionDelay: 15000,
connectionTimeout: 15000, connectionTimeout: 15000,
reconnectionDelayGrowFactor: 1.5, reconnectionDelayGrowFactor: 2,
maxRetries: 15, maxRetries: 4,
maxReconnectionDelay: 1000000, maxReconnectionDelay: 1000000,
}); });
} }

View File

@ -1,4 +1,4 @@
import { WebsocketClient, WebsocketConnection } from '..'; import { type WebsocketClient, type WebsocketConnection } from '..';
import WebsocketConnectionWeb from '../WebsocketConnectionWeb'; import WebsocketConnectionWeb from '../WebsocketConnectionWeb';
class WebsocketWebClient implements WebsocketClient { class WebsocketWebClient implements WebsocketClient {

View File

@ -1,16 +1,16 @@
import { ApiClient, Auth } from '..'; import { type ApiClient, type Auth } from '..';
import { systemClient } from '../../System'; import { systemClient } from '../../System';
class ApiNativeClient implements ApiClient { class ApiNativeClient implements ApiClient {
private assetsCache: { [path: string]: string } = {}; private assetsCache: Record<string, string> = {};
private assetsPromises: { [path: string]: Promise<string | undefined> } = {}; private assetsPromises: Record<string, Promise<string | undefined>> = {};
private readonly getHeaders: (auth?: Auth) => HeadersInit = (auth) => { private readonly getHeaders: (auth?: Auth) => HeadersInit = (auth) => {
let headers = { let headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}; };
if (auth) { if (auth != null) {
headers = { headers = {
...headers, ...headers,
...{ ...{
@ -19,7 +19,7 @@ class ApiNativeClient implements ApiClient {
}; };
} }
if (auth?.keys) { if (auth?.keys != null) {
headers = { headers = {
...headers, ...headers,
...{ ...{
@ -31,7 +31,7 @@ class ApiNativeClient implements ApiClient {
return headers; return headers;
}; };
private readonly parseResponse = (response: { [key: string]: any }): object => { private readonly parseResponse = (response: Record<string, any>): object => {
if (response.headers['set-cookie']) { if (response.headers['set-cookie']) {
response.headers['set-cookie'].forEach((cookie: string) => { response.headers['set-cookie'].forEach((cookie: string) => {
const keySplit: string[] = cookie.split('='); const keySplit: string[] = cookie.split('=');
@ -46,7 +46,9 @@ class ApiNativeClient implements ApiClient {
path, path,
body, body,
) => { ) => {
return await new Promise((res, _rej) => res({})); return await new Promise((res, _rej) => {
res({});
});
}; };
public delete: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined> = public delete: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined> =

View File

@ -1,4 +1,4 @@
import { ApiClient, Auth } from '..'; import { type ApiClient, type Auth } from '..';
import { systemClient } from '../../System'; import { systemClient } from '../../System';
class ApiWebClient implements ApiClient { class ApiWebClient implements ApiClient {
@ -7,7 +7,7 @@ class ApiWebClient implements ApiClient {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}; };
if (auth) { if (auth != null) {
headers = { headers = {
...headers, ...headers,
...{ ...{
@ -17,7 +17,7 @@ class ApiWebClient implements ApiClient {
} }
// set cookies before sending the request // set cookies before sending the request
if (auth?.keys) { if (auth?.keys != null) {
systemClient.setCookie('public_key', auth.keys.pubKey); systemClient.setCookie('public_key', auth.keys.pubKey);
systemClient.setCookie('encrypted_private_key', auth.keys.encPrivKey); systemClient.setCookie('encrypted_private_key', auth.keys.encPrivKey);
} }

View File

@ -1,4 +1,4 @@
import { PublicOrder, Favorites } from '../models'; import { type PublicOrder, type Favorites } from '../models';
interface AmountFilter { interface AmountFilter {
amount: string; amount: string;

View File

@ -2,7 +2,7 @@ import { Base91 } from 'base-ex';
export default function hexToBase85(hex: string): string { export default function hexToBase85(hex: string): string {
const hexes = hex.match(/.{1,2}/g); const hexes = hex.match(/.{1,2}/g);
if (!hexes) return ''; if (hexes == null) return '';
const byteArray = hexes.map((byte) => parseInt(byte, 16)); const byteArray = hexes.map((byte) => parseInt(byte, 16));
const b91 = new Base91(); const b91 = new Base91();
const base91string = b91.encode(new Uint8Array(byteArray)); const base91string = b91.encode(new Uint8Array(byteArray));

View File

@ -1,4 +1,4 @@
import { requestProvider, WeblnProvider } from 'webln'; import { requestProvider, type WeblnProvider } from 'webln';
const getWebln = async (): Promise<WeblnProvider> => { const getWebln = async (): Promise<WeblnProvider> => {
const resultPromise = new Promise<WeblnProvider>(async (resolve, reject) => { const resultPromise = new Promise<WeblnProvider>(async (resolve, reject) => {