mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 20:21:35 +00:00
Add robot garage (#370)
* Add garage model * Add robot select to profile * Replace Robot for Garage init * Add Garage inners, not re-rendering * Revert * Collect new phrases and small fixes * Small fixes * Fix unencrypted # hack on Turtle chat * Small fixes and collect phrases
This commit is contained in:
parent
d88c2a5eff
commit
c0b8a6d3ac
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Grid, ButtonGroup, Dialog, Box } from '@mui/material';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
@ -7,49 +7,24 @@ import DepthChart from '../../components/Charts/DepthChart';
|
||||
import { NoRobotDialog } from '../../components/Dialogs';
|
||||
import MakerForm from '../../components/MakerForm';
|
||||
import BookTable from '../../components/BookTable';
|
||||
import { Page } from '../NavBar';
|
||||
import { Book, Favorites, LimitList, Maker } from '../../models';
|
||||
|
||||
// Icons
|
||||
import { BarChart, FormatListBulleted } from '@mui/icons-material';
|
||||
import { AppContext, AppContextProps } from '../../contexts/AppContext';
|
||||
|
||||
interface BookPageProps {
|
||||
book: Book;
|
||||
limits: { list: LimitList; loading: boolean };
|
||||
fetchLimits: () => void;
|
||||
fav: Favorites;
|
||||
setFav: (state: Favorites) => void;
|
||||
onViewOrder: () => void;
|
||||
fetchBook: () => void;
|
||||
clearOrder: () => void;
|
||||
windowSize: { width: number; height: number };
|
||||
lastDayPremium: number;
|
||||
maker: Maker;
|
||||
setMaker: (state: Maker) => void;
|
||||
hasRobot: boolean;
|
||||
setPage: (state: Page) => void;
|
||||
setCurrentOrder: (state: number) => void;
|
||||
baseUrl: string;
|
||||
}
|
||||
|
||||
const BookPage = ({
|
||||
lastDayPremium = 0,
|
||||
limits,
|
||||
book = { orders: [], loading: true },
|
||||
const BookPage = (): JSX.Element => {
|
||||
const {
|
||||
robot,
|
||||
fetchBook,
|
||||
fetchLimits,
|
||||
clearOrder,
|
||||
fav,
|
||||
setFav,
|
||||
onViewOrder,
|
||||
maker,
|
||||
setMaker,
|
||||
windowSize,
|
||||
hasRobot = false,
|
||||
setPage = () => null,
|
||||
setCurrentOrder = () => null,
|
||||
setPage,
|
||||
setCurrentOrder,
|
||||
baseUrl,
|
||||
}: BookPageProps): JSX.Element => {
|
||||
book,
|
||||
setDelay,
|
||||
setOrder,
|
||||
} = useContext<AppContextProps>(AppContext);
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
const [view, setView] = useState<'list' | 'depth'>('list');
|
||||
@ -62,15 +37,16 @@ const BookPage = ({
|
||||
const chartWidthEm = width - maxBookTableWidth;
|
||||
|
||||
useEffect(() => {
|
||||
if (book.orders.length < 1) {
|
||||
fetchBook(true, false);
|
||||
} else {
|
||||
fetchBook(false, true);
|
||||
}
|
||||
fetchBook();
|
||||
}, []);
|
||||
|
||||
const onViewOrder = function () {
|
||||
setOrder(undefined);
|
||||
setDelay(10000);
|
||||
};
|
||||
|
||||
const onOrderClicked = function (id: number) {
|
||||
if (hasRobot) {
|
||||
if (robot.avatarLoaded) {
|
||||
history.push('/order/' + id);
|
||||
setPage('order');
|
||||
setCurrentOrder(id);
|
||||
@ -108,6 +84,7 @@ const BookPage = ({
|
||||
</ButtonGroup>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container direction='column' alignItems='center' spacing={1} sx={{ minWidth: 400 }}>
|
||||
<NoRobotDialog open={openNoRobot} onClose={() => setOpenNoRobot(false)} setPage={setPage} />
|
||||
@ -115,21 +92,13 @@ const BookPage = ({
|
||||
<Dialog open={openMaker} onClose={() => setOpenMaker(false)}>
|
||||
<Box sx={{ maxWidth: '18em', padding: '0.5em' }}>
|
||||
<MakerForm
|
||||
limits={limits}
|
||||
fetchLimits={fetchLimits}
|
||||
maker={maker}
|
||||
setMaker={setMaker}
|
||||
fav={fav}
|
||||
setFav={setFav}
|
||||
setPage={setPage}
|
||||
hasRobot={hasRobot}
|
||||
hasRobot={robot.AvatarLoaded}
|
||||
onOrderCreated={(id) => {
|
||||
clearOrder();
|
||||
setCurrentOrder(id);
|
||||
setPage('order');
|
||||
history.push('/order/' + id);
|
||||
}}
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
</Box>
|
||||
</Dialog>
|
||||
|
@ -19,38 +19,18 @@ import { AppContextProps, AppContext } from '../contexts/AppContext';
|
||||
const Main = (): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
book,
|
||||
fetchBook,
|
||||
maker,
|
||||
setMaker,
|
||||
clearOrder,
|
||||
torStatus,
|
||||
settings,
|
||||
limits,
|
||||
fetchLimits,
|
||||
robot,
|
||||
setRobot,
|
||||
fetchRobot,
|
||||
setOrder,
|
||||
setDelay,
|
||||
info,
|
||||
fav,
|
||||
setFav,
|
||||
baseUrl,
|
||||
order,
|
||||
page,
|
||||
setPage,
|
||||
slideDirection,
|
||||
setSlideDirection,
|
||||
currentOrder,
|
||||
setCurrentOrder,
|
||||
closeAll,
|
||||
open,
|
||||
setOpen,
|
||||
windowSize,
|
||||
badOrder,
|
||||
navbarHeight,
|
||||
setBadOrder,
|
||||
} = useContext<AppContextProps>(AppContext);
|
||||
|
||||
const Router = window.NativeRobosats === undefined ? BrowserRouter : HashRouter;
|
||||
@ -101,16 +81,7 @@ const Main = (): JSX.Element => {
|
||||
appear={slideDirection.in != undefined}
|
||||
>
|
||||
<div>
|
||||
<RobotPage
|
||||
setPage={setPage}
|
||||
torStatus={torStatus}
|
||||
fetchRobot={fetchRobot}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
windowSize={windowSize}
|
||||
robot={robot}
|
||||
setRobot={setRobot}
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
<RobotPage />
|
||||
</div>
|
||||
</Slide>
|
||||
)}
|
||||
@ -123,27 +94,7 @@ const Main = (): JSX.Element => {
|
||||
appear={slideDirection.in != undefined}
|
||||
>
|
||||
<div>
|
||||
<BookPage
|
||||
book={book}
|
||||
fetchBook={fetchBook}
|
||||
onViewOrder={() => {
|
||||
setOrder(undefined);
|
||||
setDelay(10000);
|
||||
}}
|
||||
limits={limits}
|
||||
fetchLimits={fetchLimits}
|
||||
fav={fav}
|
||||
setFav={setFav}
|
||||
maker={maker}
|
||||
setMaker={setMaker}
|
||||
clearOrder={clearOrder}
|
||||
lastDayPremium={info.last_day_nonkyc_btc_premium}
|
||||
windowSize={windowSize}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
setPage={setPage}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
<BookPage />
|
||||
</div>
|
||||
</Slide>
|
||||
</Route>
|
||||
@ -155,7 +106,7 @@ const Main = (): JSX.Element => {
|
||||
appear={slideDirection.in != undefined}
|
||||
>
|
||||
<div>
|
||||
<MakerPage hasRobot={robot.avatarLoaded} />
|
||||
<MakerPage />
|
||||
</div>
|
||||
</Slide>
|
||||
</Route>
|
||||
@ -169,10 +120,7 @@ const Main = (): JSX.Element => {
|
||||
appear={slideDirection.in != undefined}
|
||||
>
|
||||
<div>
|
||||
<OrderPage
|
||||
locationOrderId={props.match.params.orderId}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
/>
|
||||
<OrderPage locationOrderId={props.match.params.orderId} />
|
||||
</div>
|
||||
</Slide>
|
||||
)}
|
||||
@ -192,19 +140,9 @@ const Main = (): JSX.Element => {
|
||||
</Switch>
|
||||
</Box>
|
||||
<div style={{ alignContent: 'center', display: 'flex' }}>
|
||||
<NavBar width={windowSize.width} height={navbarHeight} hasRobot={robot.avatarLoaded} />
|
||||
<NavBar width={windowSize.width} height={navbarHeight} />
|
||||
</div>
|
||||
<MainDialogs
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
setRobot={setRobot}
|
||||
setPage={setPage}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
info={info}
|
||||
robot={robot}
|
||||
closeAll={closeAll}
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
<MainDialogs />
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
@ -10,13 +10,18 @@ import BookTable from '../../components/BookTable';
|
||||
|
||||
import { AppContext, AppContextProps } from '../../contexts/AppContext';
|
||||
|
||||
interface MakerPageProps {
|
||||
hasRobot: boolean;
|
||||
}
|
||||
|
||||
const MakerPage = ({ hasRobot = false }: MakerPageProps): JSX.Element => {
|
||||
const { book, fav, maker, clearOrder, windowSize, setCurrentOrder, navbarHeight, setPage } =
|
||||
useContext<AppContextProps>(AppContext);
|
||||
const MakerPage = (): JSX.Element => {
|
||||
const {
|
||||
robot,
|
||||
book,
|
||||
fav,
|
||||
maker,
|
||||
clearOrder,
|
||||
windowSize,
|
||||
setCurrentOrder,
|
||||
navbarHeight,
|
||||
setPage,
|
||||
} = useContext<AppContextProps>(AppContext);
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
|
||||
@ -74,7 +79,7 @@ const MakerPage = ({ hasRobot = false }: MakerPageProps): JSX.Element => {
|
||||
setPage('order');
|
||||
history.push('/order/' + id);
|
||||
}}
|
||||
hasRobot={hasRobot}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
disableRequest={matches.length > 0 && !showMatches}
|
||||
collapseAll={showMatches}
|
||||
onSubmit={() => setShowMatches(matches.length > 0)}
|
||||
|
@ -20,17 +20,16 @@ import { AppContext, AppContextProps } from '../../contexts/AppContext';
|
||||
interface NavBarProps {
|
||||
width: number;
|
||||
height: number;
|
||||
hasRobot: boolean;
|
||||
}
|
||||
|
||||
const NavBar = ({ width, height, hasRobot = false }: NavBarProps): JSX.Element => {
|
||||
const NavBar = ({ width, height }: NavBarProps): JSX.Element => {
|
||||
const {
|
||||
robot,
|
||||
page,
|
||||
settings,
|
||||
setPage,
|
||||
setSlideDirection,
|
||||
open,
|
||||
robot,
|
||||
setOpen,
|
||||
closeAll,
|
||||
currentOrder,
|
||||
@ -43,7 +42,7 @@ const NavBar = ({ width, height, hasRobot = false }: NavBarProps): JSX.Element =
|
||||
const smallBar = width < 50;
|
||||
|
||||
const tabSx = smallBar
|
||||
? { position: 'relative', bottom: robot.nickname ? '1em' : '0em', minWidth: '1em' }
|
||||
? { position: 'relative', bottom: robot.avatarLoaded ? '0.9em' : '0.13em', minWidth: '1em' }
|
||||
: { position: 'relative', bottom: '1em', minWidth: '2em' };
|
||||
const pagesPosition = {
|
||||
robot: 1,
|
||||
@ -137,7 +136,7 @@ const NavBar = ({ width, height, hasRobot = false }: NavBarProps): JSX.Element =
|
||||
sx={tabSx}
|
||||
label={smallBar ? undefined : t('Order')}
|
||||
value='order'
|
||||
disabled={!hasRobot || currentOrder == undefined}
|
||||
disabled={!robot.avatarLoaded || currentOrder == undefined}
|
||||
icon={<Assignment />}
|
||||
iconPosition='start'
|
||||
/>
|
||||
|
@ -6,20 +6,18 @@ import { useHistory } from 'react-router-dom';
|
||||
import TradeBox from '../../components/TradeBox';
|
||||
import OrderDetails from '../../components/OrderDetails';
|
||||
|
||||
import { Page } from '../NavBar';
|
||||
import { Order, Settings } from '../../models';
|
||||
import { apiClient } from '../../services/api';
|
||||
import { AppContext, AppContextProps } from '../../contexts/AppContext';
|
||||
|
||||
interface OrderPageProps {
|
||||
hasRobot: boolean;
|
||||
locationOrderId: number;
|
||||
}
|
||||
|
||||
const OrderPage = ({ hasRobot = false, locationOrderId }: OrderPageProps): JSX.Element => {
|
||||
const OrderPage = ({ locationOrderId }: OrderPageProps): JSX.Element => {
|
||||
const {
|
||||
windowSize,
|
||||
order,
|
||||
robot,
|
||||
settings,
|
||||
setOrder,
|
||||
setCurrentOrder,
|
||||
@ -106,7 +104,7 @@ const OrderPage = ({ hasRobot = false, locationOrderId }: OrderPageProps): JSX.E
|
||||
setOrder={setOrder}
|
||||
baseUrl={baseUrl}
|
||||
setPage={setPage}
|
||||
hasRobot={hasRobot}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
/>
|
||||
</Paper>
|
||||
</Grid>
|
||||
@ -121,6 +119,7 @@ const OrderPage = ({ hasRobot = false, locationOrderId }: OrderPageProps): JSX.E
|
||||
>
|
||||
<TradeBox
|
||||
order={order}
|
||||
robot={robot}
|
||||
settings={settings}
|
||||
setOrder={setOrder}
|
||||
setBadOrder={setBadOrder}
|
||||
@ -158,12 +157,13 @@ const OrderPage = ({ hasRobot = false, locationOrderId }: OrderPageProps): JSX.E
|
||||
setOrder={setOrder}
|
||||
baseUrl={baseUrl}
|
||||
setPage={setPage}
|
||||
hasRobot={hasRobot}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: tab == 'contract' ? '' : 'none' }}>
|
||||
<TradeBox
|
||||
order={order}
|
||||
robot={robot}
|
||||
settings={settings}
|
||||
setOrder={setOrder}
|
||||
setBadOrder={setBadOrder}
|
||||
@ -189,7 +189,7 @@ const OrderPage = ({ hasRobot = false, locationOrderId }: OrderPageProps): JSX.E
|
||||
setOrder={setOrder}
|
||||
baseUrl={baseUrl}
|
||||
setPage={setPage}
|
||||
hasRobot={hasRobot}
|
||||
hasRobot={robot.avatarLoaded}
|
||||
/>
|
||||
</Paper>
|
||||
)
|
||||
|
@ -49,17 +49,16 @@ const Onboarding = ({
|
||||
}: OnboardingProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
const theme = useTheme();
|
||||
|
||||
const [step, setStep] = useState<'1' | '2' | '3'>('1');
|
||||
const [generatedToken, setGeneratedToken] = useState<boolean>(false);
|
||||
const [showMimickProgress, setShowMimickProgress] = useState<boolean>(false);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const generateToken = () => {
|
||||
setGeneratedToken(true);
|
||||
setInputToken(genBase62Token(36));
|
||||
setShowMimickProgress(true);
|
||||
setTimeout(() => setShowMimickProgress(false), 1000);
|
||||
setLoading(true);
|
||||
setTimeout(() => setLoading(false), 1000);
|
||||
};
|
||||
|
||||
const changePage = function (newPage: Page) {
|
||||
@ -104,10 +103,8 @@ const Onboarding = ({
|
||||
</Alert>
|
||||
</Grid>
|
||||
<Grid item sx={{ width: '100%' }}>
|
||||
{showMimickProgress ? (
|
||||
<LinearProgress sx={{ height: '0.7em' }} />
|
||||
) : (
|
||||
<TokenInput
|
||||
loading={loading}
|
||||
autoFocusTarget='copyButton'
|
||||
inputToken={inputToken}
|
||||
setInputToken={setInputToken}
|
||||
@ -116,7 +113,6 @@ const Onboarding = ({
|
||||
robot={robot}
|
||||
onPressEnter={() => null}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography>
|
||||
|
@ -1,22 +1,37 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useContext, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
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 {
|
||||
Button,
|
||||
Grid,
|
||||
LinearProgress,
|
||||
Typography,
|
||||
Alert,
|
||||
Select,
|
||||
MenuItem,
|
||||
Box,
|
||||
useTheme,
|
||||
Tooltip,
|
||||
} from '@mui/material';
|
||||
import { Bolt, Add, DeleteSweep, Logout, Download } from '@mui/icons-material';
|
||||
import RobotAvatar from '../../components/RobotAvatar';
|
||||
import TokenInput from './TokenInput';
|
||||
import { Page } from '../NavBar';
|
||||
import { Robot } from '../../models';
|
||||
import { Slot, Robot } from '../../models';
|
||||
import { AppContext, AppContextProps } from '../../contexts/AppContext';
|
||||
import { genBase62Token } from '../../utils';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
|
||||
interface RobotProfileProps {
|
||||
robot: Robot;
|
||||
setRobot: (state: Robot) => void;
|
||||
setView: (state: 'welcome' | 'onboarding' | 'recovery' | 'profile') => void;
|
||||
getGenerateRobot: (token: string, slot?: number) => void;
|
||||
inputToken: string;
|
||||
setCurrentOrder: (state: number) => void;
|
||||
logoutRobot: () => void;
|
||||
inputToken: string;
|
||||
setInputToken: (state: string) => void;
|
||||
getGenerateRobot: (token: string) => void;
|
||||
setPage: (state: Page) => void;
|
||||
baseUrl: string;
|
||||
badRequest: string;
|
||||
@ -27,9 +42,9 @@ const RobotProfile = ({
|
||||
robot,
|
||||
setRobot,
|
||||
inputToken,
|
||||
getGenerateRobot,
|
||||
setInputToken,
|
||||
setCurrentOrder,
|
||||
getGenerateRobot,
|
||||
logoutRobot,
|
||||
setPage,
|
||||
setView,
|
||||
@ -37,11 +52,41 @@ const RobotProfile = ({
|
||||
baseUrl,
|
||||
width,
|
||||
}: RobotProfileProps): JSX.Element => {
|
||||
const { currentSlot, garage, setCurrentSlot, windowSize } =
|
||||
useContext<AppContextProps>(AppContext);
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const history = useHistory();
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (robot.nickname && robot.avatarLoaded) {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [robot]);
|
||||
|
||||
const handleAddRobot = () => {
|
||||
getGenerateRobot(genBase62Token(36), garage.slots.length);
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
const handleChangeSlot = (e) => {
|
||||
const slot = e.target.value;
|
||||
getGenerateRobot(garage.slots[slot].robot.token, slot);
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container direction='column' alignItems='center' spacing={2} padding={2}>
|
||||
<Grid container direction='column' alignItems='center' spacing={1} padding={1} paddingTop={2}>
|
||||
<Grid
|
||||
item
|
||||
container
|
||||
direction='column'
|
||||
alignItems='center'
|
||||
spacing={1}
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
<Grid item sx={{ height: '2.3em', position: 'relative' }}>
|
||||
{robot.avatarLoaded && robot.nickname ? (
|
||||
<Typography align='center' component='h5' variant='h5'>
|
||||
@ -99,17 +144,16 @@ const RobotProfile = ({
|
||||
tooltipPosition='top'
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{robot.found ? (
|
||||
{robot.found && !robot.lastOrderId ? (
|
||||
<Typography align='center' variant='h6'>
|
||||
{t('Welcome back!')}
|
||||
</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
{robot.activeOrderId ? (
|
||||
{robot.activeOrderId && robot.avatarLoaded && robot.nickname ? (
|
||||
<Grid item>
|
||||
<Button
|
||||
onClick={() => {
|
||||
@ -123,7 +167,7 @@ const RobotProfile = ({
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
{robot.lastOrderId ? (
|
||||
{robot.lastOrderId && robot.avatarLoaded && robot.nickname ? (
|
||||
<Grid item container direction='column' alignItems='center'>
|
||||
<Grid item>
|
||||
<Button
|
||||
@ -145,16 +189,9 @@ const RobotProfile = ({
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item sx={{ position: 'relative', right: '1em' }}>
|
||||
<Button
|
||||
color='inherit'
|
||||
size='small'
|
||||
onClick={() => {
|
||||
logoutRobot();
|
||||
setView('welcome');
|
||||
}}
|
||||
>
|
||||
<Refresh />
|
||||
{t('Generate a new Robot')}
|
||||
<Button color='success' size='small' onClick={handleAddRobot}>
|
||||
<Add />
|
||||
{t('Add a new Robot')}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@ -163,11 +200,37 @@ const RobotProfile = ({
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
<Grid item sx={{ width: '100%' }}>
|
||||
<Grid
|
||||
item
|
||||
container
|
||||
direction='row'
|
||||
justifyContent='stretch'
|
||||
alignItems='stretch'
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
<Grid
|
||||
item
|
||||
xs={2}
|
||||
sx={{ display: 'flex', justifyContent: 'stretch', alignItems: 'stretch' }}
|
||||
>
|
||||
<Tooltip enterTouchDelay={0} enterDelay={300} enterNextDelay={1000} title={t('Logout')}>
|
||||
<Button
|
||||
sx={{ minWidth: '2em', width: '100%' }}
|
||||
color='primary'
|
||||
variant='outlined'
|
||||
onClick={() => {
|
||||
logoutRobot();
|
||||
setView('welcome');
|
||||
}}
|
||||
>
|
||||
<Logout />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TokenInput
|
||||
inputToken={inputToken}
|
||||
editable={false}
|
||||
showDownload={true}
|
||||
label={t('Store your token safely')}
|
||||
setInputToken={setInputToken}
|
||||
setRobot={setRobot}
|
||||
@ -176,21 +239,102 @@ const RobotProfile = ({
|
||||
onPressEnter={() => null}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item sx={{ width: '100%' }}>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: 'background.paper',
|
||||
border: '1px solid',
|
||||
borderRadius: '4px',
|
||||
borderColor: theme.palette.mode === 'dark' ? '#434343' : '#c4c4c4',
|
||||
}}
|
||||
>
|
||||
<Grid container direction='column' alignItems='center' spacing={2} padding={2}>
|
||||
<Grid item sx={{ width: '100%' }}>
|
||||
<Typography variant='caption'>{t('Robot Garage')}</Typography>
|
||||
<Select
|
||||
fullWidth
|
||||
required={true}
|
||||
inputProps={{
|
||||
style: { textAlign: 'center' },
|
||||
}}
|
||||
value={loading ? 'loading' : currentSlot}
|
||||
onChange={handleChangeSlot}
|
||||
>
|
||||
{loading ? (
|
||||
<MenuItem key={'loading'} value={'loading'}>
|
||||
<Typography>{t('Building...')}</Typography>
|
||||
</MenuItem>
|
||||
) : (
|
||||
garage.slots.map((slot: Slot, index: number) => {
|
||||
return (
|
||||
<MenuItem key={index} value={index}>
|
||||
<Grid
|
||||
container
|
||||
direction='row'
|
||||
justifyContent='flex-start'
|
||||
alignItems='center'
|
||||
style={{ height: '2.8em' }}
|
||||
spacing={1}
|
||||
>
|
||||
<Grid item>
|
||||
<RobotAvatar
|
||||
nickname={slot.robot.nickname}
|
||||
smooth={true}
|
||||
style={{ width: '2.6em', height: '2.6em' }}
|
||||
placeholderType='loading'
|
||||
baseUrl={baseUrl}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant={windowSize.width < 26 ? 'caption' : undefined}>
|
||||
{slot.robot.nickname}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</MenuItem>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</Select>
|
||||
</Grid>
|
||||
|
||||
<Grid item container direction='row' alignItems='center' justifyContent='space-evenly'>
|
||||
<Grid item>
|
||||
<LoadingButton loading={loading} color='primary' onClick={handleAddRobot}>
|
||||
<Add /> <div style={{ width: '0.5em' }} />
|
||||
{t('Add Robot')}
|
||||
</LoadingButton>
|
||||
</Grid>
|
||||
|
||||
{window.NativeRobosats === undefined ? (
|
||||
<Grid item>
|
||||
<Button color='primary' onClick={() => garage.download()}>
|
||||
<Download />
|
||||
</Button>
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
<Grid item>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
onClick={() => {
|
||||
garage.delete();
|
||||
setCurrentSlot(0);
|
||||
logoutRobot();
|
||||
setView('welcome');
|
||||
}}
|
||||
>
|
||||
<Logout /> <div style={{ width: '0.5em' }} />
|
||||
{t('Logout Robot')}
|
||||
<DeleteSweep /> <div style={{ width: '0.5em' }} />
|
||||
{t('Delete Garage')}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IconButton, TextField, Tooltip, useTheme } from '@mui/material';
|
||||
import { IconButton, LinearProgress, TextField, Tooltip } from '@mui/material';
|
||||
import { Robot } from '../../models';
|
||||
import { Download, ContentCopy } from '@mui/icons-material';
|
||||
import { ContentCopy } from '@mui/icons-material';
|
||||
import { systemClient } from '../../services/System';
|
||||
import { saveAsJson } from '../../utils';
|
||||
|
||||
interface TokenInputProps {
|
||||
robot: Robot;
|
||||
editable?: boolean;
|
||||
showDownload?: boolean;
|
||||
fullWidth?: boolean;
|
||||
loading?: boolean;
|
||||
setRobot: (state: Robot) => void;
|
||||
inputToken: string;
|
||||
autoFocusTarget?: 'textfield' | 'copyButton' | 'none';
|
||||
@ -27,12 +27,12 @@ const TokenInput = ({
|
||||
showCopy = true,
|
||||
label,
|
||||
setRobot,
|
||||
showDownload = false,
|
||||
fullWidth = true,
|
||||
onPressEnter,
|
||||
autoFocusTarget = 'textfield',
|
||||
inputToken,
|
||||
badRequest,
|
||||
loading = false,
|
||||
setInputToken,
|
||||
}: TokenInputProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
@ -52,6 +52,9 @@ const TokenInput = ({
|
||||
};
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <LinearProgress sx={{ height: '0.8em' }} />;
|
||||
} else {
|
||||
return (
|
||||
<TextField
|
||||
error={!!badRequest}
|
||||
@ -72,17 +75,6 @@ const TokenInput = ({
|
||||
}
|
||||
}}
|
||||
InputProps={{
|
||||
startAdornment: showDownload ? (
|
||||
<Tooltip enterTouchDelay={250} title={t('Download token and PGP credentials')}>
|
||||
<IconButton
|
||||
color='primary'
|
||||
sx={{ position: 'relative', top: label ? '0.4em' : '0em' }}
|
||||
onClick={() => saveAsJson(robot.nickname + '.json', createJsonFile())}
|
||||
>
|
||||
<Download sx={{ width: '1em', height: '1em' }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
) : null,
|
||||
endAdornment: showCopy ? (
|
||||
<Tooltip open={showCopied} title={t('Copied!')}>
|
||||
<IconButton
|
||||
@ -102,6 +94,7 @@ const TokenInput = ({
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default TokenInput;
|
||||
|
@ -12,9 +12,7 @@ import {
|
||||
} from '@mui/material';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { Page } from '../NavBar';
|
||||
import { Robot } from '../../models';
|
||||
import { systemClient } from '../../services/System';
|
||||
import { apiClient } from '../../services/api';
|
||||
import Onboarding from './Onboarding';
|
||||
import Welcome from './Welcome';
|
||||
@ -25,7 +23,7 @@ import { genKey } from '../../pgp';
|
||||
import { AppContext, AppContextProps } from '../../contexts/AppContext';
|
||||
|
||||
const RobotPage = (): JSX.Element => {
|
||||
const { setPage, setCurrentOrder, fetchRobot, torStatus, windowSize, robot, setRobot, baseUrl } =
|
||||
const { robot, setRobot, setPage, setCurrentOrder, fetchRobot, torStatus, windowSize, baseUrl } =
|
||||
useContext<AppContextProps>(AppContext);
|
||||
const { t } = useTranslation();
|
||||
const params = useParams();
|
||||
@ -49,7 +47,7 @@ const RobotPage = (): JSX.Element => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getGenerateRobot = (token: string) => {
|
||||
const getGenerateRobot = (token: string, slot?: number) => {
|
||||
setInputToken(token);
|
||||
genKey(token).then(function (key) {
|
||||
fetchRobot({
|
||||
@ -59,24 +57,16 @@ const RobotPage = (): JSX.Element => {
|
||||
encPrivKey: key.encryptedPrivateKeyArmored,
|
||||
},
|
||||
newToken: token,
|
||||
slot,
|
||||
refCode,
|
||||
setBadRequest,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const deleteRobot = () => {
|
||||
apiClient.delete(baseUrl, '/api/user');
|
||||
logoutRobot();
|
||||
};
|
||||
|
||||
const logoutRobot = () => {
|
||||
setInputToken('');
|
||||
systemClient.deleteCookie('sessionid');
|
||||
systemClient.deleteItem('robot_token');
|
||||
systemClient.deleteItem('pub_key');
|
||||
systemClient.deleteItem('enc_priv_key');
|
||||
setTimeout(() => setRobot(new Robot()), 10);
|
||||
setRobot(new Robot());
|
||||
};
|
||||
|
||||
if (!(window.NativeRobosats === undefined) && !(torStatus == 'DONE' || torStatus == '"Done"')) {
|
||||
@ -146,7 +136,7 @@ const RobotPage = (): JSX.Element => {
|
||||
<Onboarding
|
||||
setView={setView}
|
||||
robot={robot}
|
||||
setRobot={setRobot}
|
||||
setRobot={() => null}
|
||||
badRequest={badRequest}
|
||||
inputToken={inputToken}
|
||||
setInputToken={setInputToken}
|
||||
@ -160,9 +150,10 @@ const RobotPage = (): JSX.Element => {
|
||||
<RobotProfile
|
||||
setView={setView}
|
||||
robot={robot}
|
||||
setRobot={setRobot}
|
||||
setRobot={() => null}
|
||||
setCurrentOrder={setCurrentOrder}
|
||||
badRequest={badRequest}
|
||||
getGenerateRobot={getGenerateRobot}
|
||||
logoutRobot={logoutRobot}
|
||||
width={width}
|
||||
inputToken={inputToken}
|
||||
@ -177,7 +168,7 @@ const RobotPage = (): JSX.Element => {
|
||||
<Recovery
|
||||
setView={setView}
|
||||
robot={robot}
|
||||
setRobot={setRobot}
|
||||
setRobot={() => null}
|
||||
badRequest={badRequest}
|
||||
inputToken={inputToken}
|
||||
setInputToken={setInputToken}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Dialog,
|
||||
@ -14,6 +14,7 @@ import {
|
||||
} from '@mui/material';
|
||||
import { systemClient } from '../../services/System';
|
||||
import ContentCopy from '@mui/icons-material/ContentCopy';
|
||||
import { AppContext, AppContextProps } from '../../contexts/AppContext';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@ -23,6 +24,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const StoreTokenDialog = ({ open, onClose, onClickBack, onClickDone }: Props): JSX.Element => {
|
||||
const { robot } = useContext<AppContextProps>(AppContext);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -41,17 +43,13 @@ const StoreTokenDialog = ({ open, onClose, onClickBack, onClickDone }: Props): J
|
||||
sx={{ width: '100%', maxWidth: '550px' }}
|
||||
disabled
|
||||
label={t('Back it up!')}
|
||||
value={systemClient.getItem('robot_token')}
|
||||
value={robot.token}
|
||||
variant='filled'
|
||||
size='small'
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
systemClient.copyToClipboard(systemClient.getItem('robot_token'))
|
||||
}
|
||||
>
|
||||
<IconButton onClick={() => systemClient.copyToClipboard(robot.token)}>
|
||||
<ContentCopy color='primary' />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
@ -40,6 +40,7 @@ const RobotAvatar: React.FC<Props> = ({
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const [avatarSrc, setAvatarSrc] = useState<string>();
|
||||
const [nicknameReady, setNicknameReady] = useState<boolean>(false);
|
||||
|
||||
const backgroundData =
|
||||
placeholderType == 'generating' ? placeholder.generating : placeholder.loading;
|
||||
@ -55,11 +56,15 @@ const RobotAvatar: React.FC<Props> = ({
|
||||
if (nickname != undefined) {
|
||||
if (window.NativeRobosats === undefined) {
|
||||
setAvatarSrc(baseUrl + '/static/assets/avatars/' + nickname + '.png');
|
||||
setNicknameReady(true);
|
||||
} else {
|
||||
setNicknameReady(true);
|
||||
apiClient
|
||||
.fileImageUrl(baseUrl, '/static/assets/avatars/' + nickname + '.png')
|
||||
.then(setAvatarSrc);
|
||||
}
|
||||
} else {
|
||||
setNicknameReady(false);
|
||||
}
|
||||
}, [nickname]);
|
||||
|
||||
@ -93,7 +98,7 @@ const RobotAvatar: React.FC<Props> = ({
|
||||
>
|
||||
<div className={className}>
|
||||
<SmoothImage
|
||||
src={avatarSrc}
|
||||
src={nicknameReady ? avatarSrc : null}
|
||||
imageStyles={{
|
||||
borderRadius: '50%',
|
||||
border: '0.3px solid #55555',
|
||||
@ -110,7 +115,7 @@ const RobotAvatar: React.FC<Props> = ({
|
||||
className={avatarClass}
|
||||
style={style}
|
||||
alt={nickname}
|
||||
src={avatarSrc}
|
||||
src={nicknameReady ? avatarSrc : null}
|
||||
imgProps={{
|
||||
sx: { transform: flipHorizontally ? 'scaleX(-1)' : '' },
|
||||
style: { transform: flipHorizontally ? 'scaleX(-1)' : '' },
|
||||
|
@ -1,11 +1,10 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Tooltip, TextField, Grid, Container, Paper, Typography } from '@mui/material';
|
||||
import { Button, Tooltip, TextField, Grid, Paper } from '@mui/material';
|
||||
import { encryptMessage, decryptMessage } from '../../../../pgp';
|
||||
import { saveAsJson } from '../../../../utils';
|
||||
import { AuditPGPDialog } from '../../../Dialogs';
|
||||
import { systemClient } from '../../../../services/System';
|
||||
import { websocketClient, WebsocketConnection } from '../../../../services/Websocket';
|
||||
import { Robot } from '../../../../models';
|
||||
|
||||
// Icons
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
@ -19,6 +18,7 @@ import ChatBottom from '../ChatBottom';
|
||||
interface Props {
|
||||
orderId: number;
|
||||
status: number;
|
||||
robot: Robot;
|
||||
userNick: string;
|
||||
takerNick: string;
|
||||
messages: EncryptedChatMessage[];
|
||||
@ -31,6 +31,7 @@ interface Props {
|
||||
const EncryptedSocketChat: React.FC<Props> = ({
|
||||
orderId,
|
||||
status,
|
||||
robot,
|
||||
userNick,
|
||||
takerNick,
|
||||
messages,
|
||||
@ -45,14 +46,10 @@ const EncryptedSocketChat: React.FC<Props> = ({
|
||||
const audio = new Audio(`/static/assets/sounds/chat-open.mp3`);
|
||||
const [connected, setConnected] = useState<boolean>(false);
|
||||
const [peerConnected, setPeerConnected] = useState<boolean>(false);
|
||||
const [ownPubKey] = useState<string>(
|
||||
(systemClient.getItem('pub_key') ?? '').split('\\').join('\n'),
|
||||
);
|
||||
const [ownEncPrivKey] = useState<string>(
|
||||
(systemClient.getItem('enc_priv_key') ?? '').split('\\').join('\n'),
|
||||
);
|
||||
const [ownPubKey] = useState<string>(robot.pubKey);
|
||||
const [ownEncPrivKey] = useState<string>(robot.encPrivKey);
|
||||
const [peerPubKey, setPeerPubKey] = useState<string>();
|
||||
const [token] = useState<string>(systemClient.getItem('robot_token') || '');
|
||||
const [token] = useState<string>(robot.token);
|
||||
const [serverMessages, setServerMessages] = useState<ServerMessage[]>([]);
|
||||
const [value, setValue] = useState<string>('');
|
||||
const [connection, setConnection] = useState<WebsocketConnection>();
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, TextField, Grid, Container, Paper } from '@mui/material';
|
||||
import { Button, TextField, Grid, Paper } from '@mui/material';
|
||||
import { encryptMessage, decryptMessage } from '../../../../pgp';
|
||||
import { AuditPGPDialog } from '../../../Dialogs';
|
||||
import { systemClient } from '../../../../services/System';
|
||||
import { Robot } from '../../../../models';
|
||||
|
||||
// Icons
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
@ -17,6 +17,7 @@ import ChatBottom from '../ChatBottom';
|
||||
|
||||
interface Props {
|
||||
orderId: number;
|
||||
robot: Robot;
|
||||
userNick: string;
|
||||
takerNick: string;
|
||||
chatOffset: number;
|
||||
@ -29,6 +30,7 @@ interface Props {
|
||||
|
||||
const EncryptedTurtleChat: React.FC<Props> = ({
|
||||
orderId,
|
||||
robot,
|
||||
userNick,
|
||||
takerNick,
|
||||
chatOffset,
|
||||
@ -43,14 +45,10 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
||||
|
||||
const audio = new Audio(`/static/assets/sounds/chat-open.mp3`);
|
||||
const [peerConnected, setPeerConnected] = useState<boolean>(false);
|
||||
const [ownPubKey] = useState<string>(
|
||||
(systemClient.getItem('pub_key') ?? '').split('\\').join('\n'),
|
||||
);
|
||||
const [ownEncPrivKey] = useState<string>(
|
||||
(systemClient.getItem('enc_priv_key') ?? '').split('\\').join('\n'),
|
||||
);
|
||||
const [ownPubKey] = useState<string>(robot.pubKey || '');
|
||||
const [ownEncPrivKey] = useState<string>(robot.encPrivKey || '');
|
||||
const [peerPubKey, setPeerPubKey] = useState<string>();
|
||||
const [token] = useState<string>(systemClient.getItem('robot_token') || '');
|
||||
const [token] = useState<string>(robot.token || '');
|
||||
const [value, setValue] = useState<string>('');
|
||||
const [audit, setAudit] = useState<boolean>(false);
|
||||
const [waitingEcho, setWaitingEcho] = useState<boolean>(false);
|
||||
@ -171,8 +169,9 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
||||
// If input string contains '#' send unencrypted and unlogged message
|
||||
else if (value.substring(0, 1) == '#') {
|
||||
apiClient
|
||||
.post(baseUrl, `/api/chat`, {
|
||||
.post(baseUrl, `/api/chat/`, {
|
||||
PGP_message: value,
|
||||
order_id: orderId,
|
||||
offset: lastIndex,
|
||||
})
|
||||
.then((response) => {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Robot } from '../../../models';
|
||||
import EncryptedSocketChat from './EncryptedSocketChat';
|
||||
import EncryptedTurtleChat from './EncryptedTurtleChat';
|
||||
|
||||
interface Props {
|
||||
orderId: number;
|
||||
status: number;
|
||||
takerNick: string;
|
||||
makerNick: string;
|
||||
userNick: string;
|
||||
@ -15,6 +17,7 @@ interface Props {
|
||||
|
||||
export interface EncryptedChatMessage {
|
||||
userNick: string;
|
||||
robot: Robot;
|
||||
validSignature: boolean;
|
||||
plainTextMessage: string;
|
||||
encryptedMessage: string;
|
||||
@ -32,17 +35,20 @@ export interface ServerMessage {
|
||||
const EncryptedChat: React.FC<Props> = ({
|
||||
orderId,
|
||||
takerNick,
|
||||
robot,
|
||||
userNick,
|
||||
chatOffset,
|
||||
baseUrl,
|
||||
setMessages,
|
||||
messages,
|
||||
status,
|
||||
}: Props): JSX.Element => {
|
||||
const [turtleMode, setTurtleMode] = useState<boolean>(window.ReactNativeWebView !== undefined);
|
||||
|
||||
return turtleMode ? (
|
||||
<EncryptedTurtleChat
|
||||
messages={messages}
|
||||
robot={robot}
|
||||
setMessages={setMessages}
|
||||
orderId={orderId}
|
||||
takerNick={takerNick}
|
||||
@ -54,7 +60,9 @@ const EncryptedChat: React.FC<Props> = ({
|
||||
/>
|
||||
) : (
|
||||
<EncryptedSocketChat
|
||||
status={status}
|
||||
messages={messages}
|
||||
robot={robot}
|
||||
setMessages={setMessages}
|
||||
orderId={orderId}
|
||||
takerNick={takerNick}
|
||||
|
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Grid, Typography, Tooltip, Collapse, IconButton } from '@mui/material';
|
||||
import currencies from '../../../../static/assets/currencies.json';
|
||||
|
||||
import { Order } from '../../../models';
|
||||
import { Order, Robot } from '../../../models';
|
||||
import { pn } from '../../../utils';
|
||||
import EncryptedChat, { EncryptedChatMessage } from '../EncryptedChat';
|
||||
import Countdown, { zeroPad } from 'react-countdown';
|
||||
@ -11,6 +11,7 @@ import { LoadingButton } from '@mui/lab';
|
||||
|
||||
interface ChatPromptProps {
|
||||
order: Order;
|
||||
robot: Robot;
|
||||
onClickConfirmSent: () => void;
|
||||
loadingSent: boolean;
|
||||
onClickConfirmReceived: () => void;
|
||||
@ -24,6 +25,7 @@ interface ChatPromptProps {
|
||||
|
||||
export const ChatPrompt = ({
|
||||
order,
|
||||
robot,
|
||||
onClickConfirmSent,
|
||||
onClickConfirmReceived,
|
||||
loadingSent,
|
||||
@ -116,6 +118,7 @@ export const ChatPrompt = ({
|
||||
<Grid item>
|
||||
<EncryptedChat
|
||||
status={order.status}
|
||||
robot={robot}
|
||||
chatOffset={order.chat_last_index}
|
||||
orderId={order.id}
|
||||
takerNick={order.taker_nick}
|
||||
|
@ -93,6 +93,7 @@ const closeAll: OpenDialogProps = {
|
||||
interface TradeBoxProps {
|
||||
order: Order;
|
||||
setOrder: (state: Order) => void;
|
||||
robot: Robot;
|
||||
setBadOrder: (state: string | undefined) => void;
|
||||
onRenewOrder: () => void;
|
||||
onStartAgain: () => void;
|
||||
@ -103,6 +104,7 @@ interface TradeBoxProps {
|
||||
const TradeBox = ({
|
||||
order,
|
||||
setOrder,
|
||||
robot,
|
||||
settings,
|
||||
baseUrl,
|
||||
setBadOrder,
|
||||
@ -230,7 +232,7 @@ const TradeBox = ({
|
||||
const submitStatement = function () {
|
||||
let statement = dispute.statement;
|
||||
if (dispute.attachLogs) {
|
||||
const payload = { statement, messages, token: systemClient.getItem('robot_token') };
|
||||
const payload = { statement, messages, token: robot.token };
|
||||
statement = JSON.stringify(payload, null, 2);
|
||||
}
|
||||
setLoadingButtons({ ...noLoadingButtons, submitStatement: true });
|
||||
@ -461,6 +463,7 @@ const TradeBox = ({
|
||||
return (
|
||||
<ChatPrompt
|
||||
order={order}
|
||||
robot={robot}
|
||||
onClickConfirmSent={confirmFiatSent}
|
||||
onClickConfirmReceived={() => setOpen({ ...open, confirmFiatReceived: true })}
|
||||
loadingSent={loadingButtons.fiatSent}
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
LimitList,
|
||||
Maker,
|
||||
Robot,
|
||||
Garage,
|
||||
Info,
|
||||
Settings,
|
||||
Favorites,
|
||||
@ -22,7 +23,6 @@ import { sha256 } from 'js-sha256';
|
||||
|
||||
import defaultCoordinators from '../../static/federation.json';
|
||||
import { useTheme } from '@mui/material';
|
||||
import { systemClient } from '../services/System';
|
||||
|
||||
const getWindowSize = function (fontSize: number) {
|
||||
// returns window size in EM units
|
||||
@ -61,10 +61,11 @@ export interface SlideDirection {
|
||||
}
|
||||
|
||||
export interface fetchRobotProps {
|
||||
action?: 'login' | 'generate';
|
||||
action?: 'login' | 'generate' | 'refresh';
|
||||
newKeys?: { encPrivKey: string; pubKey: string } | null;
|
||||
newToken?: string | null;
|
||||
refCode?: string | null;
|
||||
slot?: number | null;
|
||||
setBadRequest?: (state: string) => void;
|
||||
}
|
||||
|
||||
@ -78,6 +79,10 @@ export interface AppContextProps {
|
||||
setSettings: (state: Settings) => void;
|
||||
book: Book;
|
||||
info: Info;
|
||||
garage: Garage;
|
||||
setGarage: (state: Garage) => void;
|
||||
currentSlot: number;
|
||||
setCurrentSlot: (state: number) => void;
|
||||
setBook: (state: Book) => void;
|
||||
fetchBook: () => void;
|
||||
limits: { list: LimitList; loading: boolean };
|
||||
@ -200,7 +205,13 @@ export const AppContextProvider = ({
|
||||
list: [],
|
||||
loading: true,
|
||||
});
|
||||
const [robot, setRobot] = useState<Robot>(new Robot());
|
||||
const [garage, setGarage] = useState<Garage>(() => {
|
||||
const initialState = { setGarage };
|
||||
const newGarage = new Garage(initialState);
|
||||
return newGarage;
|
||||
});
|
||||
const [currentSlot, setCurrentSlot] = useState<number>(garage.slots.length - 1);
|
||||
const [robot, setRobot] = useState<Robot>(new Robot(garage.slots[currentSlot].robot));
|
||||
const [maker, setMaker] = useState<Maker>(defaultMaker);
|
||||
const [info, setInfo] = useState<Info>(defaultInfo);
|
||||
const [coordinators, setCoordinators] = useState<Coordinator[]>(defaultCoordinators);
|
||||
@ -219,7 +230,6 @@ export const AppContextProvider = ({
|
||||
in: undefined,
|
||||
out: undefined,
|
||||
});
|
||||
|
||||
const [currentOrder, setCurrentOrder] = useState<number | undefined>(undefined);
|
||||
|
||||
const navbarHeight = 2.5;
|
||||
@ -239,6 +249,13 @@ export const AppContextProvider = ({
|
||||
getWindowSize(theme.typography.fontSize),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('torStatus', (event) => {
|
||||
// UX improv: delay the "Conencted" status by 10 secs to avoid long waits for first requests
|
||||
setTimeout(() => setTorStatus(event?.detail), event?.detail === '"Done"' ? 10000 : 0);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== undefined) {
|
||||
window.addEventListener('resize', onResize);
|
||||
@ -257,15 +274,18 @@ export const AppContextProvider = ({
|
||||
|
||||
useEffect(() => {
|
||||
let host = '';
|
||||
let protocol = '';
|
||||
if (window.NativeRobosats === undefined) {
|
||||
host = getHost();
|
||||
protocol = location.protocol;
|
||||
} else {
|
||||
protocol = 'http:';
|
||||
host =
|
||||
settings.network === 'mainnet'
|
||||
? coordinators[0].mainnetOnion
|
||||
: coordinators[0].testnetOnion;
|
||||
}
|
||||
setBaseUrl(`${location.protocol}//${host}`);
|
||||
setBaseUrl(`${protocol}//${host}`);
|
||||
}, [settings.network]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -371,14 +391,19 @@ export const AppContextProvider = ({
|
||||
newKeys = null,
|
||||
newToken = null,
|
||||
refCode = null,
|
||||
slot = null,
|
||||
setBadRequest = () => {},
|
||||
}: fetchRobotProps) {
|
||||
setRobot({ ...robot, loading: true, avatarLoaded: false });
|
||||
const oldRobot = robot;
|
||||
const targetSlot = slot ?? currentSlot;
|
||||
if (action != 'refresh') {
|
||||
setRobot(new Robot());
|
||||
}
|
||||
setBadRequest('');
|
||||
|
||||
let requestBody = {};
|
||||
if (action == 'login') {
|
||||
requestBody.token_sha256 = sha256(newToken ?? robot.token);
|
||||
if (action == 'login' || action == 'refresh') {
|
||||
requestBody.token_sha256 = sha256(newToken ?? oldRobot.token);
|
||||
} else if (action == 'generate' && newToken != null) {
|
||||
const strength = tokenStrength(newToken);
|
||||
requestBody.token_sha256 = sha256(newToken);
|
||||
@ -386,11 +411,12 @@ export const AppContextProvider = ({
|
||||
requestBody.counts = strength.counts;
|
||||
requestBody.length = newToken.length;
|
||||
requestBody.ref_code = refCode;
|
||||
requestBody.public_key = newKeys.pubKey ?? robot.pubkey;
|
||||
requestBody.encrypted_private_key = newKeys.encPrivKey ?? robot.encPrivKey;
|
||||
requestBody.public_key = newKeys.pubKey ?? oldRobot.pubkey;
|
||||
requestBody.encrypted_private_key = newKeys.encPrivKey ?? oldRobot.encPrivKey;
|
||||
}
|
||||
|
||||
apiClient.post(baseUrl, '/api/user/', requestBody).then((data: any) => {
|
||||
let newRobot = robot;
|
||||
setCurrentOrder(
|
||||
data.active_order_id
|
||||
? data.active_order_id
|
||||
@ -400,25 +426,25 @@ export const AppContextProvider = ({
|
||||
);
|
||||
if (data.bad_request) {
|
||||
setBadRequest(data.bad_request);
|
||||
setRobot({
|
||||
...robot,
|
||||
newRobot = {
|
||||
...oldRobot,
|
||||
loading: false,
|
||||
nickname: data.nickname ?? robot.nickname,
|
||||
nickname: data.nickname ?? oldRobot.nickname,
|
||||
activeOrderId: data.active_order_id ?? null,
|
||||
referralCode: data.referral_code ?? robot.referralCode,
|
||||
earnedRewards: data.earned_rewards ?? robot.earnedRewards,
|
||||
lastOrderId: data.last_order_id ?? robot.lastOrderId,
|
||||
referralCode: data.referral_code ?? oldRobot.referralCode,
|
||||
earnedRewards: data.earned_rewards ?? oldRobot.earnedRewards,
|
||||
lastOrderId: data.last_order_id ?? oldRobot.lastOrderId,
|
||||
stealthInvoices: data.wants_stealth ?? robot.stealthInvoices,
|
||||
tgEnabled: data.tg_enabled,
|
||||
tgBotName: data.tg_bot_name,
|
||||
tgToken: data.tg_token,
|
||||
found: false,
|
||||
});
|
||||
};
|
||||
} else {
|
||||
setRobot({
|
||||
...robot,
|
||||
newRobot = {
|
||||
...oldRobot,
|
||||
nickname: data.nickname,
|
||||
token: newToken ?? robot.token,
|
||||
token: newToken ?? oldRobot.token,
|
||||
loading: false,
|
||||
activeOrderId: data.active_order_id ?? null,
|
||||
lastOrderId: data.last_order_id ?? null,
|
||||
@ -433,11 +459,11 @@ export const AppContextProvider = ({
|
||||
shannonEntropy: data.token_shannon_entropy,
|
||||
pubKey: data.public_key,
|
||||
encPrivKey: data.encrypted_private_key,
|
||||
copiedToken: data.found ? true : robot.copiedToken,
|
||||
});
|
||||
systemClient.setItem('robot_token', newToken ?? robot.token);
|
||||
systemClient.setItem('pub_key', data.public_key.split('\n').join('\\'));
|
||||
systemClient.setItem('enc_priv_key', data.encrypted_private_key.split('\n').join('\\'));
|
||||
copiedToken: data.found ? true : false,
|
||||
};
|
||||
setRobot(newRobot);
|
||||
garage.updateRobot(newRobot, targetSlot);
|
||||
setCurrentSlot(targetSlot);
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -445,9 +471,9 @@ export const AppContextProvider = ({
|
||||
useEffect(() => {
|
||||
if (baseUrl != '' && page != 'robot') {
|
||||
if (open.profile || (robot.token && robot.nickname === null)) {
|
||||
fetchRobot({ action: 'login' }); // fetch existing robot
|
||||
fetchRobot({ action: 'refresh' }); // refresh/update existing robot
|
||||
} else if (robot.token && robot.encPrivKey && robot.pubKey) {
|
||||
fetchRobot({ action: 'login' }); // create new robot with existing token and keys (on network and coordinator change)
|
||||
fetchRobot({ action: 'refresh' }); // create new robot with existing token and keys (on network and coordinator change)
|
||||
}
|
||||
}
|
||||
}, [open.profile, baseUrl]);
|
||||
@ -460,8 +486,11 @@ export const AppContextProvider = ({
|
||||
setSettings,
|
||||
book,
|
||||
setBook,
|
||||
garage,
|
||||
setGarage,
|
||||
currentSlot,
|
||||
setCurrentSlot,
|
||||
fetchBook,
|
||||
fetchRobot,
|
||||
limits,
|
||||
info,
|
||||
setLimits,
|
||||
@ -471,6 +500,7 @@ export const AppContextProvider = ({
|
||||
clearOrder,
|
||||
robot,
|
||||
setRobot,
|
||||
fetchRobot,
|
||||
baseUrl,
|
||||
setBaseUrl,
|
||||
fav,
|
||||
|
51
frontend/src/models/Garage.model.ts
Normal file
51
frontend/src/models/Garage.model.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { Robot, Order } from '.';
|
||||
import { systemClient } from '../services/System';
|
||||
import { saveAsJson } from '../utils';
|
||||
export interface Slot {
|
||||
robot: Robot;
|
||||
order: Order | null;
|
||||
}
|
||||
|
||||
const emptySlot: Slot = { robot: new Robot(), order: null };
|
||||
|
||||
class Garage {
|
||||
constructor(initialState?: Garage) {
|
||||
if (initialState?.slots === undefined && systemClient.getItem('garage') != '') {
|
||||
this.slots = JSON.parse(systemClient.getItem('garage'));
|
||||
console.log('Robot Garage was loaded from local storage');
|
||||
} else {
|
||||
this.slots = [emptySlot];
|
||||
}
|
||||
this.setGarage = initialState?.setGarage || (() => {});
|
||||
}
|
||||
slots: Slot[] = [emptySlot];
|
||||
setGarage: (state: Garage) => void = () => {};
|
||||
|
||||
save = () => {
|
||||
systemClient.setItem('garage', JSON.stringify(this.slots));
|
||||
this.setGarage(new Garage(this));
|
||||
};
|
||||
|
||||
delete = () => {
|
||||
this.slots = [emptySlot];
|
||||
systemClient.deleteItem('garage');
|
||||
this.save();
|
||||
};
|
||||
|
||||
updateRobot: (robot: Robot, index: number) => void = (robot, index) => {
|
||||
this.slots[index] = { robot, order: null };
|
||||
this.save();
|
||||
};
|
||||
|
||||
download = () => {
|
||||
saveAsJson(`robotGarage_${new Date().toISOString()}.json`, this.slots);
|
||||
};
|
||||
|
||||
deleteSlot: (index?: number) => void = (index) => {
|
||||
const targetSlot = index ?? this.slots.length - 1;
|
||||
this.slots.splice(targetSlot, 1);
|
||||
this.save();
|
||||
};
|
||||
}
|
||||
|
||||
export default Garage;
|
@ -1,10 +1,10 @@
|
||||
import { systemClient } from '../services/System';
|
||||
|
||||
class Robot {
|
||||
constructor() {
|
||||
this.token = systemClient.getItem('robot_token') ?? undefined;
|
||||
this.pubKey = systemClient.getItem('pub_key') ?? undefined;
|
||||
this.encPrivKey = systemClient.getItem('enc_priv_key') ?? undefined;
|
||||
constructor(garageRobot?: Robot) {
|
||||
if (garageRobot) {
|
||||
this.token = garageRobot?.token ?? undefined;
|
||||
this.pubKey = garageRobot?.pubKey ?? undefined;
|
||||
this.encPrivKey = garageRobot?.encPrivKey ?? undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public nickname?: string;
|
||||
|
@ -39,7 +39,7 @@ class BaseSettings {
|
||||
: i18n.resolvedLanguage.substring(0, 2);
|
||||
|
||||
const networkCookie = systemClient.getItem('settings_network');
|
||||
this.network = networkCookie !== '' ? networkCookie : undefined;
|
||||
this.network = networkCookie !== '' ? networkCookie : 'mainnet';
|
||||
}
|
||||
|
||||
public frontend: 'basic' | 'pro' = 'basic';
|
||||
@ -47,7 +47,7 @@ class BaseSettings {
|
||||
public fontSize: number = 14;
|
||||
public language?: Language;
|
||||
public freezeViewports: boolean = false;
|
||||
public network: 'mainnet' | 'testnet' | undefined = undefined;
|
||||
public network: 'mainnet' | 'testnet' = 'mainnet';
|
||||
public coordinator: Coordinator | undefined = undefined;
|
||||
public host?: string;
|
||||
public unsafeClient: boolean = false;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Robot from './Robot.model';
|
||||
import Garage from './Garage.model';
|
||||
import Settings from './Settings.default.basic';
|
||||
export { Robot, Settings };
|
||||
export { Robot, Garage, Settings };
|
||||
|
||||
export type { LimitList } from './Limit.model';
|
||||
export type { Limit } from './Limit.model';
|
||||
@ -9,6 +10,7 @@ export type { Order } from './Order.model';
|
||||
export type { PublicOrder } from './Book.model';
|
||||
export type { Book } from './Book.model';
|
||||
export type { Info } from './Info.model';
|
||||
export type { Slot } from './Garage.model';
|
||||
export type { Language } from './Settings.model';
|
||||
export type { Favorites } from './Favorites.model';
|
||||
export type { Coordinator } from './Coordinator.model';
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Ordre activa #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Última ordre #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "La reutilització de la identitat de trading degrada la teva privadesa davant d'altres usuaris, coordinadors i observadors.",
|
||||
"Generate a new Robot": "Generar un nou Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Guarda el teu token de manera segura",
|
||||
"Logout Robot": "Tanca sessió Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Descarrega el token i les credencials PGP",
|
||||
"Copied!": "Copiat!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Genera un token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Ordres de venta públiques",
|
||||
"Book liquidity": "Liquiditat en el llibre",
|
||||
"Today active robots": "Robots actius avui",
|
||||
"24h non-KYC bitcoin premium": "Prima de bitcoin sense KYC en 24h",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Comissió del creador",
|
||||
"Taker fee": "Comissió del prenedor",
|
||||
"Current onchain payout fee": "Cost actual de rebre onchain",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Ulož si svůj token bezpečně",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Zkopirováno!!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Veřejné prodejní nabídky",
|
||||
"Book liquidity": "Dostupná likvidita",
|
||||
"Today active robots": "Dnešní aktivní roboti",
|
||||
"24h non-KYC bitcoin premium": "24h no-KYC bitcoin přirážka",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Poplatek tvůrce",
|
||||
"Taker fee": "Poplatek příjemce",
|
||||
"Current onchain payout fee": "Současný poplatek za vyplacení na onchain ",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Verwahre deinen Token sicher",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Kopiert!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Öffentliche Verkaufsangebote",
|
||||
"Book liquidity": "Marktplatz-Liquidität",
|
||||
"Today active robots": "Heute aktive Roboter",
|
||||
"24h non-KYC bitcoin premium": "24h non-KYC Bitcoin-Aufschlag",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Makergebühr",
|
||||
"Taker fee": "Takergebühr",
|
||||
"Current onchain payout fee": "Current onchain payout fee",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Store your token safely",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Copied!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Public sell orders",
|
||||
"Book liquidity": "Book liquidity",
|
||||
"Today active robots": "Today active robots",
|
||||
"24h non-KYC bitcoin premium": "24h non-KYC bitcoin premium",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Maker fee",
|
||||
"Taker fee": "Taker fee",
|
||||
"Current onchain payout fee": "Current onchain payout fee",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Guarda tu token de forma segura",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "¡Copiado!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Órdenes de venta públicas",
|
||||
"Book liquidity": "Liquidez en el libro",
|
||||
"Today active robots": "Robots activos hoy",
|
||||
"24h non-KYC bitcoin premium": "Prima de bitcoin sin KYC en 24h",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Comisión del creador",
|
||||
"Taker fee": "Comisión del tomador",
|
||||
"Current onchain payout fee": "Coste actual de recibir onchain",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Gorde zure tokena era seguru batean",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Kopiatuta!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Salmenta eskaera publikoak",
|
||||
"Book liquidity": "Liburuaren likidezia",
|
||||
"Today active robots": "Robot aktiboak gaur",
|
||||
"24h non-KYC bitcoin premium": "24 orduko ez-KYC prima",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Egile kuota",
|
||||
"Taker fee": "Hartzaile kuota",
|
||||
"Current onchain payout fee": "Oraingo onchain jasotze-kuota",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Stockez votre jeton en sécurité",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Copié!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Ordres de vente publics",
|
||||
"Book liquidity": "Liquidité du livre",
|
||||
"Today active robots": "Robots actifs aujourd'hui",
|
||||
"24h non-KYC bitcoin premium": "Prime bitcoin non-KYC 24h",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Frais du createur",
|
||||
"Taker fee": "Frais du preneur",
|
||||
"Current onchain payout fee": "Current onchain payout fee",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Custodisci il tuo gettone in modo sicuro",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Copiato!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Ordini di vendita pubblici",
|
||||
"Book liquidity": "Registro della liquidità",
|
||||
"Today active robots": "I Robottini attivi oggi",
|
||||
"24h non-KYC bitcoin premium": "Premio bitcoin non-KYC 24h",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Commissione dell'offerente",
|
||||
"Taker fee": "Commissione dell'acquirente",
|
||||
"Current onchain payout fee": "Current onchain payout fee",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Przechowuj swój token bezpiecznie",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Skopiowane!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Zlecenia sprzedaży publicznej",
|
||||
"Book liquidity": "Płynność księgowa",
|
||||
"Today active robots": "Dziś aktywne roboty",
|
||||
"24h non-KYC bitcoin premium": "24h premia bitcoin non-KYC",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Opłata producenta",
|
||||
"Taker fee": "Opłata takera",
|
||||
"Current onchain payout fee": "Current onchain payout fee",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Guarde seu token de forma segura",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Copiado!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Ordens de venda públicss",
|
||||
"Book liquidity": "Liquidez do livro",
|
||||
"Today active robots": "Robôs ativos hoje",
|
||||
"24h non-KYC bitcoin premium": "Prêmio de bitcoin não-KYC nas últimas 24 horas",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Taxa do criador",
|
||||
"Taker fee": "Taxa do tomador",
|
||||
"Current onchain payout fee": "Taxa de pagamento onchain atual",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Храните Ваш токен в безопасности",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Скопировано!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Ордера на продажу",
|
||||
"Book liquidity": "Ликвидность книги ордеров",
|
||||
"Today active robots": "Сегодня активных роботов",
|
||||
"24h non-KYC bitcoin premium": "Наценка на Биткойн без ЗСК за 24 часа",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Комиссия мейкера",
|
||||
"Taker fee": "Комиссия тейкера",
|
||||
"Current onchain payout fee": "Текущая комиссия за выплату ончейн",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "Spara din token säkert",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "Kopierat!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "Publika säljordrar",
|
||||
"Book liquidity": "Orderbokslikviditet",
|
||||
"Today active robots": "Aktiva robotar idag",
|
||||
"24h non-KYC bitcoin premium": "24h non-KYC bitcoin premium",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "Makeravgift",
|
||||
"Taker fee": "Takeravgift",
|
||||
"Current onchain payout fee": "Aktuell utbetalningsavgift (on-chain)",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "รักษา token ของคุณไว้ให้ดี",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "คัดลอกแล้ว!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "จำนวนรายการขาย",
|
||||
"Book liquidity": "สภาพคล่องทางบ้ญชี",
|
||||
"Today active robots": "จำนวนโรบอทที่ใช้งานในวันนี้",
|
||||
"24h non-KYC bitcoin premium": "ค่าพรีเมี่ยม 24 ชม.ที่แล้วสำหรับ bitcoin non-KYC",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "ค่าธรรมเนียม Maker",
|
||||
"Taker fee": "ค่าธรรมเนียม Taker",
|
||||
"Current onchain payout fee": "ค่าธรรมเนียมการจ่าย On-chain ตอนนี้",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "请安全地存储你的令牌",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "已复制!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "公开出售订单",
|
||||
"Book liquidity": "账面流动性",
|
||||
"Today active robots": "今天活跃的机器人",
|
||||
"24h non-KYC bitcoin premium": "24小时 non-KYC 比特币溢价",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "挂单方费用",
|
||||
"Taker fee": "吃单方费用",
|
||||
"Current onchain payout fee": "当前链上支付费用",
|
||||
|
@ -12,11 +12,14 @@
|
||||
"Active order #{{orderID}}": "Active order #{{orderID}}",
|
||||
"Last order #{{orderID}}": "Last order #{{orderID}}",
|
||||
"Reusing trading identity degrades your privacy against other users, coordinators and observers.": "Reusing trading identity degrades your privacy against other users, coordinators and observers.",
|
||||
"Generate a new Robot": "Generate a new Robot",
|
||||
"Add a new Robot": "Add a new Robot",
|
||||
"Logout": "Logout",
|
||||
"Store your token safely": "請安全地存儲你的令牌",
|
||||
"Logout Robot": "Logout Robot",
|
||||
"Robot Garage": "Robot Garage",
|
||||
"Building...": "Building...",
|
||||
"Add Robot": "Add Robot",
|
||||
"Delete Garage": "Delete Garage",
|
||||
"#4": "Phrases in basic/RobotPage/TokenInput.tsx",
|
||||
"Download token and PGP credentials": "Download token and PGP credentials",
|
||||
"Copied!": "已複製!",
|
||||
"#5": "Phrases in basic/RobotPage/Onboarding.tsx",
|
||||
"1. Generate a token": "1. Generate a token",
|
||||
@ -144,7 +147,7 @@
|
||||
"Public sell orders": "公開出售訂單",
|
||||
"Book liquidity": "賬面流動性",
|
||||
"Today active robots": "今天活躍的機器人",
|
||||
"24h non-KYC bitcoin premium": "24小時 non-KYC 比特幣溢價",
|
||||
"Last 24h mean premium": "Last 24h mean premium",
|
||||
"Maker fee": "掛單方費用",
|
||||
"Taker fee": "吃單方費用",
|
||||
"Current onchain payout fee": "當前鏈上支付費用",
|
||||
|
Loading…
Reference in New Issue
Block a user