Add functional homepage (#289)

* App as functional component

* Add Main component WIP

* Add Maker and Book page to new main.tsx

* Add old UserGen and BottomBar to new main.tsx

* Small fixes

* Try out to revert depth chart

* Small fixes (more)
This commit is contained in:
Reckless_Satoshi 2022-10-20 17:24:53 +00:00 committed by GitHub
parent 130bd2222b
commit 04126ae0bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 858 additions and 860 deletions

View File

@ -3235,11 +3235,11 @@
} }
}, },
"node_modules/@mui/utils": { "node_modules/@mui/utils": {
"version": "5.10.3", "version": "5.10.9",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.3.tgz", "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.9.tgz",
"integrity": "sha512-4jXMDPfx6bpMVuheLaOpKTjpzw39ogAZLeaLj5+RJec3E37/hAZMYjURfblLfTWMMoGoqkY03mNsZaEwNobBow==", "integrity": "sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.9", "@babel/runtime": "^7.19.0",
"@types/prop-types": "^15.7.5", "@types/prop-types": "^15.7.5",
"@types/react-is": "^16.7.1 || ^17.0.0", "@types/react-is": "^16.7.1 || ^17.0.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
@ -17137,11 +17137,11 @@
"requires": {} "requires": {}
}, },
"@mui/utils": { "@mui/utils": {
"version": "5.10.3", "version": "5.10.9",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.3.tgz", "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.9.tgz",
"integrity": "sha512-4jXMDPfx6bpMVuheLaOpKTjpzw39ogAZLeaLj5+RJec3E37/hAZMYjURfblLfTWMMoGoqkY03mNsZaEwNobBow==", "integrity": "sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==",
"requires": { "requires": {
"@babel/runtime": "^7.18.9", "@babel/runtime": "^7.19.0",
"@types/prop-types": "^15.7.5", "@types/prop-types": "^15.7.5",
"@types/react-is": "^16.7.1 || ^17.0.0", "@types/react-is": "^16.7.1 || ^17.0.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",

View File

@ -1,137 +0,0 @@
import React, { Component, Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import HomePage from './HomePage';
import { CssBaseline, IconButton } from '@mui/material';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import UnsafeAlert from './UnsafeAlert';
import { LearnDialog } from './Dialogs';
import TorConnection from './TorConnection';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18n/Web';
// Icons
import DarkModeIcon from '@mui/icons-material/DarkMode';
import LightModeIcon from '@mui/icons-material/LightMode';
import SchoolIcon from '@mui/icons-material/School';
import { systemClient } from '../services/System';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
expandedSettings: false,
openLearn: false,
theme: createTheme({
palette: {
mode:
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light',
background: {
default:
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? '#070707'
: '#fff',
},
},
}),
};
}
handleThemeChange = () => {
if (this.state.theme.palette.mode === 'light') {
this.setState(({ theme }) => ({
theme: createTheme({
typography: {
fontSize: theme.typography.fontSize,
},
palette: {
mode: 'dark',
background: {
default: '#070707',
},
},
}),
}));
}
if (this.state.theme.palette.mode === 'dark') {
this.setState(({ theme }) => ({
theme: createTheme({
typography: {
fontSize: theme.typography.fontSize,
},
palette: {
mode: 'light',
background: {
default: '#fff',
},
},
}),
}));
}
};
onSettingsClick = () => {
this.setState({
expandedSettings: !this.state.expandedSettings,
});
};
onZoomClick = (direction) => {
let zoomChange;
direction === 'out' ? (zoomChange = -1) : (zoomChange = 1);
this.setState(({ theme }) => ({
theme: {
...theme,
typography: {
fontSize: this.state.theme.typography.fontSize + zoomChange,
},
},
}));
};
render() {
return (
<Suspense fallback='loading language'>
<I18nextProvider i18n={i18n}>
<ThemeProvider theme={this.state.theme}>
<CssBaseline />
<LearnDialog
open={this.state.openLearn}
onClose={() => this.setState({ openLearn: false })}
/>
<TorConnection />
<IconButton
color='inherit'
sx={{ position: 'fixed', right: '34px', color: 'text.secondary' }}
onClick={() => this.setState({ openLearn: true })}
>
<SchoolIcon />
</IconButton>
<IconButton
color='inherit'
sx={{ position: 'fixed', right: '0px', color: 'text.secondary' }}
onClick={() => this.handleThemeChange()}
>
{this.state.theme.palette.mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
</IconButton>
<UnsafeAlert className='unsafeAlert' />
<HomePage {...this.state} />
</ThemeProvider>
</I18nextProvider>
</Suspense>
);
}
}
const loadApp = () => {
if (systemClient.loading) {
setTimeout(loadApp, 200);
} else {
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<App />);
}
};
loadApp();

View File

@ -0,0 +1,102 @@
import React, { Suspense, useState } from 'react';
import ReactDOM from 'react-dom/client';
import Main from './Main';
import { CssBaseline, IconButton } from '@mui/material';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import UnsafeAlert from './UnsafeAlert';
import { LearnDialog } from './Dialogs';
import TorConnection from './TorConnection';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18n/Web';
// Icons
import DarkModeIcon from '@mui/icons-material/DarkMode';
import LightModeIcon from '@mui/icons-material/LightMode';
import SchoolIcon from '@mui/icons-material/School';
import { systemClient } from '../services/System';
const defaultTheme = createTheme({
palette: {
mode:
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light',
background: {
default:
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? '#070707'
: '#fff',
},
},
});
const App = (): JSX.Element => {
const [openLearn, setOpenLearn] = useState<boolean>(false);
const [theme, setTheme] = useState(defaultTheme);
const handleModeChange = function () {
if (theme.palette.mode === 'light') {
setTheme(
createTheme({
palette: {
mode: 'dark',
background: {
default: '#070707',
},
},
}),
);
} else if (theme.palette.mode === 'dark') {
setTheme(
createTheme({
palette: {
mode: 'light',
background: {
default: '#fff',
},
},
}),
);
}
};
return (
<Suspense fallback='loading language'>
<I18nextProvider i18n={i18n}>
<ThemeProvider theme={theme}>
<CssBaseline />
<LearnDialog open={openLearn} onClose={() => setOpenLearn(false)} />
<TorConnection />
<IconButton
color='inherit'
sx={{ position: 'fixed', right: '34px', color: 'text.secondary' }}
onClick={() => setOpenLearn(true)}
>
<SchoolIcon />
</IconButton>
<IconButton
color='inherit'
sx={{ position: 'fixed', right: '0px', color: 'text.secondary' }}
onClick={() => handleModeChange()}
>
{theme.palette.mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
</IconButton>
<UnsafeAlert className='unsafeAlert' />
<Main />
</ThemeProvider>
</I18nextProvider>
</Suspense>
);
};
const loadApp = () => {
if (systemClient.loading) {
setTimeout(loadApp, 200);
} else {
const root = ReactDOM.createRoot(document.getElementById('app') ?? new HTMLElement());
root.render(<App />);
}
};
loadApp();

View File

@ -5,7 +5,7 @@ import { useHistory } from 'react-router-dom';
import currencyDict from '../../../static/assets/currencies.json'; import currencyDict from '../../../static/assets/currencies.json';
import DepthChart from '../Charts/DepthChart'; import DepthChart from '../Charts/DepthChart';
import { Order, LimitList, Maker } from '../../models'; import { Book, Favorites, LimitList, Maker } from '../../models';
// Icons // Icons
import { BarChart, FormatListBulleted } from '@mui/icons-material'; import { BarChart, FormatListBulleted } from '@mui/icons-material';
@ -13,43 +13,37 @@ import BookTable from './BookTable';
import { MakerForm } from '../MakerPage'; import { MakerForm } from '../MakerPage';
interface BookPageProps { interface BookPageProps {
bookLoading?: boolean; book: Book;
bookRefreshing?: boolean; limits: { list: LimitList; loading: boolean };
loadingLimits: boolean;
lastDayPremium: number;
orders: Order[];
limits: LimitList;
fetchLimits: () => void; fetchLimits: () => void;
type: number; fav: Favorites;
currency: number; setFav: (state: Favorites) => void;
windowWidth: number; fetchBook: () => void;
windowHeight: number; windowSize: { width: number; height: number };
fetchBook: (loading: boolean, refreshing: boolean) => void; lastDayPremium: number;
setAppState: (state: object) => void; maker: Maker;
setMaker: (state: Maker) => void;
} }
const BookPage = ({ const BookPage = ({
bookLoading = false,
bookRefreshing = false,
lastDayPremium = 0, lastDayPremium = 0,
loadingLimits,
orders = [],
limits, limits,
fetchLimits, book = { orders: [], loading: true },
type,
currency,
windowWidth,
windowHeight,
setAppState,
fetchBook, fetchBook,
fetchLimits,
fav,
setFav,
maker,
setMaker,
windowSize,
}: BookPageProps): JSX.Element => { }: BookPageProps): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
const [view, setView] = useState<'list' | 'depth'>('list'); const [view, setView] = useState<'list' | 'depth'>('list');
const [openMaker, setOpenMaker] = useState<boolean>(false); const [openMaker, setOpenMaker] = useState<boolean>(false);
const doubleView = windowWidth > 115; const doubleView = windowSize.width > 115;
const width = windowWidth * 0.9; const width = windowSize.width * 0.9;
const maxBookTableWidth = 85; const maxBookTableWidth = 85;
const chartWidthEm = width - maxBookTableWidth; const chartWidthEm = width - maxBookTableWidth;
@ -72,10 +66,8 @@ const BookPage = ({
badSatoshisText: '', badSatoshisText: '',
}; };
const [maker, setMaker] = useState<Maker>(defaultMaker);
useEffect(() => { useEffect(() => {
if (orders.length < 1) { if (book.orders.length < 1) {
fetchBook(true, false); fetchBook(true, false);
} else { } else {
fetchBook(false, true); fetchBook(false, true);
@ -84,11 +76,11 @@ const BookPage = ({
const handleCurrencyChange = function (e) { const handleCurrencyChange = function (e) {
const currency = e.target.value; const currency = e.target.value;
setAppState({ currency }); setFav({ ...fav, currency });
}; };
const handleTypeChange = function (mouseEvent, val) { const handleTypeChange = function (mouseEvent, val) {
setAppState({ type: val }); setFav({ ...fav, type: val });
}; };
const NoOrdersFound = function () { const NoOrdersFound = function () {
@ -102,12 +94,14 @@ const BookPage = ({
> >
<Grid item> <Grid item>
<Typography align='center' component='h5' variant='h5'> <Typography align='center' component='h5' variant='h5'>
{type == 0 {fav.type == 0
? t('No orders found to sell BTC for {{currencyCode}}', { ? t('No orders found to sell BTC for {{currencyCode}}', {
currencyCode: currency == 0 ? t('ANY') : currencyDict[currency.toString()], currencyCode:
fav.currency == 0 ? t('ANY') : currencyDict[fav.currency.toString()],
}) })
: t('No orders found to buy BTC for {{currencyCode}}', { : t('No orders found to buy BTC for {{currencyCode}}', {
currencyCode: currency == 0 ? t('ANY') : currencyDict[currency.toString()], currencyCode:
fav.currency == 0 ? t('ANY') : currencyDict[fav.currency.toString()],
})} })}
</Typography> </Typography>
</Grid> </Grid>
@ -159,14 +153,11 @@ const BookPage = ({
<MakerForm <MakerForm
limits={limits} limits={limits}
fetchLimits={fetchLimits} fetchLimits={fetchLimits}
loadingLimits={loadingLimits}
pricingMethods={false} pricingMethods={false}
setAppState={setAppState}
maker={maker} maker={maker}
defaultMaker={defaultMaker}
setMaker={setMaker} setMaker={setMaker}
type={type} fav={fav}
currency={currency} setFav={setFav}
/> />
</Box> </Box>
</Dialog> </Dialog>
@ -180,20 +171,17 @@ const BookPage = ({
justifyContent='center' justifyContent='center'
spacing={1} spacing={1}
direction='row' direction='row'
style={{ width: `${windowWidth}em` }} style={{ width: `${windowSize.width}em` }}
> >
<Grid item> <Grid item>
<BookTable <BookTable
loading={bookLoading} clickRefresh={() => fetchBook()}
refreshing={bookRefreshing} book={book}
clickRefresh={() => fetchBook(false, true)} fav={fav}
orders={orders}
type={type}
currency={currency}
maxWidth={maxBookTableWidth} // EM units maxWidth={maxBookTableWidth} // EM units
maxHeight={windowHeight * 0.825 - 5} // EM units maxHeight={windowSize.height * 0.825 - 5} // EM units
fullWidth={windowWidth} // EM units fullWidth={windowSize.width} // EM units
fullHeight={windowHeight} // EM units fullHeight={windowSize.height} // EM units
defaultFullscreen={false} defaultFullscreen={false}
onCurrencyChange={handleCurrencyChange} onCurrencyChange={handleCurrencyChange}
onTypeChange={handleTypeChange} onTypeChange={handleTypeChange}
@ -202,41 +190,33 @@ const BookPage = ({
</Grid> </Grid>
<Grid item> <Grid item>
<DepthChart <DepthChart
orders={orders} orders={book.orders}
lastDayPremium={lastDayPremium} lastDayPremium={lastDayPremium}
currency={currency} currency={fav.currency}
compact={true} limits={limits.list}
setAppState={setAppState}
limits={limits}
maxWidth={chartWidthEm} // EM units maxWidth={chartWidthEm} // EM units
maxHeight={windowHeight * 0.825 - 5} // EM units maxHeight={windowSize.height * 0.825 - 5} // EM units
/> />
</Grid> </Grid>
</Grid> </Grid>
) : view === 'depth' ? ( ) : view === 'depth' ? (
<DepthChart <DepthChart
bookLoading={bookLoading} orders={book.orders}
orders={orders}
lastDayPremium={lastDayPremium} lastDayPremium={lastDayPremium}
currency={currency} currency={fav.currency}
compact={true} limits={limits.list}
setAppState={setAppState} maxWidth={windowSize.width * 0.8} // EM units
limits={limits} maxHeight={windowSize.height * 0.825 - 5} // EM units
maxWidth={windowWidth * 0.8} // EM units
maxHeight={windowHeight * 0.825 - 5} // EM units
/> />
) : ( ) : (
<BookTable <BookTable
loading={bookLoading} book={book}
refreshing={bookRefreshing} clickRefresh={() => fetchBook()}
clickRefresh={() => fetchBook(false, true)} fav={fav}
orders={orders} maxWidth={windowSize.width * 0.97} // EM units
type={type} maxHeight={windowSize.height * 0.825 - 5} // EM units
currency={currency} fullWidth={windowSize.width} // EM units
maxWidth={windowWidth * 0.97} // EM units fullHeight={windowSize.height} // EM units
maxHeight={windowHeight * 0.825 - 5} // EM units
fullWidth={windowWidth} // EM units
fullHeight={windowHeight} // EM units
defaultFullscreen={false} defaultFullscreen={false}
onCurrencyChange={handleCurrencyChange} onCurrencyChange={handleCurrencyChange}
onTypeChange={handleTypeChange} onTypeChange={handleTypeChange}

View File

@ -18,7 +18,7 @@ import {
} from '@mui/material'; } from '@mui/material';
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 { Order } from '../../models'; import { Book, Favorites } from '../../models';
import filterOrders from '../../utils/filterOrders'; import filterOrders from '../../utils/filterOrders';
import BookControl from './BookControl'; import BookControl from './BookControl';
@ -30,15 +30,12 @@ import hexToRgb from '../../utils/hexToRgb';
import statusBadgeColor from '../../utils/statusBadgeColor'; import statusBadgeColor from '../../utils/statusBadgeColor';
// Icons // Icons
import { Fullscreen, FullscreenExit, Refresh, WidthFull } from '@mui/icons-material'; import { Fullscreen, FullscreenExit, Refresh } from '@mui/icons-material';
interface Props { interface Props {
loading?: boolean;
refreshing?: boolean;
clickRefresh?: () => void; clickRefresh?: () => void;
orders: Order[]; book: Book;
type: number; fav?: Favorites;
currency: number;
maxWidth: number; maxWidth: number;
maxHeight: number; maxHeight: number;
fullWidth?: number; fullWidth?: number;
@ -46,18 +43,15 @@ interface Props {
defaultFullscreen: boolean; defaultFullscreen: boolean;
showControls?: boolean; showControls?: boolean;
showFooter?: boolean; showFooter?: boolean;
onCurrencyChange?: () => void; onCurrencyChange?: (e: any) => void;
onTypeChange?: () => void; onTypeChange?: (mouseEvent: any, val: number) => void;
noResultsOverlay?: JSX.Element; noResultsOverlay?: () => JSX.Element;
} }
const BookTable = ({ const BookTable = ({
loading = false,
refreshing = false,
clickRefresh, clickRefresh,
orders, book,
type, fav,
currency,
maxWidth, maxWidth,
maxHeight, maxHeight,
fullWidth, fullWidth,
@ -666,8 +660,8 @@ const BookTable = ({
return ( return (
<BookControl <BookControl
width={width} width={width}
type={type} type={fav.type}
currency={currency} currency={fav.currency}
onCurrencyChange={onCurrencyChange} onCurrencyChange={onCurrencyChange}
onTypeChange={onTypeChange} onTypeChange={onTypeChange}
paymentMethod={paymentMethods} paymentMethod={paymentMethods}
@ -702,17 +696,17 @@ const BookTable = ({
rows={ rows={
showControls showControls
? filterOrders({ ? filterOrders({
orders, orders: book.orders,
baseFilter: { currency, type }, baseFilter: fav,
paymentMethods, paymentMethods,
}) })
: orders : book.orders
} }
loading={loading || refreshing} loading={book.loading}
columns={columns} columns={columns}
hideFooter={!showFooter} hideFooter={!showFooter}
components={gridComponents()} components={gridComponents()}
pageSize={loading ? 0 : pageSize} pageSize={book.loading && book.orders.length == 0 ? 0 : pageSize}
rowsPerPageOptions={width < 22 ? [] : [0, pageSize, defaultPageSize * 2, 50, 100]} rowsPerPageOptions={width < 22 ? [] : [0, pageSize, defaultPageSize * 2, 50, 100]}
onPageSizeChange={(newPageSize) => { onPageSizeChange={(newPageSize) => {
setPageSize(newPageSize); setPageSize(newPageSize);
@ -728,16 +722,20 @@ const BookTable = ({
<Paper style={{ width: '100%', height: '100%', overflow: 'auto' }}> <Paper style={{ width: '100%', height: '100%', overflow: 'auto' }}>
<DataGrid <DataGrid
localeText={localeText} localeText={localeText}
rows={orders.filter( rows={
(order) => showControls
(order.type == type || type == null) && ? filterOrders({
(order.currency == currency || currency == 0), orders: book.orders,
)} baseFilter: fav,
loading={loading || refreshing} paymentMethods,
})
: book.orders
}
loading={book.loading}
columns={columns} columns={columns}
hideFooter={!showFooter} hideFooter={!showFooter}
components={gridComponents()} components={gridComponents()}
pageSize={loading ? 0 : pageSize} pageSize={book.loading && book.orders.length == 0 ? 0 : pageSize}
rowsPerPageOptions={[0, pageSize, defaultPageSize * 2, 50, 100]} rowsPerPageOptions={[0, pageSize, defaultPageSize * 2, 50, 100]}
onPageSizeChange={(newPageSize) => { onPageSizeChange={(newPageSize) => {
setPageSize(newPageSize); setPageSize(newPageSize);

View File

@ -4,7 +4,6 @@ import {
Badge, Badge,
Tooltip, Tooltip,
ListItemAvatar, ListItemAvatar,
Avatar,
Paper, Paper,
Grid, Grid,
IconButton, IconButton,
@ -42,31 +41,16 @@ import {
UpdateClientDialog, UpdateClientDialog,
} from './Dialogs'; } from './Dialogs';
import checkVer from '../utils/checkVer';
class BottomBar extends Component { class BottomBar extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
profileShown: false,
openStatsForNerds: false, openStatsForNerds: false,
openCommuniy: false, openCommunity: false,
openExchangeSummary: false, openExchangeSummary: false,
openClaimRewards: false, openClaimRewards: false,
openUpdateClient: false,
num_public_buy_orders: 0,
num_public_sell_orders: 0,
book_liquidity: 0,
active_robots_today: 0,
maker_fee: 0,
taker_fee: 0,
last_day_nonkyc_btc_premium: 0,
last_day_volume: 0,
lifetime_volume: 0,
robosats_running_commit_hash: '000000000000000',
openProfile: false, openProfile: false,
profileShown: false,
alternative_site: 'robosats...',
node_id: '00000000',
showRewards: false, showRewards: false,
rewardInvoice: null, rewardInvoice: null,
badInvoice: false, badInvoice: false,
@ -75,36 +59,6 @@ class BottomBar extends Component {
}; };
} }
componentDidMount() {
this.getInfo();
}
getInfo() {
this.setState(null);
apiClient.get('/api/info/').then((data) => {
const versionInfo = checkVer(data.version.major, data.version.minor, data.version.patch);
this.setState({
...data,
openUpdateClient: versionInfo.updateAvailable,
coordinatorVersion: versionInfo.coordinatorVersion,
clientVersion: versionInfo.clientVersion,
});
this.props.setAppState({
nickname: data.nickname,
loading: false,
activeOrderId: data.active_order_id ? data.active_order_id : null,
lastOrderId: data.last_order_id ? data.last_order_id : null,
referralCode: data.referral_code,
tgEnabled: data.tg_enabled,
tgBotName: data.tg_bot_name,
tgToken: data.tg_token,
earnedRewards: data.earned_rewards,
lastDayPremium: data.last_day_nonkyc_btc_premium,
stealthInvoices: data.wants_stealth,
});
});
}
handleClickOpenStatsForNerds = () => { handleClickOpenStatsForNerds = () => {
this.setState({ openStatsForNerds: true }); this.setState({ openStatsForNerds: true });
}; };
@ -114,15 +68,14 @@ class BottomBar extends Component {
}; };
handleClickOpenCommunity = () => { handleClickOpenCommunity = () => {
this.setState({ openCommuniy: true }); this.setState({ openCommunity: true });
}; };
handleClickCloseCommunity = () => { handleClickCloseCommunity = () => {
this.setState({ openCommuniy: false }); this.setState({ openCommunity: false });
}; };
handleClickOpenProfile = () => { handleClickOpenProfile = () => {
this.getInfo();
this.setState({ openProfile: true, profileShown: true }); this.setState({ openProfile: true, profileShown: true });
}; };
@ -130,35 +83,44 @@ class BottomBar extends Component {
this.setState({ openProfile: false }); this.setState({ openProfile: false });
}; };
handleClickOpenExchangeSummary = () => {
this.setState({ openExchangeSummary: true });
};
handleClickCloseExchangeSummary = () => {
this.setState({ openExchangeSummary: false });
};
handleSubmitInvoiceClicked = (e, rewardInvoice) => { handleSubmitInvoiceClicked = (e, rewardInvoice) => {
this.setState({ this.setState({ badInvoice: false, showRewardsSpinner: true });
badInvoice: false,
showRewardsSpinner: true,
});
apiClient apiClient
.post('/api/reward/', { .post('/api/reward/', {
invoice: rewardInvoice, invoice: rewardInvoice,
}) })
.then( .then((data) => {
(data) => this.setState({ badInvoice: data.bad_invoice, showRewardsSpinner: false });
this.setState({ this.props.setInfo({
...this.props.info,
badInvoice: data.bad_invoice, badInvoice: data.bad_invoice,
openClaimRewards: !data.successful_withdrawal, openClaimRewards: !data.successful_withdrawal,
withdrawn: !!data.successful_withdrawal, withdrawn: !!data.successful_withdrawal,
showRewardsSpinner: false, showRewardsSpinner: false,
}) & });
this.props.setAppState({ this.props.setRobot({
earnedRewards: data.successful_withdrawal ? 0 : this.props.earnedRewards, ...this.props.robot,
}), earnedRewards: data.successful_withdrawal ? 0 : this.props.robot.earnedRewards,
); });
});
e.preventDefault(); e.preventDefault();
}; };
handleSetStealthInvoice = (wantsStealth) => { handleSetStealthInvoice = (wantsStealth) => {
apiClient apiClient
.put('/api/stealth/', { wantsStealth }) .put('/api/stealth/', { wantsStealth })
.then((data) => this.props.setAppState({ stealthInvoices: data?.wantsStealth })); .then((data) =>
this.props.setRobot({ ...this.props.robot, stealthInvoices: data?.wantsStealth }),
);
}; };
getHost() { getHost() {
@ -171,19 +133,21 @@ class BottomBar extends Component {
showProfileButton = () => { showProfileButton = () => {
return ( return (
this.props.avatarLoaded && this.props.robot.avatarLoaded &&
(this.props.token ? systemClient.getCookie('robot_token') === this.props.token : true) && (this.props.robot.token
? systemClient.getCookie('robot_token') === this.props.robot.token
: true) &&
systemClient.getCookie('sessionid') systemClient.getCookie('sessionid')
); );
}; };
bottomBarDesktop = () => { bottomBarDesktop = () => {
const { t } = this.props; const { t } = this.props;
const hasRewards = this.props.earnedRewards > 0; const hasRewards = this.props.robot.earnedRewards > 0;
const hasOrder = !!( const hasOrder = !!(
(this.props.activeOrderId > 0) & (this.props.robot.activeOrderId > 0) &
!this.state.profileShown & !this.state.profileShown &
this.props.avatarLoaded this.props.robot.avatarLoaded
); );
const fontSize = this.props.theme.typography.fontSize; const fontSize = this.props.theme.typography.fontSize;
const fontSizeFactor = fontSize / 14; // default fontSize is 14 const fontSizeFactor = fontSize / 14; // default fontSize is 14
@ -192,7 +156,10 @@ class BottomBar extends Component {
secondaryTypographyProps: { fontSize: (fontSize * 12) / 14 }, secondaryTypographyProps: { fontSize: (fontSize * 12) / 14 },
}; };
return ( return (
<Paper elevation={6} style={{ height: '2.85em', width: '100%' }}> <Paper
elevation={6}
style={{ height: '2.5em', width: `${(this.props.windowSize.width / 16) * 14}em` }}
>
<Grid container> <Grid container>
<Grid item xs={1.9}> <Grid item xs={1.9}>
<div style={{ display: this.showProfileButton() ? '' : 'none' }}> <div style={{ display: this.showProfileButton() ? '' : 'none' }}>
@ -208,16 +175,18 @@ class BottomBar extends Component {
<RobotAvatar <RobotAvatar
style={{ marginTop: -13 }} style={{ marginTop: -13 }}
statusColor={ statusColor={
(this.props.activeOrderId > 0) & !this.props.profileShown (this.props.robot.activeOrderId > 0) & !this.state.profileShown
? 'primary' ? 'primary'
: undefined : undefined
} }
nickname={this.props.nickname} nickname={this.props.robot.nickname}
onLoad={() => this.props.setAppState({ avatarLoaded: true })} onLoad={() =>
this.props.setRobot({ ...this.props.robot, avatarLoaded: true })
}
/> />
</ListItemAvatar> </ListItemAvatar>
</Tooltip> </Tooltip>
<ListItemText primary={this.props.nickname} /> <ListItemText primary={this.props.robot.nickname} />
</ListItemButton> </ListItemButton>
</div> </div>
</Grid> </Grid>
@ -228,10 +197,6 @@ class BottomBar extends Component {
<IconButton <IconButton
disabled={!this.showProfileButton()} disabled={!this.showProfileButton()}
color='primary' color='primary'
onClick={() =>
this.props.setAppState({ buyChecked: false, sellChecked: true, type: 0 }) &
this.getInfo()
}
to={`/book/`} to={`/book/`}
component={LinkRouter} component={LinkRouter}
> >
@ -240,7 +205,7 @@ class BottomBar extends Component {
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
{...typographyProps} {...typographyProps}
primary={this.state.num_public_buy_orders} primary={this.props.info.num_public_buy_orders}
secondary={t('Public Buy Orders')} secondary={t('Public Buy Orders')}
/> />
</ListItem> </ListItem>
@ -252,10 +217,6 @@ class BottomBar extends Component {
<IconButton <IconButton
disabled={!this.showProfileButton()} disabled={!this.showProfileButton()}
color='primary' color='primary'
onClick={() =>
this.props.setAppState({ buyChecked: true, sellChecked: false, type: 1 }) &
this.getInfo()
}
to={`/book/`} to={`/book/`}
component={LinkRouter} component={LinkRouter}
> >
@ -264,7 +225,7 @@ class BottomBar extends Component {
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
{...typographyProps} {...typographyProps}
primary={this.state.num_public_sell_orders} primary={this.props.info.num_public_sell_orders}
secondary={t('Public Sell Orders')} secondary={t('Public Sell Orders')}
/> />
</ListItem> </ListItem>
@ -276,7 +237,6 @@ class BottomBar extends Component {
<IconButton <IconButton
disabled={!this.showProfileButton()} disabled={!this.showProfileButton()}
color='primary' color='primary'
onClick={() => this.getInfo()}
to={`/`} to={`/`}
component={LinkRouter} component={LinkRouter}
> >
@ -285,7 +245,7 @@ class BottomBar extends Component {
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
{...typographyProps} {...typographyProps}
primary={this.state.active_robots_today} primary={this.props.info.active_robots_today}
secondary={t('Today Active Robots')} secondary={t('Today Active Robots')}
/> />
</ListItem> </ListItem>
@ -300,7 +260,7 @@ class BottomBar extends Component {
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
{...typographyProps} {...typographyProps}
primary={this.state.last_day_nonkyc_btc_premium + '%'} primary={this.props.info.last_day_nonkyc_btc_premium + '%'}
secondary={t('24h Avg Premium')} secondary={t('24h Avg Premium')}
/> />
</ListItem> </ListItem>
@ -315,7 +275,7 @@ class BottomBar extends Component {
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
{...typographyProps} {...typographyProps}
primary={(this.state.maker_fee + this.state.taker_fee) * 100} primary={(this.props.info.maker_fee + this.props.info.taker_fee) * 100}
secondary={t('Trade Fee')} secondary={t('Trade Fee')}
/> />
</ListItem> </ListItem>
@ -470,28 +430,19 @@ class BottomBar extends Component {
); );
}; };
handleClickOpenExchangeSummary = () => {
// avoid calling getInfo while sessionid not yet set. Temporary fix.
if (systemClient.getCookie('sessionid')) {
this.getInfo();
}
this.setState({ openExchangeSummary: true });
};
handleClickCloseExchangeSummary = () => {
this.setState({ openExchangeSummary: false });
};
bottomBarPhone = () => { bottomBarPhone = () => {
const { t } = this.props; const { t } = this.props;
const hasRewards = this.props.earnedRewards > 0; const hasRewards = this.props.robot.earnedRewards > 0;
const hasOrder = !!( const hasOrder = !!(
(this.state.active_order_id > 0) & (this.props.info.active_order_id > 0) &
!this.state.profileShown & !this.state.profileShown &
this.props.avatarLoaded this.props.robot.avatarLoaded
); );
return ( return (
<Paper elevation={6} style={{ height: '2.85em', width: '100%' }}> <Paper
elevation={6}
style={{ height: '2.85em', width: `${(this.props.windowSize.width / 16) * 14}em` }}
>
<Grid container> <Grid container>
<Grid item xs={1.6}> <Grid item xs={1.6}>
<div style={{ display: this.showProfileButton() ? '' : 'none' }}> <div style={{ display: this.showProfileButton() ? '' : 'none' }}>
@ -510,12 +461,12 @@ class BottomBar extends Component {
style={{ width: 55, height: 55 }} style={{ width: 55, height: 55 }}
avatarClass='phoneFlippedSmallAvatar' avatarClass='phoneFlippedSmallAvatar'
statusColor={ statusColor={
(this.props.activeOrderId > 0) & !this.props.profileShown (this.props.activeOrderId > 0) & !this.state.profileShown
? 'primary' ? 'primary'
: undefined : undefined
} }
nickname={this.props.nickname} nickname={this.props.robot.nickname}
onLoad={() => this.props.setAppState({ avatarLoaded: true })} onLoad={() => this.props.setRobot({ ...this.props.robot, avatarLoaded: true })}
/> />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
@ -527,14 +478,10 @@ class BottomBar extends Component {
<IconButton <IconButton
disabled={!this.showProfileButton()} disabled={!this.showProfileButton()}
color='primary' color='primary'
onClick={() =>
this.props.setAppState({ buyChecked: false, sellChecked: true, type: 0 }) &
this.getInfo()
}
to={`/book/`} to={`/book/`}
component={LinkRouter} component={LinkRouter}
> >
<Badge badgeContent={this.state.num_public_buy_orders} color='action'> <Badge badgeContent={this.props.info.num_public_buy_orders} color='action'>
<InventoryIcon /> <InventoryIcon />
</Badge> </Badge>
</IconButton> </IconButton>
@ -546,14 +493,10 @@ class BottomBar extends Component {
<IconButton <IconButton
disabled={!this.showProfileButton()} disabled={!this.showProfileButton()}
color='primary' color='primary'
onClick={() =>
this.props.setAppState({ buyChecked: true, sellChecked: false, type: 1 }) &
this.getInfo()
}
to={`/book/`} to={`/book/`}
component={LinkRouter} component={LinkRouter}
> >
<Badge badgeContent={this.state.num_public_sell_orders} color='action'> <Badge badgeContent={this.props.info.num_public_sell_orders} color='action'>
<SellIcon /> <SellIcon />
</Badge> </Badge>
</IconButton> </IconButton>
@ -565,11 +508,11 @@ class BottomBar extends Component {
<IconButton <IconButton
disabled={!this.showProfileButton()} disabled={!this.showProfileButton()}
color='primary' color='primary'
onClick={() => this.getInfo()} onClick={() => this.props.fetchInfo()}
to={`/`} to={`/`}
component={LinkRouter} component={LinkRouter}
> >
<Badge badgeContent={this.state.active_robots_today} color='action'> <Badge badgeContent={this.props.info.active_robots_today} color='action'>
<SmartToyIcon /> <SmartToyIcon />
</Badge> </Badge>
</IconButton> </IconButton>
@ -579,7 +522,10 @@ class BottomBar extends Component {
<Grid item xs={1.8} align='center'> <Grid item xs={1.8} align='center'>
<Tooltip enterTouchDelay={300} title={t('24h non-KYC bitcoin premium')}> <Tooltip enterTouchDelay={300} title={t('24h non-KYC bitcoin premium')}>
<IconButton color='primary' onClick={this.handleClickOpenExchangeSummary}> <IconButton color='primary' onClick={this.handleClickOpenExchangeSummary}>
<Badge badgeContent={this.state.last_day_nonkyc_btc_premium + '%'} color='action'> <Badge
badgeContent={this.props.info.last_day_nonkyc_btc_premium + '%'}
color='action'
>
<PriceChangeIcon /> <PriceChangeIcon />
</Badge> </Badge>
</IconButton> </IconButton>
@ -622,65 +568,67 @@ class BottomBar extends Component {
return ( return (
<div> <div>
<CommunityDialog <CommunityDialog
isOpen={this.state.openCommuniy} open={this.state.openCommunity}
handleClickCloseCommunity={this.handleClickCloseCommunity} handleClickCloseCommunity={this.handleClickCloseCommunity}
/> />
<UpdateClientDialog <UpdateClientDialog
open={this.state.openUpdateClient} open={this.state.openUpdateClient}
coordinatorVersion={this.state.coordinatorVersion} coordinatorVersion={this.props.info.coordinatorVersion}
clientVersion={this.state.clientVersion} clientVersion={this.props.info.clientVersion}
handleClickClose={() => this.setState({ openUpdateClient: false })} handleClickClose={() =>
this.props.setInfo({ ...this.props.info, openUpdateClient: false })
}
/> />
<ExchangeSummaryDialog <ExchangeSummaryDialog
isOpen={this.state.openExchangeSummary} open={this.state.openExchangeSummary}
handleClickCloseExchangeSummary={this.handleClickCloseExchangeSummary} handleClickCloseExchangeSummary={this.handleClickCloseExchangeSummary}
numPublicBuyOrders={this.state.num_public_buy_orders} numPublicBuyOrders={this.props.info.num_public_buy_orders}
numPublicSellOrders={this.state.num_public_sell_orders} numPublicSellOrders={this.props.info.num_public_sell_orders}
bookLiquidity={this.state.book_liquidity} bookLiquidity={this.props.info.book_liquidity}
activeRobotsToday={this.state.active_robots_today} activeRobotsToday={this.props.info.active_robots_today}
lastDayNonkycBtcPremium={this.state.last_day_nonkyc_btc_premium} lastDayNonkycBtcPremium={this.props.info.last_day_nonkyc_btc_premium}
makerFee={this.state.maker_fee} makerFee={this.props.info.maker_fee}
takerFee={this.state.taker_fee} takerFee={this.props.info.taker_fee}
swapFeeRate={this.state.current_swap_fee_rate} swapFeeRate={this.props.info.current_swap_fee_rate}
/> />
<ProfileDialog <ProfileDialog
isOpen={this.state.openProfile} open={this.state.openProfile}
handleClickCloseProfile={this.handleClickCloseProfile} handleClickCloseProfile={this.handleClickCloseProfile}
nickname={this.props.nickname} nickname={this.props.robot.nickname}
activeOrderId={this.props.activeOrderId} activeOrderId={this.props.robot.activeOrderId}
lastOrderId={this.props.lastOrderId} lastOrderId={this.props.robotlastOrderId}
referralCode={this.props.referralCode} referralCode={this.props.robot.referralCode}
tgEnabled={this.props.tgEnabled} tgEnabled={this.props.robot.tgEnabled}
tgBotName={this.props.tgBotName} tgBotName={this.props.robot.tgBotName}
tgToken={this.props.tgToken} tgToken={this.props.robot.tgToken}
handleSubmitInvoiceClicked={this.handleSubmitInvoiceClicked} handleSubmitInvoiceClicked={this.handleSubmitInvoiceClicked}
host={this.getHost()} host={this.getHost()}
showRewardsSpinner={this.state.showRewardsSpinner} showRewardsSpinner={this.state.showRewardsSpinner}
withdrawn={this.state.withdrawn} withdrawn={this.props.info.withdrawn}
badInvoice={this.state.badInvoice} badInvoice={this.props.info.badInvoice}
earnedRewards={this.props.earnedRewards} earnedRewards={this.props.robot.earnedRewards}
setAppState={this.props.setAppState} updateRobot={(newParam) => this.props.setRobot({ ...robot, ...newParam })}
stealthInvoices={this.props.stealthInvoices} stealthInvoices={this.props.robot.stealthInvoices}
handleSetStealthInvoice={this.handleSetStealthInvoice} handleSetStealthInvoice={this.handleSetStealthInvoice}
/> />
<StatsDialog <StatsDialog
isOpen={this.state.openStatsForNerds} open={this.state.openStatsForNerds}
handleClickCloseStatsForNerds={this.handleClickCloseStatsForNerds} handleClickCloseStatsForNerds={this.handleClickCloseStatsForNerds}
coordinatorVersion={this.state.coordinatorVersion} coordinatorVersion={this.props.info.coordinatorVersion}
clientVersion={this.state.clientVersion} clientVersion={this.props.info.clientVersion}
lndVersion={this.state.lnd_version} lndVersion={this.props.info.lnd_version}
network={this.state.network} network={this.props.info.network}
nodeAlias={this.state.node_alias} nodeAlias={this.props.info.node_alias}
nodeId={this.state.node_id} nodeId={this.props.info.node_id}
alternativeName={this.state.alternative_name} alternativeName={this.props.info.alternative_name}
alternativeSite={this.state.alternative_site} alternativeSite={this.props.info.alternative_site}
commitHash={this.state.robosats_running_commit_hash} commitHash={this.props.info.robosats_running_commit_hash}
lastDayVolume={this.state.last_day_volume} lastDayVolume={this.props.info.last_day_volume}
lifetimeVolume={this.state.lifetime_volume} lifetimeVolume={this.props.info.lifetime_volume}
/> />
<MediaQuery minWidth={1200}>{this.bottomBarDesktop()}</MediaQuery> <MediaQuery minWidth={1200}>{this.bottomBarDesktop()}</MediaQuery>

View File

@ -28,14 +28,12 @@ import currencyDict from '../../../../static/assets/currencies.json';
import PaymentText from '../../PaymentText'; import PaymentText from '../../PaymentText';
import getNivoScheme from '../NivoScheme'; import getNivoScheme from '../NivoScheme';
import median from '../../../utils/match'; import median from '../../../utils/match';
import { apiClient } from '../../../services/api/index';
import statusBadgeColor from '../../../utils/statusBadgeColor'; import statusBadgeColor from '../../../utils/statusBadgeColor';
interface DepthChartProps { interface DepthChartProps {
orders: Order[]; orders: Order[];
lastDayPremium: number | undefined; lastDayPremium: number | undefined;
currency: number; currency: number;
setAppState: (state: object) => void;
limits: LimitList; limits: LimitList;
maxWidth: number; maxWidth: number;
maxHeight: number; maxHeight: number;
@ -45,7 +43,6 @@ const DepthChart: React.FC<DepthChartProps> = ({
orders, orders,
lastDayPremium, lastDayPremium,
currency, currency,
setAppState,
limits, limits,
maxWidth, maxWidth,
maxHeight, maxHeight,
@ -64,14 +61,6 @@ const DepthChart: React.FC<DepthChartProps> = ({
const height = maxHeight < 20 ? 20 : maxHeight; const height = maxHeight < 20 ? 20 : maxHeight;
const width = maxWidth < 20 ? 20 : maxWidth > 72.8 ? 72.8 : maxWidth; const width = maxWidth < 20 ? 20 : maxWidth > 72.8 ? 72.8 : maxWidth;
useEffect(() => {
if (Object.keys(limits).length === 0) {
apiClient.get('/api/limits/').then((data) => {
setAppState({ limits: data });
});
}
}, []);
useEffect(() => { useEffect(() => {
setCurrencyCode(currency === 0 ? 1 : currency); setCurrencyCode(currency === 0 ? 1 : currency);
}, [currency]); }, [currency]);

View File

@ -12,13 +12,13 @@ export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => {
axis: { axis: {
ticks: { ticks: {
line: { line: {
strokeWidth: '1', strokeWidth: 1,
stroke: 'rgb(0, 0, 0)', stroke: 'rgb(0, 0, 0)',
}, },
}, },
domain: { domain: {
line: { line: {
strokeWidth: '1', strokeWidth: 1,
stroke: 'rgb(0, 0, 0)', stroke: 'rgb(0, 0, 0)',
}, },
}, },
@ -36,13 +36,13 @@ export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => {
fill: 'rgb(255, 255, 255)', fill: 'rgb(255, 255, 255)',
}, },
line: { line: {
strokeWidth: '1', strokeWidth: 1,
stroke: 'rgb(255, 255, 255)', stroke: 'rgb(255, 255, 255)',
}, },
}, },
domain: { domain: {
line: { line: {
strokeWidth: '1', strokeWidth: 1,
stroke: 'rgb(255, 255, 255)', stroke: 'rgb(255, 255, 255)',
}, },
}, },

View File

@ -20,11 +20,11 @@ import RedditIcon from '@mui/icons-material/Reddit';
import Flags from 'country-flag-icons/react/3x2'; import Flags from 'country-flag-icons/react/3x2';
interface Props { interface Props {
isOpen: boolean; open: boolean;
handleClickCloseCommunity: () => void; handleClickCloseCommunity: () => void;
} }
const CommunityDialog = ({ isOpen, handleClickCloseCommunity }: Props): JSX.Element => { const CommunityDialog = ({ open = false, handleClickCloseCommunity }: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
const flagProps = { const flagProps = {
@ -38,7 +38,7 @@ const CommunityDialog = ({ isOpen, handleClickCloseCommunity }: Props): JSX.Elem
return ( return (
<Dialog <Dialog
open={isOpen} open={open}
onClose={handleClickCloseCommunity} onClose={handleClickCloseCommunity}
aria-labelledby='community-dialog-title' aria-labelledby='community-dialog-title'
aria-describedby='community-description' aria-describedby='community-description'

View File

@ -24,7 +24,7 @@ import LinkIcon from '@mui/icons-material/Link';
import { pn } from '../../utils/prettyNumbers'; import { pn } from '../../utils/prettyNumbers';
interface Props { interface Props {
isOpen: boolean; open: boolean;
handleClickCloseExchangeSummary: () => void; handleClickCloseExchangeSummary: () => void;
numPublicBuyOrders: number; numPublicBuyOrders: number;
numPublicSellOrders: number; numPublicSellOrders: number;
@ -37,7 +37,7 @@ interface Props {
} }
const ExchangeSummaryDialog = ({ const ExchangeSummaryDialog = ({
isOpen, open = false,
handleClickCloseExchangeSummary, handleClickCloseExchangeSummary,
numPublicBuyOrders, numPublicBuyOrders,
numPublicSellOrders, numPublicSellOrders,
@ -55,7 +55,7 @@ const ExchangeSummaryDialog = ({
return ( return (
<Dialog <Dialog
open={isOpen} open={open}
onClose={handleClickCloseExchangeSummary} onClose={handleClickCloseExchangeSummary}
aria-labelledby='exchange-summary-title' aria-labelledby='exchange-summary-title'
aria-describedby='exchange-summary-description' aria-describedby='exchange-summary-description'

View File

@ -41,7 +41,7 @@ import { getWebln } from '../../utils/webln';
import RobotAvatar from '../Robots/RobotAvatar'; import RobotAvatar from '../Robots/RobotAvatar';
interface Props { interface Props {
isOpen: boolean; open: boolean;
handleClickCloseProfile: () => void; handleClickCloseProfile: () => void;
nickname: string; nickname: string;
activeOrderId: string | number; activeOrderId: string | number;
@ -57,12 +57,12 @@ interface Props {
badInvoice: boolean | string; badInvoice: boolean | string;
earnedRewards: number; earnedRewards: number;
stealthInvoices: boolean; stealthInvoices: boolean;
handleSetStealthInvoice: (stealth: boolean) => void; handleSetStealthInvoice: (wantsStealth: boolean) => void;
setAppState: (state: any) => void; // TODO: move to a ContextProvider updateRobot: (state: any) => void; // TODO: move to a ContextProvider
} }
const ProfileDialog = ({ const ProfileDialog = ({
isOpen, open = false,
handleClickCloseProfile, handleClickCloseProfile,
nickname, nickname,
activeOrderId, activeOrderId,
@ -77,7 +77,7 @@ const ProfileDialog = ({
withdrawn, withdrawn,
badInvoice, badInvoice,
earnedRewards, earnedRewards,
setAppState, updateRobot,
stealthInvoices, stealthInvoices,
handleSetStealthInvoice, handleSetStealthInvoice,
}: Props): JSX.Element => { }: Props): JSX.Element => {
@ -101,7 +101,7 @@ const ProfileDialog = ({
if (robotToken) { if (robotToken) {
systemClient.copyToClipboard(robotToken); systemClient.copyToClipboard(robotToken);
setAppState({ copiedToken: true }); updateRobot({ copiedToken: true });
} }
}; };
@ -128,7 +128,7 @@ const ProfileDialog = ({
return ( return (
<Dialog <Dialog
open={isOpen} open={open}
onClose={handleClickCloseProfile} onClose={handleClickCloseProfile}
aria-labelledby='profile-title' aria-labelledby='profile-title'
aria-describedby='profile-description' aria-describedby='profile-description'

View File

@ -26,7 +26,7 @@ import { AmbossIcon, BitcoinSignIcon, RoboSatsNoTextIcon } from '../Icons';
import { pn } from '../../utils/prettyNumbers'; import { pn } from '../../utils/prettyNumbers';
interface Props { interface Props {
isOpen: boolean; open: boolean;
handleClickCloseStatsForNerds: () => void; handleClickCloseStatsForNerds: () => void;
lndVersion: string; lndVersion: string;
coordinatorVersion: string; coordinatorVersion: string;
@ -42,7 +42,7 @@ interface Props {
} }
const StatsDialog = ({ const StatsDialog = ({
isOpen, open = false,
handleClickCloseStatsForNerds, handleClickCloseStatsForNerds,
lndVersion, lndVersion,
coordinatorVersion, coordinatorVersion,
@ -60,7 +60,7 @@ const StatsDialog = ({
return ( return (
<Dialog <Dialog
open={isOpen} open={open}
onClose={handleClickCloseStatsForNerds} onClose={handleClickCloseStatsForNerds}
aria-labelledby='stats-for-nerds-dialog-title' aria-labelledby='stats-for-nerds-dialog-title'
aria-describedby='stats-for-nerds-description' aria-describedby='stats-for-nerds-description'

View File

@ -27,7 +27,7 @@ interface Props {
} }
const UpdateClientDialog = ({ const UpdateClientDialog = ({
open, open = false,
clientVersion, clientVersion,
coordinatorVersion, coordinatorVersion,
handleClickClose, handleClickClose,

View File

@ -75,7 +75,7 @@ class Chat extends Component {
this.setState({ connected: false }); this.setState({ connected: false });
}); });
this.setState({ connected: true, connection: connection }); this.setState({ connected: true, connection });
}); });
} }

View File

@ -1,187 +0,0 @@
import React, { Component } from 'react';
import { HashRouter, BrowserRouter, Switch, Route } from 'react-router-dom';
import UserGenPage from './UserGenPage';
import MakerPage from './MakerPage';
import BookPage from './BookPage';
import OrderPage from './OrderPage';
import BottomBar from './BottomBar';
import { apiClient } from '../services/api';
export default class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
nickname: null,
token: null,
copiedToken: false,
avatarLoaded: false,
buyChecked: false,
sellChecked: false,
type: null,
currency: 0,
bookCurrencyCode: 'ANY',
orders: new Array(),
bookLoading: true,
bookRefreshing: false,
activeOrderId: null,
lastOrderId: null,
earnedRewards: 0,
referralCode: '',
lastDayPremium: 0,
limits: {},
loadingLimits: true,
maker: {},
};
}
componentDidMount = () => {
if (typeof window !== undefined) {
this.setState({
windowWidth: window.innerWidth / this.props.theme.typography.fontSize,
windowHeight: window.innerHeight / this.props.theme.typography.fontSize,
});
window.addEventListener('resize', this.onResize);
}
this.fetchBook(true, false);
this.fetchLimits(true);
};
componentWillUnmount = () => {
if (typeof window !== undefined) {
window.removeEventListener('resize', this.onResize);
}
};
onResize = () => {
this.setState({
windowWidth: window.innerWidth / this.props.theme.typography.fontSize,
windowHeight: window.innerHeight / this.props.theme.typography.fontSize,
});
};
setAppState = (newState) => {
this.setState(newState);
};
redirectTo(location) {
this.props.history.push(location);
}
getBasename() {
if (window.NativeRobosats) {
// Only for Android
return window.location.pathname;
}
return '';
}
fetchBook = (loading, refreshing) => {
this.setState({ bookLoading: loading, bookRefreshing: refreshing });
apiClient.get('/api/book/').then((data) =>
this.setState({
bookLoading: false,
bookRefreshing: false,
orders: data.not_found ? [] : data,
}),
);
};
fetchLimits = (loading) => {
this.setState({ loadingLimits: loading });
const limits = apiClient.get('/api/limits/').then((data) => {
this.setState({ limits: data, loadingLimits: false });
return data;
});
return limits;
};
render() {
const fontSize = this.props.theme.typography.fontSize;
const fontSizeFactor = fontSize / 14; // default fontSize is 14
const Router = window.NativeRobosats ? HashRouter : BrowserRouter;
return (
<Router basename={this.getBasename()}>
<div className='appCenter'>
<Switch>
<Route
exact
path='/'
render={(props) => (
<UserGenPage
{...props}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
)}
/>
<Route
path='/ref/:refCode'
render={(props) => (
<UserGenPage
{...props}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
)}
/>
<Route
path='/make'
render={(props) => (
<MakerPage
{...props}
{...this.state}
{...this.props}
fetchLimits={this.fetchLimits}
setAppState={this.setAppState}
/>
)}
/>
<Route
path='/book'
render={(props) => (
<BookPage
{...props}
{...this.state}
{...this.props}
fetchBook={this.fetchBook}
fetchLimits={this.fetchLimits}
setAppState={this.setAppState}
/>
)}
/>
<Route
path='/order/:orderId'
render={(props) => (
<OrderPage
{...props}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
)}
/>
</Switch>
</div>
<div
className='bottomBar'
style={{
height: `${40 * fontSizeFactor}px`,
width: `${(this.state.windowWidth / 16) * 14}em`,
}}
>
<BottomBar
redirectTo={this.redirectTo}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
</div>
</Router>
);
}
}

View File

@ -0,0 +1,198 @@
import React, { useEffect, useState } from 'react';
import { HashRouter, BrowserRouter, Switch, Route, useHistory } from 'react-router-dom';
import { useTheme } from '@mui/material';
import UserGenPage from './UserGenPage';
import MakerPage from './MakerPage';
import BookPage from './BookPage';
import OrderPage from './OrderPage';
import BottomBar from './BottomBar';
import { apiClient } from '../services/api';
import checkVer from '../utils/checkVer';
import {
Book,
LimitList,
Maker,
Robot,
Info,
Settings,
Favorites,
defaultMaker,
defaultRobot,
defaultInfo,
defaultSettings,
} from '../models';
const getWindowSize = function (fontSize: number) {
// returns window size in EM units
return {
width: window.innerWidth / fontSize,
height: window.innerHeight / fontSize,
};
};
const Main = (): JSX.Element => {
const theme = useTheme();
const history = useHistory();
const Router = window.NativeRobosats != null ? HashRouter : BrowserRouter;
const basename = window.NativeRobosats != null ? window.location.pathname : '';
// All app data structured
const [book, setBook] = useState<Book>({ orders: [], loading: true });
const [limits, setLimits] = useState<{ list: LimitList; loading: boolean }>({
list: [],
loading: true,
});
const [robot, setRobot] = useState<Robot>(defaultRobot);
const [maker, setMaker] = useState<Maker>(defaultMaker);
const [info, setInfo] = useState<Info>(defaultInfo);
const [fav, setFav] = useState<Favorites>({ type: null, currency: 0 });
const [settings, setSettings] = useState<Settings>(defaultSettings);
const [windowSize, setWindowSize] = useState<{ width: number; height: number }>(
getWindowSize(theme.typography.fontSize),
);
useEffect(() => {
if (typeof window !== undefined) {
window.addEventListener('resize', onResize);
}
fetchBook();
fetchLimits();
fetchInfo();
return () => {
if (typeof window !== undefined) {
window.removeEventListener('resize', onResize);
}
};
}, []);
const onResize = function () {
setWindowSize(getWindowSize(theme.typography.fontSize));
};
const fetchBook = function () {
setBook({ ...book, loading: true });
apiClient.get('/api/book/').then((data: any) =>
setBook({
loading: false,
orders: data.not_found ? [] : data,
}),
);
};
const fetchLimits = async () => {
setLimits({ ...limits, loading: true });
const data = apiClient.get('/api/limits/').then((data) => {
setLimits({ list: data ?? [], loading: false });
return data;
});
return await data;
};
const fetchInfo = function () {
apiClient.get('/api/info/').then((data: any) => {
const versionInfo: any = checkVer(data.version.major, data.version.minor, data.version.patch);
setInfo({
...data,
openUpdateClient: versionInfo.updateAvailable,
coordinatorVersion: versionInfo.coordinatorVersion,
clientVersion: versionInfo.clientVersion,
});
setRobot({
...robot,
nickname: data.nickname,
loading: false,
activeOrderId: data.active_order_id ?? null,
lastOrderId: data.last_order_id ?? null,
referralCode: data.referral_code,
tgEnabled: data.tg_enabled,
tgBotName: data.tg_bot_name,
tgToken: data.tg_token,
earnedRewards: data.earned_rewards ?? 0,
stealthInvoices: data.wants_stealth,
});
});
};
console.log(robot);
return (
<Router basename={basename}>
<div className='appCenter'>
<Switch>
<Route
exact
path='/'
render={(props: any) => (
<UserGenPage match={props.match} theme={theme} robot={robot} setRobot={setRobot} />
)}
/>
<Route
path='/ref/:refCode'
render={(props: any) => (
<UserGenPage match={props.match} theme={theme} robot={robot} setRobot={setRobot} />
)}
/>
<Route
path='/make'
render={() => (
<MakerPage
orders={book.orders}
limits={limits}
fetchLimits={fetchLimits}
maker={maker}
setMaker={setMaker}
fav={fav}
setFav={setFav}
windowSize={windowSize}
/>
)}
/>
<Route
path='/book'
render={() => (
<BookPage
book={book}
fetchBook={fetchBook}
limits={limits}
fetchLimits={fetchLimits}
fav={fav}
setFav={setFav}
maker={maker}
setMaker={setMaker}
lastDayPremium={info.last_day_nonkyc_btc_premium}
windowSize={windowSize}
/>
)}
/>
<Route
path='/order/:orderId'
render={(props: any) => <OrderPage theme={theme} history={history} {...props} />}
/>
</Switch>
</div>
<div
style={{
height: '2.5em',
position: 'fixed',
bottom: 0,
}}
>
<BottomBar
theme={theme}
windowSize={windowSize}
redirectTo={(location: string) => history.push(location)}
robot={robot}
setRobot={setRobot}
info={info}
setInfo={setInfo}
fetchInfo={fetchInfo}
/>
</div>
</Router>
);
};
export default Main;

View File

@ -24,7 +24,7 @@ import {
IconButton, IconButton,
} from '@mui/material'; } from '@mui/material';
import { LimitList, Maker, defaultMaker } from '../../models'; import { LimitList, Maker, Favorites, defaultMaker } from '../../models';
import { LocalizationProvider, TimePicker } from '@mui/x-date-pickers'; import { LocalizationProvider, TimePicker } from '@mui/x-date-pickers';
import DateFnsUtils from '@date-io/date-fns'; import DateFnsUtils from '@date-io/date-fns';
@ -43,14 +43,12 @@ import { SelfImprovement, Lock, HourglassTop, DeleteSweep, Edit } from '@mui/ico
import { LoadingButton } from '@mui/lab'; import { LoadingButton } from '@mui/lab';
interface MakerFormProps { interface MakerFormProps {
limits: LimitList; limits: { list: LimitList; loading: boolean };
fetchLimits: (loading) => void; fetchLimits: () => void;
loadingLimits: boolean;
pricingMethods: boolean; pricingMethods: boolean;
maker: Maker; maker: Maker;
type: number; fav: Favorites;
currency: number; setFav: (state: Favorites) => void;
setAppState: (state: object) => void;
setMaker: (state: Maker) => void; setMaker: (state: Maker) => void;
disableRequest?: boolean; disableRequest?: boolean;
collapseAll?: boolean; collapseAll?: boolean;
@ -62,11 +60,9 @@ interface MakerFormProps {
const MakerForm = ({ const MakerForm = ({
limits, limits,
fetchLimits, fetchLimits,
loadingLimits,
pricingMethods, pricingMethods,
currency, fav,
type, setFav,
setAppState,
maker, maker,
setMaker, setMaker,
disableRequest = false, disableRequest = false,
@ -79,7 +75,6 @@ const MakerForm = ({
const theme = useTheme(); const theme = useTheme();
const history = useHistory(); const history = useHistory();
const [badRequest, setBadRequest] = useState<string | null>(null); const [badRequest, setBadRequest] = useState<string | null>(null);
const [advancedOptions, setAdvancedOptions] = useState<boolean>(false);
const [amountLimits, setAmountLimits] = useState<number[]>([1, 1000]); const [amountLimits, setAmountLimits] = useState<number[]>([1, 1000]);
const [satoshisLimits, setSatoshisLimits] = useState<number[]>([20000, 4000000]); const [satoshisLimits, setSatoshisLimits] = useState<number[]>([20000, 4000000]);
const [currentPrice, setCurrentPrice] = useState<number | string>('...'); const [currentPrice, setCurrentPrice] = useState<number | string>('...');
@ -93,27 +88,26 @@ const MakerForm = ({
const amountSafeThresholds = [1.03, 0.98]; const amountSafeThresholds = [1.03, 0.98];
useEffect(() => { useEffect(() => {
setCurrencyCode(currencyDict[currency == 0 ? 1 : currency]); setCurrencyCode(currencyDict[fav.currency == 0 ? 1 : fav.currency]);
if (Object.keys(limits).length === 0) { if (Object.keys(limits.list).length === 0) {
setAppState({ loadingLimits: true }); fetchLimits().then((data) => {
fetchLimits(true).then((data) => { updateAmountLimits(data, fav.currency, maker.premium);
updateAmountLimits(data, currency, maker.premium); updateCurrentPrice(data, fav.currency, maker.premium);
updateCurrentPrice(data, currency, maker.premium);
updateSatoshisLimits(data); updateSatoshisLimits(data);
}); });
} else { } else {
updateAmountLimits(limits, currency, maker.premium); updateAmountLimits(limits.list, fav.currency, maker.premium);
updateCurrentPrice(limits, currency, maker.premium); updateCurrentPrice(limits.list, fav.currency, maker.premium);
updateSatoshisLimits(limits); updateSatoshisLimits(limits.list);
fetchLimits(false); fetchLimits();
} }
}, []); }, []);
const updateAmountLimits = function (limits: LimitList, currency: number, premium: number) { const updateAmountLimits = function (limitList: LimitList, currency: number, premium: number) {
const index = currency === 0 ? 1 : currency; const index = currency == 0 ? 1 : currency;
let minAmountLimit: number = limits[index].min_amount * (1 + premium / 100); let minAmountLimit: number = limitList[index].min_amount * (1 + premium / 100);
let maxAmountLimit: number = limits[index].max_amount * (1 + premium / 100); let maxAmountLimit: number = limitList[index].max_amount * (1 + premium / 100);
// apply thresholds to ensure good request // apply thresholds to ensure good request
minAmountLimit = minAmountLimit * amountSafeThresholds[0]; minAmountLimit = minAmountLimit * amountSafeThresholds[0];
@ -121,19 +115,19 @@ const MakerForm = ({
setAmountLimits([minAmountLimit, maxAmountLimit]); setAmountLimits([minAmountLimit, maxAmountLimit]);
}; };
const updateSatoshisLimits = function (limits: LimitList) { const updateSatoshisLimits = function (limitList: LimitList) {
const minAmount: number = limits[1000].min_amount * 100000000; const minAmount: number = limitList[1000].min_amount * 100000000;
const maxAmount: number = limits[1000].max_amount * 100000000; const maxAmount: number = limitList[1000].max_amount * 100000000;
setSatoshisLimits([minAmount, maxAmount]); setSatoshisLimits([minAmount, maxAmount]);
}; };
const updateCurrentPrice = function (limits: LimitList, currency: number, premium: number) { const updateCurrentPrice = function (limitsList: LimitList, currency: number, premium: number) {
const index = currency === 0 ? 1 : currency; const index = currency == 0 ? 1 : currency;
let price = '...'; let price = '...';
if (maker.is_explicit && maker.amount > 0 && maker.satoshis > 0) { if (maker.isExplicit && maker.amount > 0 && maker.satoshis > 0) {
price = maker.amount / (maker.satoshis / 100000000); price = maker.amount / (maker.satoshis / 100000000);
} else if (!maker.is_explicit) { } else if (!maker.is_explicit) {
price = limits[index].price * (1 + premium / 100); price = limitsList[index].price * (1 + premium / 100);
} }
setCurrentPrice(parseFloat(Number(price).toPrecision(5))); setCurrentPrice(parseFloat(Number(price).toPrecision(5)));
}; };
@ -141,17 +135,17 @@ const MakerForm = ({
const handleCurrencyChange = function (newCurrency: number) { const handleCurrencyChange = function (newCurrency: number) {
const currencyCode: string = currencyDict[newCurrency]; const currencyCode: string = currencyDict[newCurrency];
setCurrencyCode(currencyCode); setCurrencyCode(currencyCode);
setAppState({ setFav({
...fav,
currency: newCurrency, currency: newCurrency,
bookCurrencyCode: currencyCode,
}); });
updateAmountLimits(limits, newCurrency, maker.premium); updateAmountLimits(limits.list, newCurrency, maker.premium);
updateCurrentPrice(limits, newCurrency, maker.premium); updateCurrentPrice(limits.list, newCurrency, maker.premium);
if (advancedOptions) { if (maker.advancedOptions) {
setMaker({ setMaker({
...maker, ...maker,
minAmount: parseFloat(Number(limits[newCurrency].max_amount * 0.25).toPrecision(2)), minAmount: parseFloat(Number(limits.list[newCurrency].max_amount * 0.25).toPrecision(2)),
maxAmount: parseFloat(Number(limits[newCurrency].max_amount * 0.75).toPrecision(2)), maxAmount: parseFloat(Number(limits.list[newCurrency].max_amount * 0.75).toPrecision(2)),
}); });
} }
}; };
@ -198,8 +192,8 @@ const MakerForm = ({
badPremiumText = t('Must be more than {{min}}%', { min }); badPremiumText = t('Must be more than {{min}}%', { min });
premium = -99.99; premium = -99.99;
} }
updateCurrentPrice(limits, currency, premium); updateCurrentPrice(limits.list, fav.currency, premium);
updateAmountLimits(limits, currency, premium); updateAmountLimits(limits.list, fav.currency, premium);
setMaker({ setMaker({
...maker, ...maker,
premium, premium,
@ -235,7 +229,7 @@ const MakerForm = ({
}; };
const handleClickExplicit = function () { const handleClickExplicit = function () {
if (!advancedOptions) { if (!maker.advancedOptions) {
setMaker({ setMaker({
...maker, ...maker,
isExplicit: true, isExplicit: true,
@ -247,12 +241,12 @@ const MakerForm = ({
if (!disableRequest) { if (!disableRequest) {
setSubmittingRequest(true); setSubmittingRequest(true);
const body = { const body = {
type: type == 0 ? 1 : 0, type: fav.type == 0 ? 1 : 0,
currency: currency == 0 ? 1 : currency, currency: fav.currency == 0 ? 1 : fav.currency,
amount: advancedOptions ? null : maker.amount, amount: maker.advancedOptions ? null : maker.amount,
has_range: advancedOptions, has_range: maker.advancedOptions,
min_amount: advancedOptions ? maker.minAmount : null, min_amount: maker.advancedOptions ? maker.minAmount : null,
max_amount: advancedOptions ? maker.maxAmount : null, max_amount: maker.advancedOptions ? maker.maxAmount : null,
payment_method: payment_method:
maker.paymentMethodsText === '' ? 'not specified' : maker.paymentMethodsText, maker.paymentMethodsText === '' ? 'not specified' : maker.paymentMethodsText,
is_explicit: maker.isExplicit, is_explicit: maker.isExplicit,
@ -300,13 +294,12 @@ const MakerForm = ({
}; };
const handleClickAdvanced = function () { const handleClickAdvanced = function () {
if (advancedOptions) { if (maker.advancedOptions) {
handleClickRelative(); handleClickRelative();
setMaker({ ...maker, advancedOptions: false });
} else { } else {
resetRange(); resetRange(true);
} }
setAdvancedOptions(!advancedOptions);
}; };
const minAmountError = function () { const minAmountError = function () {
@ -327,17 +320,18 @@ const MakerForm = ({
); );
}; };
const resetRange = function () { const resetRange = function (advancedOptions: boolean) {
const index = currency === 0 ? 1 : currency; const index = fav.currency === 0 ? 1 : fav.currency;
const minAmount = maker.amount const minAmount = maker.amount
? parseFloat((maker.amount / 2).toPrecision(2)) ? parseFloat((maker.amount / 2).toPrecision(2))
: parseFloat(Number(limits[index].max_amount * 0.25).toPrecision(2)); : parseFloat(Number(limits.list[index].max_amount * 0.25).toPrecision(2));
const maxAmount = maker.amount const maxAmount = maker.amount
? parseFloat(maker.amount) ? parseFloat(maker.amount)
: parseFloat(Number(limits[index].max_amount * 0.75).toPrecision(2)); : parseFloat(Number(limits.list[index].max_amount * 0.75).toPrecision(2));
setMaker({ setMaker({
...maker, ...maker,
advancedOptions,
minAmount, minAmount,
maxAmount, maxAmount,
}); });
@ -379,20 +373,20 @@ const MakerForm = ({
const disableSubmit = function () { const disableSubmit = function () {
return ( return (
type == null || fav.type == null ||
(maker.amount != '' && (maker.amount != '' &&
!advancedOptions && !maker.advancedOptions &&
(maker.amount < amountLimits[0] || maker.amount > amountLimits[1])) || (maker.amount < amountLimits[0] || maker.amount > amountLimits[1])) ||
(maker.amount == null && (!advancedOptions || loadingLimits)) || (maker.amount == null && (!maker.advancedOptions || limits.loading)) ||
(advancedOptions && (minAmountError() || maxAmountError())) || (maker.advancedOptions && (minAmountError() || maxAmountError())) ||
(maker.amount <= 0 && !advancedOptions) || (maker.amount <= 0 && !maker.advancedOptions) ||
(maker.isExplicit && (maker.badSatoshisText != '' || maker.satoshis == '')) || (maker.isExplicit && (maker.badSatoshisText != '' || maker.satoshis == '')) ||
(!maker.isExplicit && maker.badPremiumText != '') (!maker.isExplicit && maker.badPremiumText != '')
); );
}; };
const clearMaker = function () { const clearMaker = function () {
setAppState({ type: null }); setFav({ ...fav, type: null });
setMaker(defaultMaker); setMaker(defaultMaker);
}; };
@ -404,8 +398,12 @@ const MakerForm = ({
align='center' align='center'
color={disableSubmit() ? 'text.secondary' : 'text.primary'} color={disableSubmit() ? 'text.secondary' : 'text.primary'}
> >
{type == null ? t('Order for ') : type == 1 ? t('Buy order for ') : t('Sell order for ')} {fav.type == null
{advancedOptions && maker.minAmount != '' ? t('Order for ')
: fav.type == 1
? t('Buy order for ')
: t('Sell order for ')}
{maker.advancedOptions && maker.minAmount != ''
? pn(maker.minAmount) + '-' + pn(maker.maxAmount) ? pn(maker.minAmount) + '-' + pn(maker.maxAmount)
: pn(maker.amount)} : pn(maker.amount)}
{' ' + currencyCode} {' ' + currencyCode}
@ -437,12 +435,12 @@ const MakerForm = ({
return ( return (
<Box> <Box>
<ConfirmationDialogs /> <ConfirmationDialogs />
<Collapse in={loadingLimits}> <Collapse in={limits.list.length == 0}>
<div style={{ display: loadingLimits ? '' : 'none' }}> <div style={{ display: limits.list.length == 0 ? '' : 'none' }}>
<LinearProgress /> <LinearProgress />
</div> </div>
</Collapse> </Collapse>
<Collapse in={!(loadingLimits || collapseAll)}> <Collapse in={!(limits.list.length == 0 || collapseAll)}>
<Grid container justifyContent='space-between' spacing={0} sx={{ maxHeight: '1em' }}> <Grid container justifyContent='space-between' spacing={0} sx={{ maxHeight: '1em' }}>
<Grid item> <Grid item>
<IconButton <IconButton
@ -478,8 +476,8 @@ const MakerForm = ({
> >
<Switch <Switch
size='small' size='small'
disabled={loadingLimits} disabled={limits.list.length == 0}
checked={advancedOptions} checked={maker.advancedOptions}
onChange={handleClickAdvanced} onChange={handleClickAdvanced}
/> />
<SelfImprovement sx={{ color: 'text.secondary' }} /> <SelfImprovement sx={{ color: 'text.secondary' }} />
@ -499,17 +497,18 @@ const MakerForm = ({
<div style={{ textAlign: 'center' }}> <div style={{ textAlign: 'center' }}>
<ButtonGroup> <ButtonGroup>
<Button <Button
size={advancedOptions ? 'small' : 'large'} size={maker.advancedOptions ? 'small' : 'large'}
variant='contained' variant='contained'
onClick={() => onClick={() =>
setAppState({ setFav({
...fav,
type: 1, type: 1,
}) })
} }
disableElevation={type == 1} disableElevation={fav.type == 1}
sx={{ sx={{
backgroundColor: type == 1 ? 'primary.main' : 'background.paper', backgroundColor: fav.type == 1 ? 'primary.main' : 'background.paper',
color: type == 1 ? 'background.paper' : 'text.secondary', color: fav.type == 1 ? 'background.paper' : 'text.secondary',
':hover': { ':hover': {
color: 'background.paper', color: 'background.paper',
}, },
@ -518,18 +517,19 @@ const MakerForm = ({
{t('Buy')} {t('Buy')}
</Button> </Button>
<Button <Button
size={advancedOptions ? 'small' : 'large'} size={maker.advancedOptions ? 'small' : 'large'}
variant='contained' variant='contained'
onClick={() => onClick={() =>
setAppState({ setFav({
...fav,
type: 0, type: 0,
}) })
} }
disableElevation={type == 0} disableElevation={fav.type == 0}
color='secondary' color='secondary'
sx={{ sx={{
backgroundColor: type == 0 ? 'secondary.main' : 'background.paper', backgroundColor: fav.type == 0 ? 'secondary.main' : 'background.paper',
color: type == 0 ? 'background.secondary' : 'text.secondary', color: fav.type == 0 ? 'background.secondary' : 'text.secondary',
':hover': { ':hover': {
color: 'background.paper', color: 'background.paper',
}, },
@ -543,11 +543,11 @@ const MakerForm = ({
</Grid> </Grid>
<Grid item> <Grid item>
<Collapse in={advancedOptions}> <Collapse in={maker.advancedOptions}>
<AmountRange <AmountRange
minAmount={maker.minAmount} minAmount={maker.minAmount}
handleRangeAmountChange={handleRangeAmountChange} handleRangeAmountChange={handleRangeAmountChange}
currency={currency} currency={fav.currency}
currencyCode={currencyCode} currencyCode={currencyCode}
handleCurrencyChange={handleCurrencyChange} handleCurrencyChange={handleCurrencyChange}
amountLimits={amountLimits} amountLimits={amountLimits}
@ -558,7 +558,7 @@ const MakerForm = ({
handleMaxAmountChange={handleMaxAmountChange} handleMaxAmountChange={handleMaxAmountChange}
/> />
</Collapse> </Collapse>
<Collapse in={!advancedOptions}> <Collapse in={!maker.advancedOptions}>
<Grid item> <Grid item>
<Grid container alignItems='stretch' style={{ display: 'flex' }}> <Grid container alignItems='stretch' style={{ display: 'flex' }}>
<Grid item xs={6}> <Grid item xs={6}>
@ -571,8 +571,8 @@ const MakerForm = ({
> >
<TextField <TextField
fullWidth fullWidth
disabled={advancedOptions} disabled={maker.advancedOptions}
variant={advancedOptions ? 'filled' : 'outlined'} variant={maker.advancedOptions ? 'filled' : 'outlined'}
error={ error={
maker.amount != '' && maker.amount != '' &&
(maker.amount < amountLimits[0] || maker.amount > amountLimits[1]) (maker.amount < amountLimits[0] || maker.amount > amountLimits[1])
@ -613,7 +613,7 @@ const MakerForm = ({
inputProps={{ inputProps={{
style: { textAlign: 'center' }, style: { textAlign: 'center' },
}} }}
value={currency == 0 ? 1 : currency} value={fav.currency == 0 ? 1 : fav.currency}
onChange={(e) => handleCurrencyChange(e.target.value)} onChange={(e) => handleCurrencyChange(e.target.value)}
> >
{Object.entries(currencyDict).map(([key, value]) => ( {Object.entries(currencyDict).map(([key, value]) => (
@ -635,10 +635,10 @@ const MakerForm = ({
<AutocompletePayments <AutocompletePayments
onAutocompleteChange={handlePaymentMethodChange} onAutocompleteChange={handlePaymentMethodChange}
// listBoxProps={{ sx: { width: '15.3em', maxHeight: '20em' } }} // listBoxProps={{ sx: { width: '15.3em', maxHeight: '20em' } }}
optionsType={currency == 1000 ? 'swap' : 'fiat'} optionsType={fav.currency == 1000 ? 'swap' : 'fiat'}
error={maker.badPaymentMethod} error={maker.badPaymentMethod}
helperText={maker.badPaymentMethod ? t('Must be shorter than 65 characters') : ''} helperText={maker.badPaymentMethod ? t('Must be shorter than 65 characters') : ''}
label={currency == 1000 ? t('Swap Destination(s)') : t('Fiat Payment Method(s)')} label={fav.currency == 1000 ? t('Swap Destination(s)') : t('Fiat Payment Method(s)')}
tooltipTitle={t( tooltipTitle={t(
'Enter your preferred fiat payment methods. Fast methods are highly recommended.', 'Enter your preferred fiat payment methods. Fast methods are highly recommended.',
)} )}
@ -649,7 +649,7 @@ const MakerForm = ({
/> />
</Grid> </Grid>
{!advancedOptions && pricingMethods ? ( {!maker.advancedOptions && pricingMethods ? (
<Grid item xs={12}> <Grid item xs={12}>
<Box <Box
sx={{ sx={{
@ -691,7 +691,7 @@ const MakerForm = ({
title={t('Set a fix amount of satoshis')} title={t('Set a fix amount of satoshis')}
> >
<FormControlLabel <FormControlLabel
disabled={advancedOptions} disabled={maker.advancedOptions}
value='explicit' value='explicit'
control={<Radio color='secondary' />} control={<Radio color='secondary' />}
label={t('Exact')} label={t('Exact')}
@ -748,7 +748,7 @@ const MakerForm = ({
</div> </div>
</Grid> </Grid>
<Grid item> <Grid item>
<Collapse in={advancedOptions}> <Collapse in={maker.advancedOptions}>
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item xs={12}> <Grid item xs={12}>
<LocalizationProvider dateAdapter={DateFnsUtils}> <LocalizationProvider dateAdapter={DateFnsUtils}>
@ -944,7 +944,7 @@ const MakerForm = ({
</Typography> </Typography>
</Grid> </Grid>
<Collapse in={!loadingLimits}> <Collapse in={!(limits.list.length == 0)}>
<Tooltip <Tooltip
placement='top' placement='top'
enterTouchDelay={0} enterTouchDelay={0}

View File

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button, Grid, Paper, Collapse, Typography } from '@mui/material'; import { Button, Grid, Paper, Collapse, Typography } from '@mui/material';
import { LimitList, Maker, Order, defaultMaker } from '../../models'; import { LimitList, Maker, Order, Favorites, defaultMaker } from '../../models';
import MakerForm from './MakerForm'; import MakerForm from './MakerForm';
import BookTable from '../BookPage/BookTable'; import BookTable from '../BookPage/BookTable';
@ -10,38 +10,35 @@ import { useHistory } from 'react-router-dom';
import filterOrders from '../../utils/filterOrders'; import filterOrders from '../../utils/filterOrders';
interface MakerPageProps { interface MakerPageProps {
limits: LimitList; limits: { list: LimitList; loading: boolean };
fetchLimits: () => void; fetchLimits: () => void;
orders: Order[]; orders: Order[];
loadingLimits: boolean; fav: Favorites;
type: number; maker: Maker;
windowHeight: number; setFav: (state: Favorites) => void;
windowWidth: number; setMaker: (state: Maker) => void;
currency: number; windowSize: { width: number; height: number };
setAppState: (state: object) => void;
} }
const MakerPage = ({ const MakerPage = ({
limits, limits,
fetchLimits, fetchLimits,
orders, orders,
loadingLimits, fav,
currency, maker,
type, setFav,
setAppState, setMaker,
windowHeight, windowSize,
windowWidth,
}: MakerPageProps): JSX.Element => { }: MakerPageProps): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
const [maker, setMaker] = useState<Maker>(defaultMaker); const maxHeight = windowSize.height * 0.85 - 7;
const maxHeight = windowHeight ? windowHeight * 0.85 - 7 : 1000;
const [showMatches, setShowMatches] = useState<boolean>(false); const [showMatches, setShowMatches] = useState<boolean>(false);
const matches = filterOrders({ const matches = filterOrders({
orders, orders,
baseFilter: { currency: currency == 0 ? 1 : currency, type }, baseFilter: { currency: fav.currency === 0 ? 1 : fav.currency, type: fav.type },
paymentMethods: maker.paymentMethods, paymentMethods: maker.paymentMethods,
amountFilter: { amountFilter: {
amount: maker.amount, amount: maker.amount,
@ -61,10 +58,11 @@ const MakerPage = ({
</Grid> </Grid>
<Grid item> <Grid item>
<BookTable <BookTable
orders={matches.slice(0, matches.length > 4 ? 4 : matches.length)} book={{
type={type} orders: matches.slice(0, matches.length > 4 ? 4 : matches.length),
currency={currency} loading: false,
maxWidth={Math.min(windowWidth, 60)} // EM units }}
maxWidth={Math.min(windowSize.width, 60)} // EM units
maxHeight={Math.min(matches.length * 3.25 + 3.575, 16.575)} // EM units maxHeight={Math.min(matches.length * 3.25 + 3.575, 16.575)} // EM units
defaultFullscreen={false} defaultFullscreen={false}
showControls={false} showControls={false}
@ -82,13 +80,11 @@ const MakerPage = ({
<MakerForm <MakerForm
limits={limits} limits={limits}
fetchLimits={fetchLimits} fetchLimits={fetchLimits}
loadingLimits={loadingLimits}
pricingMethods={false} pricingMethods={false}
setAppState={setAppState} fav={fav}
setFav={setFav}
maker={maker} maker={maker}
setMaker={setMaker} setMaker={setMaker}
type={type}
currency={currency}
disableRequest={matches.length > 0 && !showMatches} disableRequest={matches.length > 0 && !showMatches}
collapseAll={showMatches} collapseAll={showMatches}
onSubmit={() => setShowMatches(matches.length > 0)} onSubmit={() => setShowMatches(matches.length > 0)}

View File

@ -525,10 +525,7 @@ class OrderPage extends Component {
<StoreTokenDialog <StoreTokenDialog
open={this.state.openStoreToken} open={this.state.openStoreToken}
onClose={() => this.setState({ openStoreToken: false })} onClose={() => this.setState({ openStoreToken: false })}
onClickCopy={() => onClickCopy={() => systemClient.copyToClipboard(systemClient.getCookie('robot_token'))}
systemClient.copyToClipboard(systemClient.getCookie('robot_token')) &
this.props.setAppState({ copiedToken: true })
}
copyIconColor={this.props.copiedToken ? 'inherit' : 'primary'} copyIconColor={this.props.copiedToken ? 'inherit' : 'primary'}
onClickBack={() => this.setState({ openStoreToken: false })} onClickBack={() => this.setState({ openStoreToken: false })}
onClickDone={() => onClickDone={() =>

View File

@ -11,7 +11,6 @@ import {
IconButton, IconButton,
} from '@mui/material'; } from '@mui/material';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import SmoothImage from 'react-smooth-image';
import { InfoDialog } from './Dialogs'; import { InfoDialog } from './Dialogs';
import SmartToyIcon from '@mui/icons-material/SmartToy'; import SmartToyIcon from '@mui/icons-material/SmartToy';
@ -35,7 +34,7 @@ class UserGenPage extends Component {
this.state = { this.state = {
openInfo: false, openInfo: false,
tokenHasChanged: false, tokenHasChanged: false,
token: '', inputToken: '',
}; };
this.refCode = this.props.match.params.refCode; this.refCode = this.props.match.params.refCode;
@ -44,19 +43,18 @@ class UserGenPage extends Component {
componentDidMount() { componentDidMount() {
// Checks in parent HomePage if there is already a nick and token // Checks in parent HomePage if there is already a nick and token
// Displays the existing one // Displays the existing one
if (this.props.nickname != null) { if (this.props.robot.nickname != null) {
this.setState({ this.setState({
token: this.props.token ? this.props.token : '', inputToken: this.props.robot.token ? this.props.robot.token : '',
loadingRobot: false,
}); });
} else if (window.NativeRobosats && systemClient.getCookie('robot_token')) { } else if (window.NativeRobosats && systemClient.getCookie('robot_token')) {
const token = systemClient.getCookie('robot_token'); const token = systemClient.getCookie('robot_token');
this.setState({ token }); this.setState({ inputToken: token });
this.getGeneratedUser(token); this.getGeneratedUser(token);
} else { } else {
const newToken = genBase62Token(36); const newToken = genBase62Token(36);
this.setState({ this.setState({
token: newToken, inputToken: newToken,
}); });
this.getGeneratedUser(newToken); this.getGeneratedUser(newToken);
} }
@ -65,6 +63,7 @@ class UserGenPage extends Component {
getGeneratedUser = (token) => { getGeneratedUser = (token) => {
const strength = tokenStrength(token); const strength = tokenStrength(token);
const refCode = this.refCode; const refCode = this.refCode;
this.props.setRobot({ ...this.props.robot, loading: true });
const requestBody = genKey(token).then(function (key) { const requestBody = genKey(token).then(function (key) {
return { return {
@ -79,46 +78,44 @@ class UserGenPage extends Component {
}); });
requestBody.then((body) => requestBody.then((body) =>
apiClient.post('/api/user/', body).then((data) => { apiClient.post('/api/user/', body).then((data) => {
this.setState({
bit_entropy: data.token_bits_entropy,
shannon_entropy: data.token_shannon_entropy,
bad_request: data.bad_request,
found: data.found,
loadingRobot: false,
stealthInvoices: data.wants_stealth,
}) &
// Add nick and token to App state (token only if not a bad request) // Add nick and token to App state (token only if not a bad request)
(data.bad_request data.bad_request
? this.props.setAppState({ ? this.props.setRobot({
...this.props.robot,
nickname: data.nickname, nickname: data.nickname,
avatarLoaded: false, avatarLoaded: false,
activeOrderId: data.active_order_id ? data.active_order_id : null, activeOrderId: data.active_order_id ? data.active_order_id : null,
referralCode: data.referral_code, referralCode: data.referral_code,
earnedRewards: data.earned_rewards, earnedRewards: data.earned_rewards ?? 0,
lastOrderId: data.last_order_id ? data.last_order_id : null, lastOrderId: data.last_order_id ? data.last_order_id : null,
stealthInvoices: data.wants_stealth, stealthInvoices: data.wants_stealth,
}) })
: this.props.setAppState({ : this.props.setRobot({
...this.props.robot,
nickname: data.nickname, nickname: data.nickname,
token, token,
avatarLoaded: false, avatarLoaded: false,
activeOrderId: data.active_order_id ? data.active_order_id : null, activeOrderId: data.active_order_id ? data.active_order_id : null,
lastOrderId: data.last_order_id ? data.last_order_id : null, lastOrderId: data.last_order_id ? data.last_order_id : null,
referralCode: data.referral_code, referralCode: data.referral_code,
earnedRewards: data.earned_rewards, earnedRewards: data.earned_rewards ?? 0,
stealthInvoices: data.wants_stealth, stealthInvoices: data.wants_stealth,
tgEnabled: data.tg_enabled, tgEnabled: data.tg_enabled,
tgBotName: data.tg_bot_name, tgBotName: data.tg_bot_name,
tgToken: data.tg_token, tgToken: data.tg_token,
bitsEntropy: data.token_bits_entropy,
shannonEntropy: data.token_shannon_entropy,
pub_key: data.public_key,
enc_priv_key: data.encrypted_private_key,
}) & }) &
systemClient.setCookie('robot_token', token) & systemClient.setCookie('robot_token', token) &
systemClient.setCookie('pub_key', data.public_key.split('\n').join('\\')) & systemClient.setCookie('pub_key', data.public_key.split('\n').join('\\')) &
systemClient.setCookie( systemClient.setCookie(
'enc_priv_key', 'enc_priv_key',
data.encrypted_private_key.split('\n').join('\\'), data.encrypted_private_key.split('\n').join('\\'),
)) & );
// If the robot has been found (recovered) we assume the token is backed up // If the robot has been found (recovered) we assume the token is backed up
(data.found ? this.props.setAppState({ copiedToken: true }) : null); data.found ? this.props.setRobot({ ...this.props.robot, copiedToken: true }) : null;
}), }),
); );
}; };
@ -133,26 +130,27 @@ class UserGenPage extends Component {
} }
handleClickNewRandomToken = () => { handleClickNewRandomToken = () => {
const token = genBase62Token(36); const inputToken = genBase62Token(36);
this.setState({ this.setState({
token, inputToken,
tokenHasChanged: true, tokenHasChanged: true,
}); });
this.props.setAppState({ copiedToken: true }); this.props.setRobot({ ...this.props.robot, copiedToken: true });
}; };
handleChangeToken = (e) => { handleChangeToken = (e) => {
this.setState({ this.setState({
token: e.target.value.split(' ').join(''), inputToken: e.target.value.split(' ').join(''),
tokenHasChanged: true, tokenHasChanged: true,
}); });
}; };
handleClickSubmitToken = () => { handleClickSubmitToken = () => {
this.delGeneratedUser(); this.delGeneratedUser();
this.getGeneratedUser(this.state.token); this.getGeneratedUser(this.state.inputToken);
this.setState({ loadingRobot: true, tokenHasChanged: false }); this.setState({ tokenHasChanged: false });
this.props.setAppState({ this.props.setRobot({
...this.props.robot,
avatarLoaded: false, avatarLoaded: false,
nickname: null, nickname: null,
token: null, token: null,
@ -172,11 +170,11 @@ class UserGenPage extends Component {
createJsonFile = () => { createJsonFile = () => {
return { return {
token: systemClient.getCookie('robot_token'), token: this.props.robot.token,
token_shannon_entropy: this.state.shannon_entropy, token_shannon_entropy: this.props.robot.shannonEntropy,
token_bit_entropy: this.state.bit_entropy, token_bit_entropy: this.props.robot.bitsEntropy,
public_key: systemClient.getCookie('pub_key').split('\\').join('\n'), public_key: this.props.robot.pub_key,
encrypted_private_key: systemClient.getCookie('enc_priv_key').split('\\').join('\n'), encrypted_private_key: this.props.robot.enc_priv_key,
}; };
}; };
@ -195,12 +193,12 @@ class UserGenPage extends Component {
align='center' align='center'
sx={{ width: 370 * fontSizeFactor, height: 260 * fontSizeFactor }} sx={{ width: 370 * fontSizeFactor, height: 260 * fontSizeFactor }}
> >
{this.props.avatarLoaded && this.props.nickname ? ( {this.props.robot.avatarLoaded && this.props.robot.nickname ? (
<div> <div>
<Grid item xs={12} align='center'> <Grid item xs={12} align='center'>
<Typography component='h5' variant='h5'> <Typography component='h5' variant='h5'>
<b> <b>
{this.props.nickname && systemClient.getCookie('sessionid') ? ( {this.props.robot.nickname && systemClient.getCookie('sessionid') ? (
<div <div
style={{ style={{
display: 'flex', display: 'flex',
@ -217,7 +215,7 @@ class UserGenPage extends Component {
width: 33 * fontSizeFactor, width: 33 * fontSizeFactor,
}} }}
/> />
<a>{this.props.nickname}</a> <a>{this.props.robot.nickname}</a>
<BoltIcon <BoltIcon
sx={{ sx={{
color: '#fcba03', color: '#fcba03',
@ -234,7 +232,7 @@ class UserGenPage extends Component {
</Grid> </Grid>
<Grid item xs={12} align='center'> <Grid item xs={12} align='center'>
<RobotAvatar <RobotAvatar
nickname={this.props.nickname} nickname={this.props.robot.nickname}
smooth={true} smooth={true}
style={{ maxWidth: 203 * fontSizeFactor, maxHeight: 203 * fontSizeFactor }} style={{ maxWidth: 203 * fontSizeFactor, maxHeight: 203 * fontSizeFactor }}
imageStyle={{ imageStyle={{
@ -245,7 +243,7 @@ class UserGenPage extends Component {
width: `${201 * fontSizeFactor}px`, width: `${201 * fontSizeFactor}px`,
}} }}
tooltip={t('This is your trading avatar')} tooltip={t('This is your trading avatar')}
tooltipPosition='up' tooltipPosition='top'
/> />
<br /> <br />
</Grid> </Grid>
@ -271,7 +269,7 @@ class UserGenPage extends Component {
error={!!this.state.bad_request} error={!!this.state.bad_request}
label={t('Store your token safely')} label={t('Store your token safely')}
required={true} required={true}
value={this.state.token} value={this.state.inputToken}
variant='standard' variant='standard'
helperText={this.state.bad_request} helperText={this.state.bad_request}
size='small' size='small'
@ -301,11 +299,14 @@ class UserGenPage extends Component {
<IconButton <IconButton
color='primary' color='primary'
disabled={ disabled={
!this.props.avatarLoaded || !this.props.robot.avatarLoaded ||
!(systemClient.getCookie('robot_token') === this.state.token) !(systemClient.getCookie('robot_token') === this.state.inputToken)
} }
onClick={() => onClick={() =>
saveAsJson(this.props.nickname + '.json', this.createJsonFile()) saveAsJson(
this.props.robot.nickname + '.json',
this.createJsonFile(),
)
} }
> >
<DownloadIcon <DownloadIcon
@ -318,14 +319,14 @@ class UserGenPage extends Component {
<Grid item xs={6}> <Grid item xs={6}>
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}> <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
<IconButton <IconButton
color={this.props.copiedToken ? 'inherit' : 'primary'} color={this.props.robot.copiedToken ? 'inherit' : 'primary'}
disabled={ disabled={
!this.props.avatarLoaded || !this.props.robot.avatarLoaded ||
!(systemClient.getCookie('robot_token') === this.state.token) !(systemClient.getCookie('robot_token') === this.state.inputToken)
} }
onClick={() => onClick={() =>
systemClient.copyToClipboard(systemClient.getCookie('robot_token')) & systemClient.copyToClipboard(systemClient.getCookie('robot_token')) &
this.props.setAppState({ copiedToken: true }) this.props.setRobot({ ...this.props.robot, copiedToken: true })
} }
> >
<ContentCopy <ContentCopy
@ -376,9 +377,9 @@ class UserGenPage extends Component {
<ButtonGroup variant='contained' aria-label='outlined primary button group'> <ButtonGroup variant='contained' aria-label='outlined primary button group'>
<Button <Button
disabled={ disabled={
this.state.loadingRobot !== false || this.props.robot.loading ||
!(this.props.token !(this.props.robot.token
? systemClient.getCookie('robot_token') === this.props.token ? systemClient.getCookie('robot_token') === this.props.robot.token
: true) : true)
} }
color='primary' color='primary'
@ -397,9 +398,9 @@ class UserGenPage extends Component {
/> />
<Button <Button
disabled={ disabled={
this.state.loadingRobot !== false || this.props.robot.loading ||
!(this.props.token !(this.props.robot.token
? systemClient.getCookie('robot_token') === this.props.token ? systemClient.getCookie('robot_token') === this.props.robot.token
: true) : true)
} }
color='secondary' color='secondary'
@ -411,11 +412,11 @@ class UserGenPage extends Component {
</ButtonGroup> </ButtonGroup>
</Grid> </Grid>
<Grid item xs={12} align='center' sx={{ width: 370 * fontSizeFactor }}> <Grid item xs={12} align='center' sx={{ width: '26.43em' }}>
<Grid item> <Grid item>
<div style={{ height: 30 * fontSizeFactor }} /> <div style={{ height: '2.143em' }} />
</Grid> </Grid>
<div style={{ width: 370 * fontSizeFactor, left: 30 * fontSizeFactor }}> <div style={{ width: '26.43em', left: '2.143em' }}>
<Grid container align='center'> <Grid container align='center'>
<Grid item xs={0.8} /> <Grid item xs={0.8} />
<Grid item xs={7.5} align='right'> <Grid item xs={7.5} align='right'>
@ -424,10 +425,7 @@ class UserGenPage extends Component {
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={2.5} align='left'> <Grid item xs={2.5} align='left'>
<RoboSatsNoTextIcon <RoboSatsNoTextIcon color='primary' sx={{ height: '3.143em', width: '3.143em' }} />
color='primary'
sx={{ height: 72 * fontSizeFactor, width: 72 * fontSizeFactor }}
/>
</Grid> </Grid>
</Grid> </Grid>
</div> </div>

View File

@ -23,4 +23,9 @@ export interface Order {
maker_status: 'Active' | 'Seen recently' | 'Inactive'; maker_status: 'Active' | 'Seen recently' | 'Inactive';
} }
export interface Book {
orders: Order[];
loading: boolean;
}
export default Order; export default Order;

View File

@ -0,0 +1,6 @@
export interface Favorites {
type: number | null;
currency: number;
}
export default Favorites;

View File

@ -0,0 +1,49 @@
export interface Info {
num_public_buy_orders: number;
num_public_sell_orders: number;
book_liquidity: number;
active_robots_today: number;
last_day_nonkyc_btc_premium: number;
last_day_volume: number;
lifetime_volume: number;
lnd_version: string;
robosats_running_commit_hash: string;
alternative_site: string;
alternative_name: string;
node_alias: string;
node_id: string;
version: { major: number | null; minor: number | null; patch: number | null };
maker_fee: number;
taker_fee: number;
bond_size: number;
current_swap_fee_rate: number;
coordinatorVersion: string;
clientVersion: string;
openUpdateClient: boolean;
}
export const defaultInfo: Info = {
num_public_buy_orders: 0,
num_public_sell_orders: 0,
book_liquidity: 0,
active_robots_today: 0,
last_day_nonkyc_btc_premium: 0,
last_day_volume: 0,
lifetime_volume: 0,
lnd_version: 'v0.0.0-beta',
robosats_running_commit_hash: '000000000000000',
alternative_site: 'RoboSats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion',
alternative_name: 'RoboSats Mainnet',
node_alias: '🤖RoboSats⚡(RoboDevs)',
node_id: '033b58d7681fe5dd2fb21fd741996cda5449616f77317dd1156b80128d6a71b807',
version: { major: null, minor: null, patch: null },
maker_fee: 0,
taker_fee: 0,
bond_size: 0,
current_swap_fee_rate: 0,
coordinatorVersion: 'v?.?.?',
clientVersion: 'v?.?.?',
openUpdateClient: false,
};
export default Info;

View File

@ -1,4 +1,5 @@
export interface Maker { export interface Maker {
advancedOptions: boolean;
isExplicit: boolean; isExplicit: boolean;
amount: string; amount: string;
paymentMethods: string[]; paymentMethods: string[];
@ -18,6 +19,7 @@ export interface Maker {
} }
export const defaultMaker: Maker = { export const defaultMaker: Maker = {
advancedOptions: false,
isExplicit: false, isExplicit: false,
amount: '', amount: '',
paymentMethods: [], paymentMethods: [],

View File

@ -0,0 +1,49 @@
import { systemClient } from '../services/System';
export interface Robot {
nickname: string | null;
token: string | null;
pub_key: string | null;
enc_priv_key: string | null;
bitsEntropy: number | null;
shannonEntropy: number | null;
stealthInvoices: boolean;
activeOrderId: number | null;
lastOrderId: number | null;
earnedRewards: number;
referralCode: string;
tgEnabled: boolean;
tgBotName: string;
tgToken: string;
loading: boolean;
avatarLoaded: boolean;
copiedToken: boolean;
}
export const defaultRobot: Robot = {
nickname: null,
token: systemClient.getCookie('robot_token') ?? null,
pub_key:
systemClient.getCookie('pub_key') === undefined
? null
: systemClient.getCookie('pub_key').split('\\').join('\n'),
enc_priv_key:
systemClient.getCookie('enc_priv_key') === undefined
? null
: systemClient.getCookie('enc_priv_key').split('\\').join('\n'),
bitsEntropy: null,
shannonEntropy: null,
stealthInvoices: true,
activeOrderId: null,
lastOrderId: null,
earnedRewards: 0,
referralCode: '',
tgEnabled: false,
tgBotName: 'unknown',
tgToken: 'unknown',
loading: true,
avatarLoaded: false,
copiedToken: false,
};
export default Robot;

View File

@ -0,0 +1,5 @@
export interface Settings {}
export const defaultSettings: Settings = {};
export default Settings;

View File

@ -1,5 +1,14 @@
export type { LimitList } from './Limit.model'; export type { LimitList } from './Limit.model';
export type { Limit } from './Limit.model'; export type { Limit } from './Limit.model';
export type { Maker } from './Maker.model'; export type { Maker } from './Maker.model';
export type { Order } from './Book.model';
export type { Book } from './Book.model';
export type { Robot } from './Robot.model';
export type { Info } from './Info.model';
export type { Settings } from './Settings.model';
export type { Favorites } from './Favorites.model';
export { defaultMaker } from './Maker.model'; export { defaultMaker } from './Maker.model';
export type { Order } from './Order.model'; export { defaultRobot } from './Robot.model';
export { defaultSettings } from './Settings.model';
export { defaultInfo } from './Info.model';

View File

@ -11,8 +11,8 @@ export const checkVer: (
return { updateAvailable: null }; return { updateAvailable: null };
} }
const semver = packageJson.version.split('.'); const semver = packageJson.version.split('.');
const updateAvailable = major > Number(semver[0]) || minor > Number(semver[1]); const updateAvailable: boolean = major > Number(semver[0]) || minor > Number(semver[1]);
const patchAvailable = !updateAvailable && patch > Number(semver[2]); const patchAvailable: boolean = !updateAvailable && patch > Number(semver[2]);
return { return {
updateAvailable, updateAvailable,

View File

@ -1,9 +1,4 @@
import Order from '../models/Order.model'; import { Order, Favorites } from '../models';
interface BaseFilter {
currency: number;
type: number | null;
}
interface AmountFilter { interface AmountFilter {
amount: string; amount: string;
@ -14,12 +9,12 @@ interface AmountFilter {
interface FilterOrders { interface FilterOrders {
orders: Order[]; orders: Order[];
baseFilter: BaseFilter; baseFilter: Favorites;
amountFilter?: AmountFilter | null; amountFilter?: AmountFilter | null;
paymentMethods?: string[]; paymentMethods?: string[];
} }
const filterByPayment = function (order: Order, paymentMethods: string[]) { const filterByPayment = function (order: Order, paymentMethods: any[]) {
if (paymentMethods.length === 0) { if (paymentMethods.length === 0) {
return true; return true;
} else { } else {
@ -32,17 +27,19 @@ const filterByPayment = function (order: Order, paymentMethods: string[]) {
}; };
const filterByAmount = function (order: Order, filter: AmountFilter) { const filterByAmount = function (order: Order, filter: AmountFilter) {
const filterMaxAmount = filter.amount != '' ? filter.amount : filter.maxAmount; const filterMaxAmount =
const filterMinAmount = filter.amount != '' ? filter.amount : filter.minAmount; Number(filter.amount != '' ? filter.amount : filter.maxAmount) * (1 + filter.threshold);
const orderMinAmount = const filterMinAmount =
order.amount === '' || order.amount === null ? order.min_amount : order.amount; Number(filter.amount != '' ? filter.amount : filter.minAmount) * (1 - filter.threshold);
const orderMaxAmount =
order.amount === '' || order.amount === null ? order.max_amount : order.amount;
return ( const orderMinAmount = Number(
orderMaxAmount < filterMaxAmount * (1 + filter.threshold) && order.amount === '' || order.amount === null ? order.min_amount : order.amount,
orderMinAmount > filterMinAmount * (1 - filter.threshold)
); );
const orderMaxAmount = Number(
order.amount === '' || order.amount === null ? order.max_amount : order.amount,
);
return Math.max(filterMinAmount, orderMinAmount) <= Math.min(filterMaxAmount, orderMaxAmount);
}; };
const filterOrders = function ({ const filterOrders = function ({
@ -60,7 +57,6 @@ const filterOrders = function ({
return typeChecks && currencyChecks && paymentMethodChecks && amountChecks; return typeChecks && currencyChecks && paymentMethodChecks && amountChecks;
}); });
return filteredOrders; return filteredOrders;
}; };

View File

@ -79,11 +79,6 @@ input[type='number'] {
-moz-appearance: textfield; -moz-appearance: textfield;
} }
.bottomBar {
position: fixed;
bottom: 0;
}
.amboss { .amboss {
fill: url(#SVGID_1_); fill: url(#SVGID_1_);
} }