diff --git a/frontend/src/basic/RobotPage/Onboarding.tsx b/frontend/src/basic/RobotPage/Onboarding.tsx index 60e8d8d0..aacfe730 100644 --- a/frontend/src/basic/RobotPage/Onboarding.tsx +++ b/frontend/src/basic/RobotPage/Onboarding.tsx @@ -12,6 +12,9 @@ import { Link, Typography, useTheme, + Accordion, + AccordionSummary, + AccordionDetails, } from '@mui/material'; import { Page } from '../NavBar'; import { Robot } from '../../models'; @@ -65,252 +68,231 @@ const Onboarding = ({ }; return ( - - - - {t('1. Generate a token')} - - - - - - - {t( - 'This temporary key gives you access to a unique and private robot identity for your trade.', - )} - - - {!generatedToken ? ( - - - - ) : ( - - - - - - {`${t('Store it somewhere safe!')} `} - {t( - `This token is the one and only key to your robot and trade. You will need it later to recover your order or check its status.`, - )} - - - - {showMimickProgress ? ( - - ) : ( - null} - /> - )} - - - - {t('You can also add your own random characters into the token or')} - - - - - - - - - - - )} + + + + + {t('1. Generate a token')} + + + + + + + {t( + 'This temporary key gives you access to a unique and private robot identity for your trade.', + )} + - - - - - - - {t('2. Meet your robot identity')} - - - - + {!generatedToken ? ( - - {robot.avatarLoaded && robot.nickname ? ( - t('This is your trading avatar') - ) : ( - <> - {t('Building your robot!')} - - - )} - - - - - - - - {robot.avatarLoaded && robot.nickname ? ( - - {t('Hi! My name is')} - -
- - {robot.nickname} - -
-
-
- ) : null} - - - - - -
-
-
-
- - - - {t('3. Browse or create an order')} - - - - - - - {t( - 'RoboSats is a peer-to-peer marketplace. You can browse the public offers or create a new one.', - )} - - - - - - - - - - - - - {`${t('If you need help on your RoboSats journey join our public support')} `} - - {t('Telegram group')} - - {`, ${t('or visit the robot school for documentation.')} `} - - - - + ) : ( + + + + + + {`${t('Store it somewhere safe!')} `} + {t( + `This token is the one and only key to your robot and trade. You will need it later to recover your order or check its status.`, + )} + + + + {showMimickProgress ? ( + + ) : ( + null} + /> + )} + + + + {t('You can also add your own random characters into the token or')} + + + + + + + + + + + )} + + + + + + + + {t('2. Meet your robot identity')} + + + + + + + {robot.avatarLoaded && robot.nickname ? ( + t('This is your trading avatar') + ) : ( + <> + {t('Building your robot!')} + + + )} + - - - - - - -
+ + + + + + {robot.avatarLoaded && robot.nickname ? ( + + {t('Hi! My name is')} + +
+ + {robot.nickname} + +
+
+
+ ) : null} + + + + + + + + + + + + + {t('3. Browse or create an order')} + + + + + + + {t( + 'RoboSats is a peer-to-peer marketplace. You can browse the public offers or create a new one.', + )} + + + + + + + + + + + + + {`${t('If you need help on your RoboSats journey join our public support')} `} + + {t('Telegram group')} + + {`, ${t('or visit the robot school for documentation.')} `} + + + + + + + + + + + + ); }; diff --git a/frontend/src/basic/RobotPage/RobotProfile.tsx b/frontend/src/basic/RobotPage/RobotProfile.tsx index a8d32d4f..91774ffa 100644 --- a/frontend/src/basic/RobotPage/RobotProfile.tsx +++ b/frontend/src/basic/RobotPage/RobotProfile.tsx @@ -1,17 +1,20 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Button, Grid, LinearProgress, Typography, useTheme } from '@mui/material'; -import { Bolt, Logout } from '@mui/icons-material'; +import { useHistory } from 'react-router-dom'; +import { Button, Link, Grid, LinearProgress, Typography, Alert } from '@mui/material'; +import { Bolt, Logout, Refresh } from '@mui/icons-material'; import RobotAvatar from '../../components/RobotAvatar'; import TokenInput from './TokenInput'; import { Page } from '../NavBar'; import { Robot } from '../../models'; +import { genBase62Token } from '../../utils'; interface RobotProfileProps { robot: Robot; setRobot: (state: Robot) => void; setView: (state: 'welcome' | 'onboarding' | 'recovery' | 'profile') => void; inputToken: string; + setCurrentOrder: (state: number) => void; logoutRobot: () => void; setInputToken: (state: string) => void; getGenerateRobot: (token: string) => void; @@ -27,7 +30,10 @@ const RobotProfile = ({ setRobot, inputToken, setInputToken, + setCurrentOrder, + getGenerateRobot, logoutRobot, + setPage, setView, badRequest, baseUrl, @@ -35,7 +41,12 @@ const RobotProfile = ({ width, }: RobotProfileProps): JSX.Element => { const { t } = useTranslation(); - const theme = useTheme(); + const history = useHistory(); + + const getNewRobot = () => { + logoutRobot(); + setTimeout(() => getGenerateRobot(genBase62Token(36)), 10); + }; return ( @@ -73,7 +84,7 @@ const RobotProfile = ({ ) : ( <> - {t('Rebuilding your robot!')} + {t('Building your robot!')} )} @@ -102,18 +113,60 @@ const RobotProfile = ({ {t('Welcome back!')} -
) : ( <> )} - - {/* This robot has an active order + {robot.activeOrderId ? ( + + + {t('One active order')} + { + history.push('/order/' + robot.activeOrderId); + setPage('order'); + setCurrentOrder(robot.activeOrderId); + }} + > + {` #${robot.activeOrderId}`} + + + + ) : null} - This robot has a past order. Reusing Robot degrades your privacy: Get a new robot! */} - + {robot.lastOrderId ? ( + + + {t('Your past order')} + { + history.push('/order/' + robot.lastOrderId); + setPage('order'); + setCurrentOrder(robot.lastOrderId); + }} + > + {` #${robot.lastOrderId}`} + + + + + + {t( + 'Reusing trading identity degrades your privacy against other users, coordinators and observers.', + )} + + + + + + + + ) : null} { - setRobot({ ...robot, nickname: undefined, token: undefined, avatarLoaded: false }); setInputToken(''); setRobotFound(false); systemClient.deleteCookie('sessionid'); systemClient.deleteItem('robot_token'); systemClient.deleteItem('pub_key'); systemClient.deleteItem('enc_priv_key'); + setTimeout(() => setRobot(new Robot()), 10); }; if (window?.NativeRobosats & (torStatus != 'DONE')) { @@ -154,7 +163,7 @@ const RobotPage = ({ > - + {t('Connecting to TOR')} @@ -182,7 +191,7 @@ const RobotPage = ({ - {t('Your traffic is encrypted and annonimized using TOR. ')} + {t('Connection encrypted and anonymized using TOR.')} {t( 'This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.', )} @@ -226,6 +235,7 @@ const RobotPage = ({ robot={robot} robotFound={robotFound} setRobot={setRobot} + setCurrentOrder={setCurrentOrder} badRequest={badRequest} logoutRobot={logoutRobot} width={width} diff --git a/frontend/src/basic/UserGenPage.js b/frontend/src/basic/UserGenPage.js deleted file mode 100644 index 6a10f91a..00000000 --- a/frontend/src/basic/UserGenPage.js +++ /dev/null @@ -1,395 +0,0 @@ -import React, { Component } from 'react'; -import { withTranslation } from 'react-i18next'; -import { - Button, - Tooltip, - Grid, - Typography, - TextField, - ButtonGroup, - CircularProgress, - IconButton, -} from '@mui/material'; - -import SmartToyIcon from '@mui/icons-material/SmartToy'; -import CasinoIcon from '@mui/icons-material/Casino'; -import ContentCopy from '@mui/icons-material/ContentCopy'; -import BoltIcon from '@mui/icons-material/Bolt'; -import DownloadIcon from '@mui/icons-material/Download'; -import { RoboSatsNoTextIcon } from '../components/Icons'; - -import { sha256 } from 'js-sha256'; -import { genBase62Token, tokenStrength, saveAsJson } from '../utils'; -import { genKey } from '../pgp'; -import { systemClient } from '../services/System'; -import { apiClient } from '../services/api/index'; -import RobotAvatar from '../components/RobotAvatar'; - -class UserGenPage extends Component { - constructor(props) { - super(props); - this.state = { - tokenHasChanged: false, - inputToken: '', - found: false, - }; - - this.refCode = this.props.match.params.refCode; - } - - componentDidMount() { - // Checks in parent HomePage if there is already a nick and token - // Displays the existing one - if (this.props.robot.nickname != null) { - this.setState({ inputToken: this.props.robot.token }); - } else if (this.props.robot.token) { - this.setState({ inputToken: this.props.robot.token }); - this.getGeneratedUser(this.props.robot.token); - } else { - const newToken = genBase62Token(36); - this.setState({ - inputToken: newToken, - }); - this.getGeneratedUser(newToken); - } - } - - getGeneratedUser = (token) => { - const strength = tokenStrength(token); - const refCode = this.refCode; - this.props.setRobot({ ...this.props.robot, loading: true, avatarLoaded: false }); - - const requestBody = genKey(token).then(function (key) { - return { - token_sha256: sha256(token), - public_key: key.publicKeyArmored, - encrypted_private_key: key.encryptedPrivateKeyArmored, - unique_values: strength.uniqueValues, - counts: strength.counts, - length: token.length, - ref_code: refCode, - }; - }); - requestBody.then((body) => - apiClient.post(this.props.baseUrl, '/api/user/', body).then((data) => { - this.setState({ found: data.found, bad_request: data.bad_request }); - this.props.setCurrentOrder( - data.active_order_id - ? data.active_order_id - : data.last_order_id - ? data.last_order_id - : null, - ); - // Add nick and token to App state (token only if not a bad request) - data.bad_request - ? this.props.setRobot({ - ...this.props.robot, - avatarLoaded: true, - loading: false, - nickname: data.nickname ?? this.props.robot.nickname, - activeOrderId: data.active_order_id ?? null, - referralCode: data.referral_code ?? this.props.referralCode, - earnedRewards: data.earned_rewards ?? this.props.earnedRewards, - lastOrderId: data.last_order_id ?? this.props.lastOrderId, - stealthInvoices: data.wants_stealth ?? this.props.stealthInvoices, - tgEnabled: data.tg_enabled, - tgBotName: data.tg_bot_name, - tgToken: data.tg_token, - }) - : this.props.setRobot({ - ...this.props.robot, - nickname: data.nickname, - token, - 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, - 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, - pubKey: data.public_key, - encPrivKey: data.encrypted_private_key, - copiedToken: data.found ? true : this.props.robot.copiedToken, - }) & - systemClient.setItem('robot_token', token) & - systemClient.setItem('pub_key', data.public_key.split('\n').join('\\')) & - systemClient.setItem('enc_priv_key', data.encrypted_private_key.split('\n').join('\\')); - }), - ); - }; - - delGeneratedUser() { - apiClient.delete(this.props.baseUrl, '/api/user'); - - systemClient.deleteCookie('sessionid'); - systemClient.deleteItem('robot_token'); - systemClient.deleteItem('pub_key'); - systemClient.deleteItem('enc_priv_key'); - } - - handleClickNewRandomToken = () => { - const inputToken = genBase62Token(36); - this.setState({ - inputToken, - tokenHasChanged: true, - }); - this.props.setRobot({ ...this.props.robot, copiedToken: true }); - }; - - handleChangeToken = (e) => { - this.setState({ - inputToken: e.target.value.split(' ').join(''), - tokenHasChanged: true, - }); - }; - - handleClickSubmitToken = () => { - this.delGeneratedUser(); - this.getGeneratedUser(this.state.inputToken); - this.setState({ tokenHasChanged: false }); - this.props.setRobot({ - ...this.props.robot, - avatarLoaded: false, - nickname: null, - token: null, - copiedToken: false, - lastOrderId: null, - activeOrderId: null, - }); - }; - - createJsonFile = () => { - return { - 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, - }; - }; - - render() { - const { t, i18n } = this.props; - const fontSize = this.props.theme.typography.fontSize; - const fontSizeFactor = fontSize / 14; // to scale sizes, default fontSize is 14 - return ( - - -
- - - {this.props.robot.avatarLoaded && this.props.robot.nickname ? ( -
- - - - {this.props.robot.nickname && systemClient.getCookie('sessionid') ? ( - - ) : ( - '' - )} - - - - - -
-
-
- ) : ( - - )} -
- {this.state.found ? ( - - - {this.state.found ? t('A robot avatar was found, welcome back!') : null} -
-
-
- ) : ( - '' - )} - - - { - if (e.key === 'Enter') { - this.handleClickSubmitToken(); - } - }} - InputProps={{ - startAdornment: ( -
- - - - - - saveAsJson( - this.props.robot.nickname + '.json', - this.createJsonFile(), - ) - } - > - - - - - - - - - systemClient.copyToClipboard(systemClient.getItem('robot_token')) & - this.props.setRobot({ ...this.props.robot, copiedToken: true }) - } - > - - - - - -
- ), - endAdornment: ( - - - - - - ), - }} - /> -
-
- - {this.state.tokenHasChanged ? ( - - ) : ( - -
- -
-
- )} -
- - - -
- -
- - - - - {t('Simple and Private LN P2P Exchange')} - - - - - - -
- - - ); - } -} - -export default withTranslation()(UserGenPage);