mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-07 06:50:09 +00:00
Refactor utils
This commit is contained in:
parent
b4205761fe
commit
d3d0f3ee1a
@ -1,642 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import { withTranslation } from 'react-i18next';
|
|
||||||
import {
|
|
||||||
Badge,
|
|
||||||
Tooltip,
|
|
||||||
ListItemAvatar,
|
|
||||||
Paper,
|
|
||||||
Grid,
|
|
||||||
IconButton,
|
|
||||||
Select,
|
|
||||||
MenuItem,
|
|
||||||
ListItemText,
|
|
||||||
ListItem,
|
|
||||||
ListItemIcon,
|
|
||||||
ListItemButton,
|
|
||||||
} from '@mui/material';
|
|
||||||
import MediaQuery from 'react-responsive';
|
|
||||||
import Flags from 'country-flag-icons/react/3x2';
|
|
||||||
import { Link as LinkRouter } from 'react-router-dom';
|
|
||||||
import { apiClient } from '../services/api';
|
|
||||||
import { systemClient } from '../services/System';
|
|
||||||
import RobotAvatar from '../components/RobotAvatar';
|
|
||||||
|
|
||||||
// Icons
|
|
||||||
import BarChartIcon from '@mui/icons-material/BarChart';
|
|
||||||
import PeopleIcon from '@mui/icons-material/People';
|
|
||||||
import InventoryIcon from '@mui/icons-material/Inventory';
|
|
||||||
import SellIcon from '@mui/icons-material/Sell';
|
|
||||||
import SmartToyIcon from '@mui/icons-material/SmartToy';
|
|
||||||
import PercentIcon from '@mui/icons-material/Percent';
|
|
||||||
import PriceChangeIcon from '@mui/icons-material/PriceChange';
|
|
||||||
|
|
||||||
// Missing flags
|
|
||||||
import { CataloniaFlag, BasqueCountryFlag } from '../components/Icons';
|
|
||||||
|
|
||||||
import {
|
|
||||||
CommunityDialog,
|
|
||||||
ExchangeSummaryDialog,
|
|
||||||
ProfileDialog,
|
|
||||||
StatsDialog,
|
|
||||||
UpdateClientDialog,
|
|
||||||
} from '../components/Dialogs';
|
|
||||||
|
|
||||||
class BottomBar extends Component {
|
|
||||||
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 }),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
getHost() {
|
|
||||||
const url =
|
|
||||||
window.location != window.parent.location
|
|
||||||
? this.getHost(document.referrer)
|
|
||||||
: document.location.href;
|
|
||||||
return url.split('/')[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleChangeLang = (e) => {
|
|
||||||
const { i18n } = this.props;
|
|
||||||
i18n.changeLanguage(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
LangSelect = () => {
|
|
||||||
const { i18n } = this.props;
|
|
||||||
const lang = i18n.resolvedLanguage == null ? 'en' : i18n.resolvedLanguage.substring(0, 2);
|
|
||||||
const flagProps = {
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
size='small'
|
|
||||||
value={lang}
|
|
||||||
inputProps={{
|
|
||||||
style: { textAlign: 'center' },
|
|
||||||
}}
|
|
||||||
renderValue={(value) => value.toUpperCase()}
|
|
||||||
onChange={this.handleChangeLang}
|
|
||||||
>
|
|
||||||
<MenuItem value={'en'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.US {...flagProps} />
|
|
||||||
</div>
|
|
||||||
EN
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'es'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.ES {...flagProps} />
|
|
||||||
</div>
|
|
||||||
ES
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'de'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.DE {...flagProps} />
|
|
||||||
</div>
|
|
||||||
DE
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'pl'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.PL {...flagProps} />
|
|
||||||
</div>
|
|
||||||
PL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'fr'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.FR {...flagProps} />
|
|
||||||
</div>
|
|
||||||
FR
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'ru'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.RU {...flagProps} />
|
|
||||||
</div>
|
|
||||||
RU
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'it'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.IT {...flagProps} />
|
|
||||||
</div>
|
|
||||||
IT
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'pt'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.BR {...flagProps} />
|
|
||||||
</div>
|
|
||||||
PT
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'zh-si'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.CN {...flagProps} />
|
|
||||||
</div>
|
|
||||||
简体
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'zh-tr'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.CN {...flagProps} />
|
|
||||||
</div>
|
|
||||||
繁體
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'sv'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.SE {...flagProps} />
|
|
||||||
</div>
|
|
||||||
SV
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'cs'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.CZ {...flagProps} />
|
|
||||||
</div>
|
|
||||||
CS
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'th'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<Flags.TH {...flagProps} />
|
|
||||||
</div>
|
|
||||||
TH
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'ca'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<CataloniaFlag {...flagProps} />
|
|
||||||
</div>
|
|
||||||
CA
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'eu'}>
|
|
||||||
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
|
||||||
<BasqueCountryFlag {...flagProps} />
|
|
||||||
</div>
|
|
||||||
EU
|
|
||||||
</MenuItem>
|
|
||||||
</Select>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
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>
|
|
||||||
<CommunityDialog
|
|
||||||
open={this.state.openCommunity}
|
|
||||||
handleClickCloseCommunity={this.handleClickCloseCommunity}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<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}
|
|
||||||
host={this.getHost()}
|
|
||||||
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 withTranslation()(BottomBar);
|
|
@ -6,11 +6,11 @@ import UserGenPage from './UserGenPage';
|
|||||||
import MakerPage from './MakerPage';
|
import MakerPage from './MakerPage';
|
||||||
import BookPage from './BookPage';
|
import BookPage from './BookPage';
|
||||||
import OrderPage from './OrderPage';
|
import OrderPage from './OrderPage';
|
||||||
import BottomBar from './BottomBar';
|
import NavBar from './NavBar';
|
||||||
import { LearnDialog } from '../components/Dialogs';
|
import { LearnDialog } from '../components/Dialogs';
|
||||||
|
|
||||||
import { apiClient } from '../services/api';
|
import { apiClient } from '../services/api';
|
||||||
import checkVer from '../utils/checkVer';
|
import { checkVer } from '../utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Book,
|
Book,
|
||||||
@ -211,7 +211,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
|||||||
bottom: 0,
|
bottom: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<BottomBar
|
<NavBar
|
||||||
theme={theme}
|
theme={theme}
|
||||||
windowSize={windowSize}
|
windowSize={windowSize}
|
||||||
redirectTo={(location: string) => history.push(location)}
|
redirectTo={(location: string) => history.push(location)}
|
||||||
|
@ -5,7 +5,7 @@ import { Button, Grid, Paper, Collapse, Typography } from '@mui/material';
|
|||||||
|
|
||||||
import { LimitList, Maker, Book, Favorites } from '../../models';
|
import { LimitList, Maker, Book, Favorites } from '../../models';
|
||||||
|
|
||||||
import filterOrders from '../../utils/filterOrders';
|
import { filterOrders } from '../../utils';
|
||||||
|
|
||||||
import MakerForm from '../../components/MakerForm';
|
import MakerForm from '../../components/MakerForm';
|
||||||
import BookTable from '../../components/BookTable';
|
import BookTable from '../../components/BookTable';
|
||||||
|
@ -0,0 +1,633 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
Badge,
|
||||||
|
Tooltip,
|
||||||
|
ListItemAvatar,
|
||||||
|
Paper,
|
||||||
|
Grid,
|
||||||
|
IconButton,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
|
ListItemText,
|
||||||
|
ListItem,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemButton,
|
||||||
|
} from '@mui/material';
|
||||||
|
import MediaQuery from 'react-responsive';
|
||||||
|
import Flags from 'country-flag-icons/react/3x2';
|
||||||
|
import { Link as LinkRouter } from 'react-router-dom';
|
||||||
|
import { apiClient } from '../../services/api';
|
||||||
|
import { systemClient } from '../../services/System';
|
||||||
|
import RobotAvatar from '../../components/RobotAvatar';
|
||||||
|
|
||||||
|
// Icons
|
||||||
|
import BarChartIcon from '@mui/icons-material/BarChart';
|
||||||
|
import PeopleIcon from '@mui/icons-material/People';
|
||||||
|
import InventoryIcon from '@mui/icons-material/Inventory';
|
||||||
|
import SellIcon from '@mui/icons-material/Sell';
|
||||||
|
import SmartToyIcon from '@mui/icons-material/SmartToy';
|
||||||
|
import PercentIcon from '@mui/icons-material/Percent';
|
||||||
|
import PriceChangeIcon from '@mui/icons-material/PriceChange';
|
||||||
|
|
||||||
|
// Missing flags
|
||||||
|
import { CataloniaFlag, BasqueCountryFlag } from '../../components/Icons';
|
||||||
|
|
||||||
|
import {
|
||||||
|
CommunityDialog,
|
||||||
|
ExchangeSummaryDialog,
|
||||||
|
ProfileDialog,
|
||||||
|
StatsDialog,
|
||||||
|
UpdateClientDialog,
|
||||||
|
} from '../../components/Dialogs';
|
||||||
|
|
||||||
|
class NavBar extends Component {
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChangeLang = (e) => {
|
||||||
|
const { i18n } = this.props;
|
||||||
|
i18n.changeLanguage(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
LangSelect = () => {
|
||||||
|
const { i18n } = this.props;
|
||||||
|
const lang = i18n.resolvedLanguage == null ? 'en' : i18n.resolvedLanguage.substring(0, 2);
|
||||||
|
const flagProps = {
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
size='small'
|
||||||
|
value={lang}
|
||||||
|
inputProps={{
|
||||||
|
style: { textAlign: 'center' },
|
||||||
|
}}
|
||||||
|
renderValue={(value) => value.toUpperCase()}
|
||||||
|
onChange={this.handleChangeLang}
|
||||||
|
>
|
||||||
|
<MenuItem value={'en'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.US {...flagProps} />
|
||||||
|
</div>
|
||||||
|
EN
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'es'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.ES {...flagProps} />
|
||||||
|
</div>
|
||||||
|
ES
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'de'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.DE {...flagProps} />
|
||||||
|
</div>
|
||||||
|
DE
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'pl'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.PL {...flagProps} />
|
||||||
|
</div>
|
||||||
|
PL
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'fr'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.FR {...flagProps} />
|
||||||
|
</div>
|
||||||
|
FR
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'ru'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.RU {...flagProps} />
|
||||||
|
</div>
|
||||||
|
RU
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'it'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.IT {...flagProps} />
|
||||||
|
</div>
|
||||||
|
IT
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'pt'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.BR {...flagProps} />
|
||||||
|
</div>
|
||||||
|
PT
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'zh-si'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.CN {...flagProps} />
|
||||||
|
</div>
|
||||||
|
简体
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'zh-tr'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.CN {...flagProps} />
|
||||||
|
</div>
|
||||||
|
繁體
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'sv'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.SE {...flagProps} />
|
||||||
|
</div>
|
||||||
|
SV
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'cs'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.CZ {...flagProps} />
|
||||||
|
</div>
|
||||||
|
CS
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'th'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<Flags.TH {...flagProps} />
|
||||||
|
</div>
|
||||||
|
TH
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'ca'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<CataloniaFlag {...flagProps} />
|
||||||
|
</div>
|
||||||
|
CA
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={'eu'}>
|
||||||
|
<div style={{ width: 24, position: 'relative', top: 3 }}>
|
||||||
|
<BasqueCountryFlag {...flagProps} />
|
||||||
|
</div>
|
||||||
|
EU
|
||||||
|
</MenuItem>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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>
|
||||||
|
<CommunityDialog
|
||||||
|
open={this.state.openCommunity}
|
||||||
|
handleClickCloseCommunity={this.handleClickCloseCommunity}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<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 withTranslation()(NavBar);
|
@ -44,12 +44,10 @@ import ArticleIcon from '@mui/icons-material/Article';
|
|||||||
import HourglassTopIcon from '@mui/icons-material/HourglassTop';
|
import HourglassTopIcon from '@mui/icons-material/HourglassTop';
|
||||||
import CheckIcon from '@mui/icons-material/Check';
|
import CheckIcon from '@mui/icons-material/Check';
|
||||||
|
|
||||||
import { pn } from '../../utils/prettyNumbers';
|
import { pn, getWebln, statusBadgeColor } from '../../utils';
|
||||||
import { systemClient } from '../../services/System';
|
import { systemClient } from '../../services/System';
|
||||||
import { getWebln } from '../../utils/webln';
|
|
||||||
import { apiClient } from '../../services/api';
|
import { apiClient } from '../../services/api';
|
||||||
import RobotAvatar from '../../components/RobotAvatar';
|
import RobotAvatar from '../../components/RobotAvatar';
|
||||||
import statusBadgeColor from '../../utils/statusBadgeColor';
|
|
||||||
import { PaymentStringAsIcons } from '../../components/PaymentMethods';
|
import { PaymentStringAsIcons } from '../../components/PaymentMethods';
|
||||||
|
|
||||||
class OrderPage extends Component {
|
class OrderPage extends Component {
|
||||||
|
@ -21,9 +21,8 @@ import DownloadIcon from '@mui/icons-material/Download';
|
|||||||
import { RoboSatsNoTextIcon } from '../components/Icons';
|
import { RoboSatsNoTextIcon } from '../components/Icons';
|
||||||
|
|
||||||
import { sha256 } from 'js-sha256';
|
import { sha256 } from 'js-sha256';
|
||||||
import { genBase62Token, tokenStrength } from '../utils/token';
|
import { genBase62Token, tokenStrength, saveAsJson } from '../utils';
|
||||||
import { genKey } from '../utils/pgp';
|
import { genKey } from '../pgp';
|
||||||
import { saveAsJson } from '../utils/saveFile';
|
|
||||||
import { systemClient } from '../services/System';
|
import { systemClient } from '../services/System';
|
||||||
import { apiClient } from '../services/api/index';
|
import { apiClient } from '../services/api/index';
|
||||||
import RobotAvatar from '../components/RobotAvatar';
|
import RobotAvatar from '../components/RobotAvatar';
|
||||||
|
@ -19,15 +19,12 @@ import {
|
|||||||
import { DataGrid, GridPagination } from '@mui/x-data-grid';
|
import { DataGrid, GridPagination } from '@mui/x-data-grid';
|
||||||
import currencyDict from '../../../static/assets/currencies.json';
|
import currencyDict from '../../../static/assets/currencies.json';
|
||||||
import { Book, Favorites } from '../../models';
|
import { Book, Favorites } from '../../models';
|
||||||
import filterOrders from '../../utils/filterOrders';
|
import { filterOrders, hexToRgb, statusBadgeColor, pn, amountToString } from '../../utils';
|
||||||
import BookControl from './BookControl';
|
import BookControl from './BookControl';
|
||||||
|
|
||||||
import { FlagWithProps } from '../Icons';
|
import { FlagWithProps } from '../Icons';
|
||||||
import { pn, amountToString } from '../../utils/prettyNumbers';
|
|
||||||
import { PaymentStringAsIcons } from '../PaymentMethods';
|
import { PaymentStringAsIcons } from '../PaymentMethods';
|
||||||
import RobotAvatar from '../RobotAvatar';
|
import RobotAvatar from '../RobotAvatar';
|
||||||
import hexToRgb from '../../utils/hexToRgb';
|
|
||||||
import statusBadgeColor from '../../utils/statusBadgeColor';
|
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
import { Fullscreen, FullscreenExit, Refresh } from '@mui/icons-material';
|
import { Fullscreen, FullscreenExit, Refresh } from '@mui/icons-material';
|
||||||
|
@ -23,12 +23,10 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { Order, LimitList } from '../../../models';
|
import { Order, LimitList } from '../../../models';
|
||||||
import RobotAvatar from '../../RobotAvatar';
|
import RobotAvatar from '../../RobotAvatar';
|
||||||
import { amountToString } from '../../../utils/prettyNumbers';
|
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 median from '../../../utils/match';
|
|
||||||
import statusBadgeColor from '../../../utils/statusBadgeColor';
|
|
||||||
|
|
||||||
interface DepthChartProps {
|
interface DepthChartProps {
|
||||||
orders: Order[];
|
orders: Order[];
|
||||||
@ -93,7 +91,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
|||||||
if (xType === 'base_amount') {
|
if (xType === 'base_amount') {
|
||||||
const prices: number[] = enrichedOrders.map((order) => order?.base_amount || 0);
|
const prices: number[] = enrichedOrders.map((order) => order?.base_amount || 0);
|
||||||
|
|
||||||
const medianValue = ~~median(prices);
|
const medianValue = ~~matchMedian(prices);
|
||||||
const maxValue = prices.sort((a, b) => b - a).slice(0, 1)[0] || 1500;
|
const maxValue = prices.sort((a, b) => b - a).slice(0, 1)[0] || 1500;
|
||||||
const maxRange = maxValue - medianValue;
|
const maxRange = maxValue - medianValue;
|
||||||
const rangeSteps = maxRange / 10;
|
const rangeSteps = maxRange / 10;
|
||||||
@ -104,7 +102,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
|||||||
} else {
|
} else {
|
||||||
if (lastDayPremium === undefined) {
|
if (lastDayPremium === undefined) {
|
||||||
const premiums: number[] = enrichedOrders.map((order) => order?.premium || 0);
|
const premiums: number[] = enrichedOrders.map((order) => order?.premium || 0);
|
||||||
setCenter(~~median(premiums));
|
setCenter(~~matchMedian(premiums));
|
||||||
} else {
|
} else {
|
||||||
setCenter(lastDayPremium);
|
setCenter(lastDayPremium);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
Link,
|
Link,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import { saveAsJson } from '../../utils/saveFile';
|
import { saveAsJson } from '../../utils';
|
||||||
import { systemClient } from '../../services/System';
|
import { systemClient } from '../../services/System';
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
|
@ -21,7 +21,7 @@ import PriceChangeIcon from '@mui/icons-material/PriceChange';
|
|||||||
import BookIcon from '@mui/icons-material/Book';
|
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/prettyNumbers';
|
import { pn } from '../../utils';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import SmoothImage from 'react-smooth-image';
|
import SmoothImage from 'react-smooth-image';
|
||||||
import MediaQuery from 'react-responsive';
|
import MediaQuery from 'react-responsive';
|
||||||
|
import { pn } from '../../utils';
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
@ -148,7 +149,7 @@ const InfoDialog = ({ maxAmount, open, onClose }: Props): JSX.Element => {
|
|||||||
<p>
|
<p>
|
||||||
{t(
|
{t(
|
||||||
'Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).',
|
'Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).',
|
||||||
{ maxAmount },
|
{ maxAmount: pn(maxAmount) },
|
||||||
)}{' '}
|
)}{' '}
|
||||||
</p>
|
</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -37,7 +37,7 @@ import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
|
|||||||
import { UserNinjaIcon, BitcoinIcon } from '../Icons';
|
import { UserNinjaIcon, BitcoinIcon } from '../Icons';
|
||||||
|
|
||||||
import { systemClient } from '../../services/System';
|
import { systemClient } from '../../services/System';
|
||||||
import { getWebln } from '../../utils/webln';
|
import { getHost, getWebln } from '../../utils';
|
||||||
import RobotAvatar from '../RobotAvatar';
|
import RobotAvatar from '../RobotAvatar';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -51,7 +51,6 @@ interface Props {
|
|||||||
tgBotName: string;
|
tgBotName: string;
|
||||||
tgToken: string;
|
tgToken: string;
|
||||||
handleSubmitInvoiceClicked: (e: any, invoice: string) => void;
|
handleSubmitInvoiceClicked: (e: any, invoice: string) => void;
|
||||||
host: string;
|
|
||||||
showRewardsSpinner: boolean;
|
showRewardsSpinner: boolean;
|
||||||
withdrawn: boolean;
|
withdrawn: boolean;
|
||||||
badInvoice: boolean | string;
|
badInvoice: boolean | string;
|
||||||
@ -72,7 +71,6 @@ const ProfileDialog = ({
|
|||||||
tgBotName,
|
tgBotName,
|
||||||
tgToken,
|
tgToken,
|
||||||
handleSubmitInvoiceClicked,
|
handleSubmitInvoiceClicked,
|
||||||
host,
|
|
||||||
showRewardsSpinner,
|
showRewardsSpinner,
|
||||||
withdrawn,
|
withdrawn,
|
||||||
badInvoice,
|
badInvoice,
|
||||||
@ -83,6 +81,7 @@ const ProfileDialog = ({
|
|||||||
}: Props): JSX.Element => {
|
}: Props): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const host = getHost();
|
||||||
|
|
||||||
const [rewardInvoice, setRewardInvoice] = useState<string>('');
|
const [rewardInvoice, setRewardInvoice] = useState<string>('');
|
||||||
const [showRewards, setShowRewards] = useState<boolean>(false);
|
const [showRewards, setShowRewards] = useState<boolean>(false);
|
||||||
|
@ -23,7 +23,7 @@ import EqualizerIcon from '@mui/icons-material/Equalizer';
|
|||||||
|
|
||||||
import { AmbossIcon, BitcoinSignIcon, RoboSatsNoTextIcon } from '../Icons';
|
import { AmbossIcon, BitcoinSignIcon, RoboSatsNoTextIcon } from '../Icons';
|
||||||
|
|
||||||
import { pn } from '../../utils/prettyNumbers';
|
import { pn } from '../../utils';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
import { FlagWithProps } from '../Icons';
|
import { FlagWithProps } from '../Icons';
|
||||||
import RangeSlider from './RangeSlider';
|
import RangeSlider from './RangeSlider';
|
||||||
import currencyDict from '../../../static/assets/currencies.json';
|
import currencyDict from '../../../static/assets/currencies.json';
|
||||||
import { pn } from '../../utils/prettyNumbers';
|
import { pn } from '../../utils';
|
||||||
|
|
||||||
const RangeThumbComponent = function (props: object) {
|
const RangeThumbComponent = function (props: object) {
|
||||||
const { children, ...other } = props;
|
const { children, ...other } = props;
|
||||||
|
@ -37,7 +37,7 @@ import { FlagWithProps } from '../Icons';
|
|||||||
import AutocompletePayments from './AutocompletePayments';
|
import AutocompletePayments from './AutocompletePayments';
|
||||||
import AmountRange from './AmountRange';
|
import AmountRange from './AmountRange';
|
||||||
import currencyDict from '../../../static/assets/currencies.json';
|
import currencyDict from '../../../static/assets/currencies.json';
|
||||||
import { pn } from '../../utils/prettyNumbers';
|
import { 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';
|
||||||
|
@ -15,8 +15,8 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import ReconnectingWebSocket from 'reconnecting-websocket';
|
import ReconnectingWebSocket from 'reconnecting-websocket';
|
||||||
import { encryptMessage, decryptMessage } from '../../utils/pgp';
|
import { encryptMessage, decryptMessage } from '../../pgp';
|
||||||
import { saveAsJson } from '../../utils/saveFile';
|
import { saveAsJson } from '../../utils';
|
||||||
import { AuditPGPDialog } from '../Dialogs';
|
import { AuditPGPDialog } from '../Dialogs';
|
||||||
import RobotAvatar from '../RobotAvatar';
|
import RobotAvatar from '../RobotAvatar';
|
||||||
import { systemClient } from '../../services/System';
|
import { systemClient } from '../../services/System';
|
||||||
|
@ -18,8 +18,7 @@ import {
|
|||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { pn } from '../../utils/prettyNumbers';
|
import { pn, saveAsJson } from '../../utils';
|
||||||
import { saveAsJson } from '../../utils/saveFile';
|
|
||||||
import RobotAvatar from '../RobotAvatar';
|
import RobotAvatar from '../RobotAvatar';
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||||||
import { withTranslation, Trans } from 'react-i18next';
|
import { withTranslation, Trans } from 'react-i18next';
|
||||||
import { Paper, Alert, AlertTitle, Button, Link } from '@mui/material';
|
import { Paper, Alert, AlertTitle, Button, Link } from '@mui/material';
|
||||||
import MediaQuery from 'react-responsive';
|
import MediaQuery from 'react-responsive';
|
||||||
|
import { getHost } from '../utils';
|
||||||
|
|
||||||
class UnsafeAlert extends Component {
|
class UnsafeAlert extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -12,18 +13,10 @@ class UnsafeAlert extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getHost() {
|
|
||||||
const url =
|
|
||||||
window.location !== window.parent.location
|
|
||||||
? this.getHost(document.referrer)
|
|
||||||
: document.location.href;
|
|
||||||
return url.split('/')[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
isSelfhosted() {
|
isSelfhosted() {
|
||||||
const http = new XMLHttpRequest();
|
const http = new XMLHttpRequest();
|
||||||
try {
|
try {
|
||||||
http.open('HEAD', `${location.protocol}//${this.getHost()}/selfhosted`, false);
|
http.open('HEAD', `${location.protocol}//${getHost()}/selfhosted`, false);
|
||||||
http.send();
|
http.send();
|
||||||
return http.status === 200;
|
return http.status === 200;
|
||||||
} catch {
|
} catch {
|
||||||
@ -72,7 +65,7 @@ class UnsafeAlert extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show unsafe alert
|
// Show unsafe alert
|
||||||
if (!window.NativeRobosats && !this.safe_urls.includes(this.getHost())) {
|
if (!window.NativeRobosats && !this.safe_urls.includes(getHost())) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<MediaQuery minWidth={800}>
|
<MediaQuery minWidth={800}>
|
||||||
|
7
frontend/src/utils/getHost.ts
Normal file
7
frontend/src/utils/getHost.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const getHost = function () {
|
||||||
|
const url =
|
||||||
|
window.location != window.parent.location ? document.referrer : document.location.href;
|
||||||
|
return url.split('/')[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getHost;
|
11
frontend/src/utils/index.ts
Normal file
11
frontend/src/utils/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export { default as checkVer } from './checkVer';
|
||||||
|
export { default as filterOrders } from './filterOrders';
|
||||||
|
export { default as getHost } from './getHost';
|
||||||
|
export { default as hexToRgb } from './hexToRgb';
|
||||||
|
export { default as matchMedian } from './match';
|
||||||
|
export { default as pn } from './prettyNumbers';
|
||||||
|
export { amountToString } from './prettyNumbers';
|
||||||
|
export { default as saveAsJson } from './saveFile';
|
||||||
|
export { default as statusBadgeColor } from './saveFile';
|
||||||
|
export { genBase62Token, tokenStrength } from './token';
|
||||||
|
export { default as getWebln } from './webln';
|
@ -1,7 +1,7 @@
|
|||||||
export const median = (arr: number[]) => {
|
export const matchMedian = (arr: number[]) => {
|
||||||
const mid = Math.floor(arr.length / 2);
|
const mid = Math.floor(arr.length / 2);
|
||||||
const nums = [...arr].sort((a, b) => a - b);
|
const nums = [...arr].sort((a, b) => a - b);
|
||||||
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
|
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default median;
|
export default matchMedian;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* @param {filename} data -- object to save
|
* @param {filename} data -- object to save
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const saveAsJson = (filename, dataObjToWrite) => {
|
const saveAsJson = (filename, dataObjToWrite) => {
|
||||||
const blob = new Blob([JSON.stringify(dataObjToWrite, null, 2)], { type: 'text/json' });
|
const blob = new Blob([JSON.stringify(dataObjToWrite, null, 2)], { type: 'text/json' });
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
|
|
||||||
@ -20,3 +20,5 @@ export const saveAsJson = (filename, dataObjToWrite) => {
|
|||||||
link.dispatchEvent(evt);
|
link.dispatchEvent(evt);
|
||||||
link.remove();
|
link.remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default saveAsJson;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { requestProvider, WeblnProvider } from 'webln';
|
import { requestProvider, WeblnProvider } from 'webln';
|
||||||
|
|
||||||
export 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) => {
|
||||||
try {
|
try {
|
||||||
const webln = await requestProvider();
|
const webln = await requestProvider();
|
||||||
@ -16,3 +16,5 @@ export const getWebln = async (): Promise<WeblnProvider> => {
|
|||||||
|
|
||||||
return await resultPromise;
|
return await resultPromise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default getWebln;
|
||||||
|
Loading…
Reference in New Issue
Block a user