mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 12:11:35 +00:00
Small fixes and partial TradeBox functional component (#309)
* Add Order model * Add permanent settings * Fix maker on book page * Add chat models * Attempt to fix Android cookies * Add Tradebox Dialogs * Add Lock Invoice box * Add taker found prompt * Fix load setting cookies * Revert TradeBox for test release * Refactor ordering of constructing theme * Add load encrypted seetings
This commit is contained in:
parent
5ae1f8ca18
commit
b25230378e
@ -10,38 +10,28 @@ import { I18nextProvider } from 'react-i18next';
|
||||
import i18n from './i18n/Web';
|
||||
|
||||
import { systemClient } from './services/System';
|
||||
import { Settings, defaultSettings } from './models';
|
||||
import { Settings } from './models';
|
||||
|
||||
const defaultTheme: Theme = createTheme({
|
||||
palette: {
|
||||
mode: defaultSettings.mode,
|
||||
background: {
|
||||
default: defaultSettings.mode === 'dark' ? '#070707' : '#fff',
|
||||
const makeTheme = function (settings: Settings) {
|
||||
const theme: Theme = createTheme({
|
||||
palette: {
|
||||
mode: settings.mode,
|
||||
background: {
|
||||
default: settings.mode === 'dark' ? '#070707' : '#fff',
|
||||
},
|
||||
},
|
||||
},
|
||||
typography: { fontSize: defaultSettings.fontSize },
|
||||
});
|
||||
typography: { fontSize: settings.fontSize },
|
||||
});
|
||||
|
||||
return theme;
|
||||
};
|
||||
|
||||
const App = (): JSX.Element => {
|
||||
const [theme, setTheme] = useState<Theme>(defaultTheme);
|
||||
const [settings, setSettings] = useState<Settings>(defaultSettings);
|
||||
|
||||
const updateTheme = function () {
|
||||
setTheme(
|
||||
createTheme({
|
||||
palette: {
|
||||
mode: settings.mode,
|
||||
background: {
|
||||
default: settings.mode === 'dark' ? '#070707' : '#fff',
|
||||
},
|
||||
},
|
||||
typography: { fontSize: settings.fontSize },
|
||||
}),
|
||||
);
|
||||
};
|
||||
const [theme, setTheme] = useState<Theme>(makeTheme(new Settings()));
|
||||
const [settings, setSettings] = useState<Settings>(new Settings());
|
||||
|
||||
useEffect(() => {
|
||||
updateTheme();
|
||||
setTheme(makeTheme(settings));
|
||||
}, [settings.fontSize, settings.mode]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -53,8 +43,11 @@ const App = (): JSX.Element => {
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<TorConnection />
|
||||
<UnsafeAlert className='unsafeAlert' />
|
||||
{window.NativeRobosats === undefined ? (
|
||||
<UnsafeAlert settings={settings} setSettings={setSettings} />
|
||||
) : (
|
||||
<TorConnection />
|
||||
)}
|
||||
<Main settings={settings} setSettings={setSettings} />
|
||||
</ThemeProvider>
|
||||
</I18nextProvider>
|
||||
|
@ -26,7 +26,7 @@ interface BookPageProps {
|
||||
setMaker: (state: Maker) => void;
|
||||
hasRobot: boolean;
|
||||
setPage: (state: Page) => void;
|
||||
setOrder: (state: number) => void;
|
||||
setCurrentOrder: (state: number) => void;
|
||||
}
|
||||
|
||||
const BookPage = ({
|
||||
@ -42,7 +42,7 @@ const BookPage = ({
|
||||
windowSize,
|
||||
hasRobot = false,
|
||||
setPage = () => null,
|
||||
setOrder = () => null,
|
||||
setCurrentOrder = () => null,
|
||||
}: BookPageProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
@ -76,7 +76,7 @@ const BookPage = ({
|
||||
if (hasRobot) {
|
||||
history.push('/order/' + id);
|
||||
setPage('order');
|
||||
setOrder(id);
|
||||
setCurrentOrder(id);
|
||||
} else {
|
||||
setOpenNoRobot(true);
|
||||
}
|
||||
@ -125,6 +125,11 @@ const BookPage = ({
|
||||
setFav={setFav}
|
||||
setPage={setPage}
|
||||
hasRobot={hasRobot}
|
||||
onOrderCreated={(id) => {
|
||||
setCurrentOrder(id);
|
||||
setPage('order');
|
||||
history.push('/order/' + id);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Dialog>
|
||||
|
@ -73,7 +73,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
in: undefined,
|
||||
out: undefined,
|
||||
});
|
||||
const [order, setOrder] = useState<number | null>(null);
|
||||
const [currentOrder, setCurrentOrder] = useState<number | null>(null);
|
||||
|
||||
const navbarHeight = 2.5;
|
||||
const closeAll = {
|
||||
@ -163,7 +163,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
|
||||
setRobot({ ...robot, loading: true });
|
||||
apiClient.post('/api/user/', requestBody).then((data: any) => {
|
||||
setOrder(
|
||||
setCurrentOrder(
|
||||
data.active_order_id
|
||||
? data.active_order_id
|
||||
: data.last_order_id
|
||||
@ -230,8 +230,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
<div>
|
||||
<UserGenPage
|
||||
setPage={setPage}
|
||||
order={order}
|
||||
setOrder={setOrder}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
match={props.match}
|
||||
theme={theme}
|
||||
robot={robot}
|
||||
@ -262,7 +261,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
windowSize={windowSize}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
setPage={setPage}
|
||||
setOrder={setOrder}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
/>
|
||||
</div>
|
||||
</Slide>
|
||||
@ -282,7 +281,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
maker={maker}
|
||||
setMaker={setMaker}
|
||||
setPage={setPage}
|
||||
setOrder={setOrder}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
fav={fav}
|
||||
setFav={setFav}
|
||||
windowSize={{ ...windowSize, height: windowSize.height - navbarHeight }}
|
||||
@ -334,13 +333,15 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
setOpen={setOpen}
|
||||
closeAll={closeAll}
|
||||
setSlideDirection={setSlideDirection}
|
||||
order={order}
|
||||
currentOrder={currentOrder}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
/>
|
||||
<MainDialogs
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
setRobot={setRobot}
|
||||
setPage={setPage}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
info={info}
|
||||
robot={robot}
|
||||
closeAll={closeAll}
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
StatsDialog,
|
||||
UpdateClientDialog,
|
||||
} from '../../components/Dialogs';
|
||||
import { Page } from '../NavBar';
|
||||
|
||||
export interface OpenDialogs {
|
||||
more: boolean;
|
||||
@ -27,6 +28,8 @@ interface MainDialogsProps {
|
||||
info: Info;
|
||||
robot: Robot;
|
||||
setRobot: (state: Robot) => void;
|
||||
setPage: (state: Page) => void;
|
||||
setCurrentOrder: (state: number) => void;
|
||||
closeAll: OpenDialogs;
|
||||
}
|
||||
|
||||
@ -37,6 +40,8 @@ const MainDialogs = ({
|
||||
closeAll,
|
||||
robot,
|
||||
setRobot,
|
||||
setPage,
|
||||
setCurrentOrder,
|
||||
}: MainDialogsProps): JSX.Element => {
|
||||
useEffect(() => {
|
||||
if (info.openUpdateClient) {
|
||||
@ -77,6 +82,8 @@ const MainDialogs = ({
|
||||
onClose={() => setOpen({ ...open, profile: false })}
|
||||
robot={robot}
|
||||
setRobot={setRobot}
|
||||
setPage={setPage}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Grid, Paper, Collapse, Typography } from '@mui/material';
|
||||
|
||||
import { LimitList, Maker, Book, Favorites } from '../../models';
|
||||
@ -21,7 +22,7 @@ interface MakerPageProps {
|
||||
setMaker: (state: Maker) => void;
|
||||
windowSize: { width: number; height: number };
|
||||
hasRobot: boolean;
|
||||
setOrder: (state: number) => void;
|
||||
setCurrentOrder: (state: number) => void;
|
||||
setPage: (state: Page) => void;
|
||||
}
|
||||
|
||||
@ -34,11 +35,12 @@ const MakerPage = ({
|
||||
setFav,
|
||||
setMaker,
|
||||
windowSize,
|
||||
setOrder,
|
||||
setCurrentOrder,
|
||||
setPage,
|
||||
hasRobot = false,
|
||||
}: MakerPageProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
|
||||
const maxHeight = windowSize.height * 0.85 - 3;
|
||||
const [showMatches, setShowMatches] = useState<boolean>(false);
|
||||
@ -95,8 +97,9 @@ const MakerPage = ({
|
||||
maker={maker}
|
||||
setMaker={setMaker}
|
||||
onOrderCreated={(id) => {
|
||||
setOrder(id);
|
||||
setCurrentOrder(id);
|
||||
setPage('order');
|
||||
history.push('/order/' + id);
|
||||
}}
|
||||
hasRobot={hasRobot}
|
||||
disableRequest={matches.length > 0 && !showMatches}
|
||||
|
@ -30,7 +30,7 @@ interface NavBarProps {
|
||||
open: OpenDialogs;
|
||||
setOpen: (state: OpenDialogs) => void;
|
||||
closeAll: OpenDialogs;
|
||||
order: number | null;
|
||||
currentOrder: number | null;
|
||||
hasRobot: boolean;
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ const NavBar = ({
|
||||
closeAll,
|
||||
width,
|
||||
height,
|
||||
order,
|
||||
currentOrder,
|
||||
hasRobot = false,
|
||||
}: NavBarProps): JSX.Element => {
|
||||
const theme = useTheme();
|
||||
@ -77,7 +77,7 @@ const NavBar = ({
|
||||
} else {
|
||||
handleSlideDirection(page, newPage);
|
||||
setPage(newPage);
|
||||
const param = newPage === 'order' ? order ?? '' : '';
|
||||
const param = newPage === 'order' ? currentOrder ?? '' : '';
|
||||
setTimeout(
|
||||
() => history.push(`/${newPage}/${param}`),
|
||||
theme.transitions.duration.leavingScreen * 3,
|
||||
@ -92,7 +92,7 @@ const NavBar = ({
|
||||
return (
|
||||
<Paper
|
||||
elevation={6}
|
||||
sx={{ height: `${height}em`, width: `${width * 0.9}em`, position: 'fixed', bottom: 0 }}
|
||||
sx={{ height: `${height}em`, width: `100%`, position: 'fixed', bottom: 0, borderRadius: 0 }}
|
||||
>
|
||||
<Tabs
|
||||
TabIndicatorProps={{ sx: { height: '0.3em', position: 'absolute', top: 0 } }}
|
||||
@ -144,7 +144,7 @@ const NavBar = ({
|
||||
sx={tabSx}
|
||||
label={smallBar ? undefined : t('Order')}
|
||||
value='order'
|
||||
disabled={!hasRobot || order == null}
|
||||
disabled={!hasRobot || currentOrder == null}
|
||||
icon={<Assignment />}
|
||||
iconPosition='start'
|
||||
/>
|
||||
@ -176,472 +176,3 @@ const NavBar = ({
|
||||
};
|
||||
|
||||
export default NavBar;
|
||||
|
||||
// constructor(props) {
|
||||
// super(props);
|
||||
// this.state = {
|
||||
// profileShown: false,
|
||||
// openStatsForNerds: false,
|
||||
// openCommunity: false,
|
||||
// openExchangeSummary: false,
|
||||
// openClaimRewards: false,
|
||||
// openProfile: false,
|
||||
// showRewards: false,
|
||||
// rewardInvoice: null,
|
||||
// badInvoice: false,
|
||||
// showRewardsSpinner: false,
|
||||
// withdrawn: false,
|
||||
// };
|
||||
// }
|
||||
|
||||
// handleClickOpenStatsForNerds = () => {
|
||||
// this.setState({ openStatsForNerds: true });
|
||||
// };
|
||||
|
||||
// handleClickCloseStatsForNerds = () => {
|
||||
// this.setState({ openStatsForNerds: false });
|
||||
// };
|
||||
|
||||
// handleClickOpenCommunity = () => {
|
||||
// this.setState({ openCommunity: true });
|
||||
// };
|
||||
|
||||
// handleClickCloseCommunity = () => {
|
||||
// this.setState({ openCommunity: false });
|
||||
// };
|
||||
|
||||
// handleClickOpenProfile = () => {
|
||||
// this.setState({ openProfile: true, profileShown: true });
|
||||
// };
|
||||
|
||||
// handleClickCloseProfile = () => {
|
||||
// this.setState({ openProfile: false });
|
||||
// };
|
||||
|
||||
// handleClickOpenExchangeSummary = () => {
|
||||
// this.setState({ openExchangeSummary: true });
|
||||
// };
|
||||
|
||||
// handleClickCloseExchangeSummary = () => {
|
||||
// this.setState({ openExchangeSummary: false });
|
||||
// };
|
||||
|
||||
// handleSubmitInvoiceClicked = (e, rewardInvoice) => {
|
||||
// this.setState({ badInvoice: false, showRewardsSpinner: true });
|
||||
|
||||
// apiClient
|
||||
// .post('/api/reward/', {
|
||||
// invoice: rewardInvoice,
|
||||
// })
|
||||
// .then((data) => {
|
||||
// this.setState({ badInvoice: data.bad_invoice, showRewardsSpinner: false });
|
||||
// this.props.setInfo({
|
||||
// ...this.props.info,
|
||||
// badInvoice: data.bad_invoice,
|
||||
// openClaimRewards: !data.successful_withdrawal,
|
||||
// withdrawn: !!data.successful_withdrawal,
|
||||
// showRewardsSpinner: false,
|
||||
// });
|
||||
// this.props.setRobot({
|
||||
// ...this.props.robot,
|
||||
// earnedRewards: data.successful_withdrawal ? 0 : this.props.robot.earnedRewards,
|
||||
// });
|
||||
// });
|
||||
// e.preventDefault();
|
||||
// };
|
||||
|
||||
// handleSetStealthInvoice = (wantsStealth) => {
|
||||
// apiClient
|
||||
// .put('/api/stealth/', { wantsStealth })
|
||||
// .then((data) =>
|
||||
// this.props.setRobot({ ...this.props.robot, stealthInvoices: data?.wantsStealth }),
|
||||
// );
|
||||
// };
|
||||
|
||||
// showProfileButton = () => {
|
||||
// return (
|
||||
// this.props.robot.avatarLoaded &&
|
||||
// (this.props.robot.token
|
||||
// ? systemClient.getCookie('robot_token') === this.props.robot.token
|
||||
// : true) &&
|
||||
// systemClient.getCookie('sessionid')
|
||||
// );
|
||||
// };
|
||||
|
||||
// bottomBarDesktop = () => {
|
||||
// const { t } = this.props;
|
||||
// const hasRewards = this.props.robot.earnedRewards > 0;
|
||||
// const hasOrder = !!(
|
||||
// (this.props.robot.activeOrderId > 0) &
|
||||
// !this.state.profileShown &
|
||||
// this.props.robot.avatarLoaded
|
||||
// );
|
||||
// const fontSize = this.props.theme.typography.fontSize;
|
||||
// const fontSizeFactor = fontSize / 14; // default fontSize is 14
|
||||
// const typographyProps = {
|
||||
// primaryTypographyProps: { fontSize },
|
||||
// secondaryTypographyProps: { fontSize: (fontSize * 12) / 14 },
|
||||
// };
|
||||
// return (
|
||||
// <Paper
|
||||
// elevation={6}
|
||||
// style={{ height: '2.5em', width: `${(this.props.windowSize.width / 16) * 14}em` }}
|
||||
// >
|
||||
// <Grid container>
|
||||
// <Grid item xs={1.9}>
|
||||
// <div style={{ display: this.showProfileButton() ? '' : 'none' }}>
|
||||
// <ListItemButton onClick={this.handleClickOpenProfile}>
|
||||
// <Tooltip
|
||||
// open={(hasRewards || hasOrder) && this.showProfileButton()}
|
||||
// title={
|
||||
// (hasRewards ? t('You can claim satoshis!') + ' ' : '') +
|
||||
// (hasOrder ? t('You have an active order') : '')
|
||||
// }
|
||||
// >
|
||||
// <ListItemAvatar sx={{ width: 30 * fontSizeFactor, height: 30 * fontSizeFactor }}>
|
||||
// <RobotAvatar
|
||||
// style={{ marginTop: -13 }}
|
||||
// statusColor={
|
||||
// (this.props.robot.activeOrderId > 0) & !this.state.profileShown
|
||||
// ? 'primary'
|
||||
// : undefined
|
||||
// }
|
||||
// nickname={this.props.robot.nickname}
|
||||
// onLoad={() =>
|
||||
// this.props.setRobot({ ...this.props.robot, avatarLoaded: true })
|
||||
// }
|
||||
// />
|
||||
// </ListItemAvatar>
|
||||
// </Tooltip>
|
||||
// <ListItemText primary={this.props.robot.nickname} />
|
||||
// </ListItemButton>
|
||||
// </div>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.9}>
|
||||
// <ListItem className='bottomItem'>
|
||||
// <ListItemIcon size='small'>
|
||||
// <IconButton
|
||||
// disabled={!this.showProfileButton()}
|
||||
// color='primary'
|
||||
// to={`/book/`}
|
||||
// component={LinkRouter}
|
||||
// >
|
||||
// <InventoryIcon />
|
||||
// </IconButton>
|
||||
// </ListItemIcon>
|
||||
// <ListItemText
|
||||
// {...typographyProps}
|
||||
// primary={this.props.info.num_public_buy_orders}
|
||||
// secondary={t('Public Buy Orders')}
|
||||
// />
|
||||
// </ListItem>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.9}>
|
||||
// <ListItem className='bottomItem'>
|
||||
// <ListItemIcon size='small'>
|
||||
// <IconButton
|
||||
// disabled={!this.showProfileButton()}
|
||||
// color='primary'
|
||||
// to={`/book/`}
|
||||
// component={LinkRouter}
|
||||
// >
|
||||
// <SellIcon />
|
||||
// </IconButton>
|
||||
// </ListItemIcon>
|
||||
// <ListItemText
|
||||
// {...typographyProps}
|
||||
// primary={this.props.info.num_public_sell_orders}
|
||||
// secondary={t('Public Sell Orders')}
|
||||
// />
|
||||
// </ListItem>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.9}>
|
||||
// <ListItem className='bottomItem'>
|
||||
// <ListItemIcon size='small'>
|
||||
// <IconButton
|
||||
// disabled={!this.showProfileButton()}
|
||||
// color='primary'
|
||||
// to={`/`}
|
||||
// component={LinkRouter}
|
||||
// >
|
||||
// <SmartToyIcon />
|
||||
// </IconButton>
|
||||
// </ListItemIcon>
|
||||
// <ListItemText
|
||||
// {...typographyProps}
|
||||
// primary={this.props.info.active_robots_today}
|
||||
// secondary={t('Today Active Robots')}
|
||||
// />
|
||||
// </ListItem>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.9}>
|
||||
// <ListItem className='bottomItem'>
|
||||
// <ListItemIcon size='small'>
|
||||
// <IconButton color='primary' onClick={this.handleClickOpenExchangeSummary}>
|
||||
// <PriceChangeIcon />
|
||||
// </IconButton>
|
||||
// </ListItemIcon>
|
||||
// <ListItemText
|
||||
// {...typographyProps}
|
||||
// primary={this.props.info.last_day_nonkyc_btc_premium + '%'}
|
||||
// secondary={t('24h Avg Premium')}
|
||||
// />
|
||||
// </ListItem>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.5}>
|
||||
// <ListItem className='bottomItem'>
|
||||
// <ListItemIcon size='small'>
|
||||
// <IconButton color='primary' onClick={this.handleClickOpenExchangeSummary}>
|
||||
// <PercentIcon />
|
||||
// </IconButton>
|
||||
// </ListItemIcon>
|
||||
// <ListItemText
|
||||
// {...typographyProps}
|
||||
// primary={(this.props.info.maker_fee + this.props.info.taker_fee) * 100}
|
||||
// secondary={t('Trade Fee')}
|
||||
// />
|
||||
// </ListItem>
|
||||
// </Grid>
|
||||
|
||||
// <Grid container item xs={1}>
|
||||
// <Grid item xs={6}>
|
||||
// {this.LangSelect()}
|
||||
// </Grid>
|
||||
// <Grid item xs={3}>
|
||||
// <Tooltip enterTouchDelay={250} title={t('Show community and support links')}>
|
||||
// <IconButton
|
||||
// color='primary'
|
||||
// aria-label='Community'
|
||||
// onClick={this.handleClickOpenCommunity}
|
||||
// >
|
||||
// <PeopleIcon />
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
// <Grid item xs={3}>
|
||||
// <Tooltip enterTouchDelay={250} title={t('Show stats for nerds')}>
|
||||
// <IconButton
|
||||
// color='primary'
|
||||
// aria-label='Stats for Nerds'
|
||||
// onClick={this.handleClickOpenStatsForNerds}
|
||||
// >
|
||||
// <BarChartIcon />
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </Paper>
|
||||
// );
|
||||
// };
|
||||
|
||||
// bottomBarPhone = () => {
|
||||
// const { t } = this.props;
|
||||
// const hasRewards = this.props.robot.earnedRewards > 0;
|
||||
// const hasOrder = !!(
|
||||
// (this.props.info.active_order_id > 0) &
|
||||
// !this.state.profileShown &
|
||||
// this.props.robot.avatarLoaded
|
||||
// );
|
||||
// return (
|
||||
// <Paper
|
||||
// elevation={6}
|
||||
// style={{ height: '2.85em', width: `${(this.props.windowSize.width / 16) * 14}em` }}
|
||||
// >
|
||||
// <Grid container>
|
||||
// <Grid item xs={1.6}>
|
||||
// <div style={{ display: this.showProfileButton() ? '' : 'none' }}>
|
||||
// <Tooltip
|
||||
// open={(hasRewards || hasOrder) && this.showProfileButton()}
|
||||
// title={
|
||||
// (hasRewards ? t('You can claim satoshis!') + ' ' : '') +
|
||||
// (hasOrder ? t('You have an active order') : '')
|
||||
// }
|
||||
// >
|
||||
// <IconButton
|
||||
// onClick={this.handleClickOpenProfile}
|
||||
// sx={{ margin: 0, bottom: 17, right: 8 }}
|
||||
// >
|
||||
// <RobotAvatar
|
||||
// style={{ width: 55, height: 55 }}
|
||||
// avatarClass='phoneFlippedSmallAvatar'
|
||||
// statusColor={
|
||||
// (this.props.activeOrderId > 0) & !this.state.profileShown
|
||||
// ? 'primary'
|
||||
// : undefined
|
||||
// }
|
||||
// nickname={this.props.robot.nickname}
|
||||
// onLoad={() => this.props.setRobot({ ...this.props.robot, avatarLoaded: true })}
|
||||
// />
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </div>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.6} align='center'>
|
||||
// <Tooltip enterTouchDelay={300} title={t('Number of public BUY orders')}>
|
||||
// <IconButton
|
||||
// disabled={!this.showProfileButton()}
|
||||
// color='primary'
|
||||
// to={`/book/`}
|
||||
// component={LinkRouter}
|
||||
// >
|
||||
// <Badge badgeContent={this.props.info.num_public_buy_orders} color='action'>
|
||||
// <InventoryIcon />
|
||||
// </Badge>
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.6} align='center'>
|
||||
// <Tooltip enterTouchDelay={300} title={t('Number of public SELL orders')}>
|
||||
// <IconButton
|
||||
// disabled={!this.showProfileButton()}
|
||||
// color='primary'
|
||||
// to={`/book/`}
|
||||
// component={LinkRouter}
|
||||
// >
|
||||
// <Badge badgeContent={this.props.info.num_public_sell_orders} color='action'>
|
||||
// <SellIcon />
|
||||
// </Badge>
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.6} align='center'>
|
||||
// <Tooltip enterTouchDelay={300} title={t('Today active robots')}>
|
||||
// <IconButton
|
||||
// disabled={!this.showProfileButton()}
|
||||
// color='primary'
|
||||
// to={`/`}
|
||||
// component={LinkRouter}
|
||||
// >
|
||||
// <Badge badgeContent={this.props.info.active_robots_today} color='action'>
|
||||
// <SmartToyIcon />
|
||||
// </Badge>
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
|
||||
// <Grid item xs={1.8} align='center'>
|
||||
// <Tooltip enterTouchDelay={300} title={t('24h non-KYC bitcoin premium')}>
|
||||
// <IconButton color='primary' onClick={this.handleClickOpenExchangeSummary}>
|
||||
// <Badge
|
||||
// badgeContent={this.props.info.last_day_nonkyc_btc_premium + '%'}
|
||||
// color='action'
|
||||
// >
|
||||
// <PriceChangeIcon />
|
||||
// </Badge>
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
|
||||
// <Grid container item xs={3.8}>
|
||||
// <Grid item xs={6}>
|
||||
// {this.LangSelect()}
|
||||
// </Grid>
|
||||
// <Grid item xs={3}>
|
||||
// <Tooltip enterTouchDelay={250} title={t('Show community and support links')}>
|
||||
// <IconButton
|
||||
// color='primary'
|
||||
// aria-label='Community'
|
||||
// onClick={this.handleClickOpenCommunity}
|
||||
// >
|
||||
// <PeopleIcon />
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
// <Grid item xs={3}>
|
||||
// <Tooltip enterTouchDelay={250} title={t('Show stats for nerds')}>
|
||||
// <IconButton
|
||||
// color='primary'
|
||||
// aria-label='Stats for Nerds'
|
||||
// onClick={() => this.props.fetchInfo()}
|
||||
// onClick={this.handleClickOpenStatsForNerds}
|
||||
// >
|
||||
// <BarChartIcon />
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </Paper>
|
||||
// );
|
||||
// };
|
||||
|
||||
// render() {
|
||||
// return (
|
||||
// <div>
|
||||
|
||||
// <UpdateClientDialog
|
||||
// open={this.state.openUpdateClient}
|
||||
// coordinatorVersion={this.props.info.coordinatorVersion}
|
||||
// clientVersion={this.props.info.clientVersion}
|
||||
// handleClickClose={() =>
|
||||
// this.props.setInfo({ ...this.props.info, openUpdateClient: false })
|
||||
// }
|
||||
// />
|
||||
|
||||
// <ExchangeSummaryDialog
|
||||
// open={this.state.openExchangeSummary}
|
||||
// handleClickCloseExchangeSummary={this.handleClickCloseExchangeSummary}
|
||||
// numPublicBuyOrders={this.props.info.num_public_buy_orders}
|
||||
// numPublicSellOrders={this.props.info.num_public_sell_orders}
|
||||
// bookLiquidity={this.props.info.book_liquidity}
|
||||
// activeRobotsToday={this.props.info.active_robots_today}
|
||||
// lastDayNonkycBtcPremium={this.props.info.last_day_nonkyc_btc_premium}
|
||||
// makerFee={this.props.info.maker_fee}
|
||||
// takerFee={this.props.info.taker_fee}
|
||||
// swapFeeRate={this.props.info.current_swap_fee_rate}
|
||||
// />
|
||||
|
||||
// <ProfileDialog
|
||||
// open={this.state.openProfile}
|
||||
// handleClickCloseProfile={this.handleClickCloseProfile}
|
||||
// nickname={this.props.robot.nickname}
|
||||
// activeOrderId={this.props.robot.activeOrderId}
|
||||
// lastOrderId={this.props.robot.lastOrderId}
|
||||
// referralCode={this.props.robot.referralCode}
|
||||
// tgEnabled={this.props.robot.tgEnabled}
|
||||
// tgBotName={this.props.robot.tgBotName}
|
||||
// tgToken={this.props.robot.tgToken}
|
||||
// handleSubmitInvoiceClicked={this.handleSubmitInvoiceClicked}
|
||||
// showRewardsSpinner={this.state.showRewardsSpinner}
|
||||
// withdrawn={this.props.info.withdrawn}
|
||||
// badInvoice={this.props.info.badInvoice}
|
||||
// earnedRewards={this.props.robot.earnedRewards}
|
||||
// updateRobot={(newParam) => this.props.setRobot({ ...robot, ...newParam })}
|
||||
// stealthInvoices={this.props.robot.stealthInvoices}
|
||||
// handleSetStealthInvoice={this.handleSetStealthInvoice}
|
||||
// />
|
||||
|
||||
// <StatsDialog
|
||||
// open={this.state.openStatsForNerds}
|
||||
// handleClickCloseStatsForNerds={this.handleClickCloseStatsForNerds}
|
||||
// coordinatorVersion={this.props.info.coordinatorVersion}
|
||||
// clientVersion={this.props.info.clientVersion}
|
||||
// lndVersion={this.props.info.lnd_version}
|
||||
// network={this.props.info.network}
|
||||
// nodeAlias={this.props.info.node_alias}
|
||||
// nodeId={this.props.info.node_id}
|
||||
// alternativeName={this.props.info.alternative_name}
|
||||
// alternativeSite={this.props.info.alternative_site}
|
||||
// commitHash={this.props.info.robosats_running_commit_hash}
|
||||
// lastDayVolume={this.props.info.last_day_volume}
|
||||
// lifetimeVolume={this.props.info.lifetime_volume}
|
||||
// />
|
||||
|
||||
// <MediaQuery minWidth={1200}>{this.bottomBarDesktop()}</MediaQuery>
|
||||
|
||||
// <MediaQuery maxWidth={1199}>{this.bottomBarPhone()}</MediaQuery>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// export default NavBar;
|
||||
|
@ -73,12 +73,12 @@ class UserGenPage extends Component {
|
||||
requestBody.then((body) =>
|
||||
apiClient.post('/api/user/', body).then((data) => {
|
||||
this.setState({ found: data.found, bad_request: data.bad_request });
|
||||
this.props.setOrder(
|
||||
this.props.setCurrentOrder(
|
||||
data.active_order_id
|
||||
? data.active_order_id
|
||||
: data.last_order_id
|
||||
? data.last_order_id
|
||||
: this.props.order,
|
||||
: null,
|
||||
);
|
||||
// Add nick and token to App state (token only if not a bad request)
|
||||
data.bad_request
|
||||
|
@ -21,7 +21,7 @@ import {
|
||||
import { AddCircleOutline, RemoveCircleOutline } from '@mui/icons-material';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Order, LimitList } from '../../../models';
|
||||
import { PublicOrder, LimitList } from '../../../models';
|
||||
import RobotAvatar from '../../RobotAvatar';
|
||||
import { amountToString, matchMedian, statusBadgeColor } from '../../../utils';
|
||||
import currencyDict from '../../../../static/assets/currencies.json';
|
||||
@ -29,7 +29,7 @@ import { PaymentStringAsIcons } from '../../PaymentMethods';
|
||||
import getNivoScheme from '../NivoScheme';
|
||||
|
||||
interface DepthChartProps {
|
||||
orders: Order[];
|
||||
orders: PublicOrder[];
|
||||
lastDayPremium?: number | undefined;
|
||||
currency: number;
|
||||
limits: LimitList;
|
||||
@ -114,15 +114,17 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
||||
}, [enrichedOrders, xType, lastDayPremium, currencyCode]);
|
||||
|
||||
const generateSeries: () => void = () => {
|
||||
const sortedOrders: Order[] =
|
||||
const sortedOrders: PublicOrder[] =
|
||||
xType === 'base_amount'
|
||||
? enrichedOrders.sort(
|
||||
(order1, order2) => (order1?.base_amount || 0) - (order2?.base_amount || 0),
|
||||
)
|
||||
: enrichedOrders.sort((order1, order2) => order1.premium - order2.premium);
|
||||
|
||||
const sortedBuyOrders: Order[] = sortedOrders.filter((order) => order.type == 0).reverse();
|
||||
const sortedSellOrders: Order[] = sortedOrders.filter((order) => order.type == 1);
|
||||
const sortedBuyOrders: PublicOrder[] = sortedOrders
|
||||
.filter((order) => order.type == 0)
|
||||
.reverse();
|
||||
const sortedSellOrders: PublicOrder[] = sortedOrders.filter((order) => order.type == 1);
|
||||
|
||||
const buySerie: Datum[] = generateSerie(sortedBuyOrders);
|
||||
const sellSerie: Datum[] = generateSerie(sortedSellOrders);
|
||||
@ -142,7 +144,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
||||
]);
|
||||
};
|
||||
|
||||
const generateSerie = (orders: Order[]): Datum[] => {
|
||||
const generateSerie = (orders: PublicOrder[]): Datum[] => {
|
||||
if (center == undefined) {
|
||||
return [];
|
||||
}
|
||||
@ -159,7 +161,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
||||
y: lastSumOrders,
|
||||
},
|
||||
{
|
||||
// Order Point
|
||||
// PublicOrder Point
|
||||
x: xType === 'base_amount' ? order.base_amount : order.premium,
|
||||
y: sumOrders,
|
||||
order,
|
||||
@ -220,7 +222,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
||||
const generateTooltip: React.FunctionComponent<PointTooltipProps> = (
|
||||
pointTooltip: PointTooltipProps,
|
||||
) => {
|
||||
const order: Order = pointTooltip.point.data.order;
|
||||
const order: PublicOrder = pointTooltip.point.data.order;
|
||||
return order ? (
|
||||
<Paper elevation={12} style={{ padding: 10, width: 250 }}>
|
||||
<Grid container justifyContent='space-between'>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Link as LinkRouter } from 'react-router-dom';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Badge,
|
||||
@ -41,16 +41,27 @@ import { getHost, getWebln } from '../../utils';
|
||||
import RobotAvatar from '../RobotAvatar';
|
||||
import { apiClient } from '../../services/api';
|
||||
import { Robot } from '../../models';
|
||||
import { Page } from '../../basic/NavBar';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
robot: Robot;
|
||||
setRobot: (state: Robot) => void;
|
||||
setPage: (state: Page) => void;
|
||||
setCurrentOrder: (state: number) => void;
|
||||
}
|
||||
|
||||
const ProfileDialog = ({ open = false, onClose, robot, setRobot }: Props): JSX.Element => {
|
||||
const ProfileDialog = ({
|
||||
open = false,
|
||||
onClose,
|
||||
robot,
|
||||
setRobot,
|
||||
setPage,
|
||||
setCurrentOrder,
|
||||
}: Props): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
const theme = useTheme();
|
||||
const host = getHost();
|
||||
|
||||
@ -179,9 +190,12 @@ const ProfileDialog = ({ open = false, onClose, robot, setRobot }: Props): JSX.E
|
||||
|
||||
{robot.activeOrderId ? (
|
||||
<ListItemButton
|
||||
onClick={onClose}
|
||||
to={`/order/${robot.activeOrderId}`}
|
||||
component={LinkRouter}
|
||||
onClick={() => {
|
||||
history.push('/order/' + robot.activeOrderId);
|
||||
setPage('order');
|
||||
setCurrentOrder(robot.activeOrderId);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Badge badgeContent='' color='primary'>
|
||||
@ -195,9 +209,12 @@ const ProfileDialog = ({ open = false, onClose, robot, setRobot }: Props): JSX.E
|
||||
</ListItemButton>
|
||||
) : robot.lastOrderId ? (
|
||||
<ListItemButton
|
||||
onClick={onClose}
|
||||
to={`/order/${robot.lastOrderId}`}
|
||||
component={LinkRouter}
|
||||
onClick={() => {
|
||||
history.push('/order/' + robot.lastOrderId);
|
||||
setPage('order');
|
||||
setCurrentOrder(robot.lastOrderId);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<NumbersIcon color='primary' />
|
||||
|
@ -266,7 +266,6 @@ const MakerForm = ({
|
||||
apiClient.post('/api/make/', body).then((data: object) => {
|
||||
setBadRequest(data.bad_request);
|
||||
if (data.id) {
|
||||
history.push('/order/' + data.id);
|
||||
onOrderCreated(data.id);
|
||||
}
|
||||
setSubmittingRequest(false);
|
||||
|
@ -24,6 +24,7 @@ import {
|
||||
SettingsOverscan,
|
||||
Link,
|
||||
} from '@mui/icons-material';
|
||||
import { systemClient } from '../../services/System';
|
||||
|
||||
interface SettingsFormProps {
|
||||
dense?: boolean;
|
||||
@ -58,7 +59,10 @@ const SettingsForm = ({
|
||||
</ListItemIcon>
|
||||
<SelectLanguage
|
||||
language={settings.language}
|
||||
setLanguage={(language) => setSettings({ ...settings, language })}
|
||||
setLanguage={(language) => {
|
||||
setSettings({ ...settings, language });
|
||||
systemClient.setCookie('settings_language', language);
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
@ -103,9 +107,11 @@ const SettingsForm = ({
|
||||
<LightMode sx={{ width: '0.67em', height: '0.67em', color: '#666' }} />
|
||||
</Paper>
|
||||
}
|
||||
onChange={(e) =>
|
||||
setSettings({ ...settings, mode: e.target.checked ? 'dark' : 'light' })
|
||||
}
|
||||
onChange={(e) => {
|
||||
const mode = e.target.checked ? 'dark' : 'light';
|
||||
setSettings({ ...settings, mode });
|
||||
systemClient.setCookie('settings_mode', mode);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@ -120,7 +126,14 @@ const SettingsForm = ({
|
||||
min={settings.frontend == 'basic' ? 12 : 10}
|
||||
max={settings.frontend == 'basic' ? 16 : 14}
|
||||
step={1}
|
||||
onChange={(e) => setSettings({ ...settings, fontSize: e.target.value })}
|
||||
onChange={(e) => {
|
||||
const fontSize = e.target.value;
|
||||
setSettings({ ...settings, fontSize });
|
||||
systemClient.setCookie(
|
||||
`settings_fontsize_${settings.frontend}`,
|
||||
fontSize.toString(),
|
||||
);
|
||||
}}
|
||||
valueLabelDisplay='off'
|
||||
marks={fontSizes.map(({ label, value }) => ({
|
||||
label: <Typography variant='caption'>{t(label)}</Typography>,
|
||||
@ -137,7 +150,7 @@ const SettingsForm = ({
|
||||
<ToggleButtonGroup
|
||||
exclusive={true}
|
||||
value={settings.network}
|
||||
onChange={(e, value) => setSettings({ ...settings, network: value })}
|
||||
onChange={(e, network) => setSettings({ ...settings, network })}
|
||||
>
|
||||
<ToggleButton value='mainnet' color='primary'>
|
||||
{t('Mainnet')}
|
||||
|
44
frontend/src/components/TradeBox/BondStatus.tsx
Normal file
44
frontend/src/components/TradeBox/BondStatus.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Box, Typography } from '@mui/material';
|
||||
import { Lock, LockOpen, Balance } from '@mui/icons-material';
|
||||
|
||||
interface BondStatusProps {
|
||||
status: 'locked' | 'settled' | 'returned' | 'hide';
|
||||
isMaker: boolean;
|
||||
}
|
||||
|
||||
const BondStatus = ({ status, isMaker }: BondStatusProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
let Icon = Lock;
|
||||
if (status === 'returned') {
|
||||
Icon = LockOpen;
|
||||
} else if (status === 'settled') {
|
||||
Icon = Balance;
|
||||
}
|
||||
|
||||
if (status === 'hide') {
|
||||
return <></>;
|
||||
} else {
|
||||
return (
|
||||
<Box>
|
||||
<Typography color='primary' variant='subtitle1' align='center'>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<Icon />
|
||||
{t(`Your ${isMaker ? 'maker' : 'taker'} bond is ${status}`)}
|
||||
</div>
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default BondStatus;
|
51
frontend/src/components/TradeBox/Dialogs/ConfirmDispute.tsx
Normal file
51
frontend/src/components/TradeBox/Dialogs/ConfirmDispute.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
Button,
|
||||
} from '@mui/material';
|
||||
|
||||
interface ConfirmDisputeDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onAgreeClick: () => void;
|
||||
}
|
||||
|
||||
export const ConfirmDisputeDialog = ({
|
||||
open,
|
||||
onClose,
|
||||
onAgreeClick,
|
||||
}: ConfirmDisputeDialogProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle>{t('Do you want to open a dispute?')}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{t(
|
||||
'The RoboSats staff will examine the statements and evidence provided. You need to build a complete case, as the staff cannot read the chat. It is best to provide a burner contact method with your statement. The satoshis in the trade escrow will be sent to the dispute winner, while the dispute loser will lose the bond.',
|
||||
)}
|
||||
</DialogContentText>
|
||||
<br />
|
||||
<DialogContentText>
|
||||
{t(
|
||||
'Make sure to EXPORT the chat log. The staff might request your exported chat log JSON in order to solve discrepancies. It is your responsibility to store it.',
|
||||
)}
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose} autoFocus>
|
||||
{t('Disagree')}
|
||||
</Button>
|
||||
<Button onClick={onAgreeClick}>{t('Agree and open dispute')}</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmDisputeDialog;
|
@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
Button,
|
||||
} from '@mui/material';
|
||||
import { Order } from '../../../models';
|
||||
import currencies from '../../../../static/assets/currencies.json';
|
||||
import { pn } from '../../../utils';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
|
||||
interface ConfirmFiatReceivedDialogProps {
|
||||
open: boolean;
|
||||
loadingButton: boolean;
|
||||
order: Order;
|
||||
onClose: () => void;
|
||||
onConfirmClick: () => void;
|
||||
}
|
||||
|
||||
export const ConfirmFiatReceivedDialog = ({
|
||||
open,
|
||||
loadingButton,
|
||||
onClose,
|
||||
order,
|
||||
onConfirmClick,
|
||||
}: ConfirmFiatReceivedDialogProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const currencyCode = currencies[order.currency.toString()];
|
||||
const amount = pn(parseFloat(parseFloat(order.amount).toFixed(order.currency == 1000 ? 8 : 4)));
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle>
|
||||
{t('Confirm you received {{amount}} {{currencyCode}}?', { currencyCode, amount })}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id='alert-dialog-description'>
|
||||
{t(
|
||||
'Confirming that you received the fiat will finalize the trade. The satoshis in the escrow will be released to the buyer. Only confirm after the {{amount}} {{currencyCode}} have arrived to your account. In addition, if you have received the payment and do not confirm it, you risk losing your bond.',
|
||||
{ currencyCode, amount },
|
||||
)}
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose} autoFocus>
|
||||
{t('Go back')}
|
||||
</Button>
|
||||
<LoadingButton loading={loadingButton} onClick={onConfirmClick}>
|
||||
{t('Confirm')}
|
||||
</LoadingButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmFiatReceivedDialog;
|
2
frontend/src/components/TradeBox/Dialogs/index.ts
Normal file
2
frontend/src/components/TradeBox/Dialogs/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { ConfirmDisputeDialog } from './ConfirmDispute';
|
||||
export { ConfirmFiatReceivedDialog } from './ConfirmFiatReceived';
|
@ -28,21 +28,13 @@ import CircularProgress from '@mui/material/CircularProgress';
|
||||
import KeyIcon from '@mui/icons-material/Key';
|
||||
import { ExportIcon } from '../../Icons';
|
||||
import { useTheme } from '@mui/system';
|
||||
import { WebSocketsChatMessage } from '../../../models';
|
||||
|
||||
interface Props {
|
||||
orderId: number;
|
||||
userNick: string;
|
||||
}
|
||||
|
||||
interface EncryptedChatMessage {
|
||||
userNick: string;
|
||||
validSignature: boolean;
|
||||
plainTextMessage: string;
|
||||
encryptedMessage: string;
|
||||
time: string;
|
||||
index: number;
|
||||
}
|
||||
|
||||
const EncryptedChat: React.FC<Props> = ({ orderId, userNick }: Props): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
@ -58,7 +50,7 @@ const EncryptedChat: React.FC<Props> = ({ orderId, userNick }: Props): JSX.Eleme
|
||||
);
|
||||
const [peerPubKey, setPeerPubKey] = useState<string>();
|
||||
const [token] = useState<string>(systemClient.getCookie('robot_token') || '');
|
||||
const [messages, setMessages] = useState<EncryptedChatMessage[]>([]);
|
||||
const [messages, setMessages] = useState<WebSocketsChatMessage[]>([]);
|
||||
const [serverMessages, setServerMessages] = useState<any[]>([]);
|
||||
const [value, setValue] = useState<string>('');
|
||||
const [connection, setConnection] = useState<WebsocketConnection>();
|
||||
|
114
frontend/src/components/TradeBox/Prompts/LockInvoice.tsx
Normal file
114
frontend/src/components/TradeBox/Prompts/LockInvoice.tsx
Normal file
@ -0,0 +1,114 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Grid, Link, Typography, TextField, Tooltip, useTheme } from '@mui/material';
|
||||
import { AccountBalanceWallet, ContentCopy } from '@mui/icons-material';
|
||||
import { NewTabIcon } from '../../Icons';
|
||||
import QRCode from 'react-qr-code';
|
||||
import { Order } from '../../../models';
|
||||
import { systemClient } from '../../../services/System';
|
||||
import currencies from '../../../../static/assets/currencies.json';
|
||||
|
||||
interface LockInvoicePromptProps {
|
||||
order: Order;
|
||||
concept: 'bond' | 'escrow';
|
||||
}
|
||||
|
||||
export const LockInvoicePrompt = ({ order, concept }: LockInvoicePromptProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const currencyCode: string = currencies[`${order.currency}`];
|
||||
|
||||
const invoice = concept === 'bond' ? order.bond_invoice : order.escrow_invoice;
|
||||
const helperText =
|
||||
concept === 'bond'
|
||||
? t(
|
||||
'This is a hold invoice, it will freeze in your wallet. It will be charged only if you cancel or lose a dispute.',
|
||||
)
|
||||
: t(
|
||||
'This is a hold invoice, it will freeze in your wallet. It will be released to the buyer once you confirm to have received the {{currencyCode}}.',
|
||||
{ currencyCode },
|
||||
);
|
||||
|
||||
const CompatibleWalletsButton = function () {
|
||||
return (
|
||||
<Button
|
||||
color='primary'
|
||||
component={Link}
|
||||
href={'https://learn.robosats.com/docs/wallets/'}
|
||||
target='_blank'
|
||||
align='center'
|
||||
>
|
||||
<AccountBalanceWallet />
|
||||
{t('See Compatible Wallets')}
|
||||
<NewTabIcon sx={{ width: '1.1em', height: '1.1em' }} />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const depositHoursMinutes = function () {
|
||||
const hours = Math.floor(order.escrow_duration / 3600);
|
||||
const minutes = Math.floor((order.escrow_duration - hours * 3600) / 60);
|
||||
const dict = { deposit_timer_hours: hours, deposit_timer_minutes: minutes };
|
||||
return dict;
|
||||
};
|
||||
|
||||
const ExpirationWarning = function () {
|
||||
return (
|
||||
<Typography variant='body2'>
|
||||
{t(
|
||||
'You risk losing your bond if you do not lock the collateral. Total time available is {{deposit_timer_hours}}h {{deposit_timer_minutes}}m.',
|
||||
depositHoursMinutes(),
|
||||
)}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={12}>
|
||||
{concept === 'bond' ? <CompatibleWalletsButton /> : <ExpirationWarning />}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
|
||||
<QRCode
|
||||
bgColor={'rgba(255, 255, 255, 0)'}
|
||||
fgColor={theme.palette.text.primary}
|
||||
value={invoice}
|
||||
size={theme.typography.fontSize * 21.8}
|
||||
onClick={() => {
|
||||
systemClient.copyToClipboard(invoice);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
|
||||
<Button
|
||||
size='small'
|
||||
color='inherit'
|
||||
onClick={() => {
|
||||
systemClient.copyToClipboard(invoice);
|
||||
}}
|
||||
>
|
||||
<ContentCopy />
|
||||
{t('Copy to clipboard')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
hiddenLabel
|
||||
variant='standard'
|
||||
size='small'
|
||||
defaultValue={invoice}
|
||||
disabled={true}
|
||||
helperText={helperText}
|
||||
color='secondary'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default LockInvoicePrompt;
|
36
frontend/src/components/TradeBox/Prompts/TakerFound.tsx
Normal file
36
frontend/src/components/TradeBox/Prompts/TakerFound.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Grid, Typography } from '@mui/material';
|
||||
import { Order } from '../../../models';
|
||||
import stepXofY from '../stepXofY';
|
||||
|
||||
interface TakerFoundPrompProps {
|
||||
order: Order;
|
||||
}
|
||||
|
||||
export const TakerFoundPrompt = ({ order }: TakerFoundPrompProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const Title = function () {
|
||||
return (
|
||||
<Typography color='primary' variant='subtitle1'>
|
||||
<b>{t('A taker has been found!')}</b>
|
||||
{` ${stepXofY(order)}`}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container spacing={1}>
|
||||
<Grid item>
|
||||
<Typography variant='body2'>
|
||||
{t(
|
||||
'Please wait for the taker to lock a bond. If the taker does not lock a bond in time, the order will be made public again.',
|
||||
)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default TakerFoundPrompt;
|
2
frontend/src/components/TradeBox/Prompts/index.ts
Normal file
2
frontend/src/components/TradeBox/Prompts/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { LockInvoicePrompt } from './LockInvoice';
|
||||
export { TakerFoundPrompt } from './TakerFound';
|
96
frontend/src/components/TradeBox/Title/index.tsx
Normal file
96
frontend/src/components/TradeBox/Title/index.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Typography, useTheme } from '@mui/material';
|
||||
import { Order } from '../../../models';
|
||||
import stepXofY from '../stepXofY';
|
||||
import currencies from '../../../../static/assets/currencies.json';
|
||||
import { pn } from '../../../utils';
|
||||
|
||||
interface TakerFoundPrompProps {
|
||||
order: Order;
|
||||
}
|
||||
|
||||
export const Title = ({ order }: TakerFoundPrompProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const currencyCode: string = currencies[`${order.currency}`];
|
||||
|
||||
let text = '';
|
||||
|
||||
if (order.is_maker && order.status === 0) {
|
||||
text = t('Lock {{amountSats}} Sats to PUBLISH order', { amountSats: pn(order.bond_satoshis) });
|
||||
} else if (order.is_taker && order.status === 3) {
|
||||
text = t('Lock {{amountSats}} Sats to TAKE order', { amountSats: pn(order.bond_satoshis) });
|
||||
} else if (order.is_seller && [6, 7].includes(order.status)) {
|
||||
text = t('Lock {{amountSats}} Sats as collateral', { amountSats: pn(order.escrow_satoshis) });
|
||||
}
|
||||
|
||||
{
|
||||
/* Maker and taker Bond request */
|
||||
}
|
||||
// {this.props.data.is_maker & (this.props.data.status == 0) ? this.showQRInvoice() : ''}
|
||||
// {this.props.data.is_taker & (this.props.data.status == 3) ? this.showQRInvoice() : ''}
|
||||
|
||||
// {/* Waiting for taker and taker bond request */}
|
||||
// {this.props.data.is_maker & (this.props.data.status == 2) ? this.showPausedOrder() : ''}
|
||||
// {this.props.data.is_maker & (this.props.data.status == 1) ? this.showMakerWait() : ''}
|
||||
// {this.props.data.is_maker & (this.props.data.status == 3) ? this.showTakerFound() : ''}
|
||||
|
||||
// {/* Send Invoice (buyer) and deposit collateral (seller) */}
|
||||
// {this.props.data.is_seller &
|
||||
// (this.props.data.status == 6 || this.props.data.status == 7)
|
||||
// ? this.showEscrowQRInvoice()
|
||||
// : ''}
|
||||
// {this.props.data.is_buyer & (this.props.data.status == 6 || this.props.data.status == 8)
|
||||
// ? this.showInputInvoice()
|
||||
// : ''}
|
||||
// {this.props.data.is_buyer & (this.props.data.status == 7)
|
||||
// ? this.showWaitingForEscrow()
|
||||
// : ''}
|
||||
// {this.props.data.is_seller & (this.props.data.status == 8)
|
||||
// ? this.showWaitingForBuyerInvoice()
|
||||
// : ''}
|
||||
|
||||
// {/* In Chatroom */}
|
||||
// {this.props.data.status == 9 || this.props.data.status == 10 ? this.showChat() : ''}
|
||||
|
||||
// {/* Trade Finished */}
|
||||
// {this.props.data.is_seller & [13, 14, 15].includes(this.props.data.status)
|
||||
// ? this.showRateSelect()
|
||||
// : ''}
|
||||
// {this.props.data.is_buyer & (this.props.data.status == 14) ? this.showRateSelect() : ''}
|
||||
|
||||
// {/* Trade Finished - Payment Routing Failed */}
|
||||
// {this.props.data.is_buyer & (this.props.data.status == 13)
|
||||
// ? this.showSendingPayment()
|
||||
// : ''}
|
||||
|
||||
// {/* Trade Finished - Payment Routing Failed */}
|
||||
// {this.props.data.is_buyer & (this.props.data.status == 15)
|
||||
// ? this.showRoutingFailed()
|
||||
// : ''}
|
||||
|
||||
// {/* Trade Finished - TODO Needs more planning */}
|
||||
// {this.props.data.status == 11 ? this.showInDisputeStatement() : ''}
|
||||
// {this.props.data.status == 16 ? this.showWaitForDisputeResolution() : ''}
|
||||
// {(this.props.data.status == 17) & this.props.data.is_taker ||
|
||||
// (this.props.data.status == 18) & this.props.data.is_maker
|
||||
// ? this.showDisputeWinner()
|
||||
// : ''}
|
||||
// {(this.props.data.status == 18) & this.props.data.is_taker ||
|
||||
// (this.props.data.status == 17) & this.props.data.is_maker
|
||||
// ? this.showDisputeLoser()
|
||||
// : ''}
|
||||
|
||||
// {/* Order has expired */}
|
||||
// {this.props.data.status == 5 ? this.showOrderExpired() : ''}
|
||||
|
||||
return (
|
||||
<Typography variant='body2'>
|
||||
<b>{text}</b>
|
||||
{stepXofY(order)}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
export default Title;
|
47
frontend/src/components/TradeBox/stepXofY.ts
Normal file
47
frontend/src/components/TradeBox/stepXofY.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { Order } from '../../models';
|
||||
|
||||
const stepXofY = function (order: Order): string {
|
||||
// set y value
|
||||
let x: number | null = null;
|
||||
let y: number | null = null;
|
||||
|
||||
if (order.is_maker) {
|
||||
y = 5;
|
||||
} else if (order.is_taker) {
|
||||
y = 4;
|
||||
}
|
||||
|
||||
// set x values
|
||||
if (order.is_maker) {
|
||||
if (order.status === 0) {
|
||||
x = 1;
|
||||
} else if ([1, 2, 3].includes(order.status)) {
|
||||
x = 2;
|
||||
} else if ([6, 7, 8].includes(order.status)) {
|
||||
x = 3;
|
||||
} else if (order.status === 9) {
|
||||
x = 4;
|
||||
} else if (order.status === 10) {
|
||||
x = 5;
|
||||
}
|
||||
} else if (order.is_taker) {
|
||||
if (order.status === 3) {
|
||||
x = 1;
|
||||
} else if ([6, 7, 8].includes(order.status)) {
|
||||
x = 2;
|
||||
} else if (order.status === 9) {
|
||||
x = 3;
|
||||
} else if (order.status === 10) {
|
||||
x = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Return "(x/y)"
|
||||
if (x != null && y != null) {
|
||||
return `(${x}/${y})`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
export default stepXofY;
|
1605
frontend/src/components/TradeBox/wip_index.tsx
Normal file
1605
frontend/src/components/TradeBox/wip_index.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,21 +9,10 @@ class UnsafeAlert extends Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
show: true,
|
||||
isSelfhosted: this.isSelfhosted(),
|
||||
};
|
||||
}
|
||||
|
||||
isSelfhosted() {
|
||||
const http = new XMLHttpRequest();
|
||||
try {
|
||||
http.open('HEAD', `${location.protocol}//${getHost()}/selfhosted`, false);
|
||||
http.send();
|
||||
return http.status === 200;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// To do. Read from Coordinators state Obj.
|
||||
safe_urls = [
|
||||
'robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion',
|
||||
'robotestagw3dcxmd66r4rgksb4nmmr43fh77bzn2ia2eucduyeafnyd.onion',
|
||||
@ -32,6 +21,26 @@ class UnsafeAlert extends Component {
|
||||
'r7r4sckft6ptmk4r2jajiuqbowqyxiwsle4iyg4fijtoordc6z7a.b32.i2p',
|
||||
];
|
||||
|
||||
checkClient() {
|
||||
const http = new XMLHttpRequest();
|
||||
const unsafeClient = !this.safe_urls.includes(getHost());
|
||||
try {
|
||||
http.open('HEAD', `${location.protocol}//${getHost()}/selfhosted`, false);
|
||||
http.send();
|
||||
this.props.setSettings({
|
||||
...this.props.settings,
|
||||
unsafeClient,
|
||||
selfhostedClient: http.status === 200,
|
||||
});
|
||||
} catch {
|
||||
this.props.setSettings({ ...this.props.settings, unsafeClient, selfhostedClient: false });
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.checkClient();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
|
||||
@ -41,7 +50,7 @@ class UnsafeAlert extends Component {
|
||||
}
|
||||
|
||||
// Show selfhosted notice
|
||||
if (this.state.isSelfhosted) {
|
||||
else if (this.props.settings.selfhostedClient) {
|
||||
return (
|
||||
<div>
|
||||
<Paper elevation={6} className='alertUnsafe'>
|
||||
@ -65,7 +74,7 @@ class UnsafeAlert extends Component {
|
||||
}
|
||||
|
||||
// Show unsafe alert
|
||||
if (!window.NativeRobosats && !this.safe_urls.includes(getHost())) {
|
||||
else if (this.props.settings.unsafeClient) {
|
||||
return (
|
||||
<div>
|
||||
<MediaQuery minWidth={800}>
|
||||
|
@ -1,4 +1,4 @@
|
||||
export interface Order {
|
||||
export interface PublicOrder {
|
||||
id: number;
|
||||
created_at: Date;
|
||||
expires_at: Date;
|
||||
@ -24,8 +24,8 @@ export interface Order {
|
||||
}
|
||||
|
||||
export interface Book {
|
||||
orders: Order[];
|
||||
orders: PublicOrder[];
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export default Order;
|
||||
export default PublicOrder;
|
||||
|
23
frontend/src/models/Chat.model.ts
Normal file
23
frontend/src/models/Chat.model.ts
Normal file
@ -0,0 +1,23 @@
|
||||
export interface WebSocketsChatMessage {
|
||||
userNick: string;
|
||||
validSignature: boolean;
|
||||
plainTextMessage: string;
|
||||
encryptedMessage: string;
|
||||
time: Date;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface APIChatMessage {
|
||||
nick: string;
|
||||
time: Date;
|
||||
message: string;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface APIChat {
|
||||
peer_pubkey: string;
|
||||
peer_connected: boolean;
|
||||
messages: APIChatMessage[];
|
||||
}
|
||||
|
||||
export default APIChat;
|
100
frontend/src/models/Order.model.ts
Normal file
100
frontend/src/models/Order.model.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import { APIChat } from '.';
|
||||
|
||||
export interface TradeRobotSummary {
|
||||
sent_fiat: number;
|
||||
received_sats: number;
|
||||
is_swap: boolean;
|
||||
received_onchain_sats: number;
|
||||
mining_fee_sats: number;
|
||||
swap_fee_sats: number;
|
||||
swap_fee_percent: number;
|
||||
sent_sats: number;
|
||||
received_fiat: number;
|
||||
trade_fee_sats: number;
|
||||
}
|
||||
|
||||
export interface TradeCoordinatorSummary {
|
||||
contract_timestamp: Date;
|
||||
contract_total_time: number;
|
||||
routing_fee_sats: number;
|
||||
trade_revenue_sats: number;
|
||||
}
|
||||
|
||||
export interface Order {
|
||||
id: number;
|
||||
status: number;
|
||||
created_at: Date;
|
||||
expires_at: Date;
|
||||
type: number;
|
||||
currency: number;
|
||||
amount: string;
|
||||
has_range: boolean;
|
||||
min_amount: string;
|
||||
max_amount: string;
|
||||
payment_method: string;
|
||||
is_explicit: true;
|
||||
premium: number;
|
||||
satoshis: number;
|
||||
bondless_taker: true;
|
||||
maker: number;
|
||||
taker: number;
|
||||
escrow_duration: number;
|
||||
total_secs_exp: number;
|
||||
penalty: Date;
|
||||
is_maker: boolean;
|
||||
is_taker: boolean;
|
||||
is_participant: boolean;
|
||||
maker_status: 'Active' | 'Seen recently' | 'Inactive';
|
||||
taker_status: 'Active' | 'Seen recently' | 'Inactive';
|
||||
price_now: number;
|
||||
premium_percentile: number;
|
||||
num_similar_orders: number;
|
||||
tg_enabled: boolean; // deprecated
|
||||
tg_token: string;
|
||||
tg_bot_name: string;
|
||||
is_buyer: boolean;
|
||||
is_seller: boolean;
|
||||
maker_nick: string;
|
||||
taker_nick: string;
|
||||
status_message: string;
|
||||
is_fiat_sent: boolean;
|
||||
is_disputed: boolean;
|
||||
ur_nick: string;
|
||||
maker_locked: boolean;
|
||||
taker_locked: boolean;
|
||||
escrow_locked: boolean;
|
||||
trade_satoshis: number;
|
||||
bond_invoice: string;
|
||||
bond_satoshis: number;
|
||||
escrow_invoice: string;
|
||||
escrow_satoshis: number;
|
||||
invoice_amount: number;
|
||||
swap_allowed: boolean;
|
||||
swap_failure_reason: string;
|
||||
suggested_mining_fee_rate: number;
|
||||
swap_fee_rate: number;
|
||||
pending_cancel: boolean;
|
||||
asked_for_cancel: boolean;
|
||||
statement_submitted: boolean;
|
||||
retries: number;
|
||||
next_retry_time: Date;
|
||||
failure_reason: string;
|
||||
invoice_expired: boolean;
|
||||
public_duration: number;
|
||||
bond_size: string;
|
||||
trade_fee_percent: number;
|
||||
bond_size_sats: number;
|
||||
bond_size_percent: number;
|
||||
chat: APIChat;
|
||||
maker_summary: TradeRobotSummary;
|
||||
taker_summary: TradeRobotSummary;
|
||||
platform_summary: TradeCoordinatorSummary;
|
||||
expiry_reason: number;
|
||||
expiry_message: string;
|
||||
num_satoshis: number;
|
||||
sent_satoshis: number;
|
||||
txid: string;
|
||||
network: 'mainnet' | 'testnet';
|
||||
}
|
||||
|
||||
export default Order;
|
@ -1,8 +1,13 @@
|
||||
import { baseSettings, Settings } from './Settings.model';
|
||||
import { systemClient } from '../services/System';
|
||||
import BaseSettings from './Settings.model';
|
||||
|
||||
export const defaultSettings: Settings = {
|
||||
...baseSettings,
|
||||
frontend: 'basic',
|
||||
};
|
||||
class Settings extends BaseSettings {
|
||||
constructor() {
|
||||
super();
|
||||
const fontSizeCookie = systemClient.getCookie('settings_fontsize_basic');
|
||||
this.fontSize = fontSizeCookie !== '' ? Number(fontSizeCookie) : 14;
|
||||
}
|
||||
public frontend: 'basic' | 'pro' = 'basic';
|
||||
}
|
||||
|
||||
export default defaultSettings;
|
||||
export default Settings;
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { baseSettings, Settings } from './Settings.model';
|
||||
import { systemClient } from '../services/System';
|
||||
import BaseSettings from './Settings.model';
|
||||
|
||||
export const defaultSettings: Settings = {
|
||||
...baseSettings,
|
||||
fontSize: 12,
|
||||
frontend: 'pro',
|
||||
};
|
||||
class Settings extends BaseSettings {
|
||||
constructor() {
|
||||
super();
|
||||
const fontSizeCookie = systemClient.getCookie('settings_fontsize_pro');
|
||||
this.fontSize = fontSizeCookie !== '' ? Number(fontSizeCookie) : 12;
|
||||
}
|
||||
public frontend: 'basic' | 'pro' = 'pro';
|
||||
}
|
||||
|
||||
export default defaultSettings;
|
||||
export default Settings;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import i18n from '../i18n/Web';
|
||||
import { systemClient } from '../services/System';
|
||||
import type Coordinator from './Coordinator.model';
|
||||
|
||||
export type Language =
|
||||
@ -19,28 +20,34 @@ export type Language =
|
||||
| 'zh-SI'
|
||||
| 'zh-TR';
|
||||
|
||||
export interface Settings {
|
||||
frontend: 'basic' | 'pro';
|
||||
mode: 'light' | 'dark';
|
||||
fontSize: number;
|
||||
language: Language;
|
||||
freezeViewports: boolean;
|
||||
network: 'mainnet' | 'testnet' | undefined;
|
||||
coordinator: Coordinator | undefined;
|
||||
class BaseSettings {
|
||||
constructor() {
|
||||
const modeCookie: 'light' | 'dark' | '' = systemClient.getCookie('settings_mode');
|
||||
this.mode =
|
||||
modeCookie !== ''
|
||||
? modeCookie
|
||||
: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? 'dark'
|
||||
: 'light';
|
||||
|
||||
const languageCookie = systemClient.getCookie('settings_language');
|
||||
this.language =
|
||||
languageCookie !== ''
|
||||
? languageCookie
|
||||
: i18n.resolvedLanguage == null
|
||||
? 'en'
|
||||
: i18n.resolvedLanguage.substring(0, 2);
|
||||
}
|
||||
|
||||
public frontend: 'basic' | 'pro' = 'basic';
|
||||
public mode: 'light' | 'dark' = 'light';
|
||||
public fontSize: number = 14;
|
||||
public language?: Language;
|
||||
public freezeViewports: boolean = false;
|
||||
public network: 'mainnet' | 'testnet' | undefined = 'mainnet';
|
||||
public coordinator: Coordinator | undefined = undefined;
|
||||
public unsafeClient: boolean = false;
|
||||
public hostedClient: boolean = false;
|
||||
}
|
||||
|
||||
export const baseSettings: Settings = {
|
||||
frontend: 'basic',
|
||||
mode:
|
||||
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? 'dark'
|
||||
: 'light',
|
||||
fontSize: 14,
|
||||
language:
|
||||
i18n.resolvedLanguage == null ? 'en' : (i18n.resolvedLanguage.substring(0, 2) as Language),
|
||||
freezeViewports: false,
|
||||
network: undefined,
|
||||
coordinator: undefined,
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
export default BaseSettings;
|
||||
|
@ -1,17 +1,18 @@
|
||||
import Robot from './Robot.model';
|
||||
import Settings from './Settings.default.basic';
|
||||
export { Robot, Settings };
|
||||
|
||||
export type { LimitList } from './Limit.model';
|
||||
export type { Limit } from './Limit.model';
|
||||
export type { Order } from './Book.model';
|
||||
export type { Maker } from './Maker.model';
|
||||
export type { Order } from './Order.model';
|
||||
export type { PublicOrder } from './Book.model';
|
||||
export type { Book } from './Book.model';
|
||||
export type { Info } from './Info.model';
|
||||
export type { Settings } from './Settings.model';
|
||||
export type { Language } from './Settings.model';
|
||||
export type { Favorites } from './Favorites.model';
|
||||
export type { Coordinator } from './Coordinator.model';
|
||||
export type { Maker } from './Maker.model';
|
||||
export { Robot };
|
||||
export type { APIChat, WebSocketsChatMessage, APIChatMessage } from './Chat.model';
|
||||
|
||||
export { defaultMaker } from './Maker.model';
|
||||
export { defaultSettings } from './Settings.default.basic';
|
||||
export { defaultInfo } from './Info.model';
|
||||
|
@ -22,8 +22,9 @@ class SystemNativeClient implements SystemClient {
|
||||
});
|
||||
};
|
||||
|
||||
public getCookie: (key: string) => string | undefined = (key) => {
|
||||
return window.NativeRobosats?.cookies[key];
|
||||
public getCookie: (key: string) => string = (key) => {
|
||||
const cookie = window.NativeRobosats?.cookies[key];
|
||||
return cookie === null || cookie === undefined ? '' : cookie;
|
||||
};
|
||||
|
||||
public setCookie: (key: string, value: string) => void = (key, value) => {
|
||||
|
@ -27,7 +27,7 @@ class SystemWebClient implements SystemClient {
|
||||
}
|
||||
};
|
||||
|
||||
public getCookie: (key: string) => string | undefined = (key) => {
|
||||
public getCookie: (key: string) => string = (key) => {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
const cookies = document.cookie.split(';');
|
||||
|
@ -47,6 +47,9 @@ const App = () => {
|
||||
EncryptedStorage.removeItem('csrftoken');
|
||||
loadCookie('robot_token');
|
||||
loadCookie('pub_key');
|
||||
loadCookie('settings_fontsize_basic');
|
||||
loadCookie('settings_language');
|
||||
loadCookie('settings_mode');
|
||||
loadCookie('enc_priv_key').then(() => injectMessageResolve(reponseId));
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user