diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 102c1204..8a4bce7d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -3235,11 +3235,11 @@ } }, "node_modules/@mui/utils": { - "version": "5.10.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.3.tgz", - "integrity": "sha512-4jXMDPfx6bpMVuheLaOpKTjpzw39ogAZLeaLj5+RJec3E37/hAZMYjURfblLfTWMMoGoqkY03mNsZaEwNobBow==", + "version": "5.10.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.9.tgz", + "integrity": "sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==", "dependencies": { - "@babel/runtime": "^7.18.9", + "@babel/runtime": "^7.19.0", "@types/prop-types": "^15.7.5", "@types/react-is": "^16.7.1 || ^17.0.0", "prop-types": "^15.8.1", @@ -17137,11 +17137,11 @@ "requires": {} }, "@mui/utils": { - "version": "5.10.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.3.tgz", - "integrity": "sha512-4jXMDPfx6bpMVuheLaOpKTjpzw39ogAZLeaLj5+RJec3E37/hAZMYjURfblLfTWMMoGoqkY03mNsZaEwNobBow==", + "version": "5.10.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.9.tgz", + "integrity": "sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==", "requires": { - "@babel/runtime": "^7.18.9", + "@babel/runtime": "^7.19.0", "@types/prop-types": "^15.7.5", "@types/react-is": "^16.7.1 || ^17.0.0", "prop-types": "^15.8.1", diff --git a/frontend/src/components/App.js b/frontend/src/components/App.js deleted file mode 100644 index 258a9600..00000000 --- a/frontend/src/components/App.js +++ /dev/null @@ -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 ( - - - - - this.setState({ openLearn: false })} - /> - - this.setState({ openLearn: true })} - > - - - this.handleThemeChange()} - > - {this.state.theme.palette.mode === 'dark' ? : } - - - - - - - ); - } -} - -const loadApp = () => { - if (systemClient.loading) { - setTimeout(loadApp, 200); - } else { - const root = ReactDOM.createRoot(document.getElementById('app')); - root.render(); - } -}; - -loadApp(); diff --git a/frontend/src/components/App.tsx b/frontend/src/components/App.tsx new file mode 100644 index 00000000..603fd9cd --- /dev/null +++ b/frontend/src/components/App.tsx @@ -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(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 ( + + + + + setOpenLearn(false)} /> + + setOpenLearn(true)} + > + + + handleModeChange()} + > + {theme.palette.mode === 'dark' ? : } + + +
+ + + + ); +}; + +const loadApp = () => { + if (systemClient.loading) { + setTimeout(loadApp, 200); + } else { + const root = ReactDOM.createRoot(document.getElementById('app') ?? new HTMLElement()); + root.render(); + } +}; + +loadApp(); diff --git a/frontend/src/components/BookPage/BookPage.tsx b/frontend/src/components/BookPage/BookPage.tsx index e760c854..70013709 100644 --- a/frontend/src/components/BookPage/BookPage.tsx +++ b/frontend/src/components/BookPage/BookPage.tsx @@ -5,7 +5,7 @@ import { useHistory } from 'react-router-dom'; import currencyDict from '../../../static/assets/currencies.json'; import DepthChart from '../Charts/DepthChart'; -import { Order, LimitList, Maker } from '../../models'; +import { Book, Favorites, LimitList, Maker } from '../../models'; // Icons import { BarChart, FormatListBulleted } from '@mui/icons-material'; @@ -13,43 +13,37 @@ import BookTable from './BookTable'; import { MakerForm } from '../MakerPage'; interface BookPageProps { - bookLoading?: boolean; - bookRefreshing?: boolean; - loadingLimits: boolean; - lastDayPremium: number; - orders: Order[]; - limits: LimitList; + book: Book; + limits: { list: LimitList; loading: boolean }; fetchLimits: () => void; - type: number; - currency: number; - windowWidth: number; - windowHeight: number; - fetchBook: (loading: boolean, refreshing: boolean) => void; - setAppState: (state: object) => void; + fav: Favorites; + setFav: (state: Favorites) => void; + fetchBook: () => void; + windowSize: { width: number; height: number }; + lastDayPremium: number; + maker: Maker; + setMaker: (state: Maker) => void; } const BookPage = ({ - bookLoading = false, - bookRefreshing = false, lastDayPremium = 0, - loadingLimits, - orders = [], limits, - fetchLimits, - type, - currency, - windowWidth, - windowHeight, - setAppState, + book = { orders: [], loading: true }, fetchBook, + fetchLimits, + fav, + setFav, + maker, + setMaker, + windowSize, }: BookPageProps): JSX.Element => { const { t } = useTranslation(); const history = useHistory(); const [view, setView] = useState<'list' | 'depth'>('list'); const [openMaker, setOpenMaker] = useState(false); - const doubleView = windowWidth > 115; - const width = windowWidth * 0.9; + const doubleView = windowSize.width > 115; + const width = windowSize.width * 0.9; const maxBookTableWidth = 85; const chartWidthEm = width - maxBookTableWidth; @@ -72,10 +66,8 @@ const BookPage = ({ badSatoshisText: '', }; - const [maker, setMaker] = useState(defaultMaker); - useEffect(() => { - if (orders.length < 1) { + if (book.orders.length < 1) { fetchBook(true, false); } else { fetchBook(false, true); @@ -84,11 +76,11 @@ const BookPage = ({ const handleCurrencyChange = function (e) { const currency = e.target.value; - setAppState({ currency }); + setFav({ ...fav, currency }); }; const handleTypeChange = function (mouseEvent, val) { - setAppState({ type: val }); + setFav({ ...fav, type: val }); }; const NoOrdersFound = function () { @@ -102,12 +94,14 @@ const BookPage = ({ > - {type == 0 + {fav.type == 0 ? 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}}', { - currencyCode: currency == 0 ? t('ANY') : currencyDict[currency.toString()], + currencyCode: + fav.currency == 0 ? t('ANY') : currencyDict[fav.currency.toString()], })} @@ -159,14 +153,11 @@ const BookPage = ({ @@ -180,20 +171,17 @@ const BookPage = ({ justifyContent='center' spacing={1} direction='row' - style={{ width: `${windowWidth}em` }} + style={{ width: `${windowSize.width}em` }} > fetchBook(false, true)} - orders={orders} - type={type} - currency={currency} + clickRefresh={() => fetchBook()} + book={book} + fav={fav} maxWidth={maxBookTableWidth} // EM units - maxHeight={windowHeight * 0.825 - 5} // EM units - fullWidth={windowWidth} // EM units - fullHeight={windowHeight} // EM units + maxHeight={windowSize.height * 0.825 - 5} // EM units + fullWidth={windowSize.width} // EM units + fullHeight={windowSize.height} // EM units defaultFullscreen={false} onCurrencyChange={handleCurrencyChange} onTypeChange={handleTypeChange} @@ -202,41 +190,33 @@ const BookPage = ({ ) : view === 'depth' ? ( ) : ( fetchBook(false, true)} - orders={orders} - type={type} - currency={currency} - maxWidth={windowWidth * 0.97} // EM units - maxHeight={windowHeight * 0.825 - 5} // EM units - fullWidth={windowWidth} // EM units - fullHeight={windowHeight} // EM units + book={book} + clickRefresh={() => fetchBook()} + fav={fav} + maxWidth={windowSize.width * 0.97} // EM units + maxHeight={windowSize.height * 0.825 - 5} // EM units + fullWidth={windowSize.width} // EM units + fullHeight={windowSize.height} // EM units defaultFullscreen={false} onCurrencyChange={handleCurrencyChange} onTypeChange={handleTypeChange} diff --git a/frontend/src/components/BookPage/BookTable.tsx b/frontend/src/components/BookPage/BookTable.tsx index 4bf5602f..645a2550 100644 --- a/frontend/src/components/BookPage/BookTable.tsx +++ b/frontend/src/components/BookPage/BookTable.tsx @@ -18,7 +18,7 @@ import { } from '@mui/material'; import { DataGrid, GridPagination } from '@mui/x-data-grid'; import currencyDict from '../../../static/assets/currencies.json'; -import { Order } from '../../models'; +import { Book, Favorites } from '../../models'; import filterOrders from '../../utils/filterOrders'; import BookControl from './BookControl'; @@ -30,15 +30,12 @@ import hexToRgb from '../../utils/hexToRgb'; import statusBadgeColor from '../../utils/statusBadgeColor'; // Icons -import { Fullscreen, FullscreenExit, Refresh, WidthFull } from '@mui/icons-material'; +import { Fullscreen, FullscreenExit, Refresh } from '@mui/icons-material'; interface Props { - loading?: boolean; - refreshing?: boolean; clickRefresh?: () => void; - orders: Order[]; - type: number; - currency: number; + book: Book; + fav?: Favorites; maxWidth: number; maxHeight: number; fullWidth?: number; @@ -46,18 +43,15 @@ interface Props { defaultFullscreen: boolean; showControls?: boolean; showFooter?: boolean; - onCurrencyChange?: () => void; - onTypeChange?: () => void; - noResultsOverlay?: JSX.Element; + onCurrencyChange?: (e: any) => void; + onTypeChange?: (mouseEvent: any, val: number) => void; + noResultsOverlay?: () => JSX.Element; } const BookTable = ({ - loading = false, - refreshing = false, clickRefresh, - orders, - type, - currency, + book, + fav, maxWidth, maxHeight, fullWidth, @@ -666,8 +660,8 @@ const BookTable = ({ return ( { setPageSize(newPageSize); @@ -728,16 +722,20 @@ const BookTable = ({ - (order.type == type || type == null) && - (order.currency == currency || currency == 0), - )} - loading={loading || refreshing} + rows={ + showControls + ? filterOrders({ + orders: book.orders, + baseFilter: fav, + paymentMethods, + }) + : book.orders + } + loading={book.loading} columns={columns} hideFooter={!showFooter} components={gridComponents()} - pageSize={loading ? 0 : pageSize} + pageSize={book.loading && book.orders.length == 0 ? 0 : pageSize} rowsPerPageOptions={[0, pageSize, defaultPageSize * 2, 50, 100]} onPageSizeChange={(newPageSize) => { setPageSize(newPageSize); diff --git a/frontend/src/components/BottomBar.js b/frontend/src/components/BottomBar.js index 9e6a859e..fb1ac8dd 100644 --- a/frontend/src/components/BottomBar.js +++ b/frontend/src/components/BottomBar.js @@ -4,7 +4,6 @@ import { Badge, Tooltip, ListItemAvatar, - Avatar, Paper, Grid, IconButton, @@ -42,31 +41,16 @@ import { UpdateClientDialog, } from './Dialogs'; -import checkVer from '../utils/checkVer'; - class BottomBar extends Component { constructor(props) { super(props); this.state = { + profileShown: false, openStatsForNerds: false, - openCommuniy: false, + openCommunity: false, openExchangeSummary: 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, - profileShown: false, - alternative_site: 'robosats...', - node_id: '00000000', showRewards: false, rewardInvoice: null, 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 = () => { this.setState({ openStatsForNerds: true }); }; @@ -114,15 +68,14 @@ class BottomBar extends Component { }; handleClickOpenCommunity = () => { - this.setState({ openCommuniy: true }); + this.setState({ openCommunity: true }); }; handleClickCloseCommunity = () => { - this.setState({ openCommuniy: false }); + this.setState({ openCommunity: false }); }; handleClickOpenProfile = () => { - this.getInfo(); this.setState({ openProfile: true, profileShown: true }); }; @@ -130,35 +83,44 @@ class BottomBar extends Component { this.setState({ openProfile: false }); }; + handleClickOpenExchangeSummary = () => { + this.setState({ openExchangeSummary: true }); + }; + + handleClickCloseExchangeSummary = () => { + this.setState({ openExchangeSummary: false }); + }; + handleSubmitInvoiceClicked = (e, rewardInvoice) => { - this.setState({ - badInvoice: false, - showRewardsSpinner: true, - }); + this.setState({ badInvoice: false, showRewardsSpinner: true }); apiClient .post('/api/reward/', { invoice: rewardInvoice, }) - .then( - (data) => - this.setState({ - badInvoice: data.bad_invoice, - openClaimRewards: !data.successful_withdrawal, - withdrawn: !!data.successful_withdrawal, - showRewardsSpinner: false, - }) & - this.props.setAppState({ - earnedRewards: data.successful_withdrawal ? 0 : this.props.earnedRewards, - }), - ); + .then((data) => { + this.setState({ badInvoice: data.bad_invoice, showRewardsSpinner: false }); + this.props.setInfo({ + ...this.props.info, + badInvoice: data.bad_invoice, + openClaimRewards: !data.successful_withdrawal, + withdrawn: !!data.successful_withdrawal, + showRewardsSpinner: false, + }); + this.props.setRobot({ + ...this.props.robot, + earnedRewards: data.successful_withdrawal ? 0 : this.props.robot.earnedRewards, + }); + }); e.preventDefault(); }; handleSetStealthInvoice = (wantsStealth) => { apiClient .put('/api/stealth/', { wantsStealth }) - .then((data) => this.props.setAppState({ stealthInvoices: data?.wantsStealth })); + .then((data) => + this.props.setRobot({ ...this.props.robot, stealthInvoices: data?.wantsStealth }), + ); }; getHost() { @@ -171,19 +133,21 @@ class BottomBar extends Component { showProfileButton = () => { return ( - this.props.avatarLoaded && - (this.props.token ? systemClient.getCookie('robot_token') === this.props.token : true) && + this.props.robot.avatarLoaded && + (this.props.robot.token + ? systemClient.getCookie('robot_token') === this.props.robot.token + : true) && systemClient.getCookie('sessionid') ); }; bottomBarDesktop = () => { const { t } = this.props; - const hasRewards = this.props.earnedRewards > 0; + const hasRewards = this.props.robot.earnedRewards > 0; const hasOrder = !!( - (this.props.activeOrderId > 0) & + (this.props.robot.activeOrderId > 0) & !this.state.profileShown & - this.props.avatarLoaded + this.props.robot.avatarLoaded ); const fontSize = this.props.theme.typography.fontSize; const fontSizeFactor = fontSize / 14; // default fontSize is 14 @@ -192,7 +156,10 @@ class BottomBar extends Component { secondaryTypographyProps: { fontSize: (fontSize * 12) / 14 }, }; return ( - +
@@ -208,16 +175,18 @@ class BottomBar extends Component { 0) & !this.props.profileShown + (this.props.robot.activeOrderId > 0) & !this.state.profileShown ? 'primary' : undefined } - nickname={this.props.nickname} - onLoad={() => this.props.setAppState({ avatarLoaded: true })} + nickname={this.props.robot.nickname} + onLoad={() => + this.props.setRobot({ ...this.props.robot, avatarLoaded: true }) + } /> - +
@@ -228,10 +197,6 @@ class BottomBar extends Component { - this.props.setAppState({ buyChecked: false, sellChecked: true, type: 0 }) & - this.getInfo() - } to={`/book/`} component={LinkRouter} > @@ -240,7 +205,7 @@ class BottomBar extends Component { @@ -252,10 +217,6 @@ class BottomBar extends Component { - this.props.setAppState({ buyChecked: true, sellChecked: false, type: 1 }) & - this.getInfo() - } to={`/book/`} component={LinkRouter} > @@ -264,7 +225,7 @@ class BottomBar extends Component { @@ -276,7 +237,6 @@ class BottomBar extends Component { this.getInfo()} to={`/`} component={LinkRouter} > @@ -285,7 +245,7 @@ class BottomBar extends Component { @@ -300,7 +260,7 @@ class BottomBar extends Component { @@ -315,7 +275,7 @@ class BottomBar extends Component { @@ -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 = () => { const { t } = this.props; - const hasRewards = this.props.earnedRewards > 0; + const hasRewards = this.props.robot.earnedRewards > 0; const hasOrder = !!( - (this.state.active_order_id > 0) & + (this.props.info.active_order_id > 0) & !this.state.profileShown & - this.props.avatarLoaded + this.props.robot.avatarLoaded ); return ( - +
@@ -510,12 +461,12 @@ class BottomBar extends Component { style={{ width: 55, height: 55 }} avatarClass='phoneFlippedSmallAvatar' statusColor={ - (this.props.activeOrderId > 0) & !this.props.profileShown + (this.props.activeOrderId > 0) & !this.state.profileShown ? 'primary' : undefined } - nickname={this.props.nickname} - onLoad={() => this.props.setAppState({ avatarLoaded: true })} + nickname={this.props.robot.nickname} + onLoad={() => this.props.setRobot({ ...this.props.robot, avatarLoaded: true })} /> @@ -527,14 +478,10 @@ class BottomBar extends Component { - this.props.setAppState({ buyChecked: false, sellChecked: true, type: 0 }) & - this.getInfo() - } to={`/book/`} component={LinkRouter} > - + @@ -546,14 +493,10 @@ class BottomBar extends Component { - this.props.setAppState({ buyChecked: true, sellChecked: false, type: 1 }) & - this.getInfo() - } to={`/book/`} component={LinkRouter} > - + @@ -565,11 +508,11 @@ class BottomBar extends Component { this.getInfo()} + onClick={() => this.props.fetchInfo()} to={`/`} component={LinkRouter} > - + @@ -579,7 +522,10 @@ class BottomBar extends Component { - + @@ -622,65 +568,67 @@ class BottomBar extends Component { return (
this.setState({ openUpdateClient: false })} + coordinatorVersion={this.props.info.coordinatorVersion} + clientVersion={this.props.info.clientVersion} + handleClickClose={() => + this.props.setInfo({ ...this.props.info, openUpdateClient: false }) + } /> this.props.setRobot({ ...robot, ...newParam })} + stealthInvoices={this.props.robot.stealthInvoices} handleSetStealthInvoice={this.handleSetStealthInvoice} /> {this.bottomBarDesktop()} diff --git a/frontend/src/components/Charts/DepthChart/index.tsx b/frontend/src/components/Charts/DepthChart/index.tsx index 172dbaf5..79eef1ad 100644 --- a/frontend/src/components/Charts/DepthChart/index.tsx +++ b/frontend/src/components/Charts/DepthChart/index.tsx @@ -28,14 +28,12 @@ import currencyDict from '../../../../static/assets/currencies.json'; import PaymentText from '../../PaymentText'; import getNivoScheme from '../NivoScheme'; import median from '../../../utils/match'; -import { apiClient } from '../../../services/api/index'; import statusBadgeColor from '../../../utils/statusBadgeColor'; interface DepthChartProps { orders: Order[]; lastDayPremium: number | undefined; currency: number; - setAppState: (state: object) => void; limits: LimitList; maxWidth: number; maxHeight: number; @@ -45,7 +43,6 @@ const DepthChart: React.FC = ({ orders, lastDayPremium, currency, - setAppState, limits, maxWidth, maxHeight, @@ -64,14 +61,6 @@ const DepthChart: React.FC = ({ const height = maxHeight < 20 ? 20 : maxHeight; 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(() => { setCurrencyCode(currency === 0 ? 1 : currency); }, [currency]); diff --git a/frontend/src/components/Charts/NivoScheme/index.ts b/frontend/src/components/Charts/NivoScheme/index.ts index 4fb90451..b5a5f847 100644 --- a/frontend/src/components/Charts/NivoScheme/index.ts +++ b/frontend/src/components/Charts/NivoScheme/index.ts @@ -12,13 +12,13 @@ export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => { axis: { ticks: { line: { - strokeWidth: '1', + strokeWidth: 1, stroke: 'rgb(0, 0, 0)', }, }, domain: { line: { - strokeWidth: '1', + strokeWidth: 1, stroke: 'rgb(0, 0, 0)', }, }, @@ -36,13 +36,13 @@ export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => { fill: 'rgb(255, 255, 255)', }, line: { - strokeWidth: '1', + strokeWidth: 1, stroke: 'rgb(255, 255, 255)', }, }, domain: { line: { - strokeWidth: '1', + strokeWidth: 1, stroke: 'rgb(255, 255, 255)', }, }, diff --git a/frontend/src/components/Dialogs/Community.tsx b/frontend/src/components/Dialogs/Community.tsx index d93fd9b3..2289e7c4 100644 --- a/frontend/src/components/Dialogs/Community.tsx +++ b/frontend/src/components/Dialogs/Community.tsx @@ -20,11 +20,11 @@ import RedditIcon from '@mui/icons-material/Reddit'; import Flags from 'country-flag-icons/react/3x2'; interface Props { - isOpen: boolean; + open: boolean; handleClickCloseCommunity: () => void; } -const CommunityDialog = ({ isOpen, handleClickCloseCommunity }: Props): JSX.Element => { +const CommunityDialog = ({ open = false, handleClickCloseCommunity }: Props): JSX.Element => { const { t } = useTranslation(); const flagProps = { @@ -38,7 +38,7 @@ const CommunityDialog = ({ isOpen, handleClickCloseCommunity }: Props): JSX.Elem return ( void; numPublicBuyOrders: number; numPublicSellOrders: number; @@ -37,7 +37,7 @@ interface Props { } const ExchangeSummaryDialog = ({ - isOpen, + open = false, handleClickCloseExchangeSummary, numPublicBuyOrders, numPublicSellOrders, @@ -55,7 +55,7 @@ const ExchangeSummaryDialog = ({ return ( void; nickname: string; activeOrderId: string | number; @@ -57,12 +57,12 @@ interface Props { badInvoice: boolean | string; earnedRewards: number; stealthInvoices: boolean; - handleSetStealthInvoice: (stealth: boolean) => void; - setAppState: (state: any) => void; // TODO: move to a ContextProvider + handleSetStealthInvoice: (wantsStealth: boolean) => void; + updateRobot: (state: any) => void; // TODO: move to a ContextProvider } const ProfileDialog = ({ - isOpen, + open = false, handleClickCloseProfile, nickname, activeOrderId, @@ -77,7 +77,7 @@ const ProfileDialog = ({ withdrawn, badInvoice, earnedRewards, - setAppState, + updateRobot, stealthInvoices, handleSetStealthInvoice, }: Props): JSX.Element => { @@ -101,7 +101,7 @@ const ProfileDialog = ({ if (robotToken) { systemClient.copyToClipboard(robotToken); - setAppState({ copiedToken: true }); + updateRobot({ copiedToken: true }); } }; @@ -128,7 +128,7 @@ const ProfileDialog = ({ return ( void; lndVersion: string; coordinatorVersion: string; @@ -42,7 +42,7 @@ interface Props { } const StatsDialog = ({ - isOpen, + open = false, handleClickCloseStatsForNerds, lndVersion, coordinatorVersion, @@ -60,7 +60,7 @@ const StatsDialog = ({ return ( { - 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 ( - -
- - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - -
-
- -
-
- ); - } -} diff --git a/frontend/src/components/Main.tsx b/frontend/src/components/Main.tsx new file mode 100644 index 00000000..274d04c7 --- /dev/null +++ b/frontend/src/components/Main.tsx @@ -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({ orders: [], loading: true }); + const [limits, setLimits] = useState<{ list: LimitList; loading: boolean }>({ + list: [], + loading: true, + }); + const [robot, setRobot] = useState(defaultRobot); + const [maker, setMaker] = useState(defaultMaker); + const [info, setInfo] = useState(defaultInfo); + const [fav, setFav] = useState({ type: null, currency: 0 }); + const [settings, setSettings] = useState(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 ( + +
+ + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + } + /> + +
+
+ history.push(location)} + robot={robot} + setRobot={setRobot} + info={info} + setInfo={setInfo} + fetchInfo={fetchInfo} + /> +
+
+ ); +}; + +export default Main; diff --git a/frontend/src/components/MakerPage/MakerForm.tsx b/frontend/src/components/MakerPage/MakerForm.tsx index 29676f9d..67f07e70 100644 --- a/frontend/src/components/MakerPage/MakerForm.tsx +++ b/frontend/src/components/MakerPage/MakerForm.tsx @@ -24,7 +24,7 @@ import { IconButton, } 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 DateFnsUtils from '@date-io/date-fns'; @@ -43,14 +43,12 @@ import { SelfImprovement, Lock, HourglassTop, DeleteSweep, Edit } from '@mui/ico import { LoadingButton } from '@mui/lab'; interface MakerFormProps { - limits: LimitList; - fetchLimits: (loading) => void; - loadingLimits: boolean; + limits: { list: LimitList; loading: boolean }; + fetchLimits: () => void; pricingMethods: boolean; maker: Maker; - type: number; - currency: number; - setAppState: (state: object) => void; + fav: Favorites; + setFav: (state: Favorites) => void; setMaker: (state: Maker) => void; disableRequest?: boolean; collapseAll?: boolean; @@ -62,11 +60,9 @@ interface MakerFormProps { const MakerForm = ({ limits, fetchLimits, - loadingLimits, pricingMethods, - currency, - type, - setAppState, + fav, + setFav, maker, setMaker, disableRequest = false, @@ -79,7 +75,6 @@ const MakerForm = ({ const theme = useTheme(); const history = useHistory(); const [badRequest, setBadRequest] = useState(null); - const [advancedOptions, setAdvancedOptions] = useState(false); const [amountLimits, setAmountLimits] = useState([1, 1000]); const [satoshisLimits, setSatoshisLimits] = useState([20000, 4000000]); const [currentPrice, setCurrentPrice] = useState('...'); @@ -93,27 +88,26 @@ const MakerForm = ({ const amountSafeThresholds = [1.03, 0.98]; useEffect(() => { - setCurrencyCode(currencyDict[currency == 0 ? 1 : currency]); - if (Object.keys(limits).length === 0) { - setAppState({ loadingLimits: true }); - fetchLimits(true).then((data) => { - updateAmountLimits(data, currency, maker.premium); - updateCurrentPrice(data, currency, maker.premium); + setCurrencyCode(currencyDict[fav.currency == 0 ? 1 : fav.currency]); + if (Object.keys(limits.list).length === 0) { + fetchLimits().then((data) => { + updateAmountLimits(data, fav.currency, maker.premium); + updateCurrentPrice(data, fav.currency, maker.premium); updateSatoshisLimits(data); }); } else { - updateAmountLimits(limits, currency, maker.premium); - updateCurrentPrice(limits, currency, maker.premium); - updateSatoshisLimits(limits); + updateAmountLimits(limits.list, fav.currency, maker.premium); + updateCurrentPrice(limits.list, fav.currency, maker.premium); + updateSatoshisLimits(limits.list); - fetchLimits(false); + fetchLimits(); } }, []); - const updateAmountLimits = function (limits: LimitList, currency: number, premium: number) { - const index = currency === 0 ? 1 : currency; - let minAmountLimit: number = limits[index].min_amount * (1 + premium / 100); - let maxAmountLimit: number = limits[index].max_amount * (1 + premium / 100); + const updateAmountLimits = function (limitList: LimitList, currency: number, premium: number) { + const index = currency == 0 ? 1 : currency; + let minAmountLimit: number = limitList[index].min_amount * (1 + premium / 100); + let maxAmountLimit: number = limitList[index].max_amount * (1 + premium / 100); // apply thresholds to ensure good request minAmountLimit = minAmountLimit * amountSafeThresholds[0]; @@ -121,19 +115,19 @@ const MakerForm = ({ setAmountLimits([minAmountLimit, maxAmountLimit]); }; - const updateSatoshisLimits = function (limits: LimitList) { - const minAmount: number = limits[1000].min_amount * 100000000; - const maxAmount: number = limits[1000].max_amount * 100000000; + const updateSatoshisLimits = function (limitList: LimitList) { + const minAmount: number = limitList[1000].min_amount * 100000000; + const maxAmount: number = limitList[1000].max_amount * 100000000; setSatoshisLimits([minAmount, maxAmount]); }; - const updateCurrentPrice = function (limits: LimitList, currency: number, premium: number) { - const index = currency === 0 ? 1 : currency; + const updateCurrentPrice = function (limitsList: LimitList, currency: number, premium: number) { + const index = currency == 0 ? 1 : currency; 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); } 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))); }; @@ -141,17 +135,17 @@ const MakerForm = ({ const handleCurrencyChange = function (newCurrency: number) { const currencyCode: string = currencyDict[newCurrency]; setCurrencyCode(currencyCode); - setAppState({ + setFav({ + ...fav, currency: newCurrency, - bookCurrencyCode: currencyCode, }); - updateAmountLimits(limits, newCurrency, maker.premium); - updateCurrentPrice(limits, newCurrency, maker.premium); - if (advancedOptions) { + updateAmountLimits(limits.list, newCurrency, maker.premium); + updateCurrentPrice(limits.list, newCurrency, maker.premium); + if (maker.advancedOptions) { setMaker({ ...maker, - minAmount: parseFloat(Number(limits[newCurrency].max_amount * 0.25).toPrecision(2)), - maxAmount: parseFloat(Number(limits[newCurrency].max_amount * 0.75).toPrecision(2)), + minAmount: parseFloat(Number(limits.list[newCurrency].max_amount * 0.25).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 }); premium = -99.99; } - updateCurrentPrice(limits, currency, premium); - updateAmountLimits(limits, currency, premium); + updateCurrentPrice(limits.list, fav.currency, premium); + updateAmountLimits(limits.list, fav.currency, premium); setMaker({ ...maker, premium, @@ -235,7 +229,7 @@ const MakerForm = ({ }; const handleClickExplicit = function () { - if (!advancedOptions) { + if (!maker.advancedOptions) { setMaker({ ...maker, isExplicit: true, @@ -247,12 +241,12 @@ const MakerForm = ({ if (!disableRequest) { setSubmittingRequest(true); const body = { - type: type == 0 ? 1 : 0, - currency: currency == 0 ? 1 : currency, - amount: advancedOptions ? null : maker.amount, - has_range: advancedOptions, - min_amount: advancedOptions ? maker.minAmount : null, - max_amount: advancedOptions ? maker.maxAmount : null, + type: fav.type == 0 ? 1 : 0, + currency: fav.currency == 0 ? 1 : fav.currency, + amount: maker.advancedOptions ? null : maker.amount, + has_range: maker.advancedOptions, + min_amount: maker.advancedOptions ? maker.minAmount : null, + max_amount: maker.advancedOptions ? maker.maxAmount : null, payment_method: maker.paymentMethodsText === '' ? 'not specified' : maker.paymentMethodsText, is_explicit: maker.isExplicit, @@ -300,13 +294,12 @@ const MakerForm = ({ }; const handleClickAdvanced = function () { - if (advancedOptions) { + if (maker.advancedOptions) { handleClickRelative(); + setMaker({ ...maker, advancedOptions: false }); } else { - resetRange(); + resetRange(true); } - - setAdvancedOptions(!advancedOptions); }; const minAmountError = function () { @@ -327,17 +320,18 @@ const MakerForm = ({ ); }; - const resetRange = function () { - const index = currency === 0 ? 1 : currency; + const resetRange = function (advancedOptions: boolean) { + const index = fav.currency === 0 ? 1 : fav.currency; const minAmount = maker.amount ? 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 ? 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({ ...maker, + advancedOptions, minAmount, maxAmount, }); @@ -379,20 +373,20 @@ const MakerForm = ({ const disableSubmit = function () { return ( - type == null || + fav.type == null || (maker.amount != '' && - !advancedOptions && + !maker.advancedOptions && (maker.amount < amountLimits[0] || maker.amount > amountLimits[1])) || - (maker.amount == null && (!advancedOptions || loadingLimits)) || - (advancedOptions && (minAmountError() || maxAmountError())) || - (maker.amount <= 0 && !advancedOptions) || + (maker.amount == null && (!maker.advancedOptions || limits.loading)) || + (maker.advancedOptions && (minAmountError() || maxAmountError())) || + (maker.amount <= 0 && !maker.advancedOptions) || (maker.isExplicit && (maker.badSatoshisText != '' || maker.satoshis == '')) || (!maker.isExplicit && maker.badPremiumText != '') ); }; const clearMaker = function () { - setAppState({ type: null }); + setFav({ ...fav, type: null }); setMaker(defaultMaker); }; @@ -404,8 +398,12 @@ const MakerForm = ({ align='center' color={disableSubmit() ? 'text.secondary' : 'text.primary'} > - {type == null ? t('Order for ') : type == 1 ? t('Buy order for ') : t('Sell order for ')} - {advancedOptions && maker.minAmount != '' + {fav.type == null + ? 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.amount)} {' ' + currencyCode} @@ -437,12 +435,12 @@ const MakerForm = ({ return ( - -
+ +
- + @@ -499,17 +497,18 @@ const MakerForm = ({
- + @@ -944,7 +944,7 @@ const MakerForm = ({ - + void; orders: Order[]; - loadingLimits: boolean; - type: number; - windowHeight: number; - windowWidth: number; - currency: number; - setAppState: (state: object) => void; + fav: Favorites; + maker: Maker; + setFav: (state: Favorites) => void; + setMaker: (state: Maker) => void; + windowSize: { width: number; height: number }; } const MakerPage = ({ limits, fetchLimits, orders, - loadingLimits, - currency, - type, - setAppState, - windowHeight, - windowWidth, + fav, + maker, + setFav, + setMaker, + windowSize, }: MakerPageProps): JSX.Element => { const { t } = useTranslation(); const history = useHistory(); - const [maker, setMaker] = useState(defaultMaker); - const maxHeight = windowHeight ? windowHeight * 0.85 - 7 : 1000; + const maxHeight = windowSize.height * 0.85 - 7; const [showMatches, setShowMatches] = useState(false); const matches = filterOrders({ orders, - baseFilter: { currency: currency == 0 ? 1 : currency, type }, + baseFilter: { currency: fav.currency === 0 ? 1 : fav.currency, type: fav.type }, paymentMethods: maker.paymentMethods, amountFilter: { amount: maker.amount, @@ -61,10 +58,11 @@ const MakerPage = ({ 4 ? 4 : matches.length)} - type={type} - currency={currency} - maxWidth={Math.min(windowWidth, 60)} // EM units + book={{ + orders: matches.slice(0, matches.length > 4 ? 4 : matches.length), + loading: false, + }} + maxWidth={Math.min(windowSize.width, 60)} // EM units maxHeight={Math.min(matches.length * 3.25 + 3.575, 16.575)} // EM units defaultFullscreen={false} showControls={false} @@ -82,13 +80,11 @@ const MakerPage = ({ 0 && !showMatches} collapseAll={showMatches} onSubmit={() => setShowMatches(matches.length > 0)} diff --git a/frontend/src/components/OrderPage.js b/frontend/src/components/OrderPage.js index 7b1eb407..837e4706 100644 --- a/frontend/src/components/OrderPage.js +++ b/frontend/src/components/OrderPage.js @@ -525,10 +525,7 @@ class OrderPage extends Component { this.setState({ openStoreToken: false })} - onClickCopy={() => - systemClient.copyToClipboard(systemClient.getCookie('robot_token')) & - this.props.setAppState({ copiedToken: true }) - } + onClickCopy={() => systemClient.copyToClipboard(systemClient.getCookie('robot_token'))} copyIconColor={this.props.copiedToken ? 'inherit' : 'primary'} onClickBack={() => this.setState({ openStoreToken: false })} onClickDone={() => diff --git a/frontend/src/components/UserGenPage.js b/frontend/src/components/UserGenPage.js index 33f75393..24a3868a 100644 --- a/frontend/src/components/UserGenPage.js +++ b/frontend/src/components/UserGenPage.js @@ -11,7 +11,6 @@ import { IconButton, } from '@mui/material'; import { Link } from 'react-router-dom'; -import SmoothImage from 'react-smooth-image'; import { InfoDialog } from './Dialogs'; import SmartToyIcon from '@mui/icons-material/SmartToy'; @@ -35,7 +34,7 @@ class UserGenPage extends Component { this.state = { openInfo: false, tokenHasChanged: false, - token: '', + inputToken: '', }; this.refCode = this.props.match.params.refCode; @@ -44,19 +43,18 @@ class UserGenPage extends Component { componentDidMount() { // Checks in parent HomePage if there is already a nick and token // Displays the existing one - if (this.props.nickname != null) { + if (this.props.robot.nickname != null) { this.setState({ - token: this.props.token ? this.props.token : '', - loadingRobot: false, + inputToken: this.props.robot.token ? this.props.robot.token : '', }); } else if (window.NativeRobosats && systemClient.getCookie('robot_token')) { const token = systemClient.getCookie('robot_token'); - this.setState({ token }); + this.setState({ inputToken: token }); this.getGeneratedUser(token); } else { const newToken = genBase62Token(36); this.setState({ - token: newToken, + inputToken: newToken, }); this.getGeneratedUser(newToken); } @@ -65,6 +63,7 @@ class UserGenPage extends Component { getGeneratedUser = (token) => { const strength = tokenStrength(token); const refCode = this.refCode; + this.props.setRobot({ ...this.props.robot, loading: true }); const requestBody = genKey(token).then(function (key) { return { @@ -79,46 +78,44 @@ class UserGenPage extends Component { }); requestBody.then((body) => 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) - (data.bad_request - ? this.props.setAppState({ - nickname: data.nickname, - avatarLoaded: false, - activeOrderId: data.active_order_id ? data.active_order_id : null, - referralCode: data.referral_code, - earnedRewards: data.earned_rewards, - lastOrderId: data.last_order_id ? data.last_order_id : null, - stealthInvoices: data.wants_stealth, - }) - : this.props.setAppState({ - nickname: data.nickname, - token, - avatarLoaded: 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, - earnedRewards: data.earned_rewards, - stealthInvoices: data.wants_stealth, - tgEnabled: data.tg_enabled, - tgBotName: data.tg_bot_name, - tgToken: data.tg_token, - }) & - systemClient.setCookie('robot_token', token) & - systemClient.setCookie('pub_key', data.public_key.split('\n').join('\\')) & - systemClient.setCookie( - 'enc_priv_key', - data.encrypted_private_key.split('\n').join('\\'), - )) & - // If the robot has been found (recovered) we assume the token is backed up - (data.found ? this.props.setAppState({ copiedToken: true }) : null); + // Add nick and token to App state (token only if not a bad request) + data.bad_request + ? this.props.setRobot({ + ...this.props.robot, + nickname: data.nickname, + avatarLoaded: false, + activeOrderId: data.active_order_id ? data.active_order_id : null, + referralCode: data.referral_code, + earnedRewards: data.earned_rewards ?? 0, + lastOrderId: data.last_order_id ? data.last_order_id : null, + stealthInvoices: data.wants_stealth, + }) + : this.props.setRobot({ + ...this.props.robot, + nickname: data.nickname, + token, + avatarLoaded: 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, + earnedRewards: data.earned_rewards ?? 0, + stealthInvoices: data.wants_stealth, + tgEnabled: data.tg_enabled, + tgBotName: data.tg_bot_name, + 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('pub_key', data.public_key.split('\n').join('\\')) & + systemClient.setCookie( + 'enc_priv_key', + data.encrypted_private_key.split('\n').join('\\'), + ); + // If the robot has been found (recovered) we assume the token is backed up + data.found ? this.props.setRobot({ ...this.props.robot, copiedToken: true }) : null; }), ); }; @@ -133,26 +130,27 @@ class UserGenPage extends Component { } handleClickNewRandomToken = () => { - const token = genBase62Token(36); + const inputToken = genBase62Token(36); this.setState({ - token, + inputToken, tokenHasChanged: true, }); - this.props.setAppState({ copiedToken: true }); + this.props.setRobot({ ...this.props.robot, copiedToken: true }); }; handleChangeToken = (e) => { this.setState({ - token: e.target.value.split(' ').join(''), + inputToken: e.target.value.split(' ').join(''), tokenHasChanged: true, }); }; handleClickSubmitToken = () => { this.delGeneratedUser(); - this.getGeneratedUser(this.state.token); - this.setState({ loadingRobot: true, tokenHasChanged: false }); - this.props.setAppState({ + this.getGeneratedUser(this.state.inputToken); + this.setState({ tokenHasChanged: false }); + this.props.setRobot({ + ...this.props.robot, avatarLoaded: false, nickname: null, token: null, @@ -172,11 +170,11 @@ class UserGenPage extends Component { createJsonFile = () => { return { - token: systemClient.getCookie('robot_token'), - token_shannon_entropy: this.state.shannon_entropy, - token_bit_entropy: this.state.bit_entropy, - public_key: systemClient.getCookie('pub_key').split('\\').join('\n'), - encrypted_private_key: systemClient.getCookie('enc_priv_key').split('\\').join('\n'), + token: this.props.robot.token, + token_shannon_entropy: this.props.robot.shannonEntropy, + token_bit_entropy: this.props.robot.bitsEntropy, + public_key: this.props.robot.pub_key, + encrypted_private_key: this.props.robot.enc_priv_key, }; }; @@ -195,12 +193,12 @@ class UserGenPage extends Component { align='center' sx={{ width: 370 * fontSizeFactor, height: 260 * fontSizeFactor }} > - {this.props.avatarLoaded && this.props.nickname ? ( + {this.props.robot.avatarLoaded && this.props.robot.nickname ? (
- {this.props.nickname && systemClient.getCookie('sessionid') ? ( + {this.props.robot.nickname && systemClient.getCookie('sessionid') ? (
- {this.props.nickname} + {this.props.robot.nickname}
@@ -271,7 +269,7 @@ class UserGenPage extends Component { error={!!this.state.bad_request} label={t('Store your token safely')} required={true} - value={this.state.token} + value={this.state.inputToken} variant='standard' helperText={this.state.bad_request} size='small' @@ -301,11 +299,14 @@ class UserGenPage extends Component { - saveAsJson(this.props.nickname + '.json', this.createJsonFile()) + saveAsJson( + this.props.robot.nickname + '.json', + this.createJsonFile(), + ) } > systemClient.copyToClipboard(systemClient.getCookie('robot_token')) & - this.props.setAppState({ copiedToken: true }) + this.props.setRobot({ ...this.props.robot, copiedToken: true }) } >