mirror of
https://github.com/RoboSats/robosats.git
synced 2024-12-13 10:56:24 +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 BookPage from './BookPage';
|
||||
import OrderPage from './OrderPage';
|
||||
import BottomBar from './BottomBar';
|
||||
import NavBar from './NavBar';
|
||||
import { LearnDialog } from '../components/Dialogs';
|
||||
|
||||
import { apiClient } from '../services/api';
|
||||
import checkVer from '../utils/checkVer';
|
||||
import { checkVer } from '../utils';
|
||||
|
||||
import {
|
||||
Book,
|
||||
@ -211,7 +211,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => {
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<BottomBar
|
||||
<NavBar
|
||||
theme={theme}
|
||||
windowSize={windowSize}
|
||||
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 filterOrders from '../../utils/filterOrders';
|
||||
import { filterOrders } from '../../utils';
|
||||
|
||||
import MakerForm from '../../components/MakerForm';
|
||||
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 CheckIcon from '@mui/icons-material/Check';
|
||||
|
||||
import { pn } from '../../utils/prettyNumbers';
|
||||
import { pn, getWebln, statusBadgeColor } from '../../utils';
|
||||
import { systemClient } from '../../services/System';
|
||||
import { getWebln } from '../../utils/webln';
|
||||
import { apiClient } from '../../services/api';
|
||||
import RobotAvatar from '../../components/RobotAvatar';
|
||||
import statusBadgeColor from '../../utils/statusBadgeColor';
|
||||
import { PaymentStringAsIcons } from '../../components/PaymentMethods';
|
||||
|
||||
class OrderPage extends Component {
|
||||
|
@ -21,9 +21,8 @@ import DownloadIcon from '@mui/icons-material/Download';
|
||||
import { RoboSatsNoTextIcon } from '../components/Icons';
|
||||
|
||||
import { sha256 } from 'js-sha256';
|
||||
import { genBase62Token, tokenStrength } from '../utils/token';
|
||||
import { genKey } from '../utils/pgp';
|
||||
import { saveAsJson } from '../utils/saveFile';
|
||||
import { genBase62Token, tokenStrength, saveAsJson } from '../utils';
|
||||
import { genKey } from '../pgp';
|
||||
import { systemClient } from '../services/System';
|
||||
import { apiClient } from '../services/api/index';
|
||||
import RobotAvatar from '../components/RobotAvatar';
|
||||
|
@ -19,15 +19,12 @@ import {
|
||||
import { DataGrid, GridPagination } from '@mui/x-data-grid';
|
||||
import currencyDict from '../../../static/assets/currencies.json';
|
||||
import { Book, Favorites } from '../../models';
|
||||
import filterOrders from '../../utils/filterOrders';
|
||||
import { filterOrders, hexToRgb, statusBadgeColor, pn, amountToString } from '../../utils';
|
||||
import BookControl from './BookControl';
|
||||
|
||||
import { FlagWithProps } from '../Icons';
|
||||
import { pn, amountToString } from '../../utils/prettyNumbers';
|
||||
import { PaymentStringAsIcons } from '../PaymentMethods';
|
||||
import RobotAvatar from '../RobotAvatar';
|
||||
import hexToRgb from '../../utils/hexToRgb';
|
||||
import statusBadgeColor from '../../utils/statusBadgeColor';
|
||||
|
||||
// Icons
|
||||
import { Fullscreen, FullscreenExit, Refresh } from '@mui/icons-material';
|
||||
|
@ -23,12 +23,10 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Order, LimitList } from '../../../models';
|
||||
import RobotAvatar from '../../RobotAvatar';
|
||||
import { amountToString } from '../../../utils/prettyNumbers';
|
||||
import { amountToString, matchMedian, statusBadgeColor } from '../../../utils';
|
||||
import currencyDict from '../../../../static/assets/currencies.json';
|
||||
import { PaymentStringAsIcons } from '../../PaymentMethods';
|
||||
import getNivoScheme from '../NivoScheme';
|
||||
import median from '../../../utils/match';
|
||||
import statusBadgeColor from '../../../utils/statusBadgeColor';
|
||||
|
||||
interface DepthChartProps {
|
||||
orders: Order[];
|
||||
@ -93,7 +91,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
||||
if (xType === 'base_amount') {
|
||||
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 maxRange = maxValue - medianValue;
|
||||
const rangeSteps = maxRange / 10;
|
||||
@ -104,7 +102,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
|
||||
} else {
|
||||
if (lastDayPremium === undefined) {
|
||||
const premiums: number[] = enrichedOrders.map((order) => order?.premium || 0);
|
||||
setCenter(~~median(premiums));
|
||||
setCenter(~~matchMedian(premiums));
|
||||
} else {
|
||||
setCenter(lastDayPremium);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
Link,
|
||||
} from '@mui/material';
|
||||
|
||||
import { saveAsJson } from '../../utils/saveFile';
|
||||
import { saveAsJson } from '../../utils';
|
||||
import { systemClient } from '../../services/System';
|
||||
|
||||
// Icons
|
||||
|
@ -21,7 +21,7 @@ import PriceChangeIcon from '@mui/icons-material/PriceChange';
|
||||
import BookIcon from '@mui/icons-material/Book';
|
||||
import LinkIcon from '@mui/icons-material/Link';
|
||||
|
||||
import { pn } from '../../utils/prettyNumbers';
|
||||
import { pn } from '../../utils';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
} from '@mui/material';
|
||||
import SmoothImage from 'react-smooth-image';
|
||||
import MediaQuery from 'react-responsive';
|
||||
import { pn } from '../../utils';
|
||||
|
||||
// Icons
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
@ -148,7 +149,7 @@ const InfoDialog = ({ maxAmount, open, onClose }: Props): JSX.Element => {
|
||||
<p>
|
||||
{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!).',
|
||||
{ maxAmount },
|
||||
{ maxAmount: pn(maxAmount) },
|
||||
)}{' '}
|
||||
</p>
|
||||
</Typography>
|
||||
|
@ -37,7 +37,7 @@ import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
|
||||
import { UserNinjaIcon, BitcoinIcon } from '../Icons';
|
||||
|
||||
import { systemClient } from '../../services/System';
|
||||
import { getWebln } from '../../utils/webln';
|
||||
import { getHost, getWebln } from '../../utils';
|
||||
import RobotAvatar from '../RobotAvatar';
|
||||
|
||||
interface Props {
|
||||
@ -51,7 +51,6 @@ interface Props {
|
||||
tgBotName: string;
|
||||
tgToken: string;
|
||||
handleSubmitInvoiceClicked: (e: any, invoice: string) => void;
|
||||
host: string;
|
||||
showRewardsSpinner: boolean;
|
||||
withdrawn: boolean;
|
||||
badInvoice: boolean | string;
|
||||
@ -72,7 +71,6 @@ const ProfileDialog = ({
|
||||
tgBotName,
|
||||
tgToken,
|
||||
handleSubmitInvoiceClicked,
|
||||
host,
|
||||
showRewardsSpinner,
|
||||
withdrawn,
|
||||
badInvoice,
|
||||
@ -83,6 +81,7 @@ const ProfileDialog = ({
|
||||
}: Props): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const host = getHost();
|
||||
|
||||
const [rewardInvoice, setRewardInvoice] = useState<string>('');
|
||||
const [showRewards, setShowRewards] = useState<boolean>(false);
|
||||
|
@ -23,7 +23,7 @@ import EqualizerIcon from '@mui/icons-material/Equalizer';
|
||||
|
||||
import { AmbossIcon, BitcoinSignIcon, RoboSatsNoTextIcon } from '../Icons';
|
||||
|
||||
import { pn } from '../../utils/prettyNumbers';
|
||||
import { pn } from '../../utils';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
import { FlagWithProps } from '../Icons';
|
||||
import RangeSlider from './RangeSlider';
|
||||
import currencyDict from '../../../static/assets/currencies.json';
|
||||
import { pn } from '../../utils/prettyNumbers';
|
||||
import { pn } from '../../utils';
|
||||
|
||||
const RangeThumbComponent = function (props: object) {
|
||||
const { children, ...other } = props;
|
||||
|
@ -37,7 +37,7 @@ import { FlagWithProps } from '../Icons';
|
||||
import AutocompletePayments from './AutocompletePayments';
|
||||
import AmountRange from './AmountRange';
|
||||
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 { LoadingButton } from '@mui/lab';
|
||||
|
@ -15,8 +15,8 @@ import {
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import ReconnectingWebSocket from 'reconnecting-websocket';
|
||||
import { encryptMessage, decryptMessage } from '../../utils/pgp';
|
||||
import { saveAsJson } from '../../utils/saveFile';
|
||||
import { encryptMessage, decryptMessage } from '../../pgp';
|
||||
import { saveAsJson } from '../../utils';
|
||||
import { AuditPGPDialog } from '../Dialogs';
|
||||
import RobotAvatar from '../RobotAvatar';
|
||||
import { systemClient } from '../../services/System';
|
||||
|
@ -18,8 +18,7 @@ import {
|
||||
AccordionDetails,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import { pn } from '../../utils/prettyNumbers';
|
||||
import { saveAsJson } from '../../utils/saveFile';
|
||||
import { pn, saveAsJson } from '../../utils';
|
||||
import RobotAvatar from '../RobotAvatar';
|
||||
|
||||
// Icons
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
import { Paper, Alert, AlertTitle, Button, Link } from '@mui/material';
|
||||
import MediaQuery from 'react-responsive';
|
||||
import { getHost } from '../utils';
|
||||
|
||||
class UnsafeAlert extends Component {
|
||||
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() {
|
||||
const http = new XMLHttpRequest();
|
||||
try {
|
||||
http.open('HEAD', `${location.protocol}//${this.getHost()}/selfhosted`, false);
|
||||
http.open('HEAD', `${location.protocol}//${getHost()}/selfhosted`, false);
|
||||
http.send();
|
||||
return http.status === 200;
|
||||
} catch {
|
||||
@ -72,7 +65,7 @@ class UnsafeAlert extends Component {
|
||||
}
|
||||
|
||||
// Show unsafe alert
|
||||
if (!window.NativeRobosats && !this.safe_urls.includes(this.getHost())) {
|
||||
if (!window.NativeRobosats && !this.safe_urls.includes(getHost())) {
|
||||
return (
|
||||
<div>
|
||||
<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 nums = [...arr].sort((a, b) => a - b);
|
||||
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
|
||||
*/
|
||||
|
||||
export const saveAsJson = (filename, dataObjToWrite) => {
|
||||
const saveAsJson = (filename, dataObjToWrite) => {
|
||||
const blob = new Blob([JSON.stringify(dataObjToWrite, null, 2)], { type: 'text/json' });
|
||||
const link = document.createElement('a');
|
||||
|
||||
@ -20,3 +20,5 @@ export const saveAsJson = (filename, dataObjToWrite) => {
|
||||
link.dispatchEvent(evt);
|
||||
link.remove();
|
||||
};
|
||||
|
||||
export default saveAsJson;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { requestProvider, WeblnProvider } from 'webln';
|
||||
|
||||
export const getWebln = async (): Promise<WeblnProvider> => {
|
||||
const getWebln = async (): Promise<WeblnProvider> => {
|
||||
const resultPromise = new Promise<WeblnProvider>(async (resolve, reject) => {
|
||||
try {
|
||||
const webln = await requestProvider();
|
||||
@ -16,3 +16,5 @@ export const getWebln = async (): Promise<WeblnProvider> => {
|
||||
|
||||
return await resultPromise;
|
||||
};
|
||||
|
||||
export default getWebln;
|
||||
|
Loading…
Reference in New Issue
Block a user