Run linter and add linter GH action

This commit is contained in:
Reckless_Satoshi 2022-09-09 10:18:04 -07:00
parent 9d73f1ec34
commit 14487a9c2d
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
67 changed files with 8457 additions and 5810 deletions

View File

@ -16,7 +16,7 @@ on:
branches: [ "main" ] branches: [ "main" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main" ] # branches: [ "main" ]
schedule: schedule:
- cron: '39 10 * * 2' - cron: '39 10 * * 2'

39
.github/workflows/linter.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Lint
on:
# Trigger the workflow on push or pull request,
# but only for the main branch
push:
branches:
- main
pull_request:
branches:
- main
jobs:
run-linters:
name: Run linters
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v2
- name: 'Setup node'
uses: actions/setup-node@v3
with:
node-version: 16.17.0
cache: npm
cache-dependency-path: frontend/package-lock.json
# ESLint and Prettier must be in `package.json`
- name: 'Install NPM Dependencies'
run: |
cd frontend
npm install -f
- name: Run linters
uses: wearerequired/lint-action@v2
with:
prettier: true
prettier_dir: frontend

View File

@ -1,13 +1,13 @@
import React, { Component , Suspense } from "react"; import React, { Component, Suspense } from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import HomePage from "./HomePage"; import HomePage from './HomePage';
import { CssBaseline, IconButton , Link} from "@mui/material"; import { CssBaseline, IconButton, Link } from '@mui/material';
import { ThemeProvider, createTheme } from '@mui/material/styles'; import { ThemeProvider, createTheme } from '@mui/material/styles';
import UnsafeAlert from "./UnsafeAlert"; import UnsafeAlert from './UnsafeAlert';
import { LearnDialog } from "./Dialogs"; import { LearnDialog } from './Dialogs';
import { I18nextProvider } from "react-i18next"; import { I18nextProvider } from 'react-i18next';
import i18n from "./i18n"; import i18n from './i18n';
//Icons //Icons
import DarkModeIcon from '@mui/icons-material/DarkMode'; import DarkModeIcon from '@mui/icons-material/DarkMode';
@ -24,63 +24,77 @@ export default class App extends Component {
dark: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches, dark: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches,
expandedSettings: false, expandedSettings: false,
openLearn: false, openLearn: false,
theme: {typography: { fontSize: 14 }}, theme: { typography: { fontSize: 14 } },
} };
} }
lightTheme = createTheme ({}); lightTheme = createTheme({});
darkTheme = createTheme({ darkTheme = createTheme({
palette: { palette: {
mode: 'dark', mode: 'dark',
background: { background: {
default: "#070707" default: '#070707',
}, },
}, },
}); });
onSettingsClick = () => { onSettingsClick = () => {
this.setState({ this.setState({
expandedSettings: ! this.state.expandedSettings expandedSettings: !this.state.expandedSettings,
}) });
} };
onZoomClick = (direction) => { onZoomClick = (direction) => {
let zoomChange; let zoomChange;
direction === "out" ? zoomChange = -1 : zoomChange = 1; direction === 'out' ? (zoomChange = -1) : (zoomChange = 1);
this.setState(({theme}) => ({ this.setState(({ theme }) => ({
theme: { theme: {
...theme, ...theme,
typography: { typography: {
fontSize: this.state.theme.typography.fontSize + zoomChange, fontSize: this.state.theme.typography.fontSize + zoomChange,
}, },
} },
})); }));
} };
render() { render() {
return ( return (
<Suspense fallback="loading language"> <Suspense fallback='loading language'>
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
<ThemeProvider theme={this.state.dark ? this.darkTheme : createTheme(this.state.theme)}> <ThemeProvider theme={this.state.dark ? this.darkTheme : createTheme(this.state.theme)}>
<CssBaseline/> <CssBaseline />
<LearnDialog open={this.state.openLearn} onClose={()=> this.setState({openLearn:false})}/> <LearnDialog
<IconButton sx={{position:'fixed',right:'34px'}} onClick={()=> this.setState({openLearn:true})}><SchoolIcon/></IconButton> open={this.state.openLearn}
<IconButton sx={{position:'fixed',right:'0px'}} onClick={()=>this.setState({dark:!this.state.dark})}> onClose={() => this.setState({ openLearn: false })}
{this.state.dark ? <LightModeIcon/>:<DarkModeIcon/>} />
</IconButton> <IconButton
<IconButton sx={{position:'fixed',right:'34px'}} onClick={()=> this.setState({openLearn:true})}><SchoolIcon/></IconButton> sx={{ position: 'fixed', right: '34px' }}
<UnsafeAlert className="unsafeAlert"/> onClick={() => this.setState({ openLearn: true })}
<HomePage {...this.state}/> >
</ThemeProvider> <SchoolIcon />
</I18nextProvider> </IconButton>
<IconButton
sx={{ position: 'fixed', right: '0px' }}
onClick={() => this.setState({ dark: !this.state.dark })}
>
{this.state.dark ? <LightModeIcon /> : <DarkModeIcon />}
</IconButton>
<IconButton
sx={{ position: 'fixed', right: '34px' }}
onClick={() => this.setState({ openLearn: true })}
>
<SchoolIcon />
</IconButton>
<UnsafeAlert className='unsafeAlert' />
<HomePage {...this.state} />
</ThemeProvider>
</I18nextProvider>
</Suspense> </Suspense>
); );
} }
} }
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(document.getElementById('app'));
document.getElementById("app")
);
root.render(<App />); root.render(<App />);

View File

@ -1,30 +1,30 @@
import React, { useState } from "react"; import React, { useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useAutocomplete } from '@mui/base/AutocompleteUnstyled'; import { useAutocomplete } from '@mui/base/AutocompleteUnstyled';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import { Button, Tooltip } from "@mui/material"; import { Button, Tooltip } from '@mui/material';
import { paymentMethods, swapDestinations } from "./payment-methods/Methods"; import { paymentMethods, swapDestinations } from './payment-methods/Methods';
// Icons // Icons
import DashboardCustomizeIcon from '@mui/icons-material/DashboardCustomize'; import DashboardCustomizeIcon from '@mui/icons-material/DashboardCustomize';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import PaymentIcon from './payment-methods/Icons' import PaymentIcon from './payment-methods/Icons';
import CheckIcon from '@mui/icons-material/Check'; import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
const Root = styled('div')( const Root = styled('div')(
({ theme }) => ` ({ theme }) => `
color: ${ color: ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.65)' : 'rgba(0,0,0,.85)'};
theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.65)' : 'rgba(0,0,0,.85)'
};
font-size: 14px; font-size: 14px;
`, `,
); );
const Label = styled('label')( const Label = styled('label')(
({ theme , error}) => ` ({ theme, error }) => `
color: ${theme.palette.mode === 'dark' ? (error? '#f44336': '#cfcfcf') : (error? '#dd0000':'#717171')}; color: ${
theme.palette.mode === 'dark' ? (error ? '#f44336' : '#cfcfcf') : error ? '#dd0000' : '#717171'
};
align: center; align: center;
padding: 0 0 4px; padding: 0 0 4px;
line-height: 1.5; f44336 line-height: 1.5; f44336
@ -34,11 +34,13 @@ const Label = styled('label')(
); );
const InputWrapper = styled('div')( const InputWrapper = styled('div')(
({ theme , error}) => ` ({ theme, error }) => `
width: 244px; width: 244px;
min-height: 44px; min-height: 44px;
max-height: 124px; max-height: 124px;
border: 1px solid ${theme.palette.mode === 'dark' ? (error? '#f44336': '#434343') : (error? '#dd0000':'#c4c4c4')}; border: 1px solid ${
theme.palette.mode === 'dark' ? (error ? '#f44336' : '#434343') : error ? '#dd0000' : '#c4c4c4'
};
background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#fff'}; background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#fff'};
border-radius: 4px; border-radius: 4px;
padding: 1px; padding: 1px;
@ -47,18 +49,32 @@ const InputWrapper = styled('div')(
overflow-y:auto; overflow-y:auto;
&:hover { &:hover {
border-color: ${theme.palette.mode === 'dark' ? (error? '#f44336':'#ffffff') : (error? '#dd0000' :'#2f2f2f')}; border-color: ${
theme.palette.mode === 'dark'
? error
? '#f44336'
: '#ffffff'
: error
? '#dd0000'
: '#2f2f2f'
};
} }
&.focused { &.focused {
border: 2px solid ${theme.palette.mode === 'dark' ? (error? '#f44336':'#90caf9') : (error? '#dd0000' :'#1976d2')}; border: 2px solid ${
theme.palette.mode === 'dark'
? error
? '#f44336'
: '#90caf9'
: error
? '#dd0000'
: '#1976d2'
};
} }
& input { & input {
background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#fff'}; background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#fff'};
color: ${ color: ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.65)' : 'rgba(0,0,0,.85)'};
theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.65)' : 'rgba(0,0,0,.85)'
};
height: 30px; height: 30px;
box-sizing: border-box; box-sizing: border-box;
padding: 4px 6px; padding: 4px 6px;
@ -78,10 +94,10 @@ function Tag(props) {
const { label, icon, onDelete, ...other } = props; const { label, icon, onDelete, ...other } = props;
return ( return (
<div {...other}> <div {...other}>
<div style={{position:'relative',left:'-5px',top:'4px'}}> <div style={{ position: 'relative', left: '-5px', top: '4px' }}>
<PaymentIcon width={22} height={22} icon={icon}/> <PaymentIcon width={22} height={22} icon={icon} />
</div> </div>
<span style={{position:'relative',left:'2px'}}>{label}</span> <span style={{ position: 'relative', left: '2px' }}>{label}</span>
<CloseIcon onClick={onDelete} /> <CloseIcon onClick={onDelete} />
</div> </div>
); );
@ -100,9 +116,7 @@ const StyledTag = styled(Tag)(
height: 34px; height: 34px;
margin: 2px; margin: 2px;
line-height: 22px; line-height: 22px;
background-color: ${ background-color: ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.08)' : '#fafafa'};
theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.08)' : '#fafafa'
};
border: 1px solid ${theme.palette.mode === 'dark' ? '#303030' : '#e8e8e8'}; border: 1px solid ${theme.palette.mode === 'dark' ? '#303030' : '#e8e8e8'};
border-radius: 2px; border-radius: 2px;
box-sizing: content-box; box-sizing: content-box;
@ -131,7 +145,7 @@ const StyledTag = styled(Tag)(
); );
const ListHeader = styled('span')( const ListHeader = styled('span')(
({ theme }) => ` ({ theme }) => `
color: ${theme.palette.mode === 'dark' ? '#90caf9' : '#1976d2'}; color: ${theme.palette.mode === 'dark' ? '#90caf9' : '#1976d2'};
align: left; align: left;
line-height:10px; line-height:10px;
@ -202,83 +216,119 @@ export default function AutocompletePayments(props) {
getOptionProps, getOptionProps,
groupedOptions, groupedOptions,
value, value,
focused="true", focused = 'true',
setAnchorEl, setAnchorEl,
} = useAutocomplete({ } = useAutocomplete({
sx: {width:'200px', align:'left'}, sx: { width: '200px', align: 'left' },
id: 'payment-methods', id: 'payment-methods',
multiple: true, multiple: true,
options: props.optionsType=="fiat" ? paymentMethods : swapDestinations, options: props.optionsType == 'fiat' ? paymentMethods : swapDestinations,
getOptionLabel: (option) => option.name, getOptionLabel: (option) => option.name,
onInputChange: (e) => setVal(e ? (e.target.value ? e.target.value : "") : ""), onInputChange: (e) => setVal(e ? (e.target.value ? e.target.value : '') : ''),
onChange: (event, value) => props.onAutocompleteChange(optionsToString(value)), onChange: (event, value) => props.onAutocompleteChange(optionsToString(value)),
onClose: () => (setVal(() => "")), onClose: () => setVal(() => ''),
}); });
const [val, setVal] = useState(); const [val, setVal] = useState();
function optionsToString(newValue){ function optionsToString(newValue) {
var str = ''; var str = '';
var arrayLength = newValue.length; var arrayLength = newValue.length;
for (var i = 0; i < arrayLength; i++) { for (var i = 0; i < arrayLength; i++) {
str += newValue[i].name + ' '; str += newValue[i].name + ' ';
} }
return str.slice(0, -1); return str.slice(0, -1);
} }
function handleAddNew(inputProps){ function handleAddNew(inputProps) {
paymentMethods.push({name: inputProps.value, icon:'custom'}) paymentMethods.push({ name: inputProps.value, icon: 'custom' });
var a = value.push({name: inputProps.value, icon:'custom'}); var a = value.push({ name: inputProps.value, icon: 'custom' });
setVal(() => ""); setVal(() => '');
if(a || a == null){props.onAutocompleteChange(optionsToString(value))} if (a || a == null) {
return false props.onAutocompleteChange(optionsToString(value));
}; }
return false;
}
return ( return (
<Root> <Root>
<div style={{height:'5px'}}></div> <div style={{ height: '5px' }}></div>
<Tooltip placement="top" enterTouchDelay={300} enterDelay={700} enterNextDelay={2000} title={props.tooltipTitle}> <Tooltip
<div {...getRootProps()} > placement='top'
<Label {...getInputLabelProps()} error={props.error ? "error" : null}> {props.label}</Label> enterTouchDelay={300}
<InputWrapper ref={setAnchorEl} error={props.error ? "error" : null} className={focused ? 'focused' : ''}> enterDelay={700}
enterNextDelay={2000}
title={props.tooltipTitle}
>
<div {...getRootProps()}>
<Label {...getInputLabelProps()} error={props.error ? 'error' : null}>
{' '}
{props.label}
</Label>
<InputWrapper
ref={setAnchorEl}
error={props.error ? 'error' : null}
className={focused ? 'focused' : ''}
>
{value.map((option, index) => ( {value.map((option, index) => (
<StyledTag label={t(option.name)} icon={option.icon} {...getTagProps({ index })} /> <StyledTag label={t(option.name)} icon={option.icon} {...getTagProps({ index })} />
))} ))}
<input {...getInputProps()} value={val ? val :""}/> <input {...getInputProps()} value={val ? val : ''} />
</InputWrapper> </InputWrapper>
</div> </div>
</Tooltip> </Tooltip>
{groupedOptions.length > 0 ? ( {groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}> <Listbox {...getListboxProps()}>
<div style={{position:'fixed', minHeight:'20px', marginLeft: 120-props.listHeaderText.length*3, marginTop: '-13px'}}> <div
<ListHeader ><i>{props.listHeaderText+""} </i> </ListHeader> style={{
</div> position: 'fixed',
minHeight: '20px',
marginLeft: 120 - props.listHeaderText.length * 3,
marginTop: '-13px',
}}
>
<ListHeader>
<i>{props.listHeaderText + ''} </i>{' '}
</ListHeader>
</div>
{groupedOptions.map((option, index) => ( {groupedOptions.map((option, index) => (
<li key={option.name} {...getOptionProps({ option, index })}> <li key={option.name} {...getOptionProps({ option, index })}>
<Button fullWidth={true} color='inherit' size="small" sx={{textTransform: "none"}} style={{justifyContent: "flex-start"}}> <Button
<div style={{position:'relative', right: '4px', top:'4px'}}> fullWidth={true}
<AddIcon style={{color : '#1976d2'}} sx={{width:18,height:18}} /> color='inherit'
</div> size='small'
{t(option.name)} sx={{ textTransform: 'none' }}
style={{ justifyContent: 'flex-start' }}
>
<div style={{ position: 'relative', right: '4px', top: '4px' }}>
<AddIcon style={{ color: '#1976d2' }} sx={{ width: 18, height: 18 }} />
</div>
{t(option.name)}
</Button> </Button>
<div style={{position:'relative', top: '5px'}}><CheckIcon/></div> <div style={{ position: 'relative', top: '5px' }}>
<CheckIcon />
</div>
</li> </li>
))} ))}
{val != null? {val != null ? (
(val.length > 2 ? val.length > 2 ? (
<Button size="small" fullWidth={true} onClick={() => handleAddNew(getInputProps())}><DashboardCustomizeIcon sx={{width:18,height:18}}/>{props.addNewButtonText}</Button> <Button size='small' fullWidth={true} onClick={() => handleAddNew(getInputProps())}>
:null) <DashboardCustomizeIcon sx={{ width: 18, height: 18 }} />
:null} {props.addNewButtonText}
</Button>
) : null
) : null}
</Listbox> </Listbox>
) : ) : //Here goes what happens if there is no groupedOptions
//Here goes what happens if there is no groupedOptions getInputProps().value.length > 0 ? (
(getInputProps().value.length > 0 ?
<Listbox {...getListboxProps()}> <Listbox {...getListboxProps()}>
<Button fullWidth={true} onClick={() => handleAddNew(getInputProps())}><DashboardCustomizeIcon sx={{width:20,height:20}}/>{props.addNewButtonText}</Button> <Button fullWidth={true} onClick={() => handleAddNew(getInputProps())}>
<DashboardCustomizeIcon sx={{ width: 20, height: 20 }} />
{props.addNewButtonText}
</Button>
</Listbox> </Listbox>
:null) ) : null}
}
</Root> </Root>
); );
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +1,77 @@
import React, { useEffect, useState } from "react" import React, { useEffect, useState } from 'react';
import { ResponsiveLine, Serie, Datum, PointTooltipProps, PointMouseHandler, Point, CustomLayer } from '@nivo/line' import {
import { Box, CircularProgress, Grid, IconButton, MenuItem, Paper, Select, useTheme } from "@mui/material" ResponsiveLine,
Serie,
Datum,
PointTooltipProps,
PointMouseHandler,
Point,
CustomLayer,
} from '@nivo/line';
import {
Box,
CircularProgress,
Grid,
IconButton,
MenuItem,
Paper,
Select,
useTheme,
} from '@mui/material';
import { AddCircleOutline, RemoveCircleOutline } from '@mui/icons-material'; import { AddCircleOutline, RemoveCircleOutline } from '@mui/icons-material';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { useHistory } from "react-router-dom" import { useHistory } from 'react-router-dom';
import { Order } from "../../../models/Order.model"; import { Order } from '../../../models/Order.model';
import { LimitList } from "../../../models/Limit.model"; import { LimitList } from '../../../models/Limit.model';
import RobotAvatar from '../../Robots/RobotAvatar' import RobotAvatar from '../../Robots/RobotAvatar';
import { amountToString } from "../../../utils/prettyNumbers"; import { amountToString } from '../../../utils/prettyNumbers';
import currencyDict from '../../../../static/assets/currencies.json'; import currencyDict from '../../../../static/assets/currencies.json';
import PaymentText from "../../PaymentText"; import PaymentText from '../../PaymentText';
import getNivoScheme from "../NivoScheme" import getNivoScheme from '../NivoScheme';
import median from "../../../utils/match"; import median from '../../../utils/match';
interface DepthChartProps { interface DepthChartProps {
bookLoading: boolean bookLoading: boolean;
orders: Order[] orders: Order[];
lastDayPremium: number | undefined lastDayPremium: number | undefined;
currency: number currency: number;
setAppState: (state: object) => void setAppState: (state: object) => void;
limits: LimitList limits: LimitList;
compact?: boolean compact?: boolean;
} }
const DepthChart: React.FC<DepthChartProps> = ({ const DepthChart: React.FC<DepthChartProps> = ({
bookLoading, orders, lastDayPremium, currency, setAppState, limits, compact bookLoading,
orders,
lastDayPremium,
currency,
setAppState,
limits,
compact,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation();
const history = useHistory() const history = useHistory();
const theme = useTheme() const theme = useTheme();
const [enrichedOrders, setEnrichedOrders] = useState<Order[]>([]) const [enrichedOrders, setEnrichedOrders] = useState<Order[]>([]);
const [series, setSeries] = useState<Serie[]>([]) const [series, setSeries] = useState<Serie[]>([]);
const [xRange, setXRange] = useState<number>(8) const [xRange, setXRange] = useState<number>(8);
const [xType, setXType] = useState<string>("premium") const [xType, setXType] = useState<string>('premium');
const [currencyCode, setCurrencyCode] = useState<number>(1) const [currencyCode, setCurrencyCode] = useState<number>(1);
const [center, setCenter] = useState<number>(0) const [center, setCenter] = useState<number>(0);
useEffect(() => { useEffect(() => {
if (Object.keys(limits).length === 0) { if (Object.keys(limits).length === 0) {
fetch('/api/limits/') fetch('/api/limits/')
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
setAppState({ limits: data }) setAppState({ limits: data });
}) });
} }
}, []) }, []);
useEffect(() => { useEffect(() => {
setCurrencyCode(currency === 0 ? 1 : currency) setCurrencyCode(currency === 0 ? 1 : currency);
}, [currency]) }, [currency]);
useEffect(() => { useEffect(() => {
if (Object.keys(limits).length > 0) { if (Object.keys(limits).length > 0) {
@ -57,172 +79,176 @@ const DepthChart: React.FC<DepthChartProps> = ({
// We need to transform all currencies to the same base (ex. USD), we don't have the exchange rate // We need to transform all currencies to the same base (ex. USD), we don't have the exchange rate
// for EUR -> USD, but we know the rate of both to BTC, so we get advantage of it and apply a // for EUR -> USD, but we know the rate of both to BTC, so we get advantage of it and apply a
// simple rule of three // simple rule of three
order.base_amount = (order.price * limits[currencyCode].price) / limits[order.currency].price order.base_amount =
return order (order.price * limits[currencyCode].price) / limits[order.currency].price;
}) return order;
setEnrichedOrders(enriched) });
setEnrichedOrders(enriched);
} }
}, [limits, orders, currencyCode]) }, [limits, orders, currencyCode]);
useEffect(() => { useEffect(() => {
if (enrichedOrders.length > 0) { if (enrichedOrders.length > 0) {
generateSeries() generateSeries();
} }
}, [enrichedOrders, xRange]) }, [enrichedOrders, xRange]);
useEffect(() => { useEffect(() => {
if (xType === 'base_amount') { if (xType === 'base_amount') {
const prices: number[] = enrichedOrders.map((order) => order?.base_amount || 0) const prices: number[] = enrichedOrders.map((order) => order?.base_amount || 0);
setCenter(~~median(prices)) setCenter(~~median(prices));
setXRange(1500) setXRange(1500);
} else if (lastDayPremium) { } else if (lastDayPremium) {
setCenter(lastDayPremium) setCenter(lastDayPremium);
setXRange(8) setXRange(8);
} }
}, [enrichedOrders, xType, lastDayPremium, currencyCode]) }, [enrichedOrders, xType, lastDayPremium, currencyCode]);
const calculateBtc = (order: Order): number => { const calculateBtc = (order: Order): number => {
const amount = parseInt(order.amount) || order.max_amount const amount = parseInt(order.amount) || order.max_amount;
return amount / order.price return amount / order.price;
} };
const generateSeries:() => void = () => { const generateSeries: () => void = () => {
let sortedOrders: Order[] = xType === 'base_amount' ? let sortedOrders: Order[] =
enrichedOrders.sort((order1, order2) => (order1?.base_amount || 0) - (order2?.base_amount || 0) ) xType === 'base_amount'
: enrichedOrders.sort((order1, order2) => order1.premium - order2.premium ) ? enrichedOrders.sort(
(order1, order2) => (order1?.base_amount || 0) - (order2?.base_amount || 0),
)
: enrichedOrders.sort((order1, order2) => order1.premium - order2.premium);
const sortedBuyOrders: Order[] = sortedOrders.filter((order) => order.type == 0).reverse() const sortedBuyOrders: Order[] = sortedOrders.filter((order) => order.type == 0).reverse();
const sortedSellOrders: Order[] = sortedOrders.filter((order) => order.type == 1) const sortedSellOrders: Order[] = sortedOrders.filter((order) => order.type == 1);
const buySerie: Datum[] = generateSerie(sortedBuyOrders) const buySerie: Datum[] = generateSerie(sortedBuyOrders);
const sellSerie: Datum[] = generateSerie(sortedSellOrders) const sellSerie: Datum[] = generateSerie(sortedSellOrders);
const maxX: number = center + xRange const maxX: number = center + xRange;
const minX: number = center - xRange const minX: number = center - xRange;
setSeries([ setSeries([
{ {
id: "buy", id: 'buy',
data: closeSerie(buySerie, maxX, minX) data: closeSerie(buySerie, maxX, minX),
}, },
{ {
id: "sell", id: 'sell',
data: closeSerie(sellSerie, minX, maxX) data: closeSerie(sellSerie, minX, maxX),
} },
]) ]);
} };
const generateSerie = (orders: Order[]): Datum[] => { const generateSerie = (orders: Order[]): Datum[] => {
if (!center) { return [] } if (!center) {
return [];
}
let sumOrders: number = 0 let sumOrders: number = 0;
let serie: Datum[] = [] let serie: Datum[] = [];
orders.forEach((order) => { orders.forEach((order) => {
const lastSumOrders = sumOrders const lastSumOrders = sumOrders;
sumOrders += calculateBtc(order) sumOrders += calculateBtc(order);
const datum: Datum[] = [ const datum: Datum[] = [
{ // Vertical Line {
x: xType === 'base_amount' ? order.base_amount : order.premium, // Vertical Line
y: lastSumOrders x: xType === 'base_amount' ? order.base_amount : order.premium,
y: lastSumOrders,
}, },
{ // Order Point {
x: xType === 'base_amount' ? order.base_amount : order.premium, // Order Point
x: xType === 'base_amount' ? order.base_amount : order.premium,
y: sumOrders, y: sumOrders,
order: order order: order,
} },
] ];
serie = [...serie, ...datum] serie = [...serie, ...datum];
}) });
const inlineSerie = serie.filter((datum: Datum) => { const inlineSerie = serie.filter((datum: Datum) => {
return (Number(datum.x) > center - xRange) && return Number(datum.x) > center - xRange && Number(datum.x) < center + xRange;
(Number(datum.x) < center + xRange) });
})
return inlineSerie return inlineSerie;
} };
const closeSerie = (serie: Datum[], limitBottom: number, limitTop: number): Datum[] =>{ const closeSerie = (serie: Datum[], limitBottom: number, limitTop: number): Datum[] => {
if (serie.length == 0) { return [] } if (serie.length == 0) {
return [];
}
// If the bottom is not 0, exdens the horizontal bottom line // If the bottom is not 0, exdens the horizontal bottom line
if (serie[0].y !== 0) { if (serie[0].y !== 0) {
const startingPoint: Datum = { const startingPoint: Datum = {
x: limitBottom, x: limitBottom,
y: serie[0].y y: serie[0].y,
} };
serie.unshift(startingPoint) serie.unshift(startingPoint);
} }
// exdens the horizontal top line // exdens the horizontal top line
const endingPoint: Datum = { const endingPoint: Datum = {
x: limitTop, x: limitTop,
y: serie[serie.length - 1].y y: serie[serie.length - 1].y,
} };
return [...serie, endingPoint] return [...serie, endingPoint];
} };
const centerLine: CustomLayer = (props) => ( const centerLine: CustomLayer = (props) => (
<path <path
key="center-line" key='center-line'
d={props.lineGenerator([ d={props.lineGenerator([
{ {
y: 0, y: 0,
x: props.xScale(center) x: props.xScale(center),
}, },
{ {
y: props.innerHeight, y: props.innerHeight,
x: props.xScale(center) x: props.xScale(center),
}, },
])} ])}
fill="none" fill='none'
stroke={getNivoScheme(theme).markers?.lineColor} stroke={getNivoScheme(theme).markers?.lineColor}
strokeWidth={getNivoScheme(theme).markers?.lineStrokeWidth} strokeWidth={getNivoScheme(theme).markers?.lineStrokeWidth}
/> />
) );
const generateTooltip: React.FunctionComponent<PointTooltipProps> = (pointTooltip: PointTooltipProps) => { const generateTooltip: React.FunctionComponent<PointTooltipProps> = (
const order: Order = pointTooltip.point.data.order pointTooltip: PointTooltipProps,
) => {
const order: Order = pointTooltip.point.data.order;
return order ? ( return order ? (
<Paper elevation={12} style={{ padding: 10, width: 250 }}> <Paper elevation={12} style={{ padding: 10, width: 250 }}>
<Grid container justifyContent="space-between"> <Grid container justifyContent='space-between'>
<Grid item xs={3}> <Grid item xs={3}>
<Grid <Grid container justifyContent='center' alignItems='center'>
container
justifyContent="center"
alignItems="center"
>
<RobotAvatar order={order} /> <RobotAvatar order={order} />
</Grid> </Grid>
</Grid> </Grid>
<Grid item xs={8}> <Grid item xs={8}>
<Grid <Grid container direction='column' justifyContent='center' alignItems='flex-start'>
container <Box>{order.maker_nick}</Box>
direction="column"
justifyContent="center"
alignItems="flex-start"
>
<Box>
{order.maker_nick}
</Box>
<Box> <Box>
<Grid <Grid
container container
direction="column" direction='column'
justifyContent="flex-start" justifyContent='flex-start'
alignItems="flex-start" alignItems='flex-start'
> >
<Grid item xs={12}> <Grid item xs={12}>
{amountToString(order.amount, order.has_range, order.min_amount, order.max_amount)} {amountToString(
{' '} order.amount,
order.has_range,
order.min_amount,
order.max_amount,
)}{' '}
{currencyDict[order.currency]} {currencyDict[order.currency]}
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<PaymentText <PaymentText
othersText={t("Others")} othersText={t('Others')}
verbose={true} verbose={true}
size={20} size={20}
text={order.payment_method} text={order.payment_method}
/> />
</Grid> </Grid>
@ -232,69 +258,67 @@ const DepthChart: React.FC<DepthChartProps> = ({
</Grid> </Grid>
</Grid> </Grid>
</Paper> </Paper>
) : <></> ) : (
} <></>
);
};
const formatAxisX = (value: number): string => { const formatAxisX = (value: number): string => {
if (xType === 'base_amount') { if (xType === 'base_amount') {
return value.toString() return value.toString();
} }
return `${value}%` return `${value}%`;
} };
const formatAxisY = (value: number): string => `${value}BTC` const formatAxisY = (value: number): string => `${value}BTC`;
const rangeSteps = xType === 'base_amount' ? 200 : 0.5 const rangeSteps = xType === 'base_amount' ? 200 : 0.5;
const handleOnClick: PointMouseHandler = (point: Point) => { const handleOnClick: PointMouseHandler = (point: Point) => {
history.push('/order/' + point.data?.order?.id); history.push('/order/' + point.data?.order?.id);
} };
return bookLoading || !center || enrichedOrders.length < 1 ? ( return bookLoading || !center || enrichedOrders.length < 1 ? (
<div style={{display: "flex", justifyContent: "center", paddingTop: 200, height: 420 }}> <div style={{ display: 'flex', justifyContent: 'center', paddingTop: 200, height: 420 }}>
<CircularProgress /> <CircularProgress />
</div> </div>
) : ( ) : (
<Grid container style={{ paddingTop: 15 }}> <Grid container style={{ paddingTop: 15 }}>
<Grid <Grid
container container
direction="row" direction='row'
justifyContent="space-around" justifyContent='space-around'
alignItems="flex-start" alignItems='flex-start'
style={{ position: "absolute" }} style={{ position: 'absolute' }}
> >
<Grid container justifyContent="flex-start" alignItems="flex-start" style={{ paddingLeft: 20 }}> <Grid
<Select container
variant="standard" justifyContent='flex-start'
value={xType} alignItems='flex-start'
onChange={(e) => setXType(e.target.value)} style={{ paddingLeft: 20 }}
> >
<MenuItem value={"premium"}> <Select variant='standard' value={xType} onChange={(e) => setXType(e.target.value)}>
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap'}}> <MenuItem value={'premium'}>
{t("Premium")} <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
{t('Premium')}
</div> </div>
</MenuItem> </MenuItem>
<MenuItem value={"base_amount"}> <MenuItem value={'base_amount'}>
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap'}}> <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
{t("Price")} {t('Price')}
</div> </div>
</MenuItem> </MenuItem>
</Select> </Select>
</Grid> </Grid>
</Grid> </Grid>
<Grid <Grid container direction='row' justifyContent='center' alignItems='center'>
container <Grid container justifyContent='center' alignItems='center'>
direction="row"
justifyContent="center"
alignItems="center"
>
<Grid container justifyContent="center" alignItems="center">
<Grid item> <Grid item>
<IconButton onClick={() => setXRange(xRange + rangeSteps)}> <IconButton onClick={() => setXRange(xRange + rangeSteps)}>
<RemoveCircleOutline /> <RemoveCircleOutline />
</IconButton> </IconButton>
</Grid> </Grid>
<Grid item> <Grid item>
<Box justifyContent="center"> <Box justifyContent='center'>
{xType === 'base_amount' ? `${center} ${currencyDict[currencyCode]}` : `${center}%`} {xType === 'base_amount' ? `${center} ${currencyDict[currencyCode]}` : `${center}%`}
</Box> </Box>
</Grid> </Grid>
@ -306,42 +330,42 @@ const DepthChart: React.FC<DepthChartProps> = ({
</Grid> </Grid>
</Grid> </Grid>
<Grid container style={{ height: 357, padding: 15 }}> <Grid container style={{ height: 357, padding: 15 }}>
<ResponsiveLine <ResponsiveLine
data={series} data={series}
enableArea={true} enableArea={true}
useMesh={true} useMesh={true}
animate={false} animate={false}
crosshairType="cross" crosshairType='cross'
tooltip={generateTooltip} tooltip={generateTooltip}
onClick={handleOnClick} onClick={handleOnClick}
axisRight={{ axisRight={{
tickSize: 5, tickSize: 5,
format: formatAxisY format: formatAxisY,
}} }}
axisLeft={{ axisLeft={{
tickSize: 5, tickSize: 5,
format: formatAxisY format: formatAxisY,
}} }}
axisBottom={{ axisBottom={{
tickSize: 5, tickSize: 5,
tickRotation: xType === 'base_amount' && compact ? 45 : 0, tickRotation: xType === 'base_amount' && compact ? 45 : 0,
format: formatAxisX format: formatAxisX,
}} }}
margin={{ left: 65, right: 60, bottom: compact ? 36 : 25, top: 10 }} margin={{ left: 65, right: 60, bottom: compact ? 36 : 25, top: 10 }}
xFormat={(value) => Number(value).toFixed(0)} xFormat={(value) => Number(value).toFixed(0)}
lineWidth={3} lineWidth={3}
theme={getNivoScheme(theme)} theme={getNivoScheme(theme)}
colors={[theme.palette.secondary.main,theme.palette.primary.main]} colors={[theme.palette.secondary.main, theme.palette.primary.main]}
xScale={{ xScale={{
type: 'linear', type: 'linear',
min: center - xRange, min: center - xRange,
max: center + xRange max: center + xRange,
}} }}
layers={['axes', 'areas', 'crosshair', 'lines', centerLine, 'slices', 'mesh']} layers={['axes', 'areas', 'crosshair', 'lines', centerLine, 'slices', 'mesh']}
/> />
</Grid> </Grid>
</Grid> </Grid>
) );
} };
export default DepthChart export default DepthChart;

View File

@ -1,61 +1,61 @@
import { light } from "@mui/material/styles/createPalette" import { light } from '@mui/material/styles/createPalette';
import { palette } from "@mui/system" import { palette } from '@mui/system';
import { Theme as NivoTheme } from "@nivo/core" import { Theme as NivoTheme } from '@nivo/core';
import { Theme as MuiTheme } from './createTheme' import { Theme as MuiTheme } from './createTheme';
export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => { export const getNivoScheme: (theme: MuiTheme) => NivoTheme = (theme) => {
const lightMode = { const lightMode = {
markers: { markers: {
lineColor: "rgb(0, 0, 0)", lineColor: 'rgb(0, 0, 0)',
lineStrokeWidth: 1 lineStrokeWidth: 1,
}, },
axis: { axis: {
ticks: { ticks: {
line: { line: {
strokeWidth: "1", strokeWidth: '1',
stroke: "rgb(0, 0, 0)" stroke: 'rgb(0, 0, 0)',
} },
}, },
domain: { domain: {
line: { line: {
strokeWidth: "1", strokeWidth: '1',
stroke: "rgb(0, 0, 0)" stroke: 'rgb(0, 0, 0)',
} },
} },
} },
} };
const darkMode = { const darkMode = {
markers: { markers: {
lineColor: "rgb(255, 255, 255)", lineColor: 'rgb(255, 255, 255)',
lineStrokeWidth: 1 lineStrokeWidth: 1,
}, },
axis: { axis: {
ticks: { ticks: {
text: { text: {
fill: "rgb(255, 255, 255)" fill: 'rgb(255, 255, 255)',
}, },
line: { line: {
strokeWidth: "1", strokeWidth: '1',
stroke: "rgb(255, 255, 255)" stroke: 'rgb(255, 255, 255)',
} },
}, },
domain: { domain: {
line: { line: {
strokeWidth: "1", strokeWidth: '1',
stroke: "rgb(255, 255, 255)" stroke: 'rgb(255, 255, 255)',
} },
} },
}, },
crosshair: { crosshair: {
line: { line: {
strokeWidth: 1, strokeWidth: 1,
stroke: "rgb(255, 255, 255)" stroke: 'rgb(255, 255, 255)',
} },
} },
} };
return theme.palette.mode === 'dark' ? darkMode : lightMode return theme.palette.mode === 'dark' ? darkMode : lightMode;
} };
export default getNivoScheme export default getNivoScheme;

View File

@ -1,51 +1,52 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
DialogTitle, DialogTitle,
Tooltip, Tooltip,
IconButton, IconButton,
TextField, TextField,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogContentText, DialogContentText,
Button, Button,
Grid, Grid,
Link, Link,
} from "@mui/material" } from '@mui/material';
import { saveAsJson } from "../../utils/saveFile"; import { saveAsJson } from '../../utils/saveFile';
import { copyToClipboard } from "../../utils/clipboard"; import { copyToClipboard } from '../../utils/clipboard';
// Icons // Icons
import KeyIcon from '@mui/icons-material/Key'; import KeyIcon from '@mui/icons-material/Key';
import ContentCopy from "@mui/icons-material/ContentCopy"; import ContentCopy from '@mui/icons-material/ContentCopy';
import ForumIcon from '@mui/icons-material/Forum'; import ForumIcon from '@mui/icons-material/Forum';
import { ExportIcon, NewTabIcon } from '../Icons'; import { ExportIcon, NewTabIcon } from '../Icons';
function CredentialTextfield(props){ function CredentialTextfield(props) {
return( return (
<Grid item align="center" xs={12}> <Grid item align='center' xs={12}>
<Tooltip placement="top" enterTouchDelay={200} enterDelay={200} title={props.tooltipTitle}> <Tooltip placement='top' enterTouchDelay={200} enterDelay={200} title={props.tooltipTitle}>
<TextField <TextField
sx={{width:"100%", maxWidth:"550px"}} sx={{ width: '100%', maxWidth: '550px' }}
disabled disabled
label={<b>{props.label}</b>} label={<b>{props.label}</b>}
value={props.value} value={props.value}
variant='filled' variant='filled'
size='small' size='small'
InputProps={{ InputProps={{
endAdornment: endAdornment: (
<Tooltip disableHoverListener enterTouchDelay={0} title={props.copiedTitle}> <Tooltip disableHoverListener enterTouchDelay={0} title={props.copiedTitle}>
<IconButton onClick={()=> copyToClipboard(props.value)}> <IconButton onClick={() => copyToClipboard(props.value)}>
<ContentCopy/> <ContentCopy />
</IconButton> </IconButton>
</Tooltip>, </Tooltip>
}} ),
/> }}
/>
</Tooltip> </Tooltip>
</Grid> </Grid>
) );
} }
type Props = { type Props = {
@ -53,15 +54,15 @@ type Props = {
onClose: () => void; onClose: () => void;
orderId: number; orderId: number;
messages: array; messages: array;
own_pub_key: string; own_pub_key: string;
own_enc_priv_key: string; own_enc_priv_key: string;
peer_pub_key: string; peer_pub_key: string;
passphrase: string; passphrase: string;
onClickBack: () => void; onClickBack: () => void;
} };
const AuditPGPDialog = ({ const AuditPGPDialog = ({
open, open,
onClose, onClose,
orderId, orderId,
messages, messages,
@ -74,103 +75,129 @@ const AuditPGPDialog = ({
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Dialog <Dialog open={open} onClose={onClose}>
open={open} <DialogTitle>{t("Don't trust, verify")}</DialogTitle>
onClose={onClose}
>
<DialogTitle >
{t("Don't trust, verify")}
</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText> <DialogContentText>
{t("Your communication is end-to-end encrypted with OpenPGP. You can verify the privacy of this chat using any tool based on the OpenPGP standard.")} {t(
'Your communication is end-to-end encrypted with OpenPGP. You can verify the privacy of this chat using any tool based on the OpenPGP standard.',
)}
</DialogContentText> </DialogContentText>
<Grid container spacing={1} align="center"> <Grid container spacing={1} align='center'>
<Grid item align='center' xs={12}>
<Grid item align="center" xs={12}> <Button
<Button component={Link} target="_blank" href="https://learn.robosats.com/docs/pgp-encryption">{t("Learn how to verify")} <NewTabIcon sx={{width:16,height:16}}/></Button> component={Link}
target='_blank'
href='https://learn.robosats.com/docs/pgp-encryption'
>
{t('Learn how to verify')} <NewTabIcon sx={{ width: 16, height: 16 }} />
</Button>
</Grid> </Grid>
<CredentialTextfield <CredentialTextfield
tooltipTitle={t("Your PGP public key. Your peer uses it to encrypt messages only you can read.")} tooltipTitle={t(
label={t("Your public key")} 'Your PGP public key. Your peer uses it to encrypt messages only you can read.',
)}
label={t('Your public key')}
value={own_pub_key} value={own_pub_key}
copiedTitle={t("Copied!")}/> copiedTitle={t('Copied!')}
/>
<CredentialTextfield <CredentialTextfield
tooltipTitle={t("Your peer PGP public key. You use it to encrypt messages only he can read and to verify your peer signed the incoming messages.")} tooltipTitle={t(
label={t("Peer public key")} 'Your peer PGP public key. You use it to encrypt messages only he can read and to verify your peer signed the incoming messages.',
)}
label={t('Peer public key')}
value={peer_pub_key} value={peer_pub_key}
copiedTitle={t("Copied!")}/> copiedTitle={t('Copied!')}
/>
<CredentialTextfield <CredentialTextfield
tooltipTitle={t("Your encrypted private key. You use it to decrypt the messages that your peer encrypted for you. You also use it to sign the messages you send.")} tooltipTitle={t(
label={t("Your encrypted private key")} 'Your encrypted private key. You use it to decrypt the messages that your peer encrypted for you. You also use it to sign the messages you send.',
)}
label={t('Your encrypted private key')}
value={own_enc_priv_key} value={own_enc_priv_key}
copiedTitle={t("Copied!")}/> copiedTitle={t('Copied!')}
/>
<CredentialTextfield <CredentialTextfield
tooltipTitle={t("The passphrase to decrypt your private key. Only you know it! Do not share. It is also your robot token.")} tooltipTitle={t(
label={t("Your private key passphrase (keep secure!)")} 'The passphrase to decrypt your private key. Only you know it! Do not share. It is also your robot token.',
)}
label={t('Your private key passphrase (keep secure!)')}
value={passphrase} value={passphrase}
copiedTitle={t("Copied!")}/> copiedTitle={t('Copied!')}
/>
<br/>
<Grid item xs={6}>
<Tooltip placement="top" enterTouchDelay={0} enterDelay={1000} enterNextDelay={2000} title={t("Save credentials as a JSON file")}>
<Button
size="small"
color="primary"
variant="contained"
onClick={()=>saveAsJson(
'keys_'+orderId+'.json',
{"own_public_key": own_pub_key,
"peer_public_key":peer_pub_key,
"encrypted_private_key":own_enc_priv_key,
"passphrase":passphrase
})}>
<div style={{width:26,height:18}}>
<ExportIcon sx={{width:18,height:18}}/>
</div>
{t("Keys")}
<div style={{width:26,height:20}}>
<KeyIcon sx={{width:20,height:20}}/>
</div>
</Button>
</Tooltip>
</Grid>
<Grid item xs={6}>
<Tooltip placement="top" enterTouchDelay={0} enterDelay={1000} enterNextDelay={2000} title={t("Save messages as a JSON file")}>
<Button
size="small"
color="primary"
variant="contained"
onClick={()=>saveAsJson(
'messages_'+orderId+'.json',
messages)}>
<div style={{width:28,height:20}}>
<ExportIcon sx={{width:18,height:18}}/>
</div>
{t("Messages")}
<div style={{width:26,height:20}}>
<ForumIcon sx={{width:20,height:20}}/>
</div>
</Button>
</Tooltip>
<br />
<Grid item xs={6}>
<Tooltip
placement='top'
enterTouchDelay={0}
enterDelay={1000}
enterNextDelay={2000}
title={t('Save credentials as a JSON file')}
>
<Button
size='small'
color='primary'
variant='contained'
onClick={() =>
saveAsJson('keys_' + orderId + '.json', {
own_public_key: own_pub_key,
peer_public_key: peer_pub_key,
encrypted_private_key: own_enc_priv_key,
passphrase: passphrase,
})
}
>
<div style={{ width: 26, height: 18 }}>
<ExportIcon sx={{ width: 18, height: 18 }} />
</div>
{t('Keys')}
<div style={{ width: 26, height: 20 }}>
<KeyIcon sx={{ width: 20, height: 20 }} />
</div>
</Button>
</Tooltip>
</Grid> </Grid>
<Grid item xs={6}>
<Tooltip
placement='top'
enterTouchDelay={0}
enterDelay={1000}
enterNextDelay={2000}
title={t('Save messages as a JSON file')}
>
<Button
size='small'
color='primary'
variant='contained'
onClick={() => saveAsJson('messages_' + orderId + '.json', messages)}
>
<div style={{ width: 28, height: 20 }}>
<ExportIcon sx={{ width: 18, height: 18 }} />
</div>
{t('Messages')}
<div style={{ width: 26, height: 20 }}>
<ForumIcon sx={{ width: 20, height: 20 }} />
</div>
</Button>
</Tooltip>
</Grid>
</Grid> </Grid>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClickBack} autoFocus>{t("Go back")}</Button> <Button onClick={onClickBack} autoFocus>
{t('Go back')}
</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
) );
} };
export default AuditPGPDialog; export default AuditPGPDialog;

View File

@ -1,5 +1,5 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -12,22 +12,19 @@ import {
ListItemButton, ListItemButton,
Tooltip, Tooltip,
Typography, Typography,
} from "@mui/material"; } from '@mui/material';
import SendIcon from '@mui/icons-material/Send'; import SendIcon from '@mui/icons-material/Send';
import GitHubIcon from '@mui/icons-material/GitHub'; import GitHubIcon from '@mui/icons-material/GitHub';
import TwitterIcon from '@mui/icons-material/Twitter'; import TwitterIcon from '@mui/icons-material/Twitter';
import RedditIcon from '@mui/icons-material/Reddit'; import RedditIcon from '@mui/icons-material/Reddit';
import Flags from 'country-flag-icons/react/3x2' import Flags from 'country-flag-icons/react/3x2';
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
handleClickCloseCommunity: () => void; handleClickCloseCommunity: () => void;
} };
const CommunityDialog = ({ const CommunityDialog = ({ isOpen, handleClickCloseCommunity }: Props): JSX.Element => {
isOpen,
handleClickCloseCommunity,
}: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
const flagProps = { const flagProps = {
@ -35,7 +32,7 @@ const CommunityDialog = ({
height: 30, height: 30,
opacity: 0.85, opacity: 0.85,
style: { style: {
filter: "drop-shadow(2px 2px 2px #444444)", filter: 'drop-shadow(2px 2px 2px #444444)',
}, },
}; };
@ -43,136 +40,139 @@ const CommunityDialog = ({
<Dialog <Dialog
open={isOpen} open={isOpen}
onClose={handleClickCloseCommunity} onClose={handleClickCloseCommunity}
aria-labelledby="community-dialog-title" aria-labelledby='community-dialog-title'
aria-describedby="community-description" aria-describedby='community-description'
> >
<DialogContent> <DialogContent>
<Typography component="h5" variant="h5"> <Typography component='h5' variant='h5'>
{t("Community")} {t('Community')}
</Typography> </Typography>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p>{t("Support is only offered via public channels. Join our Telegram community if you have questions or want to hang out with other cool robots. Please, use our Github Issues if you find a bug or want to see new features!")}</p> <p>
{t(
'Support is only offered via public channels. Join our Telegram community if you have questions or want to hang out with other cool robots. Please, use our Github Issues if you find a bug or want to see new features!',
)}
</p>
</Typography> </Typography>
<List dense> <List dense>
<Divider/> <Divider />
<ListItemButton <ListItemButton
component="a" component='a'
target="_blank" target='_blank'
href="https://twitter.com/robosats" href='https://twitter.com/robosats'
rel="noreferrer" rel='noreferrer'
> >
<ListItemIcon> <ListItemIcon>
<TwitterIcon color="primary" sx={{height:32,width:32}}/> <TwitterIcon color='primary' sx={{ height: 32, width: 32 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("Follow RoboSats in Twitter")} primary={t('Follow RoboSats in Twitter')}
secondary={t("Twitter Official Account")} secondary={t('Twitter Official Account')}
/> />
</ListItemButton> </ListItemButton>
<Divider/> <Divider />
<ListItemButton <ListItemButton
component="a" component='a'
target="_blank" target='_blank'
href="https://reddit.com/r/robosats" href='https://reddit.com/r/robosats'
rel="noreferrer" rel='noreferrer'
> >
<ListItemIcon> <ListItemIcon>
<RedditIcon color="primary" sx={{height:35,width:35}}/> <RedditIcon color='primary' sx={{ height: 35, width: 35 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("Join RoboSats' Subreddit")} primary={t("Join RoboSats' Subreddit")}
secondary={t("RoboSats in Reddit")} secondary={t('RoboSats in Reddit')}
/> />
</ListItemButton> </ListItemButton>
<Divider/> <Divider />
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<SendIcon color="primary" sx={{height:32,width:32}}/> <SendIcon color='primary' sx={{ height: 32, width: 32 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={t("RoboSats Telegram Communities")}> <ListItemText secondary={t('RoboSats Telegram Communities')}>
<Tooltip title={t("Join RoboSats Spanish speaking community!") || ""}> <Tooltip title={t('Join RoboSats Spanish speaking community!') || ''}>
<IconButton <IconButton
component="a" component='a'
target="_blank" target='_blank'
href="https://t.me/robosats_es" href='https://t.me/robosats_es'
rel="noreferrer" rel='noreferrer'
> >
<Flags.ES {...flagProps} /> <Flags.ES {...flagProps} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title={t("Join RoboSats Russian speaking community!") || ""}> <Tooltip title={t('Join RoboSats Russian speaking community!') || ''}>
<IconButton <IconButton
component="a" component='a'
target="_blank" target='_blank'
href="https://t.me/robosats_ru" href='https://t.me/robosats_ru'
rel="noreferrer" rel='noreferrer'
> >
<Flags.RU {...flagProps} /> <Flags.RU {...flagProps} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title={t("Join RoboSats Chinese speaking community!") || ""}> <Tooltip title={t('Join RoboSats Chinese speaking community!') || ''}>
<IconButton <IconButton
component="a" component='a'
target="_blank" target='_blank'
href="https://t.me/robosats_cn" href='https://t.me/robosats_cn'
rel="noreferrer" rel='noreferrer'
> >
<Flags.CN {...flagProps} /> <Flags.CN {...flagProps} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title={t("Join RoboSats English speaking community!") || ""}> <Tooltip title={t('Join RoboSats English speaking community!') || ''}>
<IconButton <IconButton
component="a" component='a'
target="_blank" target='_blank'
href="https://t.me/robosats" href='https://t.me/robosats'
rel="noreferrer" rel='noreferrer'
> >
<Flags.US {...flagProps} /> <Flags.US {...flagProps} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title={t("Join RoboSats Portuguese speaking community!") || ""}> <Tooltip title={t('Join RoboSats Portuguese speaking community!') || ''}>
<IconButton <IconButton
component="a" component='a'
target="_blank" target='_blank'
href="https://t.me/robosats_pt" href='https://t.me/robosats_pt'
rel="noreferrer" rel='noreferrer'
> >
<Flags.BR {...flagProps} /> <Flags.BR {...flagProps} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</ListItemText> </ListItemText>
</ListItem> </ListItem>
<Divider/> <Divider />
<ListItemButton <ListItemButton
component="a" component='a'
target="_blank" target='_blank'
href="https://github.com/Reckless-Satoshi/robosats/issues" href='https://github.com/Reckless-Satoshi/robosats/issues'
rel="noreferrer" rel='noreferrer'
> >
<ListItemIcon> <ListItemIcon>
<GitHubIcon color="primary" sx={{height:32,width:32}}/> <GitHubIcon color='primary' sx={{ height: 32, width: 32 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("Tell us about a new feature or a bug")} primary={t('Tell us about a new feature or a bug')}
secondary={t("Github Issues - The Robotic Satoshis Open Source Project")} secondary={t('Github Issues - The Robotic Satoshis Open Source Project')}
/> />
</ListItemButton> </ListItemButton>
</List> </List>

View File

@ -1,5 +1,5 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
@ -11,7 +11,7 @@ import {
ListItem, ListItem,
ListItemIcon, ListItemIcon,
Typography, Typography,
} from "@mui/material"; } from '@mui/material';
import InventoryIcon from '@mui/icons-material/Inventory'; import InventoryIcon from '@mui/icons-material/Inventory';
import SellIcon from '@mui/icons-material/Sell'; import SellIcon from '@mui/icons-material/Sell';
@ -21,7 +21,7 @@ import PriceChangeIcon from '@mui/icons-material/PriceChange';
import BookIcon from '@mui/icons-material/Book'; import BookIcon from '@mui/icons-material/Book';
import LinkIcon from '@mui/icons-material/Link'; import LinkIcon from '@mui/icons-material/Link';
import { pn } from "../../utils/prettyNumbers"; import { pn } from '../../utils/prettyNumbers';
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
@ -34,7 +34,7 @@ type Props = {
makerFee: number; makerFee: number;
takerFee: number; takerFee: number;
swapFeeRate: number; swapFeeRate: number;
} };
const ExchangeSummaryDialog = ({ const ExchangeSummaryDialog = ({
isOpen, isOpen,
@ -50,106 +50,108 @@ const ExchangeSummaryDialog = ({
}: Props): JSX.Element => { }: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
if (swapFeeRate === null || swapFeeRate === undefined) { if (swapFeeRate === null || swapFeeRate === undefined) {
swapFeeRate = 0 swapFeeRate = 0;
} }
return ( return (
<Dialog <Dialog
open={isOpen} open={isOpen}
onClose={handleClickCloseExchangeSummary} onClose={handleClickCloseExchangeSummary}
aria-labelledby="exchange-summary-title" aria-labelledby='exchange-summary-title'
aria-describedby="exchange-summary-description" aria-describedby='exchange-summary-description'
> >
<DialogContent> <DialogContent>
<Typography component="h5" variant="h5">{t("Exchange Summary")}</Typography> <Typography component='h5' variant='h5'>
{t('Exchange Summary')}
</Typography>
<List dense> <List dense>
<ListItem > <ListItem>
<ListItemIcon> <ListItemIcon>
<InventoryIcon /> <InventoryIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
primary={numPublicBuyOrders} primary={numPublicBuyOrders}
secondary={t("Public buy orders")} secondary={t('Public buy orders')}
/> />
</ListItem> </ListItem>
<Divider /> <Divider />
<ListItem > <ListItem>
<ListItemIcon> <ListItemIcon>
<SellIcon /> <SellIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
primary={numPublicSellOrders} primary={numPublicSellOrders}
secondary={t("Public sell orders")} secondary={t('Public sell orders')}
/> />
</ListItem> </ListItem>
<Divider/> <Divider />
<ListItem > <ListItem>
<ListItemIcon> <ListItemIcon>
<BookIcon /> <BookIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
primary={`${pn(bookLiquidity)} Sats`} primary={`${pn(bookLiquidity)} Sats`}
secondary={t("Book liquidity")} secondary={t('Book liquidity')}
/> />
</ListItem> </ListItem>
<Divider/> <Divider />
<ListItem > <ListItem>
<ListItemIcon> <ListItemIcon>
<SmartToyIcon /> <SmartToyIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
primary={activeRobotsToday} primary={activeRobotsToday}
secondary={t("Today active robots")} secondary={t('Today active robots')}
/> />
</ListItem> </ListItem>
<Divider/> <Divider />
<ListItem > <ListItem>
<ListItemIcon> <ListItemIcon>
<PriceChangeIcon /> <PriceChangeIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
primary={`${lastDayNonkycBtcPremium}%`} primary={`${lastDayNonkycBtcPremium}%`}
secondary={t("24h non-KYC bitcoin premium")} secondary={t('24h non-KYC bitcoin premium')}
/> />
</ListItem> </ListItem>
<Divider/> <Divider />
<ListItem > <ListItem>
<ListItemIcon> <ListItemIcon>
<PercentIcon /> <PercentIcon />
</ListItemIcon> </ListItemIcon>
<Grid container > <Grid container>
<Grid item xs={6}> <Grid item xs={6}>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
secondary={t("Maker fee")} secondary={t('Maker fee')}
> >
{(makerFee * 100).toFixed(3)}% {(makerFee * 100).toFixed(3)}%
</ListItemText> </ListItemText>
@ -157,9 +159,9 @@ const ExchangeSummaryDialog = ({
<Grid item xs={6}> <Grid item xs={6}>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
secondary={t("Taker fee")} secondary={t('Taker fee')}
> >
{(takerFee * 100).toFixed(3)}% {(takerFee * 100).toFixed(3)}%
</ListItemText> </ListItemText>
@ -169,19 +171,18 @@ const ExchangeSummaryDialog = ({
<Divider /> <Divider />
<ListItem > <ListItem>
<ListItemIcon> <ListItemIcon>
<LinkIcon /> <LinkIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primaryTypographyProps={{fontSize: '14px'}} primaryTypographyProps={{ fontSize: '14px' }}
secondaryTypographyProps={{fontSize: '12px'}} secondaryTypographyProps={{ fontSize: '12px' }}
primary={`${swapFeeRate.toPrecision(3)}%`} primary={`${swapFeeRate.toPrecision(3)}%`}
secondary={t("Current onchain payout fee")} secondary={t('Current onchain payout fee')}
/> />
</ListItem> </ListItem>
</List> </List>
</DialogContent> </DialogContent>
</Dialog> </Dialog>

View File

@ -1,19 +1,19 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
Typography, Typography,
Link, Link,
DialogActions, DialogActions,
DialogContent, DialogContent,
Button, Button,
Grid, Grid,
Accordion, Accordion,
AccordionDetails, AccordionDetails,
AccordionSummary, AccordionSummary,
} from "@mui/material" } from '@mui/material';
import SmoothImage from 'react-smooth-image' import SmoothImage from 'react-smooth-image';
import MediaQuery from 'react-responsive' import MediaQuery from 'react-responsive';
// Icons // Icons
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
@ -22,213 +22,292 @@ type Props = {
maxAmount: string; maxAmount: string;
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
} };
const InfoDialog = ({ const InfoDialog = ({ maxAmount, open, onClose }: Props): JSX.Element => {
maxAmount,
open,
onClose,
}: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Dialog <Dialog
open={open} open={open}
onClose={onClose} onClose={onClose}
aria-labelledby="info-dialog-title" aria-labelledby='info-dialog-title'
aria-describedby="info-dialog-description" aria-describedby='info-dialog-description'
scroll="paper"> scroll='paper'
>
<DialogContent> <DialogContent>
<MediaQuery minWidth={475}> <MediaQuery minWidth={475}>
<Grid container> <Grid container>
<Grid item xs={8}> <Grid item xs={8}>
<Typography component="h4" variant="h4">{t("What is RoboSats?")}</Typography> <Typography component='h4' variant='h4'>
<Typography component="div" variant="body2"> {t('What is RoboSats?')}
<p>{t("It is a BTC/FIAT peer-to-peer exchange over lightning.")} <br/> </Typography>
{t("It simplifies matchmaking and minimizes the need of trust. RoboSats focuses in privacy and speed.")}</p> <Typography component='div' variant='body2'>
<p>
{t('It is a BTC/FIAT peer-to-peer exchange over lightning.')} <br />
{t(
'It simplifies matchmaking and minimizes the need of trust. RoboSats focuses in privacy and speed.',
)}
</p>
<p>{t("RoboSats is an open source project ")} <Link <p>
href='https://github.com/reckless-satoshi/robosats'>{t("(GitHub).")}</Link> {t('RoboSats is an open source project ')}{' '}
</p> <Link href='https://github.com/reckless-satoshi/robosats'>{t('(GitHub).')}</Link>
</Typography> </p>
</Typography>
</Grid>
<Grid item xs={4}>
<SmoothImage
src={window.location.origin + '/static/assets/images/v0.1.2-04.png'}
imageStyles={{
borderRadius: '50%',
border: '2px solid #555',
filter: 'drop-shadow(1px 1px 1px #000000)',
height: '170px',
width: '170px',
}}
/>
</Grid>
</Grid> </Grid>
<Grid item xs={4}> <div style={{ height: 15 }} />
<SmoothImage
src={window.location.origin +'/static/assets/images/v0.1.2-04.png'}
imageStyles={{borderRadius: "50%",
border: "2px solid #555",
filter: "drop-shadow(1px 1px 1px #000000)",
height: "170px",
width: "170px"}}
/>
</Grid>
</Grid>
<div style={{height:15}}/>
</MediaQuery> </MediaQuery>
<MediaQuery maxWidth={474}> <MediaQuery maxWidth={474}>
<Typography component="h4" variant="h4">{t("What is RoboSats?")}</Typography> <Typography component='h4' variant='h4'>
<Typography component="div" variant="body2"> {t('What is RoboSats?')}
<p>{t("It is a BTC/FIAT peer-to-peer exchange over lightning.")+" "} {t("It simplifies matchmaking and minimizes the need of trust. RoboSats focuses in privacy and speed.")}</p> </Typography>
<Typography component='div' variant='body2'>
<p>
{t('It is a BTC/FIAT peer-to-peer exchange over lightning.') + ' '}{' '}
{t(
'It simplifies matchmaking and minimizes the need of trust. RoboSats focuses in privacy and speed.',
)}
</p>
<img <img
width='100%' width='100%'
src={window.location.origin +'/static/assets/images/v0.1.2-03.png'} src={window.location.origin + '/static/assets/images/v0.1.2-03.png'}
/> />
<p>{t("RoboSats is an open source project ")} <Link <p>
href='https://github.com/reckless-satoshi/robosats'>{t("(GitHub).")}</Link> {t('RoboSats is an open source project ')}{' '}
</p> <Link href='https://github.com/reckless-satoshi/robosats'>{t('(GitHub).')}</Link>
</Typography> </p>
</Typography>
</MediaQuery> </MediaQuery>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('How does it work?')}</Typography>
{t("How does it work?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p> {t("AnonymousAlice01 wants to sell bitcoin. She posts a sell order. BafflingBob02 wants to buy bitcoin and he takes Alice's order. Both have to post a small bond using lightning to prove they are real robots. Then, Alice posts the trade collateral also using a lightning hold invoice. RoboSats locks the invoice until Alice confirms she received the fiat, then the satoshis are released to Bob. Enjoy your satoshis, Bob!")}</p> <p>
<p>{t("At no point, AnonymousAlice01 and BafflingBob02 have to entrust the bitcoin funds to each other. In case they have a conflict, RoboSats staff will help resolving the dispute.")} {' '}
{t("You can find a step-by-step description of the trade pipeline in ")} {t(
<Link target="_blank" href='https://learn.robosats.com/docs/trade-pipeline/'>{t("How it works")}</Link>. "AnonymousAlice01 wants to sell bitcoin. She posts a sell order. BafflingBob02 wants to buy bitcoin and he takes Alice's order. Both have to post a small bond using lightning to prove they are real robots. Then, Alice posts the trade collateral also using a lightning hold invoice. RoboSats locks the invoice until Alice confirms she received the fiat, then the satoshis are released to Bob. Enjoy your satoshis, Bob!",
{" "+t("You can also check the full guide in ")} )}
<Link target="_blank" href='https://learn.robosats.com/read/en'>{t("How to use")}</Link>.</p> </p>
<p>
{t(
'At no point, AnonymousAlice01 and BafflingBob02 have to entrust the bitcoin funds to each other. In case they have a conflict, RoboSats staff will help resolving the dispute.',
)}
{t('You can find a step-by-step description of the trade pipeline in ')}
<Link target='_blank' href='https://learn.robosats.com/docs/trade-pipeline/'>
{t('How it works')}
</Link>
.{' ' + t('You can also check the full guide in ')}
<Link target='_blank' href='https://learn.robosats.com/read/en'>
{t('How to use')}
</Link>
.
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('What payment methods are accepted?')}</Typography>
{t("What payment methods are accepted?")
}</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p>{t("All of them as long as they are fast. You can write down your preferred payment method(s). You will have to match with a peer who also accepts that method. The step to exchange fiat has a expiry time of 24 hours before a dispute is automatically open. We highly recommend using instant fiat payment rails.")} </p> <p>
{t(
'All of them as long as they are fast. You can write down your preferred payment method(s). You will have to match with a peer who also accepts that method. The step to exchange fiat has a expiry time of 24 hours before a dispute is automatically open. We highly recommend using instant fiat payment rails.',
)}{' '}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('Are there trade limits?')}</Typography>
{t("Are there trade limits?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p>{t("Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).", {maxAmount: maxAmount})} </p> <p>
{t(
'Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).',
{ maxAmount: maxAmount },
)}{' '}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('What are the fees?')}</Typography>
{t("What are the fees?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p>{t("RoboSats total fee for an order is {{tradeFee}}%. This fee is split to be covered by both: the order maker ({{makerFee}}%) and the order taker ({{takerFee}}%). In case an onchain address is used to received the Sats a variable swap fee applies. Check the exchange details by tapping on the bottom bar icon to see the current swap fee.",{tradeFee:"0.2", makerFee:"0.025", takerFee: "0.175"})} </p> <p>
<p>{t("Be aware your fiat payment provider might charge extra fees. In any case, the buyer bears the costs of sending fiat. That includes banking charges, transfer fees and foreign exchange spreads. The seller must receive exactly the amount stated in the order details.")} </p> {t(
'RoboSats total fee for an order is {{tradeFee}}%. This fee is split to be covered by both: the order maker ({{makerFee}}%) and the order taker ({{takerFee}}%). In case an onchain address is used to received the Sats a variable swap fee applies. Check the exchange details by tapping on the bottom bar icon to see the current swap fee.',
{ tradeFee: '0.2', makerFee: '0.025', takerFee: '0.175' },
)}{' '}
</p>
<p>
{t(
'Be aware your fiat payment provider might charge extra fees. In any case, the buyer bears the costs of sending fiat. That includes banking charges, transfer fees and foreign exchange spreads. The seller must receive exactly the amount stated in the order details.',
)}{' '}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('Is RoboSats private?')}</Typography>
{t("Is RoboSats private?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p> {t("RoboSats will never ask you for your name, country or ID. RoboSats does not custody your funds and does not care who you are. RoboSats does not collect or custody any personal data. For best anonymity use Tor Browser and access the .onion hidden service.")} </p> <p>
<p>{t("Your trading peer is the only one who can potentially guess anything about you. Keep your chat short and concise. Avoid providing non-essential information other than strictly necessary for the fiat payment.")} </p> {' '}
{t(
'RoboSats will never ask you for your name, country or ID. RoboSats does not custody your funds and does not care who you are. RoboSats does not collect or custody any personal data. For best anonymity use Tor Browser and access the .onion hidden service.',
)}{' '}
</p>
<p>
{t(
'Your trading peer is the only one who can potentially guess anything about you. Keep your chat short and concise. Avoid providing non-essential information other than strictly necessary for the fiat payment.',
)}{' '}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('What are the risks?')}</Typography>
{t("What are the risks?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p> {t("This is an experimental application, things could go wrong. Trade small amounts!")}</p> <p>
<p> {t("The seller faces the same charge-back risk as with any other peer-to-peer service. Paypal or credit cards are not recommended.")}</p> {' '}
{t(
'This is an experimental application, things could go wrong. Trade small amounts!',
)}
</p>
<p>
{' '}
{t(
'The seller faces the same charge-back risk as with any other peer-to-peer service. Paypal or credit cards are not recommended.',
)}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('What is the trust model?')}</Typography>
{t("What is the trust model?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p> {t("The buyer and the seller never have to trust each other. Some trust on RoboSats is needed since linking the seller's hold invoice and buyer payment is not atomic (yet). In addition, disputes are solved by the RoboSats staff.")}</p> <p>
<p> {t("To be totally clear. Trust requirements are minimized. However, there is still one way RoboSats could run away with your satoshis: by not releasing the satoshis to the buyer. It could be argued that such move is not in RoboSats' interest as it would damage the reputation for a small payout. However, you should hesitate and only trade small quantities at a time. For large amounts use an onchain escrow service such as Bisq")}</p> {' '}
<p> {t("You can build more trust on RoboSats by inspecting the source code.")} <Link href='https://github.com/reckless-satoshi/robosats'> {t("Project source code")}</Link>. </p> {t(
"The buyer and the seller never have to trust each other. Some trust on RoboSats is needed since linking the seller's hold invoice and buyer payment is not atomic (yet). In addition, disputes are solved by the RoboSats staff.",
)}
</p>
<p>
{' '}
{t(
"To be totally clear. Trust requirements are minimized. However, there is still one way RoboSats could run away with your satoshis: by not releasing the satoshis to the buyer. It could be argued that such move is not in RoboSats' interest as it would damage the reputation for a small payout. However, you should hesitate and only trade small quantities at a time. For large amounts use an onchain escrow service such as Bisq",
)}
</p>
<p>
{' '}
{t('You can build more trust on RoboSats by inspecting the source code.')}{' '}
<Link href='https://github.com/reckless-satoshi/robosats'>
{' '}
{t('Project source code')}
</Link>
.{' '}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('What happens if RoboSats suddenly disappears?')}</Typography>
{t("What happens if RoboSats suddenly disappears?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p> {t("Your sats will return to you. Any hold invoice that is not settled would be automatically returned even if RoboSats goes down forever. This is true for both, locked bonds and trading escrows. However, there is a small window between the seller confirms FIAT RECEIVED and the moment the buyer receives the satoshis when the funds could be permanently lost if RoboSats disappears. This window is about 1 second long. Make sure to have enough inbound liquidity to avoid routing failures. If you have any problem, reach out trough the RoboSats public channels.")}</p> <p>
{' '}
{t(
'Your sats will return to you. Any hold invoice that is not settled would be automatically returned even if RoboSats goes down forever. This is true for both, locked bonds and trading escrows. However, there is a small window between the seller confirms FIAT RECEIVED and the moment the buyer receives the satoshis when the funds could be permanently lost if RoboSats disappears. This window is about 1 second long. Make sure to have enough inbound liquidity to avoid routing failures. If you have any problem, reach out trough the RoboSats public channels.',
)}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('Is RoboSats legal in my country?')}</Typography>
{t("Is RoboSats legal in my country?")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p> {t("In many countries using RoboSats is no different than using Ebay or Craiglist. Your regulation may vary. It is your responsibility to comply.")}</p> <p>
{' '}
{t(
'In many countries using RoboSats is no different than using Ebay or Craiglist. Your regulation may vary. It is your responsibility to comply.',
)}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<Accordion disableGutters={true}> <Accordion disableGutters={true}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography> <Typography>{t('Disclaimer')}</Typography>
{t("Disclaimer")}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Typography component="div" variant="body2"> <Typography component='div' variant='body2'>
<p> {t("This lightning application is provided as is. It is in active development: trade with the utmost caution. There is no private support. Support is only offered via public channels ")}<Link href='https://t.me/robosats'>{t("(Telegram)")}</Link>{t(". RoboSats will never contact you. RoboSats will definitely never ask for your robot token.")}</p> <p>
{' '}
{t(
'This lightning application is provided as is. It is in active development: trade with the utmost caution. There is no private support. Support is only offered via public channels ',
)}
<Link href='https://t.me/robosats'>{t('(Telegram)')}</Link>
{t(
'. RoboSats will never contact you. RoboSats will definitely never ask for your robot token.',
)}
</p>
</Typography> </Typography>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
<DialogActions> <DialogActions>
<Button onClick={onClose}>{t("Close")}</Button> <Button onClick={onClose}>{t('Close')}</Button>
</DialogActions> </DialogActions>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
) );
} };
export default InfoDialog; export default InfoDialog;

View File

@ -1,50 +1,49 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
DialogTitle, DialogTitle,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogContentText, DialogContentText,
Button, Button,
Link, Link,
} from "@mui/material" } from '@mui/material';
type Props = { type Props = {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
} };
const LearnDialog = ({ const LearnDialog = ({ open, onClose }: Props): JSX.Element => {
open,
onClose,
}: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Dialog <Dialog open={open} onClose={onClose}>
open={open} <DialogTitle>{t('Learn RoboSats')}</DialogTitle>
onClose={onClose}
>
<DialogTitle>
{t("Learn RoboSats")}
</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText> <DialogContentText>
{t("You are about to visit Learn RoboSats. It hosts tutorials and documentation to help you learn how to use RoboSats and understand how it works.")} {t(
'You are about to visit Learn RoboSats. It hosts tutorials and documentation to help you learn how to use RoboSats and understand how it works.',
)}
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}>{t("Back")}</Button> <Button onClick={onClose}>{t('Back')}</Button>
<Button onClick={onClose} autoFocus component={Link} href="https://learn.robosats.com" target="_blank"> <Button
onClick={onClose}
autoFocus
component={Link}
href='https://learn.robosats.com'
target='_blank'
>
{t("Let's go!")} {t("Let's go!")}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
) );
} };
export default LearnDialog; export default LearnDialog;

View File

@ -1,48 +1,43 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
DialogTitle, DialogTitle,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogContentText, DialogContentText,
Button, Button,
} from "@mui/material" } from '@mui/material';
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom';
type Props = { type Props = {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
} };
const NoRobotDialog = ({ const NoRobotDialog = ({ open, onClose }: Props): JSX.Element => {
open,
onClose,
}: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Dialog <Dialog open={open} onClose={onClose}>
open={open} <DialogTitle>{t('You do not have a robot avatar')}</DialogTitle>
onClose={onClose}
>
<DialogTitle>
{t("You do not have a robot avatar")}
</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText> <DialogContentText>
{t("You need to generate a robot avatar in order to become an order maker")} {t('You need to generate a robot avatar in order to become an order maker')}
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose} autoFocus>{t("Go back")}</Button> <Button onClick={onClose} autoFocus>
<Button onClick={onClose} to="/" component={Link}>{t("Generate Robot")}</Button> {t('Go back')}
</Button>
<Button onClick={onClose} to='/' component={Link}>
{t('Generate Robot')}
</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
) );
} };
export default NoRobotDialog; export default NoRobotDialog;

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { Link as LinkRouter } from "react-router-dom"; import { Link as LinkRouter } from 'react-router-dom';
import { import {
Avatar, Avatar,
@ -23,19 +23,19 @@ import {
TextField, TextField,
Tooltip, Tooltip,
Typography, Typography,
} from "@mui/material"; } from '@mui/material';
import BoltIcon from "@mui/icons-material/Bolt"; import BoltIcon from '@mui/icons-material/Bolt';
import NumbersIcon from "@mui/icons-material/Numbers"; import NumbersIcon from '@mui/icons-material/Numbers';
import PasswordIcon from "@mui/icons-material/Password"; import PasswordIcon from '@mui/icons-material/Password';
import ContentCopy from "@mui/icons-material/ContentCopy"; import ContentCopy from '@mui/icons-material/ContentCopy';
import PersonAddAltIcon from "@mui/icons-material/PersonAddAlt"; import PersonAddAltIcon from '@mui/icons-material/PersonAddAlt';
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents"; import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
import { UserNinjaIcon, BitcoinIcon } from "../Icons"; import { UserNinjaIcon, BitcoinIcon } from '../Icons';
import { getCookie } from "../../utils/cookies"; import { getCookie } from '../../utils/cookies';
import { copyToClipboard } from "../../utils/clipboard"; import { copyToClipboard } from '../../utils/clipboard';
import { getWebln } from "../../utils/webln"; import { getWebln } from '../../utils/webln';
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
@ -44,7 +44,7 @@ type Props = {
activeOrderId: string | number; activeOrderId: string | number;
lastOrderId: string | number; lastOrderId: string | number;
referralCode: string; referralCode: string;
handleSubmitInvoiceClicked: (e:any, invoice: string) => void; handleSubmitInvoiceClicked: (e: any, invoice: string) => void;
host: string; host: string;
showRewardsSpinner: boolean; showRewardsSpinner: boolean;
withdrawn: boolean; withdrawn: boolean;
@ -53,7 +53,7 @@ type Props = {
stealthInvoices: boolean; stealthInvoices: boolean;
handleSetStealthInvoice: (stealth: boolean) => void; handleSetStealthInvoice: (stealth: boolean) => void;
setAppState: (state: any) => void; // TODO: move to a ContextProvider setAppState: (state: any) => void; // TODO: move to a ContextProvider
} };
const ProfileDialog = ({ const ProfileDialog = ({
isOpen, isOpen,
@ -74,24 +74,23 @@ const ProfileDialog = ({
}: Props): JSX.Element => { }: Props): JSX.Element => {
const { t } = useTranslation(); const { t } = useTranslation();
const [rewardInvoice, setRewardInvoice] = useState<string>(""); const [rewardInvoice, setRewardInvoice] = useState<string>('');
const [showRewards, setShowRewards] = useState<boolean>(false); const [showRewards, setShowRewards] = useState<boolean>(false);
const [openClaimRewards, setOpenClaimRewards] = useState<boolean>(false); const [openClaimRewards, setOpenClaimRewards] = useState<boolean>(false);
const [weblnEnabled, setWeblnEnabled] = useState<boolean>(false) const [weblnEnabled, setWeblnEnabled] = useState<boolean>(false);
useEffect(() => { useEffect(() => {
getWebln() getWebln().then((webln) => {
.then((webln) => { setWeblnEnabled(webln !== undefined);
setWeblnEnabled(webln !== undefined) });
}) }, [showRewards]);
}, [showRewards])
const copyTokenHandler = () => { const copyTokenHandler = () => {
const robotToken = getCookie("robot_token"); const robotToken = getCookie('robot_token');
if (robotToken) { if (robotToken) {
copyToClipboard(robotToken); copyToClipboard(robotToken);
setAppState({copiedToken:true}); setAppState({ copiedToken: true });
} }
}; };
@ -99,59 +98,71 @@ const ProfileDialog = ({
copyToClipboard(`http://${host}/ref/${referralCode}`); copyToClipboard(`http://${host}/ref/${referralCode}`);
}; };
const handleWeblnInvoiceClicked = async (e: any) =>{ const handleWeblnInvoiceClicked = async (e: any) => {
e.preventDefault(); e.preventDefault();
if (earnedRewards) { if (earnedRewards) {
const webln = await getWebln(); const webln = await getWebln();
const invoice = webln.makeInvoice(earnedRewards).then(() => { const invoice = webln.makeInvoice(earnedRewards).then(() => {
if (invoice) { if (invoice) {
handleSubmitInvoiceClicked(e, invoice.paymentRequest) handleSubmitInvoiceClicked(e, invoice.paymentRequest);
} }
}) });
} }
} };
return ( return (
<Dialog <Dialog
open={isOpen} open={isOpen}
onClose={handleClickCloseProfile} onClose={handleClickCloseProfile}
aria-labelledby="profile-title" aria-labelledby='profile-title'
aria-describedby="profile-description" aria-describedby='profile-description'
> >
<DialogContent> <DialogContent>
<Typography component="h5" variant="h5">{t("Your Profile")}</Typography> <Typography component='h5' variant='h5'>
{t('Your Profile')}
</Typography>
<List> <List>
<Divider/> <Divider />
<ListItem className="profileNickname"> <ListItem className='profileNickname'>
<ListItemText secondary={t("Your robot")}> <ListItemText secondary={t('Your robot')}>
<Typography component="h6" variant="h6"> <Typography component='h6' variant='h6'>
{nickname ? ( {nickname ? (
<div style={{position:"relative", left:"-7px"}}> <div style={{ position: 'relative', left: '-7px' }}>
<div style={{display:"flex", alignItems:"center", justifyContent:"left", flexWrap:"wrap", width:300}}> <div
<BoltIcon sx={{ color: "#fcba03", height: "28px", width: "24px"}} /> style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'left',
flexWrap: 'wrap',
width: 300,
}}
>
<BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
<a>{nickname}</a> <a>{nickname}</a>
<BoltIcon sx={{ color: "#fcba03", height: "28px", width: "24px"}} /> <BoltIcon sx={{ color: '#fcba03', height: '28px', width: '24px' }} />
</div> </div>
</div> </div>
) ) : null}
: null}
</Typography> </Typography>
</ListItemText> </ListItemText>
<ListItemAvatar> <ListItemAvatar>
<Avatar className="profileAvatar" <Avatar
sx={{ width: 65, height:65 }} className='profileAvatar'
sx={{ width: 65, height: 65 }}
alt={nickname} alt={nickname}
src={nickname ? `${window.location.origin}/static/assets/avatars/${nickname}.png` : ""} src={
nickname ? `${window.location.origin}/static/assets/avatars/${nickname}.png` : ''
}
/> />
</ListItemAvatar> </ListItemAvatar>
</ListItem> </ListItem>
<Divider/> <Divider />
{activeOrderId ? ( {activeOrderId ? (
<ListItemButton <ListItemButton
@ -160,94 +171,94 @@ const ProfileDialog = ({
component={LinkRouter} component={LinkRouter}
> >
<ListItemIcon> <ListItemIcon>
<Badge badgeContent="" color="primary"> <Badge badgeContent='' color='primary'>
<NumbersIcon color="primary" /> <NumbersIcon color='primary' />
</Badge> </Badge>
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("One active order #{{orderID}}", { orderID: activeOrderId })} primary={t('One active order #{{orderID}}', { orderID: activeOrderId })}
secondary={t("Your current order")} secondary={t('Your current order')}
/> />
</ListItemButton> </ListItemButton>
) : ) : lastOrderId ? (
lastOrderId ? ( <ListItemButton
<ListItemButton onClick={handleClickCloseProfile}
onClick={handleClickCloseProfile} to={`/order/${lastOrderId}`}
to={`/order/${lastOrderId}`} component={LinkRouter}
component={LinkRouter} >
> <ListItemIcon>
<ListItemIcon> <NumbersIcon color='primary' />
<NumbersIcon color="primary" /> </ListItemIcon>
</ListItemIcon> <ListItemText
<ListItemText primary={t('Your last order #{{orderID}}', { orderID: lastOrderId })}
primary={t("Your last order #{{orderID}}", { orderID: lastOrderId })} secondary={t('Inactive order')}
secondary={t("Inactive order")} />
/> </ListItemButton>
</ListItemButton> ) : (
) : ( <ListItem>
<ListItem> <ListItemIcon>
<ListItemIcon> <NumbersIcon />
<NumbersIcon /> </ListItemIcon>
</ListItemIcon> <ListItemText
<ListItemText primary={t('No active orders')}
primary={t("No active orders")} secondary={t('You do not have previous orders')}
secondary={t("You do not have previous orders")} />
/> </ListItem>
</ListItem> )}
)
}
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<PasswordIcon /> <PasswordIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={t("Your token (will not remain here)")}> <ListItemText secondary={t('Your token (will not remain here)')}>
{getCookie("robot_token") ? ( {getCookie('robot_token') ? (
<TextField <TextField
disabled disabled
sx={{width:"100%", maxWidth:"450px"}} sx={{ width: '100%', maxWidth: '450px' }}
label={t("Back it up!")} label={t('Back it up!')}
value={getCookie("robot_token") } value={getCookie('robot_token')}
variant="filled" variant='filled'
size="small" size='small'
InputProps={{ InputProps={{
endAdornment: endAdornment: (
<Tooltip <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!') || ''}>
disableHoverListener <IconButton onClick={copyTokenHandler}>
enterTouchDelay={0} <ContentCopy color='inherit' />
title={t("Copied!") || ""} </IconButton>
> </Tooltip>
<IconButton onClick={copyTokenHandler}> ),
<ContentCopy color="inherit" /> }}
</IconButton>
</Tooltip>,
}}
/> />
) : ) : (
t("Cannot remember") t('Cannot remember')
} )}
</ListItemText> </ListItemText>
</ListItem> </ListItem>
<Divider/> <Divider />
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<UserNinjaIcon/> <UserNinjaIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText> <ListItemText>
<Tooltip placement="top" enterTouchDelay={0} title={t("Stealth lightning invoices do not contain details about the trade except an order reference. Enable this setting if you don't want to disclose details to a custodial lightning wallet.")}> <Tooltip
placement='top'
enterTouchDelay={0}
title={t(
"Stealth lightning invoices do not contain details about the trade except an order reference. Enable this setting if you don't want to disclose details to a custodial lightning wallet.",
)}
>
<Grid item> <Grid item>
<FormControlLabel <FormControlLabel
labelPlacement="end" labelPlacement='end'
label={t("Use stealth invoices")} label={t('Use stealth invoices')}
control={ control={
<Switch <Switch
checked={stealthInvoices} checked={stealthInvoices}
onChange={() => handleSetStealthInvoice(!stealthInvoices) onChange={() => handleSetStealthInvoice(!stealthInvoices)}
}
/> />
} }
/> />
@ -258,21 +269,19 @@ const ProfileDialog = ({
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<BitcoinIcon/> <BitcoinIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText> <ListItemText>
<FormControlLabel <FormControlLabel
labelPlacement="end" labelPlacement='end'
label={ label={
<div style={{display:'flex', alignItems:'center'}}> <div style={{ display: 'flex', alignItems: 'center' }}>
{t("Rewards and compensations")} {t('Rewards and compensations')}
</div>} </div>
}
control={ control={
<Switch <Switch checked={showRewards} onChange={() => setShowRewards(!showRewards)} />
checked={showRewards}
onChange={()=> setShowRewards(!showRewards)}
/>
} }
/> />
</ListItemText> </ListItemText>
@ -285,24 +294,25 @@ const ProfileDialog = ({
<PersonAddAltIcon /> <PersonAddAltIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={t("Share to earn 100 Sats per trade")}> <ListItemText secondary={t('Share to earn 100 Sats per trade')}>
<TextField <TextField
label={t("Your referral link")} label={t('Your referral link')}
value={host+'/ref/'+referralCode} value={host + '/ref/' + referralCode}
size="small" size='small'
InputProps={{ InputProps={{
endAdornment: endAdornment: (
<Tooltip <Tooltip
disableHoverListener disableHoverListener
enterTouchDelay={0} enterTouchDelay={0}
title={t("Copied!") || ""} title={t('Copied!') || ''}
> >
<IconButton onClick={copyReferralCodeHandler}> <IconButton onClick={copyReferralCodeHandler}>
<ContentCopy /> <ContentCopy />
</IconButton> </IconButton>
</Tooltip>, </Tooltip>
}} ),
/> }}
/>
</ListItemText> </ListItemText>
</ListItem> </ListItem>
@ -312,7 +322,7 @@ const ProfileDialog = ({
</ListItemIcon> </ListItemIcon>
{!openClaimRewards ? ( {!openClaimRewards ? (
<ListItemText secondary={t("Your earned rewards")}> <ListItemText secondary={t('Your earned rewards')}>
<Grid container> <Grid container>
<Grid item xs={9}> <Grid item xs={9}>
<Typography>{`${earnedRewards} Sats`}</Typography> <Typography>{`${earnedRewards} Sats`}</Typography>
@ -322,54 +332,56 @@ const ProfileDialog = ({
<Button <Button
disabled={earnedRewards === 0 ? true : false} disabled={earnedRewards === 0 ? true : false}
onClick={() => setOpenClaimRewards(true)} onClick={() => setOpenClaimRewards(true)}
variant="contained" variant='contained'
size="small" size='small'
> >
{t("Claim")} {t('Claim')}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
</ListItemText> </ListItemText>
) : ( ) : (
<form noValidate style={{maxWidth: 270}}> <form noValidate style={{ maxWidth: 270 }}>
<Grid container style={{ display: "flex", alignItems: "stretch"}}> <Grid container style={{ display: 'flex', alignItems: 'stretch' }}>
<Grid item style={{ display: "flex", maxWidth:160}} > <Grid item style={{ display: 'flex', maxWidth: 160 }}>
<TextField <TextField
error={badInvoice ? true : false} error={badInvoice ? true : false}
helperText={badInvoice ? badInvoice : "" } helperText={badInvoice ? badInvoice : ''}
label={t("Invoice for {{amountSats}} Sats", { amountSats: earnedRewards })} label={t('Invoice for {{amountSats}} Sats', {
size="small" amountSats: earnedRewards,
})}
size='small'
value={rewardInvoice} value={rewardInvoice}
onChange={e => { onChange={(e) => {
setRewardInvoice(e.target.value); setRewardInvoice(e.target.value);
}} }}
/> />
</Grid> </Grid>
<Grid item alignItems="stretch" style={{ display: "flex", maxWidth:80}}> <Grid item alignItems='stretch' style={{ display: 'flex', maxWidth: 80 }}>
<Button <Button
sx={{maxHeight:38}} sx={{ maxHeight: 38 }}
onClick={(e) => handleSubmitInvoiceClicked(e, rewardInvoice)} onClick={(e) => handleSubmitInvoiceClicked(e, rewardInvoice)}
variant="contained" variant='contained'
color="primary" color='primary'
size="small" size='small'
type="submit" type='submit'
> >
{t("Submit")} {t('Submit')}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
{weblnEnabled && ( {weblnEnabled && (
<Grid container style={{ display: "flex", alignItems: "stretch"}}> <Grid container style={{ display: 'flex', alignItems: 'stretch' }}>
<Grid item alignItems="stretch" style={{ display: "flex", maxWidth:240}}> <Grid item alignItems='stretch' style={{ display: 'flex', maxWidth: 240 }}>
<Button <Button
sx={{maxHeight:38, minWidth: 230}} sx={{ maxHeight: 38, minWidth: 230 }}
onClick={(e) => handleWeblnInvoiceClicked(e)} onClick={(e) => handleWeblnInvoiceClicked(e)}
variant="contained" variant='contained'
color="primary" color='primary'
size="small" size='small'
type="submit" type='submit'
> >
{t("Generate with Webln")} {t('Generate with Webln')}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
@ -379,15 +391,15 @@ const ProfileDialog = ({
</ListItem> </ListItem>
{showRewardsSpinner && ( {showRewardsSpinner && (
<div style={{display: "flex", justifyContent: "center"}}> <div style={{ display: 'flex', justifyContent: 'center' }}>
<CircularProgress /> <CircularProgress />
</div> </div>
)} )}
{withdrawn && ( {withdrawn && (
<div style={{display: "flex", justifyContent: "center"}}> <div style={{ display: 'flex', justifyContent: 'center' }}>
<Typography color="primary" variant="body2"> <Typography color='primary' variant='body2'>
<b>{t("There it goes, thank you!🥇")}</b> <b>{t('There it goes, thank you!🥇')}</b>
</Typography> </Typography>
</div> </div>
)} )}

View File

@ -1,5 +1,5 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
@ -11,19 +11,19 @@ import {
ListItem, ListItem,
ListItemIcon, ListItemIcon,
Typography, Typography,
} from "@mui/material"; } from '@mui/material';
import BoltIcon from "@mui/icons-material/Bolt"; import BoltIcon from '@mui/icons-material/Bolt';
import PublicIcon from "@mui/icons-material/Public"; import PublicIcon from '@mui/icons-material/Public';
import DnsIcon from "@mui/icons-material/Dns"; import DnsIcon from '@mui/icons-material/Dns';
import WebIcon from "@mui/icons-material/Web"; import WebIcon from '@mui/icons-material/Web';
import FavoriteIcon from "@mui/icons-material/Favorite"; import FavoriteIcon from '@mui/icons-material/Favorite';
import GitHubIcon from "@mui/icons-material/GitHub"; import GitHubIcon from '@mui/icons-material/GitHub';
import EqualizerIcon from "@mui/icons-material/Equalizer"; import EqualizerIcon from '@mui/icons-material/Equalizer';
import { AmbossIcon, BitcoinSignIcon } from "../Icons"; import { AmbossIcon, BitcoinSignIcon } from '../Icons';
import { pn } from "../../utils/prettyNumbers"; import { pn } from '../../utils/prettyNumbers';
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
@ -37,7 +37,7 @@ type Props = {
robosatsRunningCommitHash: string; robosatsRunningCommitHash: string;
lastDayVolume: number; lastDayVolume: number;
lifetimeVolume: number; lifetimeVolume: number;
} };
const StatsDialog = ({ const StatsDialog = ({
isOpen, isOpen,
@ -58,11 +58,13 @@ const StatsDialog = ({
<Dialog <Dialog
open={isOpen} open={isOpen}
onClose={handleClickCloseStatsForNerds} onClose={handleClickCloseStatsForNerds}
aria-labelledby="stats-for-nerds-dialog-title" aria-labelledby='stats-for-nerds-dialog-title'
aria-describedby="stats-for-nerds-description" aria-describedby='stats-for-nerds-description'
> >
<DialogContent> <DialogContent>
<Typography component="h5" variant="h5">{t("Stats For Nerds")}</Typography> <Typography component='h5' variant='h5'>
{t('Stats For Nerds')}
</Typography>
<List dense> <List dense>
<Divider /> <Divider />
@ -71,21 +73,21 @@ const StatsDialog = ({
<ListItemIcon> <ListItemIcon>
<BoltIcon /> <BoltIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary={lndVersion} secondary={t("LND version")} /> <ListItemText primary={lndVersion} secondary={t('LND version')} />
</ListItem> </ListItem>
<Divider /> <Divider />
{network === "testnet" ? ( {network === 'testnet' ? (
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<DnsIcon /> <DnsIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={nodeAlias}> <ListItemText secondary={nodeAlias}>
<Link <Link
target="_blank" target='_blank'
href={`https://1ml.com/testnet/node/${nodeId}`} href={`https://1ml.com/testnet/node/${nodeId}`}
rel="noreferrer" rel='noreferrer'
> >
{`${nodeId.slice(0, 12)}... (1ML)`} {`${nodeId.slice(0, 12)}... (1ML)`}
</Link> </Link>
@ -97,11 +99,7 @@ const StatsDialog = ({
<AmbossIcon /> <AmbossIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={nodeAlias}> <ListItemText secondary={nodeAlias}>
<Link <Link target='_blank' href={`https://amboss.space/node/${nodeId}`} rel='noreferrer'>
target="_blank"
href={`https://amboss.space/node/${nodeId}`}
rel="noreferrer"
>
{`${nodeId.slice(0, 12)}... (AMBOSS)`} {`${nodeId.slice(0, 12)}... (AMBOSS)`}
</Link> </Link>
</ListItemText> </ListItemText>
@ -115,11 +113,7 @@ const StatsDialog = ({
<WebIcon /> <WebIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={alternativeName}> <ListItemText secondary={alternativeName}>
<Link <Link target='_blank' href={`http://${alternativeSite}`} rel='noreferrer'>
target="_blank"
href={`http://${alternativeSite}`}
rel="noreferrer"
>
{`${alternativeSite.slice(0, 12)}...onion`} {`${alternativeSite.slice(0, 12)}...onion`}
</Link> </Link>
</ListItemText> </ListItemText>
@ -131,11 +125,11 @@ const StatsDialog = ({
<ListItemIcon> <ListItemIcon>
<GitHubIcon /> <GitHubIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={t("Currently running commit hash")}> <ListItemText secondary={t('Currently running commit hash')}>
<Link <Link
target="_blank" target='_blank'
href={`https://github.com/Reckless-Satoshi/robosats/tree/${robosatsRunningCommitHash}`} href={`https://github.com/Reckless-Satoshi/robosats/tree/${robosatsRunningCommitHash}`}
rel="noreferrer" rel='noreferrer'
> >
{`${robosatsRunningCommitHash.slice(0, 12)}...`} {`${robosatsRunningCommitHash.slice(0, 12)}...`}
</Link> </Link>
@ -148,10 +142,17 @@ const StatsDialog = ({
<ListItemIcon> <ListItemIcon>
<EqualizerIcon /> <EqualizerIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={t("24h contracted volume")}> <ListItemText secondary={t('24h contracted volume')}>
<div style={{ cursor: "pointer", display: "flex", alignItems: "center", flexWrap: "wrap" }}> <div
style={{
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
}}
>
{pn(lastDayVolume)} {pn(lastDayVolume)}
<BitcoinSignIcon sx={{ width: 14,height: 14 }} color={"text.secondary"} /> <BitcoinSignIcon sx={{ width: 14, height: 14 }} color={'text.secondary'} />
</div> </div>
</ListItemText> </ListItemText>
</ListItem> </ListItem>
@ -162,10 +163,17 @@ const StatsDialog = ({
<ListItemIcon> <ListItemIcon>
<EqualizerIcon /> <EqualizerIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText secondary={t("Lifetime contracted volume")}> <ListItemText secondary={t('Lifetime contracted volume')}>
<div style={{ cursor: "pointer", display: "flex",alignItems: "center", flexWrap: "wrap" }}> <div
style={{
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
}}
>
{pn(lifetimeVolume)} {pn(lifetimeVolume)}
<BitcoinSignIcon sx={{ width: 14, height: 14 }} color={"text.secondary"} /> <BitcoinSignIcon sx={{ width: 14, height: 14 }} color={'text.secondary'} />
</div> </div>
</ListItemText> </ListItemText>
</ListItem> </ListItem>
@ -177,14 +185,21 @@ const StatsDialog = ({
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={ primary={
<div style={{ display: "flex", alignItems: "center", justifyContent: "left", flexWrap: "wrap" }}> <div
<span>{`${t("Made with")} `}</span> style={{
<FavoriteIcon sx={{ color: "#ff0000", height: "22px", width: "22px" }} /> display: 'flex',
<span>{` ${t("and")} `}</span> alignItems: 'center',
<BoltIcon sx={{ color: "#fcba03", height: "23px",width: "23px" }} /> justifyContent: 'left',
flexWrap: 'wrap',
}}
>
<span>{`${t('Made with')} `}</span>
<FavoriteIcon sx={{ color: '#ff0000', height: '22px', width: '22px' }} />
<span>{` ${t('and')} `}</span>
<BoltIcon sx={{ color: '#fcba03', height: '23px', width: '23px' }} />
</div> </div>
} }
secondary={t("... somewhere on Earth!")} secondary={t('... somewhere on Earth!')}
/> />
</ListItem> </ListItem>
</List> </List>

View File

@ -1,19 +1,19 @@
import React from "react"; import React from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
DialogTitle, DialogTitle,
Tooltip, Tooltip,
IconButton, IconButton,
TextField, TextField,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogContentText, DialogContentText,
Button, Button,
Grid, Grid,
} from "@mui/material" } from '@mui/material';
import { getCookie } from "../../utils/cookies"; import { getCookie } from '../../utils/cookies';
import ContentCopy from "@mui/icons-material/ContentCopy"; import ContentCopy from '@mui/icons-material/ContentCopy';
type Props = { type Props = {
open: boolean; open: boolean;
@ -22,10 +22,10 @@ type Props = {
onClickCopy: () => void; onClickCopy: () => void;
onClickBack: () => void; onClickBack: () => void;
onClickDone: () => void; onClickDone: () => void;
} };
const StoreTokenDialog = ({ const StoreTokenDialog = ({
open, open,
onClose, onClose,
copyIconColor, copyIconColor,
onClickCopy, onClickCopy,
@ -35,46 +35,45 @@ const StoreTokenDialog = ({
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Dialog <Dialog open={open} onClose={onClose}>
open={open} <DialogTitle>{t('Store your robot token')}</DialogTitle>
onClose={onClose}
>
<DialogTitle >
{t("Store your robot token")}
</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText> <DialogContentText>
{t("You might need to recover your robot avatar in the future: store it safely. You can simply copy it into another application.")} {t(
'You might need to recover your robot avatar in the future: store it safely. You can simply copy it into another application.',
)}
</DialogContentText> </DialogContentText>
<br/> <br />
<Grid align="center"> <Grid align='center'>
<TextField <TextField
sx={{width:"100%", maxWidth:"550px"}} sx={{ width: '100%', maxWidth: '550px' }}
disabled disabled
label={t("Back it up!")} label={t('Back it up!')}
value={getCookie("robot_token")} value={getCookie('robot_token')}
variant='filled' variant='filled'
size='small' size='small'
InputProps={{ InputProps={{
endAdornment: endAdornment: (
<Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}> <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
<IconButton onClick={onClickCopy}> <IconButton onClick={onClickCopy}>
<ContentCopy color={copyIconColor}/> <ContentCopy color={copyIconColor} />
</IconButton> </IconButton>
</Tooltip>, </Tooltip>
}} ),
/> }}
/>
</Grid> </Grid>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClickBack} autoFocus>{t("Go back")}</Button> <Button onClick={onClickBack} autoFocus>
<Button onClick={onClickDone}>{t("Done")}</Button> {t('Go back')}
</Button>
<Button onClick={onClickDone}>{t('Done')}</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
) );
} };
export default StoreTokenDialog; export default StoreTokenDialog;

View File

@ -1,10 +1,9 @@
export { default as AuditPGPDialog } from "./AuditPGP"; export { default as AuditPGPDialog } from './AuditPGP';
export { default as CommunityDialog } from "./Community"; export { default as CommunityDialog } from './Community';
export { default as InfoDialog } from "./Info"; export { default as InfoDialog } from './Info';
export { default as LearnDialog } from "./Learn"; export { default as LearnDialog } from './Learn';
export { default as NoRobotDialog } from "./NoRobot"; export { default as NoRobotDialog } from './NoRobot';
export { default as StoreTokenDialog } from "./StoreToken"; export { default as StoreTokenDialog } from './StoreToken';
export { default as ExchangeSummaryDialog } from "./ExchangeSummary"; export { default as ExchangeSummaryDialog } from './ExchangeSummary';
export { default as ProfileDialog } from "./Profile"; export { default as ProfileDialog } from './Profile';
export { default as StatsDialog } from "./Stats"; export { default as StatsDialog } from './Stats';

View File

@ -1,17 +1,30 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { withTranslation } from "react-i18next"; import { withTranslation } from 'react-i18next';
import {Button, IconButton, Badge, Tooltip, TextField, Grid, Container, Card, CardHeader, Paper, Avatar, Typography} from "@mui/material"; import {
Button,
IconButton,
Badge,
Tooltip,
TextField,
Grid,
Container,
Card,
CardHeader,
Paper,
Avatar,
Typography,
} from '@mui/material';
import ReconnectingWebSocket from 'reconnecting-websocket'; import ReconnectingWebSocket from 'reconnecting-websocket';
import { encryptMessage , decryptMessage} from "../utils/pgp"; import { encryptMessage, decryptMessage } from '../utils/pgp';
import { getCookie } from "../utils/cookies"; import { getCookie } from '../utils/cookies';
import { saveAsJson } from "../utils/saveFile"; import { saveAsJson } from '../utils/saveFile';
import { copyToClipboard } from "../utils/clipboard"; import { copyToClipboard } from '../utils/clipboard';
import { AuditPGPDialog } from "./Dialogs" import { AuditPGPDialog } from './Dialogs';
// Icons // Icons
import CheckIcon from '@mui/icons-material/Check'; import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import ContentCopy from "@mui/icons-material/ContentCopy"; import ContentCopy from '@mui/icons-material/ContentCopy';
import VisibilityIcon from '@mui/icons-material/Visibility'; import VisibilityIcon from '@mui/icons-material/Visibility';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import KeyIcon from '@mui/icons-material/Key'; import KeyIcon from '@mui/icons-material/Key';
@ -23,120 +36,157 @@ class Chat extends Component {
} }
state = { state = {
own_pub_key: getCookie('pub_key').split('\\').join('\n'), own_pub_key: getCookie('pub_key').split('\\').join('\n'),
own_enc_priv_key: getCookie('enc_priv_key').split('\\').join('\n'), own_enc_priv_key: getCookie('enc_priv_key').split('\\').join('\n'),
peer_pub_key: null, peer_pub_key: null,
token: getCookie('robot_token'), token: getCookie('robot_token'),
messages: [], messages: [],
value:'', value: '',
connected: false, connected: false,
peer_connected: false, peer_connected: false,
audit: false, audit: false,
showPGP: new Array, showPGP: new Array(),
waitingEcho: false, waitingEcho: false,
lastSent: '---BLANK---', lastSent: '---BLANK---',
latestIndex: 0, latestIndex: 0,
scrollNow:false, scrollNow: false,
}; };
rws = new ReconnectingWebSocket('ws://' + window.location.host + '/ws/chat/' + this.props.orderId + '/', [], {connectionTimeout: 15000}); rws = new ReconnectingWebSocket(
'ws://' + window.location.host + '/ws/chat/' + this.props.orderId + '/',
[],
{ connectionTimeout: 15000 },
);
componentDidMount() { componentDidMount() {
this.rws.addEventListener('open', () => { this.rws.addEventListener('open', () => {
console.log('Connected!'); console.log('Connected!');
this.setState({connected: true}); this.setState({ connected: true });
this.rws.send(JSON.stringify({ this.rws.send(
type: "message", JSON.stringify({
message: this.state.own_pub_key, type: 'message',
nick: this.props.ur_nick, message: this.state.own_pub_key,
})); nick: this.props.ur_nick,
}),
);
}); });
this.rws.addEventListener('message', (message) => { this.rws.addEventListener('message', (message) => {
const dataFromServer = JSON.parse(message.data); const dataFromServer = JSON.parse(message.data);
console.log('Got reply!', dataFromServer.type); console.log('Got reply!', dataFromServer.type);
console.log('PGP message index', dataFromServer.index, ' latestIndex ',this.state.latestIndex); console.log(
if (dataFromServer){ 'PGP message index',
console.log(dataFromServer) dataFromServer.index,
this.setState({peer_connected: dataFromServer.peer_connected}) ' latestIndex ',
this.state.latestIndex,
);
if (dataFromServer) {
console.log(dataFromServer);
this.setState({ peer_connected: dataFromServer.peer_connected });
// If we receive our own key on a message // If we receive our own key on a message
if (dataFromServer.message == this.state.own_pub_key){console.log("OWN PUB KEY RECEIVED!!")} if (dataFromServer.message == this.state.own_pub_key) {
console.log('OWN PUB KEY RECEIVED!!');
}
// If we receive a public key other than ours (our peer key!) // If we receive a public key other than ours (our peer key!)
if (dataFromServer.message.substring(0,36) == `-----BEGIN PGP PUBLIC KEY BLOCK-----` && dataFromServer.message != this.state.own_pub_key) { if (
if (dataFromServer.message == this.state.peer_pub_key){ dataFromServer.message.substring(0, 36) == `-----BEGIN PGP PUBLIC KEY BLOCK-----` &&
console.log("PEER HAS RECONNECTED USING HIS PREVIOUSLY KNOWN PUBKEY") dataFromServer.message != this.state.own_pub_key
} else if (dataFromServer.message != this.state.peer_pub_key & this.state.peer_pub_key != null){ ) {
console.log("PEER PUBKEY HAS CHANGED") if (dataFromServer.message == this.state.peer_pub_key) {
console.log('PEER HAS RECONNECTED USING HIS PREVIOUSLY KNOWN PUBKEY');
} else if (
(dataFromServer.message != this.state.peer_pub_key) &
(this.state.peer_pub_key != null)
) {
console.log('PEER PUBKEY HAS CHANGED');
} }
console.log("PEER PUBKEY RECEIVED!!") console.log('PEER PUBKEY RECEIVED!!');
this.setState({peer_pub_key:dataFromServer.message}) this.setState({ peer_pub_key: dataFromServer.message });
// After receiving the peer pubkey we ask the server for the historic messages if any // After receiving the peer pubkey we ask the server for the historic messages if any
this.rws.send(JSON.stringify({ this.rws.send(
type: "message", JSON.stringify({
type: 'message',
message: `-----SERVE HISTORY-----`, message: `-----SERVE HISTORY-----`,
nick: this.props.ur_nick, nick: this.props.ur_nick,
})) }),
} else );
}
// If we receive an encrypted message // If we receive an encrypted message
if (dataFromServer.message.substring(0,27) == `-----BEGIN PGP MESSAGE-----` && dataFromServer.index > this.state.latestIndex){ else if (
dataFromServer.message.substring(0, 27) == `-----BEGIN PGP MESSAGE-----` &&
dataFromServer.index > this.state.latestIndex
) {
decryptMessage( decryptMessage(
dataFromServer.message.split('\\').join('\n'), dataFromServer.message.split('\\').join('\n'),
dataFromServer.user_nick == this.props.ur_nick ? this.state.own_pub_key : this.state.peer_pub_key, dataFromServer.user_nick == this.props.ur_nick
this.state.own_enc_priv_key, ? this.state.own_pub_key
this.state.token) : this.state.peer_pub_key,
.then((decryptedData) => this.state.own_enc_priv_key,
this.setState((state) => this.state.token,
({ ).then((decryptedData) =>
this.setState((state) => ({
scrollNow: true, scrollNow: true,
waitingEcho: this.state.waitingEcho == true ? (decryptedData.decryptedMessage == this.state.lastSent ? false: true ) : false, waitingEcho:
lastSent: decryptedData.decryptedMessage == this.state.lastSent ? '----BLANK----': this.state.lastSent, this.state.waitingEcho == true
latestIndex: dataFromServer.index > this.state.latestIndex ? dataFromServer.index : this.state.latestIndex, ? decryptedData.decryptedMessage == this.state.lastSent
messages: [...state.messages, ? false
{ : true
index: dataFromServer.index, : false,
encryptedMessage: dataFromServer.message.split('\\').join('\n'), lastSent:
plainTextMessage: decryptedData.decryptedMessage, decryptedData.decryptedMessage == this.state.lastSent
validSignature: decryptedData.validSignature, ? '----BLANK----'
userNick: dataFromServer.user_nick, : this.state.lastSent,
time: dataFromServer.time latestIndex:
}].sort(function(a,b) { dataFromServer.index > this.state.latestIndex
? dataFromServer.index
: this.state.latestIndex,
messages: [
...state.messages,
{
index: dataFromServer.index,
encryptedMessage: dataFromServer.message.split('\\').join('\n'),
plainTextMessage: decryptedData.decryptedMessage,
validSignature: decryptedData.validSignature,
userNick: dataFromServer.user_nick,
time: dataFromServer.time,
},
].sort(function (a, b) {
// order the message array by their index (increasing) // order the message array by their index (increasing)
return a.index - b.index return a.index - b.index;
}), }),
}) })),
)); );
}
} else
// We allow plaintext communication. The user must write # to start // We allow plaintext communication. The user must write # to start
// If we receive an plaintext message // If we receive an plaintext message
if (dataFromServer.message.substring(0,1) == "#"){ else if (dataFromServer.message.substring(0, 1) == '#') {
console.log("Got plaintext message", dataFromServer.message) console.log('Got plaintext message', dataFromServer.message);
this.setState((state) => this.setState((state) => ({
({ scrollNow: true,
scrollNow: true, messages: [
messages: [...state.messages, ...state.messages,
{ {
index: this.state.latestIndex + 0.001, index: this.state.latestIndex + 0.001,
encryptedMessage: dataFromServer.message, encryptedMessage: dataFromServer.message,
plainTextMessage: dataFromServer.message, plainTextMessage: dataFromServer.message,
validSignature: false, validSignature: false,
userNick: dataFromServer.user_nick, userNick: dataFromServer.user_nick,
time: (new Date).toString(), time: new Date().toString(),
}]})); },
} ],
}));
}
} }
}); });
this.rws.addEventListener('close', () => { this.rws.addEventListener('close', () => {
console.log('Socket is closed. Reconnect will be attempted'); console.log('Socket is closed. Reconnect will be attempted');
this.setState({connected: false}); this.setState({ connected: false });
}); });
this.rws.addEventListener('error', () => { this.rws.addEventListener('error', () => {
@ -145,216 +195,401 @@ class Chat extends Component {
} }
componentDidUpdate() { componentDidUpdate() {
// Only fire the scroll and audio when the reason for Update is a new message // Only fire the scroll and audio when the reason for Update is a new message
if (this.state.scrollNow){ if (this.state.scrollNow) {
const audio = new Audio(`/static/assets/sounds/chat-open.mp3`) const audio = new Audio(`/static/assets/sounds/chat-open.mp3`);
audio.play(); audio.play();
this.scrollToBottom(); this.scrollToBottom();
this.setState({scrollNow:false}); this.setState({ scrollNow: false });
} }
} }
scrollToBottom = () => { scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth" }); this.messagesEnd.scrollIntoView({ behavior: 'smooth' });
} };
onButtonClicked = (e) => { onButtonClicked = (e) => {
// If input string contains token. Do not set message // If input string contains token. Do not set message
if(this.state.value.indexOf(this.state.token) !== -1){ if (this.state.value.indexOf(this.state.token) !== -1) {
alert(`Aye! You just sent your own robot token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`) alert(
this.setState({value: ""}); `Aye! You just sent your own robot token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`,
);
this.setState({ value: '' });
} }
// If input string contains '#' send unencrypted and unlogged message // If input string contains '#' send unencrypted and unlogged message
else if(this.state.value.substring(0,1)=='#'){ else if (this.state.value.substring(0, 1) == '#') {
this.rws.send(JSON.stringify({ this.rws.send(
type: "message", JSON.stringify({
type: 'message',
message: this.state.value, message: this.state.value,
nick: this.props.ur_nick, nick: this.props.ur_nick,
})); }),
this.setState({value: ""}); );
this.setState({ value: '' });
} }
// Else if message is not empty send message // Else if message is not empty send message
else if(this.state.value!=''){ else if (this.state.value != '') {
this.setState({value: "", waitingEcho: true, lastSent:this.state.value}) this.setState({ value: '', waitingEcho: true, lastSent: this.state.value });
encryptMessage(this.state.value, this.state.own_pub_key, this.state.peer_pub_key, this.state.own_enc_priv_key, this.state.token) encryptMessage(
.then((encryptedMessage) => this.state.value,
console.log("Sending Encrypted MESSAGE", encryptedMessage) & this.state.own_pub_key,
this.rws.send(JSON.stringify({ this.state.peer_pub_key,
type: "message", this.state.own_enc_priv_key,
message: encryptedMessage.split('\n').join('\\'), this.state.token,
nick: this.props.ur_nick, ).then(
}) (encryptedMessage) =>
) console.log('Sending Encrypted MESSAGE', encryptedMessage) &
this.rws.send(
JSON.stringify({
type: 'message',
message: encryptedMessage.split('\n').join('\\'),
nick: this.props.ur_nick,
}),
),
); );
} }
e.preventDefault(); e.preventDefault();
} };
createJsonFile = () => { createJsonFile = () => {
return ({ return {
"credentials": { credentials: {
"own_public_key": this.state.own_pub_key, own_public_key: this.state.own_pub_key,
"peer_public_key":this.state.peer_pub_key, peer_public_key: this.state.peer_pub_key,
"encrypted_private_key":this.state.own_enc_priv_key, encrypted_private_key: this.state.own_enc_priv_key,
"passphrase":this.state.token}, passphrase: this.state.token,
"messages": this.state.messages, },
}) messages: this.state.messages,
} };
};
messageCard = (props) => { messageCard = (props) => {
const { t } = this.props; const { t } = this.props;
return( return (
<Card elevation={5} align="left" > <Card elevation={5} align='left'>
<CardHeader sx={{color: '#333333'}} <CardHeader
sx={{ color: '#333333' }}
avatar={ avatar={
<Badge variant="dot" overlap="circular" badgeContent="" color={props.userConnected ? "success" : "error"}> <Badge
<Avatar className="flippedSmallAvatar" variant='dot'
overlap='circular'
badgeContent=''
color={props.userConnected ? 'success' : 'error'}
>
<Avatar
className='flippedSmallAvatar'
alt={props.message.userNick} alt={props.message.userNick}
src={window.location.origin +'/static/assets/avatars/' + props.message.userNick + '.png'} src={
/> window.location.origin +
'/static/assets/avatars/' +
props.message.userNick +
'.png'
}
/>
</Badge> </Badge>
} }
style={{backgroundColor: props.cardColor}} style={{ backgroundColor: props.cardColor }}
title={ title={
<Tooltip placement="top" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t(props.message.validSignature ? "Verified signature by {{nickname}}": "Cannot verify signature of {{nickname}}",{"nickname": props.message.userNick})}> <Tooltip
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap', position:'relative',left:-5, width:240}}> placement='top'
<div style={{width:168,display:'flex',alignItems:'center', flexWrap:'wrap'}}> enterTouchDelay={0}
enterDelay={500}
enterNextDelay={2000}
title={t(
props.message.validSignature
? 'Verified signature by {{nickname}}'
: 'Cannot verify signature of {{nickname}}',
{ nickname: props.message.userNick },
)}
>
<div
style={{
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
position: 'relative',
left: -5,
width: 240,
}}
>
<div
style={{ width: 168, display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}
>
{props.message.userNick} {props.message.userNick}
{props.message.validSignature ? {props.message.validSignature ? (
<CheckIcon sx={{height:16}} color="success"/> <CheckIcon sx={{ height: 16 }} color='success' />
: ) : (
<CloseIcon sx={{height:16}} color="error"/> <CloseIcon sx={{ height: 16 }} color='error' />
} )}
</div> </div>
<div style={{width:20}}> <div style={{ width: 20 }}>
<IconButton sx={{height:18,width:18}} <IconButton
onClick={()=> sx={{ height: 18, width: 18 }}
this.setState(prevState => { onClick={() =>
const newShowPGP = [...prevState.showPGP]; this.setState((prevState) => {
newShowPGP[props.index] = !newShowPGP[props.index]; const newShowPGP = [...prevState.showPGP];
return {showPGP: newShowPGP}; newShowPGP[props.index] = !newShowPGP[props.index];
})}> return { showPGP: newShowPGP };
<VisibilityIcon color={this.state.showPGP[props.index]? "primary":"inherit"} sx={{height:16,width:16,color:this.state.showPGP[props.index]? "primary":"#333333"}}/> })
}
>
<VisibilityIcon
color={this.state.showPGP[props.index] ? 'primary' : 'inherit'}
sx={{
height: 16,
width: 16,
color: this.state.showPGP[props.index] ? 'primary' : '#333333',
}}
/>
</IconButton> </IconButton>
</div> </div>
<div style={{width:20}}> <div style={{ width: 20 }}>
<Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}> <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
<IconButton sx={{height:18,width:18}} <IconButton
onClick={()=> copyToClipboard(this.state.showPGP[props.index] ? props.message.encryptedMessage : props.message.plainTextMessage)}> sx={{ height: 18, width: 18 }}
<ContentCopy sx={{height:16,width:16,color:'#333333'}}/> onClick={() =>
copyToClipboard(
this.state.showPGP[props.index]
? props.message.encryptedMessage
: props.message.plainTextMessage,
)
}
>
<ContentCopy sx={{ height: 16, width: 16, color: '#333333' }} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</div> </div>
</div> </div>
</Tooltip> </Tooltip>
} }
subheader={this.state.showPGP[props.index] ? <a> {props.message.time} <br/> {"Valid signature: " + props.message.validSignature} <br/> {props.message.encryptedMessage} </a> : props.message.plainTextMessage} subheader={
subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '200px', color: '#444444', fontSize: this.state.showPGP[props.index]? 11 : null }}} this.state.showPGP[props.index] ? (
<a>
{' '}
{props.message.time} <br /> {'Valid signature: ' + props.message.validSignature}{' '}
<br /> {props.message.encryptedMessage}{' '}
</a>
) : (
props.message.plainTextMessage
)
}
subheaderTypographyProps={{
sx: {
wordWrap: 'break-word',
width: '200px',
color: '#444444',
fontSize: this.state.showPGP[props.index] ? 11 : null,
},
}}
/> />
</Card> </Card>
) );
} };
render() { render() {
const { t } = this.props; const { t } = this.props;
return ( return (
<Container component="main"> <Container component='main'>
<Grid container spacing={0.5}> <Grid container spacing={0.5}>
<Grid item xs={0.3}/> <Grid item xs={0.3} />
<Grid item xs={5.5}> <Grid item xs={5.5}>
<Paper elevation={1} style={this.state.connected ? {backgroundColor: '#e8ffe6'}: {backgroundColor: '#FFF1C5'}}> <Paper
<Typography variant='caption' sx={{color: '#333333'}}> elevation={1}
{t("You")+": "}{this.state.connected ? t("connected"): t("disconnected")} style={
</Typography> this.state.connected
</Paper> ? { backgroundColor: '#e8ffe6' }
</Grid> : { backgroundColor: '#FFF1C5' }
<Grid item xs={0.4}/>
<Grid item xs={5.5}>
<Paper elevation={1} style={this.state.peer_connected ? {backgroundColor: '#e8ffe6'}: {backgroundColor: '#FFF1C5'}}>
<Typography variant='caption' sx={{color: '#333333'}}>
{t("Peer")+": "}{this.state.peer_connected ? t("connected"): t("disconnected")}
</Typography>
</Paper>
</Grid>
<Grid item xs={0.3}/>
</Grid>
<div style={{position:'relative', left:'-2px', margin:'0 auto', width: '285px'}}>
<Paper elevation={1} style={{height: '300px', maxHeight: '300px' , width: '285px' ,overflow: 'auto', backgroundColor: '#F7F7F7' }}>
{this.state.messages.map((message, index) =>
<li style={{listStyleType:"none"}} key={index}>
{message.userNick == this.props.ur_nick ?
<this.messageCard message={message} index={index} cardColor={'#eeeeee'} userConnected={this.state.connected}/>
:
<this.messageCard message={message} index={index} cardColor={'#fafafa'} userConnected={this.state.peer_connected}/>
} }
</li>)} >
<div style={{ float:"left", clear: "both" }} ref={(el) => { this.messagesEnd = el; }}></div> <Typography variant='caption' sx={{ color: '#333333' }}>
{t('You') + ': '}
{this.state.connected ? t('connected') : t('disconnected')}
</Typography>
</Paper>
</Grid>
<Grid item xs={0.4} />
<Grid item xs={5.5}>
<Paper
elevation={1}
style={
this.state.peer_connected
? { backgroundColor: '#e8ffe6' }
: { backgroundColor: '#FFF1C5' }
}
>
<Typography variant='caption' sx={{ color: '#333333' }}>
{t('Peer') + ': '}
{this.state.peer_connected ? t('connected') : t('disconnected')}
</Typography>
</Paper>
</Grid>
<Grid item xs={0.3} />
</Grid>
<div style={{ position: 'relative', left: '-2px', margin: '0 auto', width: '285px' }}>
<Paper
elevation={1}
style={{
height: '300px',
maxHeight: '300px',
width: '285px',
overflow: 'auto',
backgroundColor: '#F7F7F7',
}}
>
{this.state.messages.map((message, index) => (
<li style={{ listStyleType: 'none' }} key={index}>
{message.userNick == this.props.ur_nick ? (
<this.messageCard
message={message}
index={index}
cardColor={'#eeeeee'}
userConnected={this.state.connected}
/>
) : (
<this.messageCard
message={message}
index={index}
cardColor={'#fafafa'}
userConnected={this.state.peer_connected}
/>
)}
</li>
))}
<div
style={{ float: 'left', clear: 'both' }}
ref={(el) => {
this.messagesEnd = el;
}}
></div>
</Paper> </Paper>
<form noValidate onSubmit={this.onButtonClicked}> <form noValidate onSubmit={this.onButtonClicked}>
<Grid alignItems="stretch" style={{ display: "flex" }}> <Grid alignItems='stretch' style={{ display: 'flex' }}>
<Grid item alignItems="stretch" style={{ display: "flex"}}> <Grid item alignItems='stretch' style={{ display: 'flex' }}>
<TextField <TextField
label={t("Type a message")} label={t('Type a message')}
variant="standard" variant='standard'
size="small" size='small'
helperText={this.state.connected ? (this.state.peer_pub_key ? null : t("Waiting for peer public key...")) : t("Connecting...")} helperText={
this.state.connected
? this.state.peer_pub_key
? null
: t('Waiting for peer public key...')
: t('Connecting...')
}
value={this.state.value} value={this.state.value}
onChange={e => { onChange={(e) => {
this.setState({ value: e.target.value }); this.setState({ value: e.target.value });
this.value = this.state.value; this.value = this.state.value;
}} }}
sx={{width: 219}} sx={{ width: 219 }}
/> />
</Grid> </Grid>
<Grid item alignItems="stretch" style={{ display: "flex" }}> <Grid item alignItems='stretch' style={{ display: 'flex' }}>
<Button sx={{'width':68}} disabled={!this.state.connected || this.state.waitingEcho || this.state.peer_pub_key == null} type="submit" variant="contained" color="primary"> <Button
{this.state.waitingEcho ? sx={{ width: 68 }}
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap', minWidth:68, width:68, position:"relative",left:15}}> disabled={
<div style={{width:20}}><KeyIcon sx={{width:18}}/></div> !this.state.connected ||
<div style={{width:18}}><CircularProgress size={16} thickness={5}/></div> this.state.waitingEcho ||
this.state.peer_pub_key == null
}
type='submit'
variant='contained'
color='primary'
>
{this.state.waitingEcho ? (
<div
style={{
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
minWidth: 68,
width: 68,
position: 'relative',
left: 15,
}}
>
<div style={{ width: 20 }}>
<KeyIcon sx={{ width: 18 }} />
</div>
<div style={{ width: 18 }}>
<CircularProgress size={16} thickness={5} />
</div>
</div> </div>
: ) : (
t("Send") t('Send')
} )}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
</form> </form>
</div> </div>
<div style={{height:4}}/> <div style={{ height: 4 }} />
<Grid container spacing={0}> <Grid container spacing={0}>
<AuditPGPDialog <AuditPGPDialog
open={this.state.audit} open={this.state.audit}
onClose={() => this.setState({audit:false})} onClose={() => this.setState({ audit: false })}
orderId={Number(this.props.orderId)} orderId={Number(this.props.orderId)}
messages={this.state.messages} messages={this.state.messages}
own_pub_key={this.state.own_pub_key} own_pub_key={this.state.own_pub_key}
own_enc_priv_key={this.state.own_enc_priv_key} own_enc_priv_key={this.state.own_enc_priv_key}
peer_pub_key={this.state.peer_pub_key ? this.state.peer_pub_key : "Not received yet"} peer_pub_key={this.state.peer_pub_key ? this.state.peer_pub_key : 'Not received yet'}
passphrase={this.state.token} passphrase={this.state.token}
onClickBack={() => this.setState({audit:false})} onClickBack={() => this.setState({ audit: false })}
/> />
<Grid item xs={6}> <Grid item xs={6}>
<Tooltip placement="bottom" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t("Verify your privacy")}> <Tooltip
<Button size="small" color="primary" variant="outlined" onClick={()=>this.setState({audit:!this.state.audit})}><KeyIcon/>{t("Audit PGP")} </Button> placement='bottom'
enterTouchDelay={0}
enterDelay={500}
enterNextDelay={2000}
title={t('Verify your privacy')}
>
<Button
size='small'
color='primary'
variant='outlined'
onClick={() => this.setState({ audit: !this.state.audit })}
>
<KeyIcon />
{t('Audit PGP')}{' '}
</Button>
</Tooltip> </Tooltip>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<Tooltip placement="bottom" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t("Save full log as a JSON file (messages and credentials)")}> <Tooltip
<Button size="small" color="primary" variant="outlined" onClick={()=>saveAsJson('complete_log_chat_'+this.props.orderId+'.json', this.createJsonFile())}><div style={{width:28,height:20}}><ExportIcon sx={{width:20,height:20}}/></div> {t("Export")} </Button> placement='bottom'
enterTouchDelay={0}
enterDelay={500}
enterNextDelay={2000}
title={t('Save full log as a JSON file (messages and credentials)')}
>
<Button
size='small'
color='primary'
variant='outlined'
onClick={() =>
saveAsJson(
'complete_log_chat_' + this.props.orderId + '.json',
this.createJsonFile(),
)
}
>
<div style={{ width: 28, height: 20 }}>
<ExportIcon sx={{ width: 20, height: 20 }} />
</div>{' '}
{t('Export')}{' '}
</Button>
</Tooltip> </Tooltip>
</Grid> </Grid>
</Grid> </Grid>
</Container> </Container>
) );
} }
} }

View File

@ -1,11 +1,11 @@
import React from "react"; import React from 'react';
import Flags from 'country-flag-icons/react/3x2' import Flags from 'country-flag-icons/react/3x2';
import SwapCallsIcon from '@mui/icons-material/SwapCalls'; import SwapCallsIcon from '@mui/icons-material/SwapCalls';
import { GoldIcon, EarthIcon } from "../Icons"; import { GoldIcon, EarthIcon } from '../Icons';
type Props = { type Props = {
code: string; code: string;
} };
const FlagWithProps = ({ code }: Props): JSX.Element => { const FlagWithProps = ({ code }: Props): JSX.Element => {
const defaultProps = { const defaultProps = {
@ -15,82 +15,80 @@ const FlagWithProps = ({ code }: Props): JSX.Element => {
let flag: JSX.Element | null = null; let flag: JSX.Element | null = null;
if(code === 'AED') flag = <Flags.AE {...defaultProps}/>; if (code === 'AED') flag = <Flags.AE {...defaultProps} />;
if(code === 'AUD') flag = <Flags.AU {...defaultProps}/>; if (code === 'AUD') flag = <Flags.AU {...defaultProps} />;
if(code === 'ARS') flag = <Flags.AR {...defaultProps}/>; if (code === 'ARS') flag = <Flags.AR {...defaultProps} />;
if(code === 'BRL') flag = <Flags.BR {...defaultProps}/>; if (code === 'BRL') flag = <Flags.BR {...defaultProps} />;
if(code === 'BYN') flag = <Flags.BY {...defaultProps}/>; if (code === 'BYN') flag = <Flags.BY {...defaultProps} />;
if(code === 'CAD') flag = <Flags.CA {...defaultProps}/>; if (code === 'CAD') flag = <Flags.CA {...defaultProps} />;
if(code === 'CHF') flag = <Flags.CH {...defaultProps}/>; if (code === 'CHF') flag = <Flags.CH {...defaultProps} />;
if(code === 'CLP') flag = <Flags.CL {...defaultProps}/>; if (code === 'CLP') flag = <Flags.CL {...defaultProps} />;
if(code === 'CNY') flag = <Flags.CN {...defaultProps}/>; if (code === 'CNY') flag = <Flags.CN {...defaultProps} />;
if(code === 'EGP') flag = <Flags.EG {...defaultProps}/>; if (code === 'EGP') flag = <Flags.EG {...defaultProps} />;
if(code === 'EUR') flag = <Flags.EU {...defaultProps}/>; if (code === 'EUR') flag = <Flags.EU {...defaultProps} />;
if(code === 'HRK') flag = <Flags.HR {...defaultProps}/>; if (code === 'HRK') flag = <Flags.HR {...defaultProps} />;
if(code === 'CZK') flag = <Flags.CZ {...defaultProps}/>; if (code === 'CZK') flag = <Flags.CZ {...defaultProps} />;
if(code === 'DKK') flag = <Flags.DK {...defaultProps}/>; if (code === 'DKK') flag = <Flags.DK {...defaultProps} />;
if(code === 'GBP') flag = <Flags.GB {...defaultProps}/>; if (code === 'GBP') flag = <Flags.GB {...defaultProps} />;
if(code === 'HKD') flag = <Flags.HK {...defaultProps}/>; if (code === 'HKD') flag = <Flags.HK {...defaultProps} />;
if(code === 'HUF') flag = <Flags.HU {...defaultProps}/>; if (code === 'HUF') flag = <Flags.HU {...defaultProps} />;
if(code === 'INR') flag = <Flags.IN {...defaultProps}/>; if (code === 'INR') flag = <Flags.IN {...defaultProps} />;
if(code === 'ISK') flag = <Flags.IS {...defaultProps}/>; if (code === 'ISK') flag = <Flags.IS {...defaultProps} />;
if(code === 'JPY') flag = <Flags.JP {...defaultProps}/>; if (code === 'JPY') flag = <Flags.JP {...defaultProps} />;
if(code === 'KRW') flag = <Flags.KR {...defaultProps}/>; if (code === 'KRW') flag = <Flags.KR {...defaultProps} />;
if(code === 'LKR') flag = <Flags.LK {...defaultProps}/>; if (code === 'LKR') flag = <Flags.LK {...defaultProps} />;
if(code === 'MAD') flag = <Flags.MA {...defaultProps}/>; if (code === 'MAD') flag = <Flags.MA {...defaultProps} />;
if(code === 'MXN') flag = <Flags.MX {...defaultProps}/>; if (code === 'MXN') flag = <Flags.MX {...defaultProps} />;
if(code === 'NOK') flag = <Flags.NO {...defaultProps}/>; if (code === 'NOK') flag = <Flags.NO {...defaultProps} />;
if(code === 'NZD') flag = <Flags.NZ {...defaultProps}/>; if (code === 'NZD') flag = <Flags.NZ {...defaultProps} />;
if(code === 'PLN') flag = <Flags.PL {...defaultProps}/>; if (code === 'PLN') flag = <Flags.PL {...defaultProps} />;
if(code === 'RON') flag = <Flags.RO {...defaultProps}/>; if (code === 'RON') flag = <Flags.RO {...defaultProps} />;
if(code === 'RUB') flag = <Flags.RU {...defaultProps}/>; if (code === 'RUB') flag = <Flags.RU {...defaultProps} />;
if(code === 'SEK') flag = <Flags.SE {...defaultProps}/>; if (code === 'SEK') flag = <Flags.SE {...defaultProps} />;
if(code === 'SGD') flag = <Flags.SG {...defaultProps}/>; if (code === 'SGD') flag = <Flags.SG {...defaultProps} />;
if(code === 'VES') flag = <Flags.VE {...defaultProps}/>; if (code === 'VES') flag = <Flags.VE {...defaultProps} />;
if(code === 'TRY') flag = <Flags.TR {...defaultProps}/>; if (code === 'TRY') flag = <Flags.TR {...defaultProps} />;
if(code === 'USD') flag = <Flags.US {...defaultProps}/>; if (code === 'USD') flag = <Flags.US {...defaultProps} />;
if(code === 'ZAR') flag = <Flags.ZA {...defaultProps}/>; if (code === 'ZAR') flag = <Flags.ZA {...defaultProps} />;
if(code === 'COP') flag = <Flags.CO {...defaultProps}/>; if (code === 'COP') flag = <Flags.CO {...defaultProps} />;
if(code === 'PEN') flag = <Flags.PE {...defaultProps}/>; if (code === 'PEN') flag = <Flags.PE {...defaultProps} />;
if(code === 'UYU') flag = <Flags.UY {...defaultProps}/>; if (code === 'UYU') flag = <Flags.UY {...defaultProps} />;
if(code === 'PYG') flag = <Flags.PY {...defaultProps}/>; if (code === 'PYG') flag = <Flags.PY {...defaultProps} />;
if(code === 'BOB') flag = <Flags.BO {...defaultProps}/>; if (code === 'BOB') flag = <Flags.BO {...defaultProps} />;
if(code === 'IDR') flag = <Flags.ID {...defaultProps}/>; if (code === 'IDR') flag = <Flags.ID {...defaultProps} />;
if(code === 'ANG') flag = <Flags.CW {...defaultProps}/>; if (code === 'ANG') flag = <Flags.CW {...defaultProps} />;
if(code === 'CRC') flag = <Flags.CR {...defaultProps}/>; if (code === 'CRC') flag = <Flags.CR {...defaultProps} />;
if(code === 'CUP') flag = <Flags.CU {...defaultProps}/>; if (code === 'CUP') flag = <Flags.CU {...defaultProps} />;
if(code === 'DOP') flag = <Flags.DO {...defaultProps}/>; if (code === 'DOP') flag = <Flags.DO {...defaultProps} />;
if(code === 'GHS') flag = <Flags.GH {...defaultProps}/>; if (code === 'GHS') flag = <Flags.GH {...defaultProps} />;
if(code === 'GTQ') flag = <Flags.GT {...defaultProps}/>; if (code === 'GTQ') flag = <Flags.GT {...defaultProps} />;
if(code === 'ILS') flag = <Flags.IL {...defaultProps}/>; if (code === 'ILS') flag = <Flags.IL {...defaultProps} />;
if(code === 'JMD') flag = <Flags.JM {...defaultProps}/>; if (code === 'JMD') flag = <Flags.JM {...defaultProps} />;
if(code === 'KES') flag = <Flags.KE {...defaultProps}/>; if (code === 'KES') flag = <Flags.KE {...defaultProps} />;
if(code === 'KZT') flag = <Flags.KZ {...defaultProps}/>; if (code === 'KZT') flag = <Flags.KZ {...defaultProps} />;
if(code === 'MYR') flag = <Flags.MY {...defaultProps}/>; if (code === 'MYR') flag = <Flags.MY {...defaultProps} />;
if(code === 'NAD') flag = <Flags.NA {...defaultProps}/>; if (code === 'NAD') flag = <Flags.NA {...defaultProps} />;
if(code === 'NGN') flag = <Flags.NG {...defaultProps}/>; if (code === 'NGN') flag = <Flags.NG {...defaultProps} />;
if(code === 'AZN') flag = <Flags.AZ {...defaultProps}/>; if (code === 'AZN') flag = <Flags.AZ {...defaultProps} />;
if(code === 'PAB') flag = <Flags.PA {...defaultProps}/>; if (code === 'PAB') flag = <Flags.PA {...defaultProps} />;
if(code === 'PHP') flag = <Flags.PH {...defaultProps}/>; if (code === 'PHP') flag = <Flags.PH {...defaultProps} />;
if(code === 'PKR') flag = <Flags.PK {...defaultProps}/>; if (code === 'PKR') flag = <Flags.PK {...defaultProps} />;
if(code === 'QAR') flag = <Flags.QA {...defaultProps}/>; if (code === 'QAR') flag = <Flags.QA {...defaultProps} />;
if(code === 'SAR') flag = <Flags.SA {...defaultProps}/>; if (code === 'SAR') flag = <Flags.SA {...defaultProps} />;
if(code === 'THB') flag = <Flags.TH {...defaultProps}/>; if (code === 'THB') flag = <Flags.TH {...defaultProps} />;
if(code === 'TTD') flag = <Flags.TT {...defaultProps}/>; if (code === 'TTD') flag = <Flags.TT {...defaultProps} />;
if(code === 'VND') flag = <Flags.VN {...defaultProps}/>; if (code === 'VND') flag = <Flags.VN {...defaultProps} />;
if(code === 'XOF') flag = <Flags.BJ {...defaultProps}/>; if (code === 'XOF') flag = <Flags.BJ {...defaultProps} />;
if(code === 'TWD') flag = <Flags.TW {...defaultProps}/>; if (code === 'TWD') flag = <Flags.TW {...defaultProps} />;
if(code === 'TZS') flag = <Flags.TZ {...defaultProps}/>; if (code === 'TZS') flag = <Flags.TZ {...defaultProps} />;
if(code === 'XAF') flag = <Flags.CM {...defaultProps}/>; if (code === 'XAF') flag = <Flags.CM {...defaultProps} />;
if(code === 'UAH') flag = <Flags.UA {...defaultProps}/>; if (code === 'UAH') flag = <Flags.UA {...defaultProps} />;
if(code === 'TND') flag = <Flags.TN {...defaultProps}/>; if (code === 'TND') flag = <Flags.TN {...defaultProps} />;
if(code === 'ANY') flag = <EarthIcon {...defaultProps}/>; if (code === 'ANY') flag = <EarthIcon {...defaultProps} />;
if(code === 'XAU') flag = <GoldIcon {...defaultProps}/>; if (code === 'XAU') flag = <GoldIcon {...defaultProps} />;
if(code === 'BTC') flag = <SwapCallsIcon color="primary"/>; if (code === 'BTC') flag = <SwapCallsIcon color='primary' />;
return ( return <div style={{ width: 28, height: 20 }}>{flag}</div>;
<div style={{width:28, height: 20}}>{flag}</div>
);
}; };
export default FlagWithProps; export default FlagWithProps;

View File

@ -1 +1 @@
export { default } from "./FlagWithProps"; export { default } from './FlagWithProps';

View File

@ -1,62 +1,128 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { BrowserRouter as Router, Switch, Route, Link, Redirect,useHistory } from "react-router-dom"; import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useHistory,
} from 'react-router-dom';
import UserGenPage from "./UserGenPage"; import UserGenPage from './UserGenPage';
import MakerPage from "./MakerPage"; import MakerPage from './MakerPage';
import BookPage from "./BookPage"; import BookPage from './BookPage';
import OrderPage from "./OrderPage"; import OrderPage from './OrderPage';
import BottomBar from "./BottomBar"; import BottomBar from './BottomBar';
export default class HomePage extends Component { export default class HomePage extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
nickname: null, nickname: null,
token: null, token: null,
copiedToken: false, copiedToken: false,
avatarLoaded: false, avatarLoaded: false,
buyChecked: false, buyChecked: false,
sellChecked: false, sellChecked: false,
type:2, type: 2,
currency:0, currency: 0,
bookCurrencyCode:'ANY', bookCurrencyCode: 'ANY',
bookOrders:new Array(), bookOrders: new Array(),
bookLoading: true, bookLoading: true,
activeOrderId: null, activeOrderId: null,
lastOrderId: null, lastOrderId: null,
earnedRewards: 0, earnedRewards: 0,
referralCode:'', referralCode: '',
lastDayPremium: 0, lastDayPremium: 0,
limits: {} limits: {},
} };
} }
setAppState=(newState)=>{ setAppState = (newState) => {
this.setState(newState) this.setState(newState);
} };
redirectTo(location) { redirectTo(location) {
this.props.history.push(location); this.props.history.push(location);
} }
render() { render() {
const fontSize = this.props.theme.typography.fontSize; const fontSize = this.props.theme.typography.fontSize;
const fontSizeFactor = fontSize / 14; // default fontSize is 14 const fontSizeFactor = fontSize / 14; // default fontSize is 14
return ( return (
<Router > <Router>
<div className='appCenter'> <div className='appCenter'>
<Switch> <Switch>
<Route exact path='/' render={(props) => <UserGenPage {...props} {...this.state} {...this.props} setAppState={this.setAppState}/>}/> <Route
<Route path='/ref/:refCode' render={(props) => <UserGenPage {...props} {...this.state} {...this.props} setAppState={this.setAppState}/>}/> exact
<Route path='/make' render={(props) => <MakerPage {...props} {...this.state} {...this.props} setAppState={this.setAppState}/>}/> path='/'
<Route path='/book' render={(props) => <BookPage {...props} {...this.state} {...this.props} setAppState={this.setAppState} />}/> render={(props) => (
<Route path="/order/:orderId" render={(props) => <OrderPage {...props} {...this.state} {...this.props} setAppState={this.setAppState}/>}/> <UserGenPage
</Switch> {...props}
</div> {...this.state}
<div className='bottomBar' style={{height: `${40*fontSizeFactor}px`, width: window.innerWidth}}> {...this.props}
<BottomBar redirectTo={this.redirectTo} {...this.state} {...this.props} setAppState={this.setAppState} /> setAppState={this.setAppState}
</div> />
</Router> )}
); />
} <Route
path='/ref/:refCode'
render={(props) => (
<UserGenPage
{...props}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
)}
/>
<Route
path='/make'
render={(props) => (
<MakerPage
{...props}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
)}
/>
<Route
path='/book'
render={(props) => (
<BookPage
{...props}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
)}
/>
<Route
path='/order/:orderId'
render={(props) => (
<OrderPage
{...props}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
)}
/>
</Switch>
</div>
<div
className='bottomBar'
style={{ height: `${40 * fontSizeFactor}px`, width: window.innerWidth }}
>
<BottomBar
redirectTo={this.redirectTo}
{...this.state}
{...this.props}
setAppState={this.setAppState}
/>
</div>
</Router>
);
}
} }

View File

@ -1,18 +1,28 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function AmbossIcon(props) { export default function AmbossIcon(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" viewBox="0 0 95.7 84.9"> <SvgIcon {...props} x='0px' y='0px' viewBox='0 0 95.7 84.9'>
<g id="Layer_2_00000052094167160547307180000012226084410257483709_"> <g id='Layer_2_00000052094167160547307180000012226084410257483709_'>
<g id="Layer_1-2"> <g id='Layer_1-2'>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0" y1="42.45" x2="95.7" y2="42.45"> <linearGradient
<stop offset="0" style={{stopColor:'#925bc9'}}/> id='SVGID_1_'
<stop offset="1" style={{stopColor:'#ff59ac'}}/> gradientUnits='userSpaceOnUse'
</linearGradient> x1='0'
<path className={"amboss"} d="M55.3,84.9V61.3h-15v23.6H0V0h95.7v84.9H55.3z M55.3,28.1h-15v17.1h15V28.1z"/> y1='42.45'
</g> x2='95.7'
y2='42.45'
>
<stop offset='0' style={{ stopColor: '#925bc9' }} />
<stop offset='1' style={{ stopColor: '#ff59ac' }} />
</linearGradient>
<path
className={'amboss'}
d='M55.3,84.9V61.3h-15v23.6H0V0h95.7v84.9H55.3z M55.3,28.1h-15v17.1h15V28.1z'
/>
</g> </g>
</SvgIcon> </g>
); </SvgIcon>
} );
}

View File

@ -1,12 +1,12 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function BasqueCountryFlag(props) { export default function BasqueCountryFlag(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" viewBox="0 0 50 28"> <SvgIcon {...props} x='0px' y='0px' viewBox='0 0 50 28'>
<path d="M0,0 v28 h50 v-28 z" fill="#D52B1E"/> <path d='M0,0 v28 h50 v-28 z' fill='#D52B1E' />
<path d="M0,0 L50,28 M50,0 L0,28" stroke="#009B48" strokeWidth="4.3"/> <path d='M0,0 L50,28 M50,0 L0,28' stroke='#009B48' strokeWidth='4.3' />
<path d="M25,0 v28 M0,14 h50" stroke="#fff" strokeWidth="4.3"/> <path d='M25,0 v28 M0,14 h50' stroke='#fff' strokeWidth='4.3' />
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,10 +1,10 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function BitcoinIcon(props) { export default function BitcoinIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} viewBox="0 0 512 512"> <SvgIcon sx={props.sx} color={props.color} viewBox='0 0 512 512'>
<path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-141.651-35.33c4.937-32.999-20.191-50.739-54.55-62.573l11.146-44.702-27.213-6.781-10.851 43.524c-7.154-1.783-14.502-3.464-21.803-5.13l10.929-43.81-27.198-6.781-11.153 44.686c-5.922-1.349-11.735-2.682-17.377-4.084l.031-.14-37.53-9.37-7.239 29.062s20.191 4.627 19.765 4.913c11.022 2.751 13.014 10.044 12.68 15.825l-12.696 50.925c.76.194 1.744.473 2.829.907-.907-.225-1.876-.473-2.876-.713l-17.796 71.338c-1.349 3.348-4.767 8.37-12.471 6.464.271.395-19.78-4.937-19.78-4.937l-13.51 31.147 35.414 8.827c6.588 1.651 13.045 3.379 19.4 5.006l-11.262 45.213 27.182 6.781 11.153-44.733a1038.209 1038.209 0 0 0 21.687 5.627l-11.115 44.523 27.213 6.781 11.262-45.128c46.404 8.781 81.299 5.239 95.986-36.727 11.836-33.79-.589-53.281-25.004-65.991 17.78-4.098 31.174-15.792 34.747-39.949zm-62.177 87.179c-8.41 33.79-65.308 15.523-83.755 10.943l14.944-59.899c18.446 4.603 77.6 13.717 68.811 48.956zm8.417-87.667c-7.673 30.736-55.031 15.12-70.393 11.292l13.548-54.327c15.363 3.828 64.836 10.973 56.845 43.035z"/> <path d='M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-141.651-35.33c4.937-32.999-20.191-50.739-54.55-62.573l11.146-44.702-27.213-6.781-10.851 43.524c-7.154-1.783-14.502-3.464-21.803-5.13l10.929-43.81-27.198-6.781-11.153 44.686c-5.922-1.349-11.735-2.682-17.377-4.084l.031-.14-37.53-9.37-7.239 29.062s20.191 4.627 19.765 4.913c11.022 2.751 13.014 10.044 12.68 15.825l-12.696 50.925c.76.194 1.744.473 2.829.907-.907-.225-1.876-.473-2.876-.713l-17.796 71.338c-1.349 3.348-4.767 8.37-12.471 6.464.271.395-19.78-4.937-19.78-4.937l-13.51 31.147 35.414 8.827c6.588 1.651 13.045 3.379 19.4 5.006l-11.262 45.213 27.182 6.781 11.153-44.733a1038.209 1038.209 0 0 0 21.687 5.627l-11.115 44.523 27.213 6.781 11.262-45.128c46.404 8.781 81.299 5.239 95.986-36.727 11.836-33.79-.589-53.281-25.004-65.991 17.78-4.098 31.174-15.792 34.747-39.949zm-62.177 87.179c-8.41 33.79-65.308 15.523-83.755 10.943l14.944-59.899c18.446 4.603 77.6 13.717 68.811 48.956zm8.417-87.667c-7.673 30.736-55.031 15.12-70.393 11.292l13.548-54.327c15.363 3.828 64.836 10.973 56.845 43.035z' />
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,10 +1,10 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function BitcoinSignIcon(props) { export default function BitcoinSignIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} viewBox="0 0 320 512"> <SvgIcon sx={props.sx} color={props.color} viewBox='0 0 320 512'>
<path d="M48 32C48 14.33 62.33 0 80 0C97.67 0 112 14.33 112 32V64H144V32C144 14.33 158.3 0 176 0C193.7 0 208 14.33 208 32V64C208 65.54 207.9 67.06 207.7 68.54C254.1 82.21 288 125.1 288 176C288 200.2 280.3 222.6 267.3 240.9C298.9 260.7 320 295.9 320 336C320 397.9 269.9 448 208 448V480C208 497.7 193.7 512 176 512C158.3 512 144 497.7 144 480V448H112V480C112 497.7 97.67 512 80 512C62.33 512 48 497.7 48 480V448H41.74C18.69 448 0 429.3 0 406.3V101.6C0 80.82 16.82 64 37.57 64H48V32zM176 224C202.5 224 224 202.5 224 176C224 149.5 202.5 128 176 128H64V224H176zM64 288V384H208C234.5 384 256 362.5 256 336C256 309.5 234.5 288 208 288H64z"/> <path d='M48 32C48 14.33 62.33 0 80 0C97.67 0 112 14.33 112 32V64H144V32C144 14.33 158.3 0 176 0C193.7 0 208 14.33 208 32V64C208 65.54 207.9 67.06 207.7 68.54C254.1 82.21 288 125.1 288 176C288 200.2 280.3 222.6 267.3 240.9C298.9 260.7 320 295.9 320 336C320 397.9 269.9 448 208 448V480C208 497.7 193.7 512 176 512C158.3 512 144 497.7 144 480V448H112V480C112 497.7 97.67 512 80 512C62.33 512 48 497.7 48 480V448H41.74C18.69 448 0 429.3 0 406.3V101.6C0 80.82 16.82 64 37.57 64H48V32zM176 224C202.5 224 224 202.5 224 176C224 149.5 202.5 128 176 128H64V224H176zM64 288V384H208C234.5 384 256 362.5 256 336C256 309.5 234.5 288 208 288H64z' />
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,49 +1,111 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function BuySatsIcon(props) { export default function BuySatsIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} x="0px" y="0px" viewBox="0 0 300 300"> <SvgIcon sx={props.sx} color={props.color} x='0px' y='0px' viewBox='0 0 300 300'>
<g> <g>
<polygon fill={props.color} points="178.391,189.96 174.934,186.875 169.489,182.018 166.596,179.436 161.154,174.579 158.645,172.34 <polygon
fill={props.color}
points='178.391,189.96 174.934,186.875 169.489,182.018 166.596,179.436 161.154,174.579 158.645,172.34
157.717,171.51 152.893,176.918 155.712,179.436 161.154,184.291 164.049,186.875 169.491,191.73 172.947,194.816 157.717,171.51 152.893,176.918 155.712,179.436 161.154,184.291 164.049,186.875 169.491,191.73 172.947,194.816
177.943,199.271 180.826,197.5 184.389,195.311 183.834,194.816 "/> 177.943,199.271 180.826,197.5 184.389,195.311 183.834,194.816 '
<polygon fill={props.color} points="166.034,194.816 160.588,189.96 157.695,187.377 152.256,182.521 150.52,180.975 149.592,180.145 />
<polygon
fill={props.color}
points='166.034,194.816 160.588,189.96 157.695,187.377 152.256,182.521 150.52,180.975 149.592,180.145
144.766,185.551 146.813,187.377 152.256,192.232 155.146,194.814 160.59,199.672 164.049,202.756 167.4,205.748 173.85,201.787 144.766,185.551 146.813,187.377 152.256,192.232 155.146,194.814 160.59,199.672 164.049,202.756 167.4,205.748 173.85,201.787
169.491,197.9 "/> 169.491,197.9 '
<polygon fill={props.color} points="157.695,202.255 152.253,197.398 149.358,194.816 143.916,189.96 142.014,188.26 137.189,193.668 />
<polygon
fill={props.color}
points='157.695,202.255 152.253,197.398 149.358,194.816 143.916,189.96 142.014,188.26 137.189,193.668
138.476,194.816 143.92,199.672 146.813,202.254 152.256,207.109 155.712,210.195 157.527,211.816 163.973,207.854 138.476,194.816 143.92,199.672 146.813,202.254 152.256,207.109 155.712,210.195 157.527,211.816 163.973,207.854
161.154,205.34 "/> 161.154,205.34 '
/>
<rect x="173.431" y="172.686" transform="matrix(0.7405 0.672 -0.672 0.7405 165.1439 -72.7109)" fill={props.color} width="6.611" height="9.654"/>
<polygon fill={props.color} points="141.129,211.877 147.035,215.203 150.877,210.975 145.981,206.533 "/> <rect
<polygon fill={props.color} points="186.961,57.038 189.855,59.621 195.298,64.477 198.756,67.562 204.199,72.418 205.449,73.534 x='173.431'
y='172.686'
transform='matrix(0.7405 0.672 -0.672 0.7405 165.1439 -72.7109)'
fill={props.color}
width='6.611'
height='9.654'
/>
<polygon
fill={props.color}
points='141.129,211.877 147.035,215.203 150.877,210.975 145.981,206.533 '
/>
<polygon
fill={props.color}
points='186.961,57.038 189.855,59.621 195.298,64.477 198.756,67.562 204.199,72.418 205.449,73.534
210.271,68.126 209.643,67.562 204.199,62.705 200.742,59.621 195.298,54.764 192.402,52.182 186.963,47.326 184.453,45.086 210.271,68.126 209.643,67.562 204.199,62.705 200.742,59.621 195.298,54.764 192.402,52.182 186.963,47.326 184.453,45.086
183.525,44.256 178.695,49.665 181.52,52.182 "/> 183.525,44.256 178.695,49.665 181.52,52.182 '
<polygon fill={props.color} points="178.062,64.979 180.954,67.562 186.398,72.418 189.855,75.503 195.298,80.359 196.396,81.34 />
<polygon
fill={props.color}
points='178.062,64.979 180.954,67.562 186.398,72.418 189.855,75.503 195.298,80.359 196.396,81.34
197.325,82.166 202.146,76.76 200.742,75.503 195.298,70.648 191.841,67.562 186.398,62.705 183.505,60.124 178.062,55.268 197.325,82.166 202.146,76.76 200.742,75.503 195.298,70.648 191.841,67.562 186.398,62.705 183.505,60.124 178.062,55.268
176.328,53.72 175.396,52.89 170.572,58.299 172.618,60.124 "/> 176.328,53.72 175.396,52.89 170.572,58.299 172.618,60.124 '
<polygon fill={props.color} points="169.723,72.418 172.618,75 178.062,79.856 181.52,82.941 186.962,87.798 188.818,89.456 />
<polygon
fill={props.color}
points='169.723,72.418 172.618,75 178.062,79.856 181.52,82.941 186.962,87.798 188.818,89.456
189.747,90.282 194.57,84.875 192.402,82.942 186.962,78.085 183.505,75 178.062,70.144 175.167,67.562 169.723,62.705 189.747,90.282 194.57,84.875 192.402,82.942 186.962,78.085 183.505,75 178.062,70.144 175.167,67.562 169.723,62.705
167.82,61.006 162.998,66.415 164.282,67.562 "/> 167.82,61.006 162.998,66.415 164.282,67.562 '
/>
<rect x="199.243" y="45.425" transform="matrix(0.7403 0.6723 -0.6723 0.7403 86.3919 -123.1221)" fill={props.color} width="6.609" height="9.656"/>
<polygon fill={props.color} points="165.298,86.425 170.193,90.867 176.684,83.72 171.789,79.28 "/> <rect
<polygon fill={props.color} points="88.684,102.6 87.755,101.77 82.927,107.177 105.743,127.533 109.679,131.046 114.503,125.64 x='199.243'
112.599,123.938 "/> y='45.425'
<polygon fill={props.color} points="80.557,111.232 79.631,110.403 74.803,115.811 94.669,133.537 100.627,138.853 101.553,139.68 transform='matrix(0.7403 0.6723 -0.6723 0.7403 86.3919 -123.1221)'
106.378,134.272 101.42,129.848 "/> fill={props.color}
<polygon fill={props.color} points="72.049,118.52 67.228,123.928 84.469,139.311 92.184,146.195 93.051,146.968 93.978,147.795 width='6.609'
98.659,142.548 98.802,142.389 91.107,135.525 "/> height='9.656'
/>
<rect x="103.471" y="102.94" transform="matrix(0.7405 0.6721 -0.6721 0.7405 100.1373 -43.7934)" fill={props.color} width="6.609" height="9.654"/> <polygon
<polygon fill={props.color} points="69.529,143.938 72.38,146.525 74.422,148.381 80.622,141.554 80.914,141.234 76.019,136.792 "/> fill={props.color}
<path fill={props.color} d="M187.466,112.718c7.511,0,14.995-1.878,21.647-5.43c10.848-5.793,18.796-15.48,22.379-27.277 points='165.298,86.425 170.193,90.867 176.684,83.72 171.789,79.28 '
/>
<polygon
fill={props.color}
points='88.684,102.6 87.755,101.77 82.927,107.177 105.743,127.533 109.679,131.046 114.503,125.64
112.599,123.938 '
/>
<polygon
fill={props.color}
points='80.557,111.232 79.631,110.403 74.803,115.811 94.669,133.537 100.627,138.853 101.553,139.68
106.378,134.272 101.42,129.848 '
/>
<polygon
fill={props.color}
points='72.049,118.52 67.228,123.928 84.469,139.311 92.184,146.195 93.051,146.968 93.978,147.795
98.659,142.548 98.802,142.389 91.107,135.525 '
/>
<rect
x='103.471'
y='102.94'
transform='matrix(0.7405 0.6721 -0.6721 0.7405 100.1373 -43.7934)'
fill={props.color}
width='6.609'
height='9.654'
/>
<polygon
fill={props.color}
points='69.529,143.938 72.38,146.525 74.422,148.381 80.622,141.554 80.914,141.234 76.019,136.792 '
/>
<path
fill={props.color}
d='M187.466,112.718c7.511,0,14.995-1.878,21.647-5.43c10.848-5.793,18.796-15.48,22.379-27.277
c3.583-11.796,2.365-24.266-3.426-35.113c-8.033-15.037-23.645-24.379-40.742-24.379c-7.51,0-14.996,1.878-21.648,5.431 c3.583-11.796,2.365-24.266-3.426-35.113c-8.033-15.037-23.645-24.379-40.742-24.379c-7.51,0-14.996,1.878-21.648,5.431
c-10.847,5.793-18.794,15.479-22.377,27.275s-2.366,24.266,3.426,35.113C154.755,103.376,170.365,112.718,187.466,112.718z c-10.847,5.793-18.794,15.479-22.377,27.275s-2.366,24.266,3.426,35.113C154.755,103.376,170.365,112.718,187.466,112.718z
M171.232,36.355c16.688-8.912,37.514-2.587,46.43,14.099c8.908,16.688,2.584,37.516-14.104,46.428 M171.232,36.355c16.688-8.912,37.514-2.587,46.43,14.099c8.908,16.688,2.584,37.516-14.104,46.428
c-16.688,8.913-37.518,2.586-46.431-14.1C148.219,66.092,154.544,45.268,171.232,36.355z"/> c-16.688,8.913-37.518,2.586-46.431-14.1C148.219,66.092,154.544,45.268,171.232,36.355z'
<path fill={props.color} d="M247.809,155.361c-6.326-5.757-17.865-13.456-34.295-22.881c-18.544-10.639-43.998-23.456-59.836-27.527 />
<path
fill={props.color}
d='M247.809,155.361c-6.326-5.757-17.865-13.456-34.295-22.881c-18.544-10.639-43.998-23.456-59.836-27.527
c-0.785-0.199-1.621-0.3-2.484-0.3c-1.917,0-5.62,0.546-15.812,4.946c-0.823-2.478-1.856-4.885-3.086-7.188 c-0.785-0.199-1.621-0.3-2.484-0.3c-1.917,0-5.62,0.546-15.812,4.946c-0.823-2.478-1.856-4.885-3.086-7.188
c-8.032-15.037-23.644-24.379-40.743-24.379c-7.509,0-14.995,1.878-21.646,5.43c-10.847,5.792-18.795,15.478-22.378,27.275 c-8.032-15.037-23.644-24.379-40.743-24.379c-7.509,0-14.995,1.878-21.646,5.43c-10.847,5.792-18.795,15.478-22.378,27.275
c-3.583,11.797-2.365,24.267,3.428,35.113c1.488,2.787,3.262,5.414,5.295,7.841c-3.117,2.348-5.28,4.3-6.706,6.043 c-3.583,11.797-2.365,24.267,3.428,35.113c1.488,2.787,3.262,5.414,5.295,7.841c-3.117,2.348-5.28,4.3-6.706,6.043
@ -60,12 +122,16 @@ export default function BuySatsIcon(props) {
c-8.912-16.687-2.588-37.511,14.1-46.422c16.689-8.914,37.516-2.588,46.43,14.101c1.647,3.086,2.772,6.316,3.407,9.585 c-8.912-16.687-2.588-37.511,14.1-46.422c16.689-8.914,37.516-2.588,46.43,14.101c1.647,3.086,2.772,6.316,3.407,9.585
C125.997,121.143,126.1,124.779,125.656,128.328z M59.715,174.898l34.511,20.586l-34.511,60.934V174.898z M102.657,200.516 C125.997,121.143,126.1,124.779,125.656,128.328z M59.715,174.898l34.511,20.586l-34.511,60.934V174.898z M102.657,200.516
l47.237,28.182l46.69-28.232l37.43,66.088c-0.445,0.067-0.896,0.114-1.358,0.114H68.718c-1.125,0-2.196-0.216-3.19-0.595 l47.237,28.182l46.69-28.232l37.43,66.088c-0.445,0.067-0.896,0.114-1.358,0.114H68.718c-1.125,0-2.196-0.216-3.19-0.595
L102.657,200.516z"/> L102.657,200.516z'
<path fill={props.color} d="M269.921,0H30.08C13.493,0,0,13.494,0,30.08v239.84C0,286.506,13.493,300,30.08,300h239.841 />
<path
fill={props.color}
d='M269.921,0H30.08C13.493,0,0,13.494,0,30.08v239.84C0,286.506,13.493,300,30.08,300h239.841
C286.506,300,300,286.506,300,269.92V30.08C300,13.494,286.506,0,269.921,0z M284.413,269.92c0,7.992-6.501,14.494-14.492,14.494 C286.506,300,300,286.506,300,269.92V30.08C300,13.494,286.506,0,269.921,0z M284.413,269.92c0,7.992-6.501,14.494-14.492,14.494
H30.08c-7.992,0-14.494-6.502-14.494-14.494V30.08c0-7.992,6.502-14.494,14.494-14.494h239.841 H30.08c-7.992,0-14.494-6.502-14.494-14.494V30.08c0-7.992,6.502-14.494,14.494-14.494h239.841
c7.991,0,14.492,6.502,14.492,14.494V269.92z"/> c7.991,0,14.492,6.502,14.492,14.494V269.92z'
</g> />
</SvgIcon> </g>
); </SvgIcon>
} );
}

View File

@ -1,11 +1,13 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function BuySatsCheckedIcon(props) { export default function BuySatsCheckedIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} x="0px" y="0px" viewBox="0 0 300 300"> <SvgIcon sx={props.sx} color={props.color} x='0px' y='0px' viewBox='0 0 300 300'>
<g> <g>
<path fill={props.color} d="M269.921,0H30.08C13.493,0,0,13.494,0,30.08v239.84C0,286.506,13.493,300,30.08,300h239.841 <path
fill={props.color}
d='M269.921,0H30.08C13.493,0,0,13.494,0,30.08v239.84C0,286.506,13.493,300,30.08,300h239.841
C286.506,300,300,286.506,300,269.92V30.08C300,13.494,286.506,0,269.921,0z M143.299,53.225 C286.506,300,300,286.506,300,269.92V30.08C300,13.494,286.506,0,269.921,0z M143.299,53.225
c3.583-11.796,11.53-21.482,22.377-27.275c6.652-3.553,14.139-5.431,21.648-5.431c15.026,0,28.906,7.216,37.501,19.173 c3.583-11.796,11.53-21.482,22.377-27.275c6.652-3.553,14.139-5.431,21.648-5.431c15.026,0,28.906,7.216,37.501,19.173
c0.573,0.797,1.123,1.615,1.647,2.454c0.56,0.895,1.092,1.812,1.594,2.752c5.791,10.847,7.009,23.317,3.426,35.113 c0.573,0.797,1.123,1.615,1.647,2.454c0.56,0.895,1.092,1.812,1.594,2.752c5.791,10.847,7.009,23.317,3.426,35.113
@ -16,8 +18,11 @@ export default function BuySatsCheckedIcon(props) {
c0.334-2.09,0.804-4.173,1.43-6.234C51.112,98.94,59.06,89.254,69.907,83.462c6.651-3.552,14.137-5.43,21.646-5.43 c0.334-2.09,0.804-4.173,1.43-6.234C51.112,98.94,59.06,89.254,69.907,83.462c6.651-3.552,14.137-5.43,21.646-5.43
c17.099,0,32.711,9.342,40.743,24.379c1.23,2.303,2.263,4.71,3.086,7.188c10.192-4.4,13.895-4.946,15.812-4.946 c17.099,0,32.711,9.342,40.743,24.379c1.23,2.303,2.263,4.71,3.086,7.188c10.192-4.4,13.895-4.946,15.812-4.946
c0.863,0,1.699,0.101,2.484,0.3c15.838,4.071,41.292,16.888,59.836,27.527c16.43,9.425,27.969,17.124,34.295,22.881 c0.863,0,1.699,0.101,2.484,0.3c15.838,4.071,41.292,16.888,59.836,27.527c16.43,9.425,27.969,17.124,34.295,22.881
C253.963,160.965,254.477,164.032,254.473,166.466L254.473,166.466z"/> C253.963,160.965,254.477,164.032,254.473,166.466L254.473,166.466z'
<path fill={props.color} d="M111.93,162.154c-14.119,7.541-30.589,6.39-43.265-1.563c-2.595,1.757-4.684,3.269-6.238,4.499 />
<path
fill={props.color}
d='M111.93,162.154c-14.119,7.541-30.589,6.39-43.265-1.563c-2.595,1.757-4.684,3.269-6.238,4.499
l56.336,33.61v-0.001c-0.178-1.596-0.265-3.194-0.264-4.787c0.006-8.962,2.806-17.76,8.005-25.075 l56.336,33.61v-0.001c-0.178-1.596-0.265-3.194-0.264-4.787c0.006-8.962,2.806-17.76,8.005-25.075
c0.347-0.488,0.704-0.969,1.072-1.443c0.654-0.843,1.341-1.664,2.061-2.461c0.72-0.796,1.473-1.568,2.257-2.314 c0.347-0.488,0.704-0.969,1.072-1.443c0.654-0.843,1.341-1.664,2.061-2.461c0.72-0.796,1.473-1.568,2.257-2.314
c2.746-2.611,5.884-4.899,9.387-6.769c20.966-11.197,47.131-3.25,58.332,17.717c1.73,3.242,3.001,6.613,3.84,10.029l-7.986,4.907 c2.746-2.611,5.884-4.899,9.387-6.769c20.966-11.197,47.131-3.25,58.332,17.717c1.73,3.242,3.001,6.613,3.84,10.029l-7.986,4.907
@ -31,8 +36,11 @@ export default function BuySatsCheckedIcon(props) {
z M167.4,205.748l-3.352-2.992l-3.459-3.084l-5.443-4.857l-2.891-2.582l-5.443-4.855l-2.047-1.826l0.58-0.649l4.246-4.757 z M167.4,205.748l-3.352-2.992l-3.459-3.084l-5.443-4.857l-2.891-2.582l-5.443-4.855l-2.047-1.826l0.58-0.649l4.246-4.757
l0.928,0.83l1.736,1.547l5.439,4.855l2.893,2.583l5.446,4.856l3.457,3.084l4.358,3.887L167.4,205.748z M180.826,197.5l-2.883,1.771 l0.928,0.83l1.736,1.547l5.439,4.855l2.893,2.583l5.446,4.856l3.457,3.084l4.358,3.887L167.4,205.748z M180.826,197.5l-2.883,1.771
l-4.996-4.455l-3.456-3.086l-5.442-4.855l-2.895-2.584l-5.442-4.855l-2.819-2.518l4.824-5.408l0.928,0.83l2.51,2.239l5.441,4.856 l-4.996-4.455l-3.456-3.086l-5.442-4.855l-2.895-2.584l-5.442-4.855l-2.819-2.518l4.824-5.408l0.928,0.83l2.51,2.239l5.441,4.856
l2.894,2.582l5.444,4.857l3.457,3.085l5.443,4.856l0.554,0.493l0.001,0.001L180.826,197.5z"/> l2.894,2.582l5.444,4.857l3.457,3.085l5.443,4.856l0.554,0.493l0.001,0.001L180.826,197.5z'
<path fill={props.color} d="M187.19,100.922c4.427,0.034,8.908-0.79,13.194-2.546c1.071-0.439,2.131-0.937,3.174-1.494 />
<path
fill={props.color}
d='M187.19,100.922c4.427,0.034,8.908-0.79,13.194-2.546c1.071-0.439,2.131-0.937,3.174-1.494
c16.688-8.912,23.012-29.74,14.104-46.428c-6.13-11.472-17.889-18.046-30.062-18.139c-5.533-0.042-11.152,1.255-16.367,4.04 c16.688-8.912,23.012-29.74,14.104-46.428c-6.13-11.472-17.889-18.046-30.062-18.139c-5.533-0.042-11.152,1.255-16.367,4.04
c-16.688,8.913-23.014,29.737-14.105,46.427C163.255,94.253,175.016,100.829,187.19,100.922z M165.298,86.425l6.491-7.145v0 c-16.688,8.913-23.014,29.737-14.105,46.427C163.255,94.253,175.016,100.829,187.19,100.922z M165.298,86.425l6.491-7.145v0
l4.895,4.44l-6.49,7.147L165.298,86.425z M189.747,90.282l-0.929-0.826l-1.856-1.658l-5.442-4.857l-3.457-3.085L172.618,75 l4.895,4.44l-6.49,7.147L165.298,86.425z M189.747,90.282l-0.929-0.826l-1.856-1.658l-5.442-4.857l-3.457-3.085L172.618,75
@ -41,12 +49,21 @@ export default function BuySatsCheckedIcon(props) {
M183.525,44.256l0.928,0.83l2.51,2.24l5.439,4.856l2.896,2.582l5.444,4.857l3.457,3.084l5.443,4.857l0.629,0.564l-4.822,5.408 M183.525,44.256l0.928,0.83l2.51,2.24l5.439,4.856l2.896,2.582l5.444,4.857l3.457,3.084l5.443,4.857l0.629,0.564l-4.822,5.408
l-1.25-1.116l-5.443-4.856l-3.458-3.085l-5.442-4.856l-2.895-2.583l-5.441-4.856l-2.824-2.517L183.525,44.256z M176.328,53.72 l-1.25-1.116l-5.443-4.856l-3.458-3.085l-5.442-4.856l-2.895-2.583l-5.441-4.856l-2.824-2.517L183.525,44.256z M176.328,53.72
l1.734,1.548l5.442,4.856l2.894,2.581l5.442,4.857l3.457,3.086l5.444,4.855l1.404,1.257l-4.821,5.406l-0.001,0l-0.928-0.826 l1.734,1.548l5.442,4.856l2.894,2.581l5.442,4.857l3.457,3.086l5.444,4.855l1.404,1.257l-4.821,5.406l-0.001,0l-0.928-0.826
l-1.099-0.981l-5.442-4.856l-3.457-3.085l-5.444-4.856l-2.892-2.583l-5.444-4.855l-2.046-1.825l4.824-5.409L176.328,53.72z"/> l-1.099-0.981l-5.442-4.856l-3.457-3.085l-5.444-4.856l-2.892-2.583l-5.444-4.855l-2.046-1.825l4.824-5.409L176.328,53.72z'
<polygon fill={props.color} points="59.715,174.898 59.715,256.418 94.226,195.484 "/> />
<path fill={props.color} d="M241.417,259.706c0.151-0.657,0.24-1.34,0.24-2.042v-84.453l-36.673,22.176L241.417,259.706z"/> <polygon fill={props.color} points='59.715,174.898 59.715,256.418 94.226,195.484 ' />
<path fill={props.color} d="M196.584,200.466l-46.69,28.232l-47.237-28.183l-37.129,65.557l0,0.001c0.994,0.379,2.065,0.595,3.19,0.595 <path
h163.938c0.462,0,0.912-0.047,1.357-0.113l-0.001-0.002L196.584,200.466z"/> fill={props.color}
<path fill={props.color} d="M68.179,149.165c2.65,2.481,5.651,4.502,8.876,6.015c9.464,4.428,20.827,4.506,30.732-0.785 d='M241.417,259.706c0.151-0.657,0.24-1.34,0.24-2.042v-84.453l-36.673,22.176L241.417,259.706z'
/>
<path
fill={props.color}
d='M196.584,200.466l-46.69,28.232l-47.237-28.183l-37.129,65.557l0,0.001c0.994,0.379,2.065,0.595,3.19,0.595
h163.938c0.462,0,0.912-0.047,1.357-0.113l-0.001-0.002L196.584,200.466z'
/>
<path
fill={props.color}
d='M68.179,149.165c2.65,2.481,5.651,4.502,8.876,6.015c9.464,4.428,20.827,4.506,30.732-0.785
c1.276-0.682,2.492-1.434,3.646-2.247c8.07-5.697,13.056-14.459,14.224-23.819c0.222-1.774,0.307-3.57,0.25-5.371 c1.276-0.682,2.492-1.434,3.646-2.247c8.07-5.697,13.056-14.459,14.224-23.819c0.222-1.774,0.307-3.57,0.25-5.371
c-0.058-1.802-0.258-3.608-0.607-5.403c-0.635-3.269-1.76-6.499-3.407-9.585c-8.914-16.688-29.741-23.015-46.43-14.101 c-0.058-1.802-0.258-3.608-0.607-5.403c-0.635-3.269-1.76-6.499-3.407-9.585c-8.914-16.688-29.741-23.015-46.43-14.101
c-11.474,6.126-18.048,17.884-18.14,30.057c-0.042,5.533,1.255,11.151,4.04,16.365C63.182,143.697,65.503,146.663,68.179,149.165z c-11.474,6.126-18.048,17.884-18.14,30.057c-0.042,5.533,1.255,11.151,4.04,16.365C63.182,143.697,65.503,146.663,68.179,149.165z
@ -54,8 +71,9 @@ export default function BuySatsCheckedIcon(props) {
l-0.927-0.827l-0.867-0.773l-7.715-6.884l-17.241-15.383l0,0l4.82-5.408l19.058,17.005l7.695,6.864L98.659,142.548z l-0.927-0.827l-0.867-0.773l-7.715-6.884l-17.241-15.383l0,0l4.82-5.408l19.058,17.005l7.695,6.864L98.659,142.548z
M101.553,139.68l-0.926-0.827l-5.958-5.316l-19.866-17.726l4.828-5.408l0.926,0.829l20.863,18.616l4.958,4.424L101.553,139.68z M101.553,139.68l-0.926-0.827l-5.958-5.316l-19.866-17.726l4.828-5.408l0.926,0.829l20.863,18.616l4.958,4.424L101.553,139.68z
M109.679,131.046l-3.936-3.513l-22.816-20.356l4.828-5.407l0.929,0.83l23.915,21.338l1.904,1.702L109.679,131.046z M109.679,131.046l-3.936-3.513l-22.816-20.356l4.828-5.407l0.929,0.83l23.915,21.338l1.904,1.702L109.679,131.046z
M101.086,109.122l6.486-7.146l4.892,4.44l0.002,0.002l-6.489,7.149l-4.894-4.442L101.086,109.122z"/> M101.086,109.122l6.486-7.146l4.892,4.44l0.002,0.002l-6.489,7.149l-4.894-4.442L101.086,109.122z'
</g> />
</SvgIcon> </g>
); </SvgIcon>
} );
}

View File

@ -1,11 +1,11 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function CataloniaFlag(props) { export default function CataloniaFlag(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" viewBox="0 0 810 540"> <SvgIcon {...props} x='0px' y='0px' viewBox='0 0 810 540'>
<rect width="810" height="540" fill="#FCDD09"/> <rect width='810' height='540' fill='#FCDD09' />
<path stroke="#DA121A" strokeWidth="60" d="M0,90H810m0,120H0m0,120H810m0,120H0"/> <path stroke='#DA121A' strokeWidth='60' d='M0,90H810m0,120H0m0,120H810m0,120H0' />
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,16 +1,21 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function EarthIcon(props) { export default function EarthIcon(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" viewBox="0 0 440.45 440.45" > <SvgIcon {...props} x='0px' y='0px' viewBox='0 0 440.45 440.45'>
<g id="XMLID_34_"> <g id='XMLID_34_'>
<g> <g>
<path style={{fill:"#1EA6C6"}} d="M102.62,211.975c0.02,0.08,0.04,0.15,0.06,0.23c1.91,7.94,3.42,19.8,1.63,35.19 <path
style={{ fill: '#1EA6C6' }}
d='M102.62,211.975c0.02,0.08,0.04,0.15,0.06,0.23c1.91,7.94,3.42,19.8,1.63,35.19
c-1.91,16.48,5.5,32.66,19.11,42.15l18.56,12.95c0,0-6.37,48.72,11.31,74.36v0.01C65.91,359.665,0,282.645,0,190.225 c-1.91,16.48,5.5,32.66,19.11,42.15l18.56,12.95c0,0-6.37,48.72,11.31,74.36v0.01C65.91,359.665,0,282.645,0,190.225
c0-53.81,22.35-102.41,58.27-137c-14.15,28.48-28.54,72.45-8.29,109.27c9.27,16.85,23.9,27.78,40.15,34.8 c0-53.81,22.35-102.41,58.27-137c-14.15,28.48-28.54,72.45-8.29,109.27c9.27,16.85,23.9,27.78,40.15,34.8
C96.36,199.975,101.02,205.395,102.62,211.975z"/> C96.36,199.975,101.02,205.395,102.62,211.975z'
<path style={{fill:"#1EA6C6"}} d="M190.23,0.005c41.46,0,79.82,13.26,111.07,35.79c0,0-16.37,25.11-15.71,50.17 />
<path
style={{ fill: '#1EA6C6' }}
d='M190.23,0.005c41.46,0,79.82,13.26,111.07,35.79c0,0-16.37,25.11-15.71,50.17
c0.15,5.99,4.84,10.89,10.81,11.52c0.42,0.04,0.85,0.07,1.27,0.07c4.55,0,8.75-2.58,10.81-6.73c4.38-8.78,15.91-19.42,45.02,1.77 c0.15,5.99,4.84,10.89,10.81,11.52c0.42,0.04,0.85,0.07,1.27,0.07c4.55,0,8.75-2.58,10.81-6.73c4.38-8.78,15.91-19.42,45.02,1.77
l0.01-0.01c2.17,3.61,4.22,7.3,6.14,11.07c0,0-10.16,2.28-23.77,0.6c-3.78-0.47-7.6,0.45-10.69,2.67 l0.01-0.01c2.17,3.61,4.22,7.3,6.14,11.07c0,0-10.16,2.28-23.77,0.6c-3.78-0.47-7.6,0.45-10.69,2.67
c-2.15,1.55-4.62,3.78-7.36,6.53c-13.89,13.96-16.19,43-16.19,43c-0.27,6.06,0,12.76,0.97,20.16 c-2.15,1.55-4.62,3.78-7.36,6.53c-13.89,13.96-16.19,43-16.19,43c-0.27,6.06,0,12.76,0.97,20.16
@ -20,28 +25,47 @@ export default function EarthIcon(props) {
c-16.59-10.07-36.14-23.07-48.73-35.16c-6.33-6.07-15.04-8.98-23.76-8.04c-11.2,1.21-27.07,3.65-42.8,8.55 c-16.59-10.07-36.14-23.07-48.73-35.16c-6.33-6.07-15.04-8.98-23.76-8.04c-11.2,1.21-27.07,3.65-42.8,8.55
c2.7-26.79-43.7-50.71-31.7-71.71c6.5-11.39,17.42-11.6,26.05-9.41c6.87,1.74,14.08-0.76,18.54-6.27 c2.7-26.79-43.7-50.71-31.7-71.71c6.5-11.39,17.42-11.6,26.05-9.41c6.87,1.74,14.08-0.76,18.54-6.27
c10.56-13.03,33.63-25.24,50.49-32.96c11.05-5.05,14.62-18.98,7.36-28.71c-22.27-29.9-53.82-49.59-53.82-49.59 c10.56-13.03,33.63-25.24,50.49-32.96c11.05-5.05,14.62-18.98,7.36-28.71c-22.27-29.9-53.82-49.59-53.82-49.59
C141.44,4.815,165.27,0.005,190.23,0.005z M197.98,61.495l23-30c0,0-10-9-46-12C167.79,18.895,194.98,38.495,197.98,61.495z"/> C141.44,4.815,165.27,0.005,190.23,0.005z M197.98,61.495l23-30c0,0-10-9-46-12C167.79,18.895,194.98,38.495,197.98,61.495z'
<path style={{fill:"#F7CF52"}} d="M353.51,92.585l-0.01,0.01c-29.11-21.19-40.64-10.55-45.02-1.77c-2.06,4.15-6.26,6.73-10.81,6.73 />
<path
style={{ fill: '#F7CF52' }}
d='M353.51,92.585l-0.01,0.01c-29.11-21.19-40.64-10.55-45.02-1.77c-2.06,4.15-6.26,6.73-10.81,6.73
c-0.42,0-0.85-0.03-1.27-0.07c-5.97-0.63-10.66-5.53-10.81-11.52c-0.66-25.06,15.71-50.17,15.71-50.17 c-0.42,0-0.85-0.03-1.27-0.07c-5.97-0.63-10.66-5.53-10.81-11.52c-0.66-25.06,15.71-50.17,15.71-50.17
C322.33,50.935,340.14,70.275,353.51,92.585z"/> C322.33,50.935,340.14,70.275,353.51,92.585z'
<path style={{fill:"#F7CF52"}} d="M380.45,190.225c0,22.57-3.93,44.23-11.15,64.32h-0.01c-6.07-10.32-8.37-22.55-8.98-33.34 />
<path
style={{ fill: '#F7CF52' }}
d='M380.45,190.225c0,22.57-3.93,44.23-11.15,64.32h-0.01c-6.07-10.32-8.37-22.55-8.98-33.34
c-0.68-11.96-11.49-20.89-23.33-19.05c-0.24,0.03-0.48,0.07-0.72,0.1c-16.41,2.4-31.48-9.2-33.65-25.64 c-0.68-11.96-11.49-20.89-23.33-19.05c-0.24,0.03-0.48,0.07-0.72,0.1c-16.41,2.4-31.48-9.2-33.65-25.64
c-0.97-7.4-1.24-14.1-0.97-20.16c0,0,2.3-29.04,16.19-43c2.74-2.75,5.21-4.98,7.36-6.53c3.09-2.22,6.91-3.14,10.69-2.67 c-0.97-7.4-1.24-14.1-0.97-20.16c0,0,2.3-29.04,16.19-43c2.74-2.75,5.21-4.98,7.36-6.53c3.09-2.22,6.91-3.14,10.69-2.67
c13.61,1.68,23.77-0.6,23.77-0.6C372.95,129.625,380.45,159.045,380.45,190.225z"/> c13.61,1.68,23.77-0.6,23.77-0.6C372.95,129.625,380.45,159.045,380.45,190.225z'
<path style={{fill:"#F7CF52"}} d="M220.98,31.495l-23,30c-3-23-30.19-42.6-23-42C210.98,22.495,220.98,31.495,220.98,31.495z"/> />
<path style={{fill:"#F7CF52"}} d="M173.42,63.145c7.26,9.73,3.69,23.66-7.36,28.71c-16.86,7.72-39.93,19.93-50.49,32.96 <path
style={{ fill: '#F7CF52' }}
d='M220.98,31.495l-23,30c-3-23-30.19-42.6-23-42C210.98,22.495,220.98,31.495,220.98,31.495z'
/>
<path
style={{ fill: '#F7CF52' }}
d='M173.42,63.145c7.26,9.73,3.69,23.66-7.36,28.71c-16.86,7.72-39.93,19.93-50.49,32.96
c-4.46,5.51-11.67,8.01-18.54,6.27c-8.63-2.19-19.55-1.98-26.05,9.41c-12,21,34.4,44.92,31.7,71.71 c-4.46,5.51-11.67,8.01-18.54,6.27c-8.63-2.19-19.55-1.98-26.05,9.41c-12,21,34.4,44.92,31.7,71.71
c-0.02-0.08-0.04-0.15-0.06-0.23c-1.6-6.58-6.26-12-12.49-14.68c-16.25-7.02-30.88-17.95-40.15-34.8 c-0.02-0.08-0.04-0.15-0.06-0.23c-1.6-6.58-6.26-12-12.49-14.68c-16.25-7.02-30.88-17.95-40.15-34.8
c-20.25-36.82-5.86-80.79,8.29-109.27c17.54-16.91,38.33-30.47,61.33-39.67C119.6,13.555,151.15,33.245,173.42,63.145z"/> c-20.25-36.82-5.86-80.79,8.29-109.27c17.54-16.91,38.33-30.47,61.33-39.67C119.6,13.555,151.15,33.245,173.42,63.145z'
<path style={{fill:"#F7CF52"}} d="M217.97,246.855c17.77,10.79,21.93,34.83,8.76,50.92c-7.41,9.05-15.93,18.74-24.47,28.12 />
<path
style={{ fill: '#F7CF52' }}
d='M217.97,246.855c17.77,10.79,21.93,34.83,8.76,50.92c-7.41,9.05-15.93,18.74-24.47,28.12
l-29.58,31.37c-14.04,14.58-19.39,19.59-19.39,19.59c-17.68-25.64-11.31-74.36-11.31-74.36l-18.56-12.95 l-29.58,31.37c-14.04,14.58-19.39,19.59-19.39,19.59c-17.68-25.64-11.31-74.36-11.31-74.36l-18.56-12.95
c-13.61-9.49-21.02-25.67-19.11-42.15c1.79-15.39,0.28-27.25-1.63-35.19c15.73-4.9,31.6-7.34,42.8-8.55 c-13.61-9.49-21.02-25.67-19.11-42.15c1.79-15.39,0.28-27.25-1.63-35.19c15.73-4.9,31.6-7.34,42.8-8.55
c8.72-0.94,17.43,1.97,23.76,8.04C181.83,223.785,201.38,236.785,217.97,246.855z"/> c8.72-0.94,17.43,1.97,23.76,8.04C181.83,223.785,201.38,236.785,217.97,246.855z'
</g> />
</g> </g>
<path style={{opacity:"0.3",fill:"#808080",enableBackground:"new"}} d="M190.23,0.005c5.8,0,11.54,0.26,17.2,0.77 </g>
<path
style={{ opacity: '0.3', fill: '#808080', enableBackground: 'new' }}
d='M190.23,0.005c5.8,0,11.54,0.26,17.2,0.77
C110.48,9.515,34.5,90.995,34.5,190.225c0,99.25,76.01,180.74,172.99,189.45c-5.68,0.51-11.44,0.77-17.26,0.77 C110.48,9.515,34.5,90.995,34.5,190.225c0,99.25,76.01,180.74,172.99,189.45c-5.68,0.51-11.44,0.77-17.26,0.77
C85.17,380.445,0,295.285,0,190.225S85.17,0.005,190.23,0.005z"/> C85.17,380.445,0,295.285,0,190.225S85.17,0.005,190.23,0.005z'
</SvgIcon> />
); </SvgIcon>
} );
}

View File

@ -1,10 +1,10 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function ExportIcon(props) { export default function ExportIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} viewBox="0 0 576 512"> <SvgIcon sx={props.sx} color={props.color} viewBox='0 0 576 512'>
<path d="M192 312C192 298.8 202.8 288 216 288H384V160H256c-17.67 0-32-14.33-32-32L224 0H48C21.49 0 0 21.49 0 48v416C0 490.5 21.49 512 48 512h288c26.51 0 48-21.49 48-48v-128H216C202.8 336 192 325.3 192 312zM256 0v128h128L256 0zM568.1 295l-80-80c-9.375-9.375-24.56-9.375-33.94 0s-9.375 24.56 0 33.94L494.1 288H384v48h110.1l-39.03 39.03C450.3 379.7 448 385.8 448 392s2.344 12.28 7.031 16.97c9.375 9.375 24.56 9.375 33.94 0l80-80C578.3 319.6 578.3 304.4 568.1 295z"/> <path d='M192 312C192 298.8 202.8 288 216 288H384V160H256c-17.67 0-32-14.33-32-32L224 0H48C21.49 0 0 21.49 0 48v416C0 490.5 21.49 512 48 512h288c26.51 0 48-21.49 48-48v-128H216C202.8 336 192 325.3 192 312zM256 0v128h128L256 0zM568.1 295l-80-80c-9.375-9.375-24.56-9.375-33.94 0s-9.375 24.56 0 33.94L494.1 288H384v48h110.1l-39.03 39.03C450.3 379.7 448 385.8 448 392s2.344 12.28 7.031 16.97c9.375 9.375 24.56 9.375 33.94 0l80-80C578.3 319.6 578.3 304.4 568.1 295z' />
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,21 +1,48 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function GoldIcon(props) { export default function GoldIcon(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" viewBox="0 0 511.882 511.882"> <SvgIcon {...props} x='0px' y='0px' viewBox='0 0 511.882 511.882'>
<polygon style={{fill:"#F6BB42"}} points="350.216,176.572 278.374,158.615 37.038,264.123 0,338.207 125.753,374.324 386.13,258.531 <polygon
"/> style={{ fill: '#F6BB42' }}
<polygon style={{fill:"#FFCE54"}} points="350.216,176.572 107.756,284.345 125.753,374.324 386.13,258.531 "/> points='350.216,176.572 278.374,158.615 37.038,264.123 0,338.207 125.753,374.324 386.13,258.531
<polygon style={{fill:"#E8AA3D"}} points="107.756,284.345 37.038,264.123 0.015,338.207 125.753,374.324 "/> '
<polygon style={{fill:"#F6BB42"}} points="475.969,212.682 404.127,194.717 162.791,300.232 125.753,374.324 251.504,410.41 />
511.882,294.625 "/> <polygon
<polygon style={{fill:"#FFCE54"}} points="475.969,212.682 233.508,320.431 251.504,410.41 511.882,294.625 "/> style={{ fill: '#FFCE54' }}
<polygon style={{fill:"#E8AA3D"}} points="233.508,320.431 162.791,300.232 125.753,374.324 251.504,410.41 "/> points='350.216,176.572 107.756,284.345 125.753,374.324 386.13,258.531 '
<polygon style={{fill:"#F6BB42"}} points="396.316,119.429 324.488,101.473 103.867,198.435 66.843,272.519 192.596,308.621 />
432.245,201.379 "/> <polygon
<polygon style={{fill:"#FFCE54"}} points="396.316,119.429 174.6,218.641 192.596,308.621 432.245,201.379 "/> style={{ fill: '#E8AA3D' }}
<polygon style={{fill:"#E8AA3D"}} points="174.6,218.641 103.867,198.435 66.843,272.519 192.596,308.621 "/> points='107.756,284.345 37.038,264.123 0.015,338.207 125.753,374.324 '
</SvgIcon> />
); <polygon
} style={{ fill: '#F6BB42' }}
points='475.969,212.682 404.127,194.717 162.791,300.232 125.753,374.324 251.504,410.41
511.882,294.625 '
/>
<polygon
style={{ fill: '#FFCE54' }}
points='475.969,212.682 233.508,320.431 251.504,410.41 511.882,294.625 '
/>
<polygon
style={{ fill: '#E8AA3D' }}
points='233.508,320.431 162.791,300.232 125.753,374.324 251.504,410.41 '
/>
<polygon
style={{ fill: '#F6BB42' }}
points='396.316,119.429 324.488,101.473 103.867,198.435 66.843,272.519 192.596,308.621
432.245,201.379 '
/>
<polygon
style={{ fill: '#FFCE54' }}
points='396.316,119.429 174.6,218.641 192.596,308.621 432.245,201.379 '
/>
<polygon
style={{ fill: '#E8AA3D' }}
points='174.6,218.641 103.867,198.435 66.843,272.519 192.596,308.621 '
/>
</SvgIcon>
);
}

View File

@ -1,10 +1,10 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function NewTabIcon(props) { export default function NewTabIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} viewBox="0 0 448 512"> <SvgIcon sx={props.sx} color={props.color} viewBox='0 0 448 512'>
<path d="M256 64C256 46.33 270.3 32 288 32H415.1C415.1 32 415.1 32 415.1 32C420.3 32 424.5 32.86 428.2 34.43C431.1 35.98 435.5 38.27 438.6 41.3C438.6 41.35 438.6 41.4 438.7 41.44C444.9 47.66 447.1 55.78 448 63.9C448 63.94 448 63.97 448 64V192C448 209.7 433.7 224 416 224C398.3 224 384 209.7 384 192V141.3L214.6 310.6C202.1 323.1 181.9 323.1 169.4 310.6C156.9 298.1 156.9 277.9 169.4 265.4L338.7 96H288C270.3 96 256 81.67 256 64V64zM0 128C0 92.65 28.65 64 64 64H160C177.7 64 192 78.33 192 96C192 113.7 177.7 128 160 128H64V416H352V320C352 302.3 366.3 288 384 288C401.7 288 416 302.3 416 320V416C416 451.3 387.3 480 352 480H64C28.65 480 0 451.3 0 416V128z"/> <path d='M256 64C256 46.33 270.3 32 288 32H415.1C415.1 32 415.1 32 415.1 32C420.3 32 424.5 32.86 428.2 34.43C431.1 35.98 435.5 38.27 438.6 41.3C438.6 41.35 438.6 41.4 438.7 41.44C444.9 47.66 447.1 55.78 448 63.9C448 63.94 448 63.97 448 64V192C448 209.7 433.7 224 416 224C398.3 224 384 209.7 384 192V141.3L214.6 310.6C202.1 323.1 181.9 323.1 169.4 310.6C156.9 298.1 156.9 277.9 169.4 265.4L338.7 96H288C270.3 96 256 81.67 256 64V64zM0 128C0 92.65 28.65 64 64 64H160C177.7 64 192 78.33 192 96C192 113.7 177.7 128 160 128H64V416H352V320C352 302.3 366.3 288 384 288C401.7 288 416 302.3 416 320V416C416 451.3 387.3 480 352 480H64C28.65 480 0 451.3 0 416V128z' />
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,11 +1,12 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function RoboSatsIcon(props) { export default function RoboSatsIcon(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" width="1000px" height="1000px" viewBox="0 0 1000 900"> <SvgIcon {...props} x='0px' y='0px' width='1000px' height='1000px' viewBox='0 0 1000 900'>
<g> <g>
<path d="M602.336,731.51c16.747-16.94,29.249-35.524,37.504-56.694c18.792-48.193,16.967-94.996-10.46-139.81 <path
d='M602.336,731.51c16.747-16.94,29.249-35.524,37.504-56.694c18.792-48.193,16.967-94.996-10.46-139.81
c-10.255-16.756-24.983-29.293-39.461-42.103c-67.731-59.932-135.412-119.919-203.104-179.895 c-10.255-16.756-24.983-29.293-39.461-42.103c-67.731-59.932-135.412-119.919-203.104-179.895
c-0.368-0.326-0.644-0.755-1.331-1.579c18.529-12.477,36.983-24.903,55.872-37.62c-9.61-6.799-18.917-13.385-28.648-20.27 c-0.368-0.326-0.644-0.755-1.331-1.579c18.529-12.477,36.983-24.903,55.872-37.62c-9.61-6.799-18.917-13.385-28.648-20.27
c11.763-14.483,23.273-28.656,34.738-42.773c13.313,7.081,24.784,5.523,32.075-4.132c6.395-8.467,5.794-20.59-1.412-28.52 c11.763-14.483,23.273-28.656,34.738-42.773c13.313,7.081,24.784,5.523,32.075-4.132c6.395-8.467,5.794-20.59-1.412-28.52
@ -15,46 +16,64 @@ export default function RoboSatsIcon(props) {
c37.661,0.119,75.351,1.898,112.093,11.01c52.81,13.096,95.741,40.904,125.379,87.462c13.802,21.681,20.643,45.764,23.136,71.039 c37.661,0.119,75.351,1.898,112.093,11.01c52.81,13.096,95.741,40.904,125.379,87.462c13.802,21.681,20.643,45.764,23.136,71.039
c3.595,36.436,1.313,72.517-8.858,107.873c-11.943,41.515-37.09,74.011-69.641,101.357c-16.133,13.552-33.803,24.811-52.581,34.343 c3.595,36.436,1.313,72.517-8.858,107.873c-11.943,41.515-37.09,74.011-69.641,101.357c-16.133,13.552-33.803,24.811-52.581,34.343
c-1.3,0.659-2.533,1.445-4.148,2.375c80.735,102.152,161.255,204.034,242.318,306.6C761.843,731.51,682.637,731.51,602.336,731.51z c-1.3,0.659-2.533,1.445-4.148,2.375c80.735,102.152,161.255,204.034,242.318,306.6C761.843,731.51,682.637,731.51,602.336,731.51z
"/> '
<path d="M282.877,389.186c25.706-0.109,46.42,20.376,46.55,46.038c0.131,25.994-20.404,46.852-46.238,46.96 />
c-25.588,0.108-46.928-21.172-46.758-46.627C236.602,409.95,257.291,389.295,282.877,389.186z"/> <path
<path d="M445.93,607.736c0.705-26.031,21.515-46.381,46.915-45.881c26.295,0.52,46.657,21.756,45.918,47.887 d='M282.877,389.186c25.706-0.109,46.42,20.376,46.55,46.038c0.131,25.994-20.404,46.852-46.238,46.96
c-0.721,25.455-21.862,45.67-47.178,45.104C465.779,654.273,445.244,633.082,445.93,607.736z"/> c-25.588,0.108-46.928-21.172-46.758-46.627C236.602,409.95,257.291,389.295,282.877,389.186z'
<path d="M175.223,550.758c23.365,20.689,46.15,40.865,69.337,61.396c-4.974,5.619-9.792,11.063-14.91,16.846 />
<path
d='M445.93,607.736c0.705-26.031,21.515-46.381,46.915-45.881c26.295,0.52,46.657,21.756,45.918,47.887
c-0.721,25.455-21.862,45.67-47.178,45.104C465.779,654.273,445.244,633.082,445.93,607.736z'
/>
<path
d='M175.223,550.758c23.365,20.689,46.15,40.865,69.337,61.396c-4.974,5.619-9.792,11.063-14.91,16.846
c-5.634-4.988-11.167-9.738-16.519-14.684c-3.131-2.896-5.343-2.492-8.415,0.467c-9.944,9.58-20.234,18.801-29.493,27.332 c-5.634-4.988-11.167-9.738-16.519-14.684c-3.131-2.896-5.343-2.492-8.415,0.467c-9.944,9.58-20.234,18.801-29.493,27.332
C175.223,613.414,175.223,582.512,175.223,550.758z"/> C175.223,613.414,175.223,582.512,175.223,550.758z'
<path d="M379.124,731.533c-30.045,0-59.057,0-89.151,0c8.955-9.23,17.236-17.769,25.724-26.519 />
<path
d='M379.124,731.533c-30.045,0-59.057,0-89.151,0c8.955-9.23,17.236-17.769,25.724-26.519
c-6.368-5.709-12.409-11.127-18.739-16.803c4.904-5.559,9.594-10.877,14.65-16.608C334.013,691.492,356.2,711.186,379.124,731.533z c-6.368-5.709-12.409-11.127-18.739-16.803c4.904-5.559,9.594-10.877,14.65-16.608C334.013,691.492,356.2,711.186,379.124,731.533z
"/> '
</g> />
<g> </g>
<path d="M208.875,819.362h-15.495v34.557h-19.45v-94.397h35.075c11.151,0,19.752,2.485,25.804,7.455 <g>
<path
d='M208.875,819.362h-15.495v34.557h-19.45v-94.397h35.075c11.151,0,19.752,2.485,25.804,7.455
c6.051,4.972,9.077,11.995,9.077,21.071c0,6.44-1.394,11.811-4.182,16.111s-7.013,7.727-12.675,10.276l20.422,38.576v0.907h-20.876 c6.051,4.972,9.077,11.995,9.077,21.071c0,6.44-1.394,11.811-4.182,16.111s-7.013,7.727-12.675,10.276l20.422,38.576v0.907h-20.876
L208.875,819.362z M193.379,803.608h15.69c4.884,0,8.666-1.242,11.346-3.729c2.68-2.484,4.02-5.91,4.02-10.276 L208.875,819.362z M193.379,803.608h15.69c4.884,0,8.666-1.242,11.346-3.729c2.68-2.484,4.02-5.91,4.02-10.276
c0-4.451-1.264-7.952-3.792-10.503c-2.529-2.55-6.409-3.825-11.638-3.825h-15.625V803.608z"/> c0-4.451-1.264-7.952-3.792-10.503c-2.529-2.55-6.409-3.825-11.638-3.825h-15.625V803.608z'
<path d="M336.208,808.859c0,9.294-1.643,17.44-4.927,24.442c-3.285,7.002-7.985,12.405-14.101,16.209 />
<path
d='M336.208,808.859c0,9.294-1.643,17.44-4.927,24.442c-3.285,7.002-7.985,12.405-14.101,16.209
c-6.117,3.804-13.129,5.705-21.039,5.705c-7.824,0-14.805-1.881-20.941-5.641c-6.138-3.761-10.892-9.131-14.263-16.111 c-6.117,3.804-13.129,5.705-21.039,5.705c-7.824,0-14.805-1.881-20.941-5.641c-6.138-3.761-10.892-9.131-14.263-16.111
c-3.372-6.979-5.08-15.009-5.122-24.086v-4.668c0-9.292,1.674-17.473,5.024-24.539c3.349-7.067,8.082-12.491,14.199-16.273 c-3.372-6.979-5.08-15.009-5.122-24.086v-4.668c0-9.292,1.674-17.473,5.024-24.539c3.349-7.067,8.082-12.491,14.199-16.273
c6.116-3.781,13.106-5.673,20.974-5.673c7.866,0,14.857,1.892,20.974,5.673c6.116,3.782,10.849,9.206,14.199,16.273 c6.116-3.781,13.106-5.673,20.974-5.673c7.866,0,14.857,1.892,20.974,5.673c6.116,3.782,10.849,9.206,14.199,16.273
c3.349,7.066,5.024,15.226,5.024,24.475V808.859z M316.499,804.58c0-9.896-1.773-17.418-5.316-22.562 c3.349,7.066,5.024,15.226,5.024,24.475V808.859z M316.499,804.58c0-9.896-1.773-17.418-5.316-22.562
c-3.545-5.144-8.602-7.716-15.171-7.716c-6.527,0-11.563,2.54-15.106,7.618c-3.545,5.079-5.339,12.524-5.381,22.335v4.604 c-3.545-5.144-8.602-7.716-15.171-7.716c-6.527,0-11.563,2.54-15.106,7.618c-3.545,5.079-5.339,12.524-5.381,22.335v4.604
c0,9.639,1.772,17.116,5.316,22.433c3.543,5.316,8.644,7.975,15.301,7.975c6.526,0,11.541-2.561,15.042-7.683 c0,9.639,1.772,17.116,5.316,22.433c3.543,5.316,8.644,7.975,15.301,7.975c6.526,0,11.541-2.561,15.042-7.683
s5.272-12.588,5.316-22.4V804.58z"/> s5.272-12.588,5.316-22.4V804.58z'
<path d="M350.342,853.919v-94.397h33.065c11.453,0,20.141,2.193,26.063,6.58c5.921,4.388,8.882,10.817,8.882,19.288 />
<path
d='M350.342,853.919v-94.397h33.065c11.453,0,20.141,2.193,26.063,6.58c5.921,4.388,8.882,10.817,8.882,19.288
c0,4.626-1.189,8.699-3.566,12.222c-2.377,3.522-5.684,6.105-9.919,7.747c4.84,1.211,8.655,3.653,11.443,7.326 c0,4.626-1.189,8.699-3.566,12.222c-2.377,3.522-5.684,6.105-9.919,7.747c4.84,1.211,8.655,3.653,11.443,7.326
c2.788,3.675,4.182,8.169,4.182,13.485c0,9.077-2.896,15.949-8.688,20.617c-5.792,4.668-14.047,7.046-24.767,7.132H350.342z c2.788,3.675,4.182,8.169,4.182,13.485c0,9.077-2.896,15.949-8.688,20.617c-5.792,4.668-14.047,7.046-24.767,7.132H350.342z
M369.792,799.069h14.393c9.811-0.172,14.717-4.084,14.717-11.734c0-4.279-1.243-7.358-3.728-9.239 M369.792,799.069h14.393c9.811-0.172,14.717-4.084,14.717-11.734c0-4.279-1.243-7.358-3.728-9.239
c-2.486-1.88-6.408-2.82-11.767-2.82h-13.615V799.069z M369.792,812.814v25.479h16.662c4.581,0,8.158-1.091,10.73-3.274 c-2.486-1.88-6.408-2.82-11.767-2.82h-13.615V799.069z M369.792,812.814v25.479h16.662c4.581,0,8.158-1.091,10.73-3.274
c2.571-2.182,3.858-5.196,3.858-9.044c0-8.645-4.474-13.031-13.421-13.161H369.792z"/> c2.571-2.182,3.858-5.196,3.858-9.044c0-8.645-4.474-13.031-13.421-13.161H369.792z'
<path d="M512.621,808.859c0,9.294-1.645,17.44-4.928,24.442c-3.285,7.002-7.986,12.405-14.102,16.209 />
<path
d='M512.621,808.859c0,9.294-1.645,17.44-4.928,24.442c-3.285,7.002-7.986,12.405-14.102,16.209
c-6.117,3.804-13.129,5.705-21.039,5.705c-7.824,0-14.805-1.881-20.941-5.641c-6.138-3.761-10.892-9.131-14.263-16.111 c-6.117,3.804-13.129,5.705-21.039,5.705c-7.824,0-14.805-1.881-20.941-5.641c-6.138-3.761-10.892-9.131-14.263-16.111
c-3.372-6.979-5.08-15.009-5.122-24.086v-4.668c0-9.292,1.674-17.473,5.024-24.539c3.349-7.067,8.082-12.491,14.199-16.273 c-3.372-6.979-5.08-15.009-5.122-24.086v-4.668c0-9.292,1.674-17.473,5.024-24.539c3.349-7.067,8.082-12.491,14.199-16.273
c6.116-3.781,13.106-5.673,20.974-5.673c7.866,0,14.857,1.892,20.974,5.673c6.116,3.782,10.849,9.206,14.199,16.273 c6.116-3.781,13.106-5.673,20.974-5.673c7.866,0,14.857,1.892,20.974,5.673c6.116,3.782,10.849,9.206,14.199,16.273
c3.35,7.066,5.025,15.226,5.025,24.475V808.859z M492.911,804.58c0-9.896-1.773-17.418-5.316-22.562 c3.35,7.066,5.025,15.226,5.025,24.475V808.859z M492.911,804.58c0-9.896-1.773-17.418-5.316-22.562
c-3.545-5.144-8.602-7.716-15.171-7.716c-6.527,0-11.563,2.54-15.106,7.618c-3.545,5.079-5.339,12.524-5.381,22.335v4.604 c-3.545-5.144-8.602-7.716-15.171-7.716c-6.527,0-11.563,2.54-15.106,7.618c-3.545,5.079-5.339,12.524-5.381,22.335v4.604
c0,9.639,1.772,17.116,5.316,22.433c3.543,5.316,8.644,7.975,15.301,7.975c6.526,0,11.541-2.561,15.042-7.683 c0,9.639,1.772,17.116,5.316,22.433c3.543,5.316,8.644,7.975,15.301,7.975c6.526,0,11.541-2.561,15.042-7.683
s5.272-12.588,5.316-22.4V804.58z"/> s5.272-12.588,5.316-22.4V804.58z'
<path d="M575.704,829.152c0-3.673-1.297-6.493-3.891-8.461c-2.593-1.966-7.261-4.041-14.004-6.224 />
<path
d='M575.704,829.152c0-3.673-1.297-6.493-3.891-8.461c-2.593-1.966-7.261-4.041-14.004-6.224
c-6.742-2.183-12.081-4.333-16.014-6.451c-10.72-5.791-16.079-13.593-16.079-23.405c0-5.1,1.437-9.648,4.312-13.647 c-6.742-2.183-12.081-4.333-16.014-6.451c-10.72-5.791-16.079-13.593-16.079-23.405c0-5.1,1.437-9.648,4.312-13.647
c2.874-3.997,7.002-7.12,12.384-9.368c5.381-2.247,11.421-3.371,18.121-3.371c6.742,0,12.75,1.222,18.023,3.663 c2.874-3.997,7.002-7.12,12.384-9.368c5.381-2.247,11.421-3.371,18.121-3.371c6.742,0,12.75,1.222,18.023,3.663
c5.272,2.442,9.368,5.89,12.286,10.341c2.917,4.452,4.376,9.509,4.376,15.171h-19.45c0-4.321-1.361-7.683-4.084-10.081 c5.272,2.442,9.368,5.89,12.286,10.341c2.917,4.452,4.376,9.509,4.376,15.171h-19.45c0-4.321-1.361-7.683-4.084-10.081
@ -62,11 +81,15 @@ export default function RoboSatsIcon(props) {
c0,3.069,1.545,5.641,4.636,7.715c3.09,2.075,7.64,4.02,13.647,5.835c11.064,3.329,19.126,7.456,24.184,12.384 c0,3.069,1.545,5.641,4.636,7.715c3.09,2.075,7.64,4.02,13.647,5.835c11.064,3.329,19.126,7.456,24.184,12.384
c5.057,4.927,7.585,11.065,7.585,18.412c0,8.169-3.091,14.578-9.271,19.224c-6.181,4.646-14.501,6.97-24.961,6.97 c5.057,4.927,7.585,11.065,7.585,18.412c0,8.169-3.091,14.578-9.271,19.224c-6.181,4.646-14.501,6.97-24.961,6.97
c-7.261,0-13.874-1.329-19.839-3.987s-10.514-6.299-13.647-10.925c-3.134-4.624-4.7-9.984-4.7-16.078h19.515 c-7.261,0-13.874-1.329-19.839-3.987s-10.514-6.299-13.647-10.925c-3.134-4.624-4.7-9.984-4.7-16.078h19.515
c0,10.416,6.225,15.624,18.672,15.624c4.625,0,8.234-0.939,10.827-2.82C574.407,835.149,575.704,832.523,575.704,829.152z"/> c0,10.416,6.225,15.624,18.672,15.624c4.625,0,8.234-0.939,10.827-2.82C574.407,835.149,575.704,832.523,575.704,829.152z'
<path d="M661.673,834.469H627.57l-6.483,19.45h-20.682l35.14-94.397h18.023l35.335,94.397h-20.683L661.673,834.469z />
M632.822,818.714h23.599l-11.864-35.334L632.822,818.714z"/> <path
<path d="M760.999,775.275h-28.916v78.644h-19.45v-78.644h-28.526v-15.754h76.893V775.275z"/> d='M661.673,834.469H627.57l-6.483,19.45h-20.682l35.14-94.397h18.023l35.335,94.397h-20.683L661.673,834.469z
<path d="M819.997,829.152c0-3.673-1.297-6.493-3.891-8.461c-2.593-1.966-7.261-4.041-14.004-6.224 M632.822,818.714h23.599l-11.864-35.334L632.822,818.714z'
/>
<path d='M760.999,775.275h-28.916v78.644h-19.45v-78.644h-28.526v-15.754h76.893V775.275z' />
<path
d='M819.997,829.152c0-3.673-1.297-6.493-3.891-8.461c-2.593-1.966-7.261-4.041-14.004-6.224
c-6.742-2.183-12.081-4.333-16.014-6.451c-10.72-5.791-16.079-13.593-16.079-23.405c0-5.1,1.437-9.648,4.312-13.647 c-6.742-2.183-12.081-4.333-16.014-6.451c-10.72-5.791-16.079-13.593-16.079-23.405c0-5.1,1.437-9.648,4.312-13.647
c2.874-3.997,7.002-7.12,12.384-9.368c5.381-2.247,11.421-3.371,18.121-3.371c6.742,0,12.75,1.222,18.023,3.663 c2.874-3.997,7.002-7.12,12.384-9.368c5.381-2.247,11.421-3.371,18.121-3.371c6.742,0,12.75,1.222,18.023,3.663
c5.272,2.442,9.368,5.89,12.286,10.341c2.917,4.452,4.376,9.509,4.376,15.171h-19.45c0-4.321-1.361-7.683-4.084-10.081 c5.272,2.442,9.368,5.89,12.286,10.341c2.917,4.452,4.376,9.509,4.376,15.171h-19.45c0-4.321-1.361-7.683-4.084-10.081
@ -74,8 +97,9 @@ export default function RoboSatsIcon(props) {
c0,3.069,1.545,5.641,4.636,7.715c3.09,2.075,7.64,4.02,13.647,5.835c11.064,3.329,19.126,7.456,24.184,12.384 c0,3.069,1.545,5.641,4.636,7.715c3.09,2.075,7.64,4.02,13.647,5.835c11.064,3.329,19.126,7.456,24.184,12.384
c5.057,4.927,7.585,11.065,7.585,18.412c0,8.169-3.091,14.578-9.271,19.224c-6.181,4.646-14.501,6.97-24.961,6.97 c5.057,4.927,7.585,11.065,7.585,18.412c0,8.169-3.091,14.578-9.271,19.224c-6.181,4.646-14.501,6.97-24.961,6.97
c-7.261,0-13.874-1.329-19.839-3.987s-10.514-6.299-13.647-10.925c-3.134-4.624-4.7-9.984-4.7-16.078h19.515 c-7.261,0-13.874-1.329-19.839-3.987s-10.514-6.299-13.647-10.925c-3.134-4.624-4.7-9.984-4.7-16.078h19.515
c0,10.416,6.225,15.624,18.672,15.624c4.625,0,8.234-0.939,10.827-2.82C818.7,835.149,819.997,832.523,819.997,829.152z"/> c0,10.416,6.225,15.624,18.672,15.624c4.625,0,8.234-0.939,10.827-2.82C818.7,835.149,819.997,832.523,819.997,829.152z'
</g> />
</SvgIcon> </g>
); </SvgIcon>
} );
}

View File

@ -1,11 +1,12 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function RoboSatsNoTextIcon(props) { export default function RoboSatsNoTextIcon(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" width="1000px" height="1000px" viewBox="0 0 1000 800"> <SvgIcon {...props} x='0px' y='0px' width='1000px' height='1000px' viewBox='0 0 1000 800'>
<g> <g>
<path d="M602.336,731.51c16.747-16.94,29.249-35.524,37.504-56.694c18.792-48.193,16.967-94.996-10.46-139.81 <path
d='M602.336,731.51c16.747-16.94,29.249-35.524,37.504-56.694c18.792-48.193,16.967-94.996-10.46-139.81
c-10.255-16.756-24.983-29.293-39.461-42.103c-67.731-59.932-135.412-119.919-203.104-179.895 c-10.255-16.756-24.983-29.293-39.461-42.103c-67.731-59.932-135.412-119.919-203.104-179.895
c-0.368-0.326-0.644-0.755-1.331-1.579c18.529-12.477,36.983-24.903,55.872-37.62c-9.61-6.799-18.917-13.385-28.648-20.27 c-0.368-0.326-0.644-0.755-1.331-1.579c18.529-12.477,36.983-24.903,55.872-37.62c-9.61-6.799-18.917-13.385-28.648-20.27
c11.763-14.483,23.273-28.656,34.738-42.773c13.313,7.081,24.784,5.523,32.075-4.132c6.395-8.467,5.794-20.59-1.412-28.52 c11.763-14.483,23.273-28.656,34.738-42.773c13.313,7.081,24.784,5.523,32.075-4.132c6.395-8.467,5.794-20.59-1.412-28.52
@ -15,18 +16,27 @@ export default function RoboSatsNoTextIcon(props) {
c37.661,0.119,75.351,1.898,112.093,11.01c52.81,13.096,95.741,40.904,125.379,87.462c13.802,21.681,20.643,45.764,23.136,71.039 c37.661,0.119,75.351,1.898,112.093,11.01c52.81,13.096,95.741,40.904,125.379,87.462c13.802,21.681,20.643,45.764,23.136,71.039
c3.595,36.436,1.313,72.517-8.858,107.873c-11.943,41.515-37.09,74.011-69.641,101.357c-16.133,13.552-33.803,24.811-52.581,34.343 c3.595,36.436,1.313,72.517-8.858,107.873c-11.943,41.515-37.09,74.011-69.641,101.357c-16.133,13.552-33.803,24.811-52.581,34.343
c-1.3,0.659-2.533,1.445-4.148,2.375c80.735,102.152,161.255,204.034,242.318,306.6C761.843,731.51,682.637,731.51,602.336,731.51z c-1.3,0.659-2.533,1.445-4.148,2.375c80.735,102.152,161.255,204.034,242.318,306.6C761.843,731.51,682.637,731.51,602.336,731.51z
"/> '
<path d="M282.877,389.186c25.706-0.109,46.42,20.376,46.55,46.038c0.131,25.994-20.404,46.852-46.238,46.96 />
c-25.588,0.108-46.928-21.172-46.758-46.627C236.602,409.95,257.291,389.295,282.877,389.186z"/> <path
<path d="M445.93,607.736c0.705-26.031,21.515-46.381,46.915-45.881c26.295,0.52,46.657,21.756,45.918,47.887 d='M282.877,389.186c25.706-0.109,46.42,20.376,46.55,46.038c0.131,25.994-20.404,46.852-46.238,46.96
c-0.721,25.455-21.862,45.67-47.178,45.104C465.779,654.273,445.244,633.082,445.93,607.736z"/> c-25.588,0.108-46.928-21.172-46.758-46.627C236.602,409.95,257.291,389.295,282.877,389.186z'
<path d="M175.223,550.758c23.365,20.689,46.15,40.865,69.337,61.396c-4.974,5.619-9.792,11.063-14.91,16.846 />
<path
d='M445.93,607.736c0.705-26.031,21.515-46.381,46.915-45.881c26.295,0.52,46.657,21.756,45.918,47.887
c-0.721,25.455-21.862,45.67-47.178,45.104C465.779,654.273,445.244,633.082,445.93,607.736z'
/>
<path
d='M175.223,550.758c23.365,20.689,46.15,40.865,69.337,61.396c-4.974,5.619-9.792,11.063-14.91,16.846
c-5.634-4.988-11.167-9.738-16.519-14.684c-3.131-2.896-5.343-2.492-8.415,0.467c-9.944,9.58-20.234,18.801-29.493,27.332 c-5.634-4.988-11.167-9.738-16.519-14.684c-3.131-2.896-5.343-2.492-8.415,0.467c-9.944,9.58-20.234,18.801-29.493,27.332
C175.223,613.414,175.223,582.512,175.223,550.758z"/> C175.223,613.414,175.223,582.512,175.223,550.758z'
<path d="M379.124,731.533c-30.045,0-59.057,0-89.151,0c8.955-9.23,17.236-17.769,25.724-26.519 />
<path
d='M379.124,731.533c-30.045,0-59.057,0-89.151,0c8.955-9.23,17.236-17.769,25.724-26.519
c-6.368-5.709-12.409-11.127-18.739-16.803c4.904-5.559,9.594-10.877,14.65-16.608C334.013,691.492,356.2,711.186,379.124,731.533z c-6.368-5.709-12.409-11.127-18.739-16.803c4.904-5.559,9.594-10.877,14.65-16.608C334.013,691.492,356.2,711.186,379.124,731.533z
"/> '
</g> />
</SvgIcon> </g>
); </SvgIcon>
} );
}

View File

@ -1,11 +1,12 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function RoboSatsTextIcon(props) { export default function RoboSatsTextIcon(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" width="2000px" height="1000px" viewBox="0 300 2000 150"> <SvgIcon {...props} x='0px' y='0px' width='2000px' height='1000px' viewBox='0 300 2000 150'>
<g> <g>
<path d="M455.556,849.519c10.487-10.606,18.315-22.243,23.484-35.499c11.767-30.177,10.624-59.483-6.55-87.546 <path
d='M455.556,849.519c10.487-10.606,18.315-22.243,23.484-35.499c11.767-30.177,10.624-59.483-6.55-87.546
c-6.421-10.492-15.644-18.342-24.709-26.363c-42.412-37.528-84.791-75.089-127.178-112.646c-0.23-0.204-0.403-0.473-0.833-0.988 c-6.421-10.492-15.644-18.342-24.709-26.363c-42.412-37.528-84.791-75.089-127.178-112.646c-0.23-0.204-0.403-0.473-0.833-0.988
c11.603-7.813,23.158-15.593,34.985-23.557c-6.017-4.258-11.845-8.382-17.938-12.692c7.366-9.069,14.573-17.943,21.752-26.783 c11.603-7.813,23.158-15.593,34.985-23.557c-6.017-4.258-11.845-8.382-17.938-12.692c7.366-9.069,14.573-17.943,21.752-26.783
c8.336,4.434,15.519,3.458,20.084-2.588c4.005-5.302,3.629-12.893-0.884-17.858c-4.39-4.829-12.207-5.82-17.747-2.248 c8.336,4.434,15.519,3.458,20.084-2.588c4.005-5.302,3.629-12.893-0.884-17.858c-4.39-4.829-12.207-5.82-17.747-2.248
@ -14,42 +15,58 @@ export default function RoboSatsTextIcon(props) {
c1.134-0.051,2.23-0.144,3.327-0.144c61.359-0.006,122.719-0.134,184.077,0.059c23.582,0.074,47.182,1.188,70.189,6.894 c1.134-0.051,2.23-0.144,3.327-0.144c61.359-0.006,122.719-0.134,184.077,0.059c23.582,0.074,47.182,1.188,70.189,6.894
c33.068,8.2,59.95,25.613,78.508,54.766c8.642,13.576,12.927,28.656,14.487,44.482c2.252,22.815,0.823,45.408-5.545,67.547 c33.068,8.2,59.95,25.613,78.508,54.766c8.642,13.576,12.927,28.656,14.487,44.482c2.252,22.815,0.823,45.408-5.545,67.547
c-7.479,25.995-23.225,46.343-43.608,63.466c-10.102,8.486-21.167,15.536-32.924,21.505c-0.814,0.413-1.585,0.905-2.597,1.487 c-7.479,25.995-23.225,46.343-43.608,63.466c-10.102,8.486-21.167,15.536-32.924,21.505c-0.814,0.413-1.585,0.905-2.597,1.487
c50.553,63.965,100.971,127.76,151.731,191.983C555.434,849.519,505.838,849.519,455.556,849.519z"/> c50.553,63.965,100.971,127.76,151.731,191.983C555.434,849.519,505.838,849.519,455.556,849.519z'
<path d="M255.521,635.166c16.096-0.067,29.067,12.759,29.148,28.827c0.083,16.276-12.776,29.339-28.953,29.405 />
c-16.022,0.067-29.385-13.258-29.278-29.196C226.544,648.168,239.5,635.234,255.521,635.166z"/> <path
<path d="M357.619,772.016c0.441-16.3,13.472-29.043,29.376-28.729c16.465,0.325,29.215,13.623,28.752,29.985 d='M255.521,635.166c16.096-0.067,29.067,12.759,29.148,28.827c0.083,16.276-12.776,29.339-28.953,29.405
c-0.451,15.939-13.688,28.597-29.541,28.242C370.048,801.155,357.19,787.886,357.619,772.016z"/> c-16.022,0.067-29.385-13.258-29.278-29.196C226.544,648.168,239.5,635.234,255.521,635.166z'
<path d="M188.111,736.337c14.63,12.955,28.898,25.589,43.417,38.445c-3.115,3.519-6.132,6.927-9.336,10.548 />
<path
d='M357.619,772.016c0.441-16.3,13.472-29.043,29.376-28.729c16.465,0.325,29.215,13.623,28.752,29.985
c-0.451,15.939-13.688,28.597-29.541,28.242C370.048,801.155,357.19,787.886,357.619,772.016z'
/>
<path
d='M188.111,736.337c14.63,12.955,28.898,25.589,43.417,38.445c-3.115,3.519-6.132,6.927-9.336,10.548
c-3.528-3.123-6.993-6.098-10.344-9.194c-1.96-1.813-3.346-1.561-5.269,0.292c-6.227,5.999-12.67,11.772-18.468,17.114 c-3.528-3.123-6.993-6.098-10.344-9.194c-1.96-1.813-3.346-1.561-5.269,0.292c-6.227,5.999-12.67,11.772-18.468,17.114
C188.111,775.57,188.111,756.221,188.111,736.337z"/> C188.111,775.57,188.111,756.221,188.111,736.337z'
<path d="M315.788,849.533c-18.813,0-36.98,0-55.824,0c5.607-5.78,10.793-11.127,16.108-16.606 />
c-3.987-3.574-7.77-6.967-11.734-10.521c3.071-3.48,6.007-6.811,9.173-10.398C287.54,824.461,301.433,836.792,315.788,849.533z"/> <path
d='M315.788,849.533c-18.813,0-36.98,0-55.824,0c5.607-5.78,10.793-11.127,16.108-16.606
c-3.987-3.574-7.77-6.967-11.734-10.521c3.071-3.48,6.007-6.811,9.173-10.398C287.54,824.461,301.433,836.792,315.788,849.533z'
/>
</g> </g>
<g> <g>
<path d="M766.812,758.155c0,18.361-3.246,34.457-9.734,48.289c-6.49,13.834-15.776,24.51-27.859,32.022 <path
d='M766.812,758.155c0,18.361-3.246,34.457-9.734,48.289c-6.49,13.834-15.776,24.51-27.859,32.022
c-12.085,7.516-25.938,11.273-41.564,11.273c-15.458,0-29.249-3.715-41.374-11.145c-12.127-7.429-21.519-18.039-28.181-31.831 c-12.085,7.516-25.938,11.273-41.564,11.273c-15.458,0-29.249-3.715-41.374-11.145c-12.127-7.429-21.519-18.039-28.181-31.831
c-6.66-13.789-10.035-29.653-10.118-47.584v-9.223c0-18.358,3.308-34.521,9.927-48.481c6.617-13.962,15.968-24.678,28.052-32.15 c-6.66-13.789-10.035-29.653-10.118-47.584v-9.223c0-18.358,3.308-34.521,9.927-48.481c6.617-13.962,15.968-24.678,28.052-32.15
c12.083-7.471,25.894-11.207,41.437-11.207c15.541,0,29.352,3.735,41.437,11.207c12.083,7.473,21.433,18.188,28.052,32.15 c12.083-7.471,25.894-11.207,41.437-11.207c15.541,0,29.352,3.735,41.437,11.207c12.083,7.473,21.433,18.188,28.052,32.15
c6.616,13.961,9.926,30.081,9.926,48.354V758.155L766.812,758.155z M727.873,749.701c0-19.553-3.503-34.411-10.504-44.574 c6.616,13.961,9.926,30.081,9.926,48.354V758.155L766.812,758.155z M727.873,749.701c0-19.553-3.503-34.411-10.504-44.574
c-7.003-10.163-16.993-15.243-29.972-15.243c-12.895,0-22.845,5.017-29.846,15.05c-7.003,10.036-10.546,24.744-10.631,44.127v9.093 c-7.003-10.163-16.993-15.243-29.972-15.243c-12.895,0-22.845,5.017-29.846,15.05c-7.003,10.036-10.546,24.744-10.631,44.127v9.093
c0,19.043,3.5,33.817,10.503,44.319c7,10.504,17.079,15.755,30.229,15.755c12.893,0,22.799-5.059,29.715-15.178 c0,19.043,3.5,33.817,10.503,44.319c7,10.504,17.079,15.755,30.229,15.755c12.893,0,22.799-5.059,29.715-15.178
c6.917-10.119,10.418-24.868,10.504-44.255L727.873,749.701L727.873,749.701z"/> c6.917-10.119,10.418-24.868,10.504-44.255L727.873,749.701L727.873,749.701z'
<path d="M794.736,847.177V660.678h65.326c22.627,0,39.791,4.336,51.491,13.001c11.699,8.668,17.549,21.372,17.549,38.107 />
<path
d='M794.736,847.177V660.678h65.326c22.627,0,39.791,4.336,51.491,13.001c11.699,8.668,17.549,21.372,17.549,38.107
c0,9.138-2.35,17.187-7.045,24.146c-4.697,6.961-11.23,12.062-19.597,15.307c9.562,2.39,17.1,7.216,22.607,14.474 c0,9.138-2.35,17.187-7.045,24.146c-4.697,6.961-11.23,12.062-19.597,15.307c9.562,2.39,17.1,7.216,22.607,14.474
c5.508,7.259,8.263,16.138,8.263,26.642c0,17.934-5.723,31.51-17.165,40.733c-11.446,9.223-27.754,13.919-48.93,14.089 c5.508,7.259,8.263,16.138,8.263,26.642c0,17.934-5.723,31.51-17.165,40.733c-11.446,9.223-27.754,13.919-48.93,14.089
L794.736,847.177L794.736,847.177z M833.162,738.813h28.437c19.383-0.341,29.076-8.069,29.076-23.186 L794.736,847.177L794.736,847.177z M833.162,738.813h28.437c19.383-0.341,29.076-8.069,29.076-23.186
c0-8.453-2.455-14.538-7.364-18.252c-4.913-3.714-12.662-5.572-23.248-5.572h-26.9V738.813L833.162,738.813z M833.162,765.968 c0-8.453-2.455-14.538-7.364-18.252c-4.913-3.714-12.662-5.572-23.248-5.572h-26.9V738.813L833.162,738.813z M833.162,765.968
v50.341h32.919c9.051,0,16.118-2.155,21.198-6.469c5.08-4.313,7.621-10.269,7.621-17.868c0-17.078-8.838-25.746-26.514-26.003 v50.341h32.919c9.051,0,16.118-2.155,21.198-6.469c5.08-4.313,7.621-10.269,7.621-17.868c0-17.078-8.838-25.746-26.514-26.003
L833.162,765.968L833.162,765.968z"/> L833.162,765.968L833.162,765.968z'
<path d="M1115.343,758.155c0,18.361-3.245,34.457-9.734,48.289c-6.492,13.834-15.776,24.51-27.858,32.022 />
<path
d='M1115.343,758.155c0,18.361-3.245,34.457-9.734,48.289c-6.492,13.834-15.776,24.51-27.858,32.022
c-12.085,7.516-25.94,11.273-41.567,11.273c-15.457,0-29.246-3.715-41.37-11.145c-12.127-7.429-21.521-18.039-28.182-31.831 c-12.085,7.516-25.94,11.273-41.567,11.273c-15.457,0-29.246-3.715-41.37-11.145c-12.127-7.429-21.521-18.039-28.182-31.831
c-6.66-13.789-10.035-29.653-10.119-47.584v-9.223c0-18.358,3.309-34.521,9.928-48.481c6.616-13.962,15.966-24.678,28.051-32.15 c-6.66-13.789-10.035-29.653-10.119-47.584v-9.223c0-18.358,3.309-34.521,9.928-48.481c6.616-13.962,15.966-24.678,28.051-32.15
c12.081-7.471,25.894-11.207,41.436-11.207s29.354,3.735,41.439,11.207c12.079,7.473,21.432,18.188,28.05,32.15 c12.081-7.471,25.894-11.207,41.436-11.207s29.354,3.735,41.439,11.207c12.079,7.473,21.432,18.188,28.05,32.15
c6.616,13.961,9.926,30.081,9.926,48.354v8.325H1115.343z M1076.405,749.701c0-19.553-3.504-34.411-10.505-44.574 c6.616,13.961,9.926,30.081,9.926,48.354v8.325H1115.343z M1076.405,749.701c0-19.553-3.504-34.411-10.505-44.574
s-16.992-15.243-29.973-15.243c-12.895,0-22.844,5.017-29.845,15.05c-7.004,10.036-10.548,24.744-10.632,44.127v9.093 s-16.992-15.243-29.973-15.243c-12.895,0-22.844,5.017-29.845,15.05c-7.004,10.036-10.548,24.744-10.632,44.127v9.093
c0,19.043,3.501,33.817,10.503,44.319c7.002,10.504,17.079,15.755,30.229,15.755c12.896,0,22.802-5.059,29.717-15.178 c0,19.043,3.501,33.817,10.503,44.319c7.002,10.504,17.079,15.755,30.229,15.755c12.896,0,22.802-5.059,29.717-15.178
c6.918-10.119,10.419-24.868,10.505-44.255L1076.405,749.701L1076.405,749.701z"/> c6.918-10.119,10.419-24.868,10.505-44.255L1076.405,749.701L1076.405,749.701z'
<path d="M1239.975,798.248c0-7.258-2.563-12.829-7.686-16.717c-5.123-3.884-14.346-7.982-27.666-12.296 />
<path
d='M1239.975,798.248c0-7.258-2.563-12.829-7.686-16.717c-5.123-3.884-14.346-7.982-27.666-12.296
c-13.323-4.312-23.869-8.561-31.64-12.744c-21.178-11.443-31.766-26.855-31.766-46.241c0-10.075,2.838-19.064,8.517-26.963 c-13.323-4.312-23.869-8.561-31.64-12.744c-21.178-11.443-31.766-26.855-31.766-46.241c0-10.075,2.838-19.064,8.517-26.963
c5.679-7.897,13.835-14.067,24.466-18.508c10.631-4.439,22.563-6.66,35.801-6.66c13.323,0,25.191,2.412,35.609,7.236 c5.679-7.897,13.835-14.067,24.466-18.508c10.631-4.439,22.563-6.66,35.801-6.66c13.323,0,25.191,2.412,35.609,7.236
c10.417,4.826,18.509,11.636,24.272,20.43c5.765,8.796,8.647,18.787,8.647,29.973h-38.426c0-8.536-2.692-15.177-8.071-19.917 c10.417,4.826,18.509,11.636,24.272,20.43c5.765,8.796,8.647,18.787,8.647,29.973h-38.426c0-8.536-2.692-15.177-8.071-19.917
@ -57,11 +74,15 @@ export default function RoboSatsTextIcon(props) {
c0,6.063,3.053,11.143,9.16,15.241c6.104,4.099,15.091,7.941,26.962,11.528c21.859,6.577,37.786,14.73,47.776,24.465 c0,6.063,3.053,11.143,9.16,15.241c6.104,4.099,15.091,7.941,26.962,11.528c21.859,6.577,37.786,14.73,47.776,24.465
c9.991,9.735,14.987,21.861,14.987,36.377c0,16.139-6.106,28.8-18.317,37.979c-12.212,9.181-28.649,13.771-49.313,13.771 c9.991,9.735,14.987,21.861,14.987,36.377c0,16.139-6.106,28.8-18.317,37.979c-12.212,9.181-28.649,13.771-49.313,13.771
c-14.347,0-27.411-2.626-39.195-7.878s-20.773-12.444-26.964-21.583c-6.192-9.136-9.286-19.725-9.286-31.767h38.556 c-14.347,0-27.411-2.626-39.195-7.878s-20.773-12.444-26.964-21.583c-6.192-9.136-9.286-19.725-9.286-31.767h38.556
c0,20.581,12.296,30.87,36.891,30.87c9.136,0,16.269-1.858,21.391-5.573C1237.414,810.097,1239.975,804.907,1239.975,798.248z"/> c0,20.581,12.296,30.87,36.891,30.87c9.136,0,16.269-1.858,21.391-5.573C1237.414,810.097,1239.975,804.907,1239.975,798.248z'
<path d="M1409.822,808.75h-67.376l-12.809,38.427h-40.861l69.424-186.498h35.611l69.809,186.498h-40.861L1409.822,808.75z />
M1352.822,777.625h46.624l-23.44-69.809L1352.822,777.625z"/> <path
<path d="M1606.055,691.805h-57.127v155.372h-38.429V691.805h-56.358v-31.126h151.914V691.805L1606.055,691.805z"/> d='M1409.822,808.75h-67.376l-12.809,38.427h-40.861l69.424-186.498h35.611l69.809,186.498h-40.861L1409.822,808.75z
<path d="M1722.617,798.248c0-7.258-2.563-12.829-7.687-16.717c-5.123-3.884-14.346-7.982-27.666-12.296 M1352.822,777.625h46.624l-23.44-69.809L1352.822,777.625z'
/>
<path d='M1606.055,691.805h-57.127v155.372h-38.429V691.805h-56.358v-31.126h151.914V691.805L1606.055,691.805z' />
<path
d='M1722.617,798.248c0-7.258-2.563-12.829-7.687-16.717c-5.123-3.884-14.346-7.982-27.666-12.296
c-13.323-4.312-23.87-8.561-31.639-12.744c-21.179-11.443-31.767-26.855-31.767-46.241c0-10.075,2.837-19.064,8.517-26.963 c-13.323-4.312-23.87-8.561-31.639-12.744c-21.179-11.443-31.767-26.855-31.767-46.241c0-10.075,2.837-19.064,8.517-26.963
c5.679-7.897,13.835-14.067,24.466-18.508c10.632-4.439,22.563-6.66,35.801-6.66c13.323,0,25.19,2.412,35.609,7.236 c5.679-7.897,13.835-14.067,24.466-18.508c10.632-4.439,22.563-6.66,35.801-6.66c13.323,0,25.19,2.412,35.609,7.236
c10.417,4.826,18.509,11.636,24.273,20.43c5.764,8.796,8.646,18.787,8.646,29.973h-38.426c0-8.536-2.692-15.177-8.072-19.917 c10.417,4.826,18.509,11.636,24.273,20.43c5.764,8.796,8.646,18.787,8.646,29.973h-38.426c0-8.536-2.692-15.177-8.072-19.917
@ -69,8 +90,9 @@ export default function RoboSatsTextIcon(props) {
c0,6.063,3.053,11.143,9.16,15.241c6.104,4.099,15.091,7.941,26.962,11.528c21.858,6.577,37.786,14.73,47.776,24.465 c0,6.063,3.053,11.143,9.16,15.241c6.104,4.099,15.091,7.941,26.962,11.528c21.858,6.577,37.786,14.73,47.776,24.465
c9.991,9.735,14.987,21.861,14.987,36.377c0,16.139-6.106,28.8-18.317,37.979c-12.212,9.181-28.648,13.771-49.313,13.771 c9.991,9.735,14.987,21.861,14.987,36.377c0,16.139-6.106,28.8-18.317,37.979c-12.212,9.181-28.648,13.771-49.313,13.771
c-14.346,0-27.411-2.626-39.195-7.878s-20.774-12.444-26.964-21.583c-6.192-9.136-9.286-19.725-9.286-31.767h38.556 c-14.346,0-27.411-2.626-39.195-7.878s-20.774-12.444-26.964-21.583c-6.192-9.136-9.286-19.725-9.286-31.767h38.556
c0,20.581,12.296,30.87,36.891,30.87c9.136,0,16.268-1.858,21.391-5.573C1720.055,810.097,1722.617,804.907,1722.617,798.248z"/> c0,20.581,12.296,30.87,36.891,30.87c9.136,0,16.268-1.858,21.391-5.573C1720.055,810.097,1722.617,804.907,1722.617,798.248z'
/>
</g> </g>
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,50 +1,112 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function SellSatsIcon(props) { export default function SellSatsIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} x="0px" y="0px" viewBox="0 0 300 300"> <SvgIcon sx={props.sx} color={props.color} x='0px' y='0px' viewBox='0 0 300 300'>
<g> <g>
<polygon fill={props.color} points="121.609,110.04 125.066,113.125 130.511,117.982 133.404,120.564 138.846,125.421 141.355,127.66 <polygon
fill={props.color}
points='121.609,110.04 125.066,113.125 130.511,117.982 133.404,120.564 138.846,125.421 141.355,127.66
142.283,128.49 147.107,123.082 144.288,120.564 138.846,115.709 135.951,113.125 130.509,108.27 127.053,105.184 142.283,128.49 147.107,123.082 144.288,120.564 138.846,115.709 135.951,113.125 130.509,108.27 127.053,105.184
122.057,100.729 119.174,102.5 115.611,104.689 116.166,105.184 "/> 122.057,100.729 119.174,102.5 115.611,104.689 116.166,105.184 '
<polygon fill={props.color} points="133.966,105.184 139.412,110.04 142.305,112.623 147.744,117.479 149.48,119.025 150.408,119.855 />
<polygon
fill={props.color}
points='133.966,105.184 139.412,110.04 142.305,112.623 147.744,117.479 149.48,119.025 150.408,119.855
155.234,114.449 153.188,112.623 147.744,107.768 144.854,105.186 139.41,100.328 135.951,97.244 132.6,94.252 126.15,98.213 155.234,114.449 153.188,112.623 147.744,107.768 144.854,105.186 139.41,100.328 135.951,97.244 132.6,94.252 126.15,98.213
130.509,102.1 "/> 130.509,102.1 '
<polygon fill={props.color} points="142.305,97.745 147.747,102.602 150.643,105.184 156.084,110.04 157.986,111.74 162.811,106.332 />
161.523,105.184 156.08,100.328 153.188,97.746 147.744,92.891 144.288,89.805 142.473,88.184 136.027,92.146 138.846,94.66 "/> <polygon
fill={props.color}
<rect x="119.966" y="117.668" transform="matrix(0.7405 0.672 -0.672 0.7405 114.3002 -51.0573)" fill={props.color} width="6.611" height="9.654"/> points='142.305,97.745 147.747,102.602 150.643,105.184 156.084,110.04 157.986,111.74 162.811,106.332
<polygon fill={props.color} points="158.871,88.123 152.965,84.797 149.123,89.025 154.02,93.467 "/> 161.523,105.184 156.08,100.328 153.188,97.746 147.744,92.891 144.288,89.805 142.473,88.184 136.027,92.146 138.846,94.66 '
<polygon fill={props.color} points="113.039,242.962 110.145,240.379 104.702,235.523 101.244,232.438 95.801,227.582 94.551,226.466 />
<rect
x='119.966'
y='117.668'
transform='matrix(0.7405 0.672 -0.672 0.7405 114.3002 -51.0573)'
fill={props.color}
width='6.611'
height='9.654'
/>
<polygon
fill={props.color}
points='158.871,88.123 152.965,84.797 149.123,89.025 154.02,93.467 '
/>
<polygon
fill={props.color}
points='113.039,242.962 110.145,240.379 104.702,235.523 101.244,232.438 95.801,227.582 94.551,226.466
89.729,231.874 90.357,232.438 95.801,237.295 99.258,240.379 104.702,245.236 107.598,247.818 113.037,252.674 115.547,254.914 89.729,231.874 90.357,232.438 95.801,237.295 99.258,240.379 104.702,245.236 107.598,247.818 113.037,252.674 115.547,254.914
116.475,255.744 121.305,250.335 118.48,247.818 "/> 116.475,255.744 121.305,250.335 118.48,247.818 '
<polygon fill={props.color} points="121.938,235.021 119.046,232.438 113.602,227.582 110.145,224.497 104.702,219.641 />
<polygon
fill={props.color}
points='121.938,235.021 119.046,232.438 113.602,227.582 110.145,224.497 104.702,219.641
103.604,218.66 102.675,217.834 97.854,223.24 99.258,224.497 104.702,229.352 108.159,232.438 113.602,237.295 116.495,239.876 103.604,218.66 102.675,217.834 97.854,223.24 99.258,224.497 104.702,229.352 108.159,232.438 113.602,237.295 116.495,239.876
121.938,244.732 123.672,246.279 124.604,247.109 129.428,241.701 127.382,239.876 "/> 121.938,244.732 123.672,246.279 124.604,247.109 129.428,241.701 127.382,239.876 '
<polygon fill={props.color} points="130.277,227.582 127.382,225 121.938,220.145 118.48,217.059 113.038,212.202 111.182,210.544 />
<polygon
fill={props.color}
points='130.277,227.582 127.382,225 121.938,220.145 118.48,217.059 113.038,212.202 111.182,210.544
110.253,209.718 105.43,215.125 107.598,217.059 113.038,221.915 116.495,225 121.938,229.855 124.833,232.438 130.277,237.295 110.253,209.718 105.43,215.125 107.598,217.059 113.038,221.915 116.495,225 121.938,229.855 124.833,232.438 130.277,237.295
132.18,238.994 137.002,233.585 135.718,232.438 "/> 132.18,238.994 137.002,233.585 135.718,232.438 '
/>
<rect x="94.143" y="244.919" transform="matrix(0.7403 0.6723 -0.6723 0.7403 193.2158 -0.6485)" fill={props.color} width="6.609" height="9.657"/>
<polygon fill={props.color} points="134.702,213.575 129.807,209.133 123.316,216.279 128.211,220.721 "/> <rect
<polygon fill={props.color} points="211.316,197.4 212.245,198.23 217.073,192.823 194.257,172.467 190.32,168.954 185.497,174.359 x='94.143'
187.4,176.062 "/> y='244.919'
<polygon fill={props.color} points="219.443,188.768 220.369,189.598 225.197,184.189 205.331,166.463 199.373,161.146 transform='matrix(0.7403 0.6723 -0.6723 0.7403 193.2158 -0.6485)'
198.447,160.32 193.622,165.729 198.58,170.152 "/> fill={props.color}
<polygon fill={props.color} points="227.951,181.48 232.771,176.072 215.531,160.689 207.816,153.805 206.949,153.032 width='6.609'
206.021,152.205 201.341,157.452 201.198,157.611 208.893,164.475 "/> height='9.657'
/>
<rect x="189.921" y="187.4" transform="matrix(0.7405 0.6721 -0.6721 0.7405 179.3349 -79.9756)" fill={props.color} width="6.609" height="9.655"/> <polygon
<polygon fill={props.color} points="230.471,156.062 227.62,153.475 225.578,151.619 219.378,158.445 219.086,158.766 223.98,163.208 fill={props.color}
"/> points='134.702,213.575 129.807,209.133 123.316,216.279 128.211,220.721 '
<path fill={props.color} d="M112.534,187.282c-7.511,0-14.995,1.878-21.647,5.43c-10.848,5.793-18.796,15.479-22.379,27.277 />
<polygon
fill={props.color}
points='211.316,197.4 212.245,198.23 217.073,192.823 194.257,172.467 190.32,168.954 185.497,174.359
187.4,176.062 '
/>
<polygon
fill={props.color}
points='219.443,188.768 220.369,189.598 225.197,184.189 205.331,166.463 199.373,161.146
198.447,160.32 193.622,165.729 198.58,170.152 '
/>
<polygon
fill={props.color}
points='227.951,181.48 232.771,176.072 215.531,160.689 207.816,153.805 206.949,153.032
206.021,152.205 201.341,157.452 201.198,157.611 208.893,164.475 '
/>
<rect
x='189.921'
y='187.4'
transform='matrix(0.7405 0.6721 -0.6721 0.7405 179.3349 -79.9756)'
fill={props.color}
width='6.609'
height='9.655'
/>
<polygon
fill={props.color}
points='230.471,156.062 227.62,153.475 225.578,151.619 219.378,158.445 219.086,158.766 223.98,163.208
'
/>
<path
fill={props.color}
d='M112.534,187.282c-7.511,0-14.995,1.878-21.647,5.43c-10.848,5.793-18.796,15.479-22.379,27.277
c-3.583,11.796-2.365,24.266,3.426,35.112c8.033,15.037,23.646,24.379,40.742,24.379c7.51,0,14.996-1.877,21.648-5.431 c-3.583,11.796-2.365,24.266,3.426,35.112c8.033,15.037,23.646,24.379,40.742,24.379c7.51,0,14.996-1.877,21.648-5.431
c10.847-5.793,18.794-15.479,22.377-27.274c3.583-11.797,2.365-24.267-3.426-35.113 c10.847-5.793,18.794-15.479,22.377-27.274c3.583-11.797,2.365-24.267-3.426-35.113
C145.245,196.624,129.635,187.282,112.534,187.282z M128.768,263.645c-16.688,8.912-37.514,2.588-46.43-14.099 C145.245,196.624,129.635,187.282,112.534,187.282z M128.768,263.645c-16.688,8.912-37.514,2.588-46.43-14.099
c-8.908-16.688-2.584-37.517,14.104-46.428c16.688-8.913,37.519-2.586,46.432,14.1 c-8.908-16.688-2.584-37.517,14.104-46.428c16.688-8.913,37.519-2.586,46.432,14.1
C151.781,233.908,145.456,254.732,128.768,263.645z"/> C151.781,233.908,145.456,254.732,128.768,263.645z'
<path fill={props.color} d="M52.191,144.639c6.326,5.757,17.865,13.457,34.295,22.881c18.544,10.64,43.998,23.457,59.836,27.527 />
<path
fill={props.color}
d='M52.191,144.639c6.326,5.757,17.865,13.457,34.295,22.881c18.544,10.64,43.998,23.457,59.836,27.527
c0.785,0.199,1.621,0.301,2.484,0.301c1.916,0,5.619-0.547,15.812-4.947c0.823,2.479,1.856,4.886,3.086,7.188 c0.785,0.199,1.621,0.301,2.484,0.301c1.916,0,5.619-0.547,15.812-4.947c0.823,2.479,1.856,4.886,3.086,7.188
c8.032,15.037,23.644,24.379,40.743,24.379c7.509,0,14.994-1.878,21.646-5.43c10.847-5.792,18.796-15.478,22.378-27.274 c8.032,15.037,23.644,24.379,40.743,24.379c7.509,0,14.994-1.878,21.646-5.43c10.847-5.792,18.796-15.478,22.378-27.274
c3.583-11.798,2.365-24.268-3.428-35.113c-1.488-2.787-3.262-5.414-5.295-7.842c3.117-2.348,5.279-4.3,6.706-6.043 c3.583-11.798,2.365-24.268-3.428-35.113c-1.488-2.787-3.262-5.414-5.295-7.842c3.117-2.348,5.279-4.3,6.706-6.043
@ -61,12 +123,16 @@ export default function SellSatsIcon(props) {
c8.911,16.687,2.588,37.511-14.101,46.422c-16.688,8.914-37.517,2.588-46.431-14.101c-1.646-3.086-2.771-6.316-3.406-9.586 c8.911,16.687,2.588,37.511-14.101,46.422c-16.688,8.914-37.517,2.588-46.431-14.101c-1.646-3.086-2.771-6.316-3.406-9.586
C174.003,178.857,173.9,175.221,174.344,171.672z M240.285,125.102l-34.512-20.586l34.512-60.934V125.102z M197.343,99.484 C174.003,178.857,173.9,175.221,174.344,171.672z M240.285,125.102l-34.512-20.586l34.512-60.934V125.102z M197.343,99.484
l-47.237-28.183l-46.689,28.232l-37.43-66.089c0.445-0.066,0.896-0.113,1.357-0.113h163.938c1.125,0,2.196,0.216,3.19,0.595 l-47.237-28.183l-46.689,28.232l-37.43-66.089c0.445-0.066,0.896-0.113,1.357-0.113h163.938c1.125,0,2.196,0.216,3.19,0.595
L197.343,99.484z"/> L197.343,99.484z'
<path fill={props.color} d="M30.079,300H269.92c16.587,0,30.08-13.494,30.08-30.08V30.08C300,13.494,286.507,0,269.92,0H30.079 />
<path
fill={props.color}
d='M30.079,300H269.92c16.587,0,30.08-13.494,30.08-30.08V30.08C300,13.494,286.507,0,269.92,0H30.079
C13.494,0,0,13.494,0,30.08v239.84C0,286.506,13.494,300,30.079,300z M15.587,30.08c0-7.992,6.501-14.494,14.492-14.494H269.92 C13.494,0,0,13.494,0,30.08v239.84C0,286.506,13.494,300,30.079,300z M15.587,30.08c0-7.992,6.501-14.494,14.492-14.494H269.92
c7.992,0,14.494,6.502,14.494,14.494v239.84c0,7.992-6.502,14.494-14.494,14.494H30.079c-7.991,0-14.492-6.502-14.492-14.494 c7.992,0,14.494,6.502,14.494,14.494v239.84c0,7.992-6.502,14.494-14.494,14.494H30.079c-7.991,0-14.492-6.502-14.492-14.494
V30.08z"/> V30.08z'
</g> />
</SvgIcon> </g>
); </SvgIcon>
} );
}

View File

@ -1,13 +1,18 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function SellSatsCheckedIcon(props) { export default function SellSatsCheckedIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} x="0px" y="0px" viewBox="0 0 300 300"> <SvgIcon sx={props.sx} color={props.color} x='0px' y='0px' viewBox='0 0 300 300'>
<g> <g>
<polygon fill={props.color} points="240.285,125.102 240.285,43.582 205.773,104.516 "/> <polygon fill={props.color} points='240.285,125.102 240.285,43.582 205.773,104.516 ' />
<path fill={props.color} d="M58.583,40.294c-0.151,0.657-0.24,1.34-0.24,2.042v84.453l36.673-22.176L58.583,40.294z"/> <path
<path fill={props.color} d="M112.81,199.078c-5.534-0.042-11.153,1.255-16.368,4.04c-16.688,8.911-23.012,29.739-14.104,46.428 fill={props.color}
d='M58.583,40.294c-0.151,0.657-0.24,1.34-0.24,2.042v84.453l36.673-22.176L58.583,40.294z'
/>
<path
fill={props.color}
d='M112.81,199.078c-5.534-0.042-11.153,1.255-16.368,4.04c-16.688,8.911-23.012,29.739-14.104,46.428
c6.13,11.472,17.889,18.046,30.062,18.139c5.533,0.042,11.152-1.255,16.368-4.04c0.521-0.278,1.033-0.568,1.534-0.87 c6.13,11.472,17.889,18.046,30.062,18.139c5.533,0.042,11.152-1.255,16.368-4.04c0.521-0.278,1.033-0.568,1.534-0.87
c1.002-0.603,1.963-1.249,2.882-1.938c1.46-1.093,2.813-2.289,4.056-3.571c5.381-5.558,8.668-12.749,9.475-20.292 c1.002-0.603,1.963-1.249,2.882-1.938c1.46-1.093,2.813-2.289,4.056-3.571c5.381-5.558,8.668-12.749,9.475-20.292
c0.706-6.601-0.487-13.471-3.841-19.756C136.746,205.746,124.985,199.171,112.81,199.078z M129.807,209.133l4.895,4.442 c0.706-6.601-0.487-13.471-3.841-19.756C136.746,205.746,124.985,199.171,112.81,199.078z M129.807,209.133l4.895,4.442
@ -18,10 +23,16 @@ export default function SellSatsCheckedIcon(props) {
l-1.404-1.257l4.821-5.406l0.001,0.001l0.928,0.825l1.098,0.98l5.443,4.856l3.457,3.085l5.444,4.855l2.892,2.584l5.444,4.854 l-1.404-1.257l4.821-5.406l0.001,0.001l0.928,0.825l1.098,0.98l5.443,4.856l3.457,3.085l5.444,4.855l2.892,2.584l5.444,4.854
l2.046,1.825L124.604,247.109z M132.18,238.994l-1.903-1.699l-5.444-4.857l-2.895-2.582L116.495,225l-3.457-3.085l-5.44-4.856 l2.046,1.825L124.604,247.109z M132.18,238.994l-1.903-1.699l-5.444-4.857l-2.895-2.582L116.495,225l-3.457-3.085l-5.44-4.856
l-2.168-1.934l4.823-5.407l0.929,0.826l1.856,1.658l5.442,4.856l3.458,3.086l4.854,4.33l0.589,0.525l2.895,2.582l5.441,4.855 l-2.168-1.934l4.823-5.407l0.929,0.826l1.856,1.658l5.442,4.856l3.458,3.086l4.854,4.33l0.589,0.525l2.895,2.582l5.441,4.855
l1.283,1.146l0.001,0.001L132.18,238.994z"/> l1.283,1.146l0.001,0.001L132.18,238.994z'
<path fill={props.color} d="M103.417,99.533l46.689-28.232l47.237,28.183l10.278-18.148l26.851-47.409l0.001-0.001 />
c-0.994-0.379-2.065-0.595-3.19-0.595H67.344c-0.461,0-0.912,0.047-1.357,0.113l0.002,0.003L103.417,99.533z"/> <path
<path fill={props.color} d="M188.072,137.845c2.039-1.089,4.131-1.976,6.249-2.708c12.551-4.337,26.17-2.534,37.015,4.271l0.001,0 fill={props.color}
d='M103.417,99.533l46.689-28.232l47.237,28.183l10.278-18.148l26.851-47.409l0.001-0.001
c-0.994-0.379-2.065-0.595-3.19-0.595H67.344c-0.461,0-0.912,0.047-1.357,0.113l0.002,0.003L103.417,99.533z'
/>
<path
fill={props.color}
d='M188.072,137.845c2.039-1.089,4.131-1.976,6.249-2.708c12.551-4.337,26.17-2.534,37.015,4.271l0.001,0
c2.595-1.757,4.685-3.269,6.238-4.499l-56.337-33.61c0,0.001,0,0.003,0,0.004c1.895,17.026-6.509,34.3-22.518,42.847 c2.595-1.757,4.685-3.269,6.238-4.499l-56.337-33.61c0,0.001,0,0.003,0,0.004c1.895,17.026-6.509,34.3-22.518,42.847
c-6.553,3.5-13.612,5.129-20.564,5.076c-15.294-0.117-30.068-8.378-37.768-22.792c-1.731-3.242-3.001-6.613-3.84-10.029 c-6.553,3.5-13.612,5.129-20.564,5.076c-15.294-0.117-30.068-8.378-37.768-22.792c-1.731-3.242-3.001-6.613-3.84-10.029
l7.985-4.906l0.001,0c0.578,3.681,1.761,7.325,3.615,10.793c4.733,8.866,12.831,14.807,21.884,17.093 l7.985-4.906l0.001,0c0.578,3.681,1.761,7.325,3.615,10.793c4.733,8.866,12.831,14.807,21.884,17.093
@ -35,8 +46,11 @@ export default function SellSatsCheckedIcon(props) {
M132.6,94.252l3.351,2.992l3.459,3.084l5.444,4.858l2.89,2.582l5.443,4.855l2.046,1.825l0.001,0.001l-4.826,5.406l-0.928-0.83 M132.6,94.252l3.351,2.992l3.459,3.084l5.444,4.858l2.89,2.582l5.443,4.855l2.046,1.825l0.001,0.001l-4.826,5.406l-0.928-0.83
l-1.736-1.546l-5.439-4.856l-2.893-2.583l-5.446-4.856l-3.457-3.084l-4.359-3.887L132.6,94.252z M119.174,102.5l2.883-1.771 l-1.736-1.546l-5.439-4.856l-2.893-2.583l-5.446-4.856l-3.457-3.084l-4.359-3.887L132.6,94.252z M119.174,102.5l2.883-1.771
l4.996,4.455l3.456,3.086l5.442,4.855l2.895,2.584l5.442,4.855l2.819,2.518l-4.824,5.408l-0.928-0.83l-2.509-2.239l-5.442-4.857 l4.996,4.455l3.456,3.086l5.442,4.855l2.895,2.584l5.442,4.855l2.819,2.518l-4.824,5.408l-0.928-0.83l-2.509-2.239l-5.442-4.857
l-2.893-2.582l-5.445-4.857l-3.457-3.085l-5.443-4.856l-0.553-0.493l-0.002-0.002L119.174,102.5z"/> l-2.893-2.582l-5.445-4.857l-3.457-3.085l-5.443-4.856l-0.553-0.493l-0.002-0.002L119.174,102.5z'
<path fill={props.color} d="M231.82,150.836c-2.649-2.482-5.65-4.502-8.875-6.015c-9.465-4.428-20.827-4.506-30.732,0.785 />
<path
fill={props.color}
d='M231.82,150.836c-2.649-2.482-5.65-4.502-8.875-6.015c-9.465-4.428-20.827-4.506-30.732,0.785
c-10.213,5.453-16.535,15.369-17.869,26.066c-0.119,0.951-0.191,1.909-0.23,2.87c-0.108,2.625,0.076,5.276,0.587,7.903 c-10.213,5.453-16.535,15.369-17.869,26.066c-0.119,0.951-0.191,1.909-0.23,2.87c-0.108,2.625,0.076,5.276,0.587,7.903
c0.635,3.271,1.76,6.5,3.405,9.587c8.914,16.688,29.744,23.015,46.432,14.101c10.432-5.569,16.812-15.792,17.956-26.751 c0.635,3.271,1.76,6.5,3.405,9.587c8.914,16.688,29.744,23.015,46.432,14.101c10.432-5.569,16.812-15.792,17.956-26.751
c0.686-6.574-0.514-13.413-3.854-19.671C236.818,156.305,234.497,153.338,231.82,150.836z M219.378,158.445l6.2-6.826l2.042,1.855 c0.686-6.574-0.514-13.413-3.854-19.671C236.818,156.305,234.497,153.338,231.82,150.836z M219.378,158.445l6.2-6.826l2.042,1.855
@ -44,8 +58,11 @@ export default function SellSatsCheckedIcon(props) {
l1.473-1.623l4.895,4.442L197.446,192.499z M212.245,198.23l-0.929-0.83L187.4,176.062l-1.903-1.703l4.823-5.405l3.937,3.513 l1.473-1.623l4.895,4.442L197.446,192.499z M212.245,198.23l-0.929-0.83L187.4,176.062l-1.903-1.703l4.823-5.405l3.937,3.513
l22.816,20.356L212.245,198.23z M220.369,189.598l-0.926-0.83l-20.863-18.615l-4.958-4.424l4.825-5.408l0.926,0.826l5.958,5.316 l22.816,20.356L212.245,198.23z M220.369,189.598l-0.926-0.83l-20.863-18.615l-4.958-4.424l4.825-5.408l0.926,0.826l5.958,5.316
l19.866,17.727L220.369,189.598z M227.951,181.48l-19.059-17.006l-7.694-6.863l0.143-0.159l4.681-5.247l0.928,0.827l0.867,0.772 l19.866,17.727L220.369,189.598z M227.951,181.48l-19.059-17.006l-7.694-6.863l0.143-0.159l4.681-5.247l0.928,0.827l0.867,0.772
l7.715,6.885l17.24,15.383L227.951,181.48z"/> l7.715,6.885l17.24,15.383L227.951,181.48z'
<path fill={props.color} d="M269.92,0H30.079C13.494,0,0,13.494,0,30.08v239.84C0,286.506,13.494,300,30.079,300H269.92 />
<path
fill={props.color}
d='M269.92,0H30.079C13.494,0,0,13.494,0,30.08v239.84C0,286.506,13.494,300,30.079,300H269.92
c16.587,0,30.08-13.494,30.08-30.08V30.08C300,13.494,286.507,0,269.92,0z M157.316,244.557c-0.187,0.741-0.392,1.481-0.615,2.219 c16.587,0,30.08-13.494,30.08-30.08V30.08C300,13.494,286.507,0,269.92,0z M157.316,244.557c-0.187,0.741-0.392,1.481-0.615,2.219
c-3.583,11.795-11.53,21.48-22.377,27.273c-6.652,3.555-14.138,5.432-21.648,5.432c-17.096,0-32.709-9.342-40.742-24.379 c-3.583,11.795-11.53,21.48-22.377,27.273c-6.652,3.555-14.138,5.432-21.648,5.432c-17.096,0-32.709-9.342-40.742-24.379
c-3.62-6.779-5.453-14.192-5.444-21.679c0.004-2.995,0.302-6.001,0.898-8.983c0.298-1.491,0.671-2.977,1.119-4.451 c-3.62-6.779-5.453-14.192-5.444-21.679c0.004-2.995,0.302-6.001,0.898-8.983c0.298-1.491,0.671-2.977,1.119-4.451
@ -57,8 +74,9 @@ export default function SellSatsCheckedIcon(props) {
c-16.43-9.424-27.969-17.124-34.295-22.88c-1.155-1.052-2.111-2.014-2.902-2.899c-3.426-3.833-3.765-6.229-3.761-8.206V42.337 c-16.43-9.424-27.969-17.124-34.295-22.88c-1.155-1.052-2.111-2.014-2.902-2.899c-3.426-3.833-3.765-6.229-3.761-8.206V42.337
c0-12.027,9.789-21.814,21.817-21.814l163.939-0.005c5.638,0,10.784,2.151,14.66,5.675c4.393,3.994,7.155,9.752,7.155,16.143 c0-12.027,9.789-21.814,21.817-21.814l163.939-0.005c5.638,0,10.784,2.151,14.66,5.675c4.393,3.994,7.155,9.752,7.155,16.143
v91.201c0,2.378-0.841,4.516-2.646,6.729c-1.427,1.743-3.589,3.695-6.706,6.043c2.033,2.428,3.807,5.055,5.295,7.841 v91.201c0,2.378-0.841,4.516-2.646,6.729c-1.427,1.743-3.589,3.695-6.706,6.043c2.033,2.428,3.807,5.055,5.295,7.841
C254.836,164.996,256.054,177.466,252.471,189.264z"/> C254.836,164.996,256.054,177.466,252.471,189.264z'
/>
</g> </g>
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,11 +1,13 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function SendReceiveIcon(props) { export default function SendReceiveIcon(props) {
return ( return (
<SvgIcon sx={props.sx} color={props.color} x="0px" y="0px" viewBox="0 0 300 300"> <SvgIcon sx={props.sx} color={props.color} x='0px' y='0px' viewBox='0 0 300 300'>
<g> <g>
<path fill={props.color} d="M150.021,2.579C68.341,2.579,2.127,68.793,2.127,150.472c0,81.682,66.214,147.895,147.895,147.895 <path
fill={props.color}
d='M150.021,2.579C68.341,2.579,2.127,68.793,2.127,150.472c0,81.682,66.214,147.895,147.895,147.895
c81.676,0,147.89-66.213,147.89-147.895C297.911,68.793,231.697,2.579,150.021,2.579z M99.195,73.557 c81.676,0,147.89-66.213,147.89-147.895C297.911,68.793,231.697,2.579,150.021,2.579z M99.195,73.557
c0,0,60.301,60.307,60.306,60.309c4.899,4.895,11.188,13.849,8.663,21.061c-1.835,5.236-6.053,9.546-9.893,13.383 c0,0,60.301,60.307,60.306,60.309c4.899,4.895,11.188,13.849,8.663,21.061c-1.835,5.236-6.053,9.546-9.893,13.383
c-0.091,0.093-59.076,59.078-59.076,59.078c-6.26,6.26-16.406,6.26-22.665,0c-6.261-6.256-6.261-16.406,0-22.665l54.247-54.25 c-0.091,0.093-59.076,59.078-59.076,59.078c-6.26,6.26-16.406,6.26-22.665,0c-6.261-6.256-6.261-16.406,0-22.665l54.247-54.25
@ -13,8 +15,9 @@ export default function SendReceiveIcon(props) {
z M146.365,73.557c3.125-3.128,7.23-4.693,11.33-4.693c4.101,0,8.204,1.565,11.335,4.693c0,0,60.303,60.307,60.308,60.309 z M146.365,73.557c3.125-3.128,7.23-4.693,11.33-4.693c4.101,0,8.204,1.565,11.335,4.693c0,0,60.303,60.307,60.308,60.309
c4.895,4.894,11.188,13.849,8.659,21.061c-1.832,5.236-6.05,9.546-9.889,13.383c-0.092,0.094-59.078,59.078-59.078,59.078 c4.895,4.894,11.188,13.849,8.659,21.061c-1.832,5.236-6.05,9.546-9.889,13.383c-0.092,0.094-59.078,59.078-59.078,59.078
c-6.256,6.26-16.405,6.26-22.665,0c-6.258-6.256-6.258-16.406,0-22.665l54.246-54.25l-54.246-54.25 c-6.256,6.26-16.405,6.26-22.665,0c-6.258-6.256-6.258-16.406,0-22.665l54.246-54.25l-54.246-54.25
C140.107,89.966,140.107,79.818,146.365,73.557z"/> C140.107,89.966,140.107,79.818,146.365,73.557z'
</g> />
</SvgIcon> </g>
); </SvgIcon>
} );
}

View File

@ -1,11 +1,10 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { SvgIcon } from "@mui/material" import { SvgIcon } from '@mui/material';
export default function UserNinjaIcon(props) { export default function UserNinjaIcon(props) {
return ( return (
<SvgIcon {...props} x="0px" y="0px" viewBox="0 0 512 512"> <SvgIcon {...props} x='0px' y='0px' viewBox='0 0 512 512'>
<path d="M64 192c27.25 0 51.75-11.5 69.25-29.75c15 54 64 93.75 122.8 93.75c70.75 0 127.1-57.25 127.1-128s-57.25-128-127.1-128c-50.38 0-93.63 29.38-114.5 71.75C124.1 47.75 96 32 64 32c0 33.37 17.12 62.75 43.13 80C81.13 129.3 64 158.6 64 192zM208 96h95.1C321.7 96 336 110.3 336 128h-160C176 110.3 190.3 96 208 96zM337.8 306.9L256 416L174.2 306.9C93.36 321.6 32 392.2 32 477.3c0 19.14 15.52 34.67 34.66 34.67H445.3c19.14 0 34.66-15.52 34.66-34.67C480 392.2 418.6 321.6 337.8 306.9z"/> <path d='M64 192c27.25 0 51.75-11.5 69.25-29.75c15 54 64 93.75 122.8 93.75c70.75 0 127.1-57.25 127.1-128s-57.25-128-127.1-128c-50.38 0-93.63 29.38-114.5 71.75C124.1 47.75 96 32 64 32c0 33.37 17.12 62.75 43.13 80C81.13 129.3 64 158.6 64 192zM208 96h95.1C321.7 96 336 110.3 336 128h-160C176 110.3 190.3 96 208 96zM337.8 306.9L256 416L174.2 306.9C93.36 321.6 32 392.2 32 477.3c0 19.14 15.52 34.67 34.66 34.67H445.3c19.14 0 34.66-15.52 34.66-34.67C480 392.2 418.6 321.6 337.8 306.9z' />
</SvgIcon> </SvgIcon>
); );
} }

View File

@ -1,20 +1,20 @@
export { default as AmbossIcon } from "./Amboss"; export { default as AmbossIcon } from './Amboss';
export { default as BitcoinIcon } from "./Bitcoin"; export { default as BitcoinIcon } from './Bitcoin';
export { default as BitcoinSignIcon } from "./BitcoinSign"; export { default as BitcoinSignIcon } from './BitcoinSign';
export { default as BuySatsIcon } from "./BuySats"; export { default as BuySatsIcon } from './BuySats';
export { default as BuySatsCheckedIcon } from "./BuySatsChecked"; export { default as BuySatsCheckedIcon } from './BuySatsChecked';
export { default as EarthIcon } from "./Earth"; export { default as EarthIcon } from './Earth';
export { default as GoldIcon } from "./Gold"; export { default as GoldIcon } from './Gold';
export { default as NewTabIcon } from "./NewTab"; export { default as NewTabIcon } from './NewTab';
export { default as RoboSatsIcon } from "./RoboSats"; export { default as RoboSatsIcon } from './RoboSats';
export { default as RoboSatsNoTextIcon } from "./RoboSatsNoText"; export { default as RoboSatsNoTextIcon } from './RoboSatsNoText';
export { default as RoboSatsTextIcon } from "./RoboSatsText"; export { default as RoboSatsTextIcon } from './RoboSatsText';
export { default as SellSatsCheckedIcon } from "./SellSatsChecked"; export { default as SellSatsCheckedIcon } from './SellSatsChecked';
export { default as SellSatsIcon } from "./SellSats"; export { default as SellSatsIcon } from './SellSats';
export { default as SendReceiveIcon } from "./SendReceive"; export { default as SendReceiveIcon } from './SendReceive';
export { default as ExportIcon } from "./Export"; export { default as ExportIcon } from './Export';
export { default as UserNinjaIcon } from "./UserNinja"; export { default as UserNinjaIcon } from './UserNinja';
// Some Flags missing on react-flags // Some Flags missing on react-flags
export { default as BasqueCountryFlag } from "./BasqueCountryFlag"; export { default as BasqueCountryFlag } from './BasqueCountryFlag';
export { default as CataloniaFlag } from "./CataloniaFlag"; export { default as CataloniaFlag } from './CataloniaFlag';

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react';
import { Box, LinearProgress } from "@mui/material" import { Box, LinearProgress } from '@mui/material';
import { calcTimeDelta } from 'react-countdown'; import { calcTimeDelta } from 'react-countdown';
type Props = { type Props = {
@ -7,10 +7,7 @@ type Props = {
totalSecsExp: number; totalSecsExp: number;
}; };
const LinearDeterminate = ({ const LinearDeterminate = ({ expiresAt, totalSecsExp }: Props): JSX.Element => {
expiresAt,
totalSecsExp,
}: Props): JSX.Element => {
const [progress, setProgress] = useState<number>(0); const [progress, setProgress] = useState<number>(0);
useEffect(() => { useEffect(() => {
@ -28,7 +25,7 @@ const LinearDeterminate = ({
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
<LinearProgress variant="determinate" value={progress} /> <LinearProgress variant='determinate' value={progress} />
</Box> </Box>
); );
}; };

View File

@ -1 +1 @@
export { default } from "./LinearDeterminate"; export { default } from './LinearDeterminate';

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,107 @@
import React, { Component } from 'react' import React, { Component } from 'react';
import { withTranslation } from "react-i18next"; import { withTranslation } from 'react-i18next';
import PaymentIcon from './payment-methods/Icons' import PaymentIcon from './payment-methods/Icons';
import {Tooltip} from "@mui/material" import { Tooltip } from '@mui/material';
import { paymentMethods, swapDestinations } from "./payment-methods/Methods"; import { paymentMethods, swapDestinations } from './payment-methods/Methods';
const ns = [{name: "not specified",icon:'notspecified'}]; const ns = [{ name: 'not specified', icon: 'notspecified' }];
const methods = ns.concat(swapDestinations).concat(paymentMethods); const methods = ns.concat(swapDestinations).concat(paymentMethods);
class PaymentText extends Component { class PaymentText extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
}
parseText() {
const { t } = this.props;
var rows = [];
var custom_methods = this.props.text;
// Adds icons for each PaymentMethod that matches
methods.forEach((method, i) => {
if (this.props.text.includes(method.name)) {
custom_methods = custom_methods.replace(method.name, '');
rows.push(
<Tooltip
key={`${method.name}-${i}`}
placement='top'
enterTouchDelay={0}
title={t(method.name)}
>
<div
style={{
display: 'inline-block',
width: this.props.size + 2,
height: this.props.size,
}}
>
<PaymentIcon width={this.props.size} height={this.props.size} icon={method.icon} />
</div>
</Tooltip>,
);
}
});
// Adds a Custom icon if there are words that do not match
var chars_left = custom_methods
.replace(' ', '')
.replace(' ', '')
.replace(' ', '')
.replace(' ', '')
.replace(' ', '');
if (chars_left.length > 0) {
rows.push(
<Tooltip
key={'pushed'}
placement='top'
enterTouchDelay={0}
title={
this.props.verbose
? this.props.othersText
: this.props.othersText + ': ' + custom_methods
}
>
<div
style={{
position: 'relative',
display: 'inline-block',
width: this.props.size + 2,
maxHeight: this.props.size,
top: '-1px',
}}
>
<PaymentIcon
width={this.props.size * 1.1}
height={this.props.size * 1.1}
icon={'custom'}
/>
</div>
</Tooltip>,
);
} }
parseText(){ if (this.props.verbose) {
const { t } = this.props;
var rows = [];
var custom_methods = this.props.text;
// Adds icons for each PaymentMethod that matches
methods.forEach((method, i) =>{
if(this.props.text.includes(method.name)){
custom_methods = custom_methods.replace(method.name,'')
rows.push(
<Tooltip key={`${method.name}-${i}`} placement="top" enterTouchDelay={0} title={t(method.name)}>
<div style={{display: 'inline-block', width: this.props.size+2, height: this.props.size}}>
<PaymentIcon width={this.props.size} height={this.props.size} icon={method.icon}/>
</div>
</Tooltip>
);
}
})
// Adds a Custom icon if there are words that do not match
var chars_left = custom_methods.replace(' ','').replace(' ','').replace(' ','').replace(' ','').replace(' ','')
if(chars_left.length > 0){rows.push(
<Tooltip key={"pushed"} placement="top" enterTouchDelay={0} title={this.props.verbose ? this.props.othersText: this.props.othersText+": "+ custom_methods} >
<div style={{position:'relative', display: 'inline-block',width: this.props.size+2, maxHeight: this.props.size, top:'-1px'}}>
<PaymentIcon width={this.props.size*1.1} height={this.props.size*1.1} icon={"custom"}/>
</div>
</Tooltip>
)}
if(this.props.verbose){
return (<>{rows} <div style={{display: 'inline-block'}}> <span>{custom_methods}</span></div></>)
}else{
return rows
}
}
render() {
return ( return (
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap'}}> <>
{this.parseText()} {rows}{' '}
</div> <div style={{ display: 'inline-block' }}>
) {' '}
<span>{custom_methods}</span>
</div>
</>
);
} else {
return rows;
} }
}
render() {
return (
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
{this.parseText()}
</div>
);
}
} }
export default withTranslation()(PaymentText); export default withTranslation()(PaymentText);

View File

@ -1,4 +1,4 @@
import { Slider } from "@mui/material" import { Slider } from '@mui/material';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
const RangeSlider = styled(Slider)(({ theme }) => ({ const RangeSlider = styled(Slider)(({ theme }) => ({
@ -6,15 +6,15 @@ const RangeSlider = styled(Slider)(({ theme }) => ({
height: 3, height: 3,
padding: '13px 0', padding: '13px 0',
'& .MuiSlider-thumb': { '& .MuiSlider-thumb': {
height: `${27/16}em`, height: `${27 / 16}em`,
width: `${27/16}em`, width: `${27 / 16}em`,
backgroundColor: '#fff', backgroundColor: '#fff',
border: '1px solid currentColor', border: '1px solid currentColor',
'&:hover': { '&:hover': {
boxShadow: '0 0 0 8px rgba(58, 133, 137, 0.16)', boxShadow: '0 0 0 8px rgba(58, 133, 137, 0.16)',
}, },
'& .range-bar': { '& .range-bar': {
height: `${9/16}em`, height: `${9 / 16}em`,
width: 1, width: 1,
backgroundColor: 'currentColor', backgroundColor: 'currentColor',
marginLeft: 1, marginLeft: 1,
@ -22,13 +22,13 @@ const RangeSlider = styled(Slider)(({ theme }) => ({
}, },
}, },
'& .MuiSlider-track': { '& .MuiSlider-track': {
height: `${3/16}em`, height: `${3 / 16}em`,
}, },
'& .MuiSlider-rail': { '& .MuiSlider-rail': {
color: theme.palette.mode === 'dark' ? '#bfbfbf' : '#d8d8d8', color: theme.palette.mode === 'dark' ? '#bfbfbf' : '#d8d8d8',
opacity: theme.palette.mode === 'dark' ? undefined : 1, opacity: theme.palette.mode === 'dark' ? undefined : 1,
height: `${3/16}em`, height: `${3 / 16}em`,
}, },
})); }));
export default RangeSlider; export default RangeSlider;

View File

@ -1,61 +1,74 @@
import React from "react" import React from 'react';
import { Badge, Tooltip } from "@mui/material"; import { Badge, Tooltip } from '@mui/material';
import SmoothImage from 'react-smooth-image' import SmoothImage from 'react-smooth-image';
import Order from "../../../models/Order.model" import Order from '../../../models/Order.model';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { SendReceiveIcon } from "../../Icons"; import { SendReceiveIcon } from '../../Icons';
interface DepthChartProps { interface DepthChartProps {
order: Order order: Order;
} }
const RobotAvatar: React.FC<DepthChartProps> = ({ order }) => { const RobotAvatar: React.FC<DepthChartProps> = ({ order }) => {
const { t } = useTranslation() const { t } = useTranslation();
const avatarSrc: string = window.location.origin +'/static/assets/avatars/' + order?.maker_nick + '.png' const avatarSrc: string =
window.location.origin + '/static/assets/avatars/' + order?.maker_nick + '.png';
const statusBadge = ( const statusBadge = (
<div style={{position:"relative", left:"6px", top:"1px"}}> <div style={{ position: 'relative', left: '6px', top: '1px' }}>
{order?.type === 0 ? {order?.type === 0 ? (
<SendReceiveIcon sx={{transform: "scaleX(-1)",height:"18px",width:"18px"}} color="secondary"/> : <SendReceiveIcon
<SendReceiveIcon sx={{height:"20px",width:"20px"}} color="primary"/>} sx={{ transform: 'scaleX(-1)', height: '18px', width: '18px' }}
color='secondary'
/>
) : (
<SendReceiveIcon sx={{ height: '20px', width: '20px' }} color='primary' />
)}
</div> </div>
) );
const statusBadgeColor = () => { const statusBadgeColor = () => {
if(!order){ return } if (!order) {
if(order.maker_status ==='Active'){ return("success") } return;
if(order.maker_status ==='Seen recently'){ return("warning") } }
if(order.maker_status ==='Inactive'){ return('error') } if (order.maker_status === 'Active') {
} return 'success';
}
if (order.maker_status === 'Seen recently') {
return 'warning';
}
if (order.maker_status === 'Inactive') {
return 'error';
}
};
return order ? ( return order ? (
<Tooltip placement="right" enterTouchDelay={0} title={t(order.maker_status) || ""}> <Tooltip placement='right' enterTouchDelay={0} title={t(order.maker_status) || ''}>
<Badge <Badge variant='dot' overlap='circular' badgeContent='' color={statusBadgeColor()}>
variant="dot" <Badge
overlap="circular" overlap='circular'
badgeContent="" anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
color={statusBadgeColor()}
>
<Badge
overlap="circular"
anchorOrigin={{horizontal: 'right', vertical: 'bottom'}}
badgeContent={statusBadge} badgeContent={statusBadge}
> >
<div style={{ width: 45, height: 45 }}> <div style={{ width: 45, height: 45 }}>
<SmoothImage <SmoothImage
src={avatarSrc} src={avatarSrc}
imageStyles={{borderRadius: "50%", imageStyles={{
transform: "scaleX(-1)", borderRadius: '50%',
border: "0.3px solid #555", transform: 'scaleX(-1)',
filter: "dropShadow(0.5px 0.5px 0.5px #000000)"}} border: '0.3px solid #555',
filter: 'dropShadow(0.5px 0.5px 0.5px #000000)',
}}
/> />
</div> </div>
</Badge> </Badge>
</Badge> </Badge>
</Tooltip> </Tooltip>
) : <></> ) : (
} <></>
);
};
export default RobotAvatar export default RobotAvatar;

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,28 @@
import React, { useState } from "react"; import React, { useState } from 'react';
import { format } from "date-fns"; import { format } from 'date-fns';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { import {
Avatar, Avatar,
Badge, Badge,
ToggleButton, ToggleButton,
ToggleButtonGroup, ToggleButtonGroup,
List, List,
ListItem, ListItem,
ListItemText, ListItemText,
ListItemIcon, ListItemIcon,
Grid, Grid,
Tooltip, Tooltip,
IconButton, IconButton,
Accordion, Accordion,
AccordionSummary, AccordionSummary,
AccordionDetails, AccordionDetails,
Typography, Typography,
} from "@mui/material" } from '@mui/material';
import { pn } from "../utils/prettyNumbers"; import { pn } from '../utils/prettyNumbers';
import { saveAsJson } from "../utils/saveFile"; import { saveAsJson } from '../utils/saveFile';
// Icons // Icons
import FlagWithProps from "./FlagWithProps"; import FlagWithProps from './FlagWithProps';
import ScheduleIcon from '@mui/icons-material/Schedule'; import ScheduleIcon from '@mui/icons-material/Schedule';
import PriceChangeIcon from '@mui/icons-material/PriceChange'; import PriceChangeIcon from '@mui/icons-material/PriceChange';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
@ -32,7 +32,7 @@ import RouteIcon from '@mui/icons-material/Route';
import AccountBoxIcon from '@mui/icons-material/AccountBox'; import AccountBoxIcon from '@mui/icons-material/AccountBox';
import LockOpenIcon from '@mui/icons-material/LockOpen'; import LockOpenIcon from '@mui/icons-material/LockOpen';
import LinkIcon from '@mui/icons-material/Link'; import LinkIcon from '@mui/icons-material/Link';
import { RoboSatsNoTextIcon , SendReceiveIcon , BitcoinIcon} from "./Icons"; import { RoboSatsNoTextIcon, SendReceiveIcon, BitcoinIcon } from './Icons';
interface Item { interface Item {
id: string; id: string;
@ -48,7 +48,7 @@ type Props = {
takerSummary: Record<string, Item>; takerSummary: Record<string, Item>;
platformSummary: Record<string, Item>; platformSummary: Record<string, Item>;
orderId: number; orderId: number;
} };
const TradeSummary = ({ const TradeSummary = ({
isMaker, isMaker,
@ -60,186 +60,261 @@ const TradeSummary = ({
platformSummary, platformSummary,
orderId, orderId,
}: Props): JSX.Element => { }: Props): JSX.Element => {
const { t , i18n } = useTranslation(); const { t, i18n } = useTranslation();
const [buttonValue, setButtonValue] = useState<number>(isMaker ? 0 : 2); const [buttonValue, setButtonValue] = useState<number>(isMaker ? 0 : 2);
var userSummary = buttonValue == 0 ? makerSummary : takerSummary; var userSummary = buttonValue == 0 ? makerSummary : takerSummary;
const contractTimestamp = new Date(platformSummary.contract_timestamp) const contractTimestamp = new Date(platformSummary.contract_timestamp);
const total_time = platformSummary.contract_total_time const total_time = platformSummary.contract_total_time;
const hours = parseInt(total_time / 3600) const hours = parseInt(total_time / 3600);
const mins = parseInt((total_time - hours * 3600) / 60) const mins = parseInt((total_time - hours * 3600) / 60);
const secs = parseInt(total_time - hours * 3600 - mins * 60) const secs = parseInt(total_time - hours * 3600 - mins * 60);
return ( return (
<Grid item xs={12} align="center"> <Grid item xs={12} align='center'>
<Accordion defaultExpanded={true} elevation={0} sx={{width:322, position:'relative', right:8}}> <Accordion
<AccordionSummary expandIcon={<ExpandMoreIcon sx={{width:28}} color="primary"/>}> defaultExpanded={true}
<Typography sx={{flexGrow:1}} color="text.secondary">{t("Trade Summary")}</Typography> elevation={0}
sx={{ width: 322, position: 'relative', right: 8 }}
>
<AccordionSummary expandIcon={<ExpandMoreIcon sx={{ width: 28 }} color='primary' />}>
<Typography sx={{ flexGrow: 1 }} color='text.secondary'>
{t('Trade Summary')}
</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<div style={{position:'relative',left:14, display:'flex',alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}> <div
<ToggleButtonGroup style={{
size="small" position: 'relative',
value={buttonValue} left: 14,
exclusive> display: 'flex',
<ToggleButton value={0} disableRipple={true} onClick={() => setButtonValue(0)}> alignItems: 'center',
<Avatar justifyContent: 'center',
className="flippedSmallAvatar" flexWrap: 'wrap',
sx={{height:24,width:24}} }}
alt={makerNick} >
src={window.location.origin +'/static/assets/avatars/' + makerNick + '.png'} <ToggleButtonGroup size='small' value={buttonValue} exclusive>
/> <ToggleButton value={0} disableRipple={true} onClick={() => setButtonValue(0)}>
&nbsp; <Avatar
{t("Maker")} className='flippedSmallAvatar'
</ToggleButton> sx={{ height: 24, width: 24 }}
<ToggleButton value={1} disableRipple={true} onClick={() => setButtonValue(1)}> alt={makerNick}
<RoboSatsNoTextIcon/> src={window.location.origin + '/static/assets/avatars/' + makerNick + '.png'}
</ToggleButton> />
<ToggleButton value={2} disableRipple={true} onClick={() => setButtonValue(2)}> &nbsp;
{t("Taker")} {t('Maker')}
&nbsp; </ToggleButton>
<Avatar <ToggleButton value={1} disableRipple={true} onClick={() => setButtonValue(1)}>
className="smallAvatar" <RoboSatsNoTextIcon />
sx={{height:28,width:28}} </ToggleButton>
alt={takerNick} <ToggleButton value={2} disableRipple={true} onClick={() => setButtonValue(2)}>
src={window.location.origin +'/static/assets/avatars/' + takerNick + '.png'} {t('Taker')}
/> &nbsp;
</ToggleButton> <Avatar
className='smallAvatar'
sx={{ height: 28, width: 28 }}
alt={takerNick}
src={window.location.origin + '/static/assets/avatars/' + takerNick + '.png'}
/>
</ToggleButton>
</ToggleButtonGroup> </ToggleButtonGroup>
<Tooltip enterTouchDelay={250} title={t("Save trade summary as file")}> <Tooltip enterTouchDelay={250} title={t('Save trade summary as file')}>
<span> <span>
<IconButton <IconButton
color="primary" color='primary'
onClick={()=> saveAsJson(`order${orderId}-summary.json`, {'order_id':orderId,'currency':currencyCode,'maker':makerSummary,'taker':takerSummary,'platform':platformSummary})} onClick={() =>
> saveAsJson(`order${orderId}-summary.json`, {
<DownloadIcon sx={{width:26, height:26}}/> order_id: orderId,
</IconButton> currency: currencyCode,
</span> maker: makerSummary,
</Tooltip> taker: takerSummary,
</div> platform: platformSummary,
{/* Maker/Taker Summary */} })
<div style={{display: [0,2].includes(buttonValue) ? '':'none'}}> }
<List dense={true}> >
<ListItem> <DownloadIcon sx={{ width: 26, height: 26 }} />
<ListItemIcon> </IconButton>
<Badge </span>
overlap="circular" </Tooltip>
anchorOrigin={{horizontal: 'right', vertical: 'bottom'}} </div>
badgeContent={<div {/* Maker/Taker Summary */}
style={{position:"relative", left:"3px", top:"2px"}}> <div style={{ display: [0, 2].includes(buttonValue) ? '' : 'none' }}>
{userSummary.is_buyer ? <List dense={true}>
<SendReceiveIcon <ListItem>
sx={{transform: "scaleX(-1)",height:"18px",width:"18px"}} <ListItemIcon>
color="secondary"/> <Badge
: <SendReceiveIcon overlap='circular'
sx={{height:"18px",width:"18px"}} anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
color="primary"/> badgeContent={
} <div style={{ position: 'relative', left: '3px', top: '2px' }}>
</div>}> {userSummary.is_buyer ? (
<AccountBoxIcon sx={{position:'relative',left:-2,width:28,height:28}}/> <SendReceiveIcon
</Badge> sx={{ transform: 'scaleX(-1)', height: '18px', width: '18px' }}
</ListItemIcon> color='secondary'
<ListItemText />
primary={userSummary.is_buyer ? t("Buyer") : t("Seller")} ) : (
secondary={t("User role")}/> <SendReceiveIcon sx={{ height: '18px', width: '18px' }} color='primary' />
)}
</div>
}
>
<AccountBoxIcon
sx={{ position: 'relative', left: -2, width: 28, height: 28 }}
/>
</Badge>
</ListItemIcon>
<ListItemText
primary={userSummary.is_buyer ? t('Buyer') : t('Seller')}
secondary={t('User role')}
/>
<ListItemIcon> <ListItemIcon>
<div style={{position:'relative',left:15,zoom:1.25,opacity: 0.7,msZoom:1.25,WebkitZoom:1.25,MozTransform:'scale(1.25,1.25)',MozTransformOrigin:'left center'}}> <div
<FlagWithProps code={currencyCode}/> style={{
</div> position: 'relative',
</ListItemIcon> left: 15,
<ListItemText zoom: 1.25,
primary={(userSummary.is_buyer ? pn(userSummary.sent_fiat) : pn(userSummary.received_fiat))+" "+currencyCode} opacity: 0.7,
secondary={userSummary.is_buyer ? t("Sent") : t("Received")}/> msZoom: 1.25,
</ListItem> WebkitZoom: 1.25,
MozTransform: 'scale(1.25,1.25)',
<ListItem> MozTransformOrigin: 'left center',
<ListItemIcon> }}
<BitcoinIcon/> >
</ListItemIcon> <FlagWithProps code={currencyCode} />
<ListItemText </div>
primary={pn(userSummary.is_buyer ? userSummary.received_sats : userSummary.sent_sats)+" Sats"} </ListItemIcon>
secondary={userSummary.is_buyer ? "BTC received" : "BTC sent"}/> <ListItemText
primary={
(userSummary.is_buyer
? pn(userSummary.sent_fiat)
: pn(userSummary.received_fiat)) +
' ' +
currencyCode
}
secondary={userSummary.is_buyer ? t('Sent') : t('Received')}
/>
</ListItem>
<ListItemText <ListItem>
primary={t("{{tradeFeeSats}} Sats ({{tradeFeePercent}}%)",{tradeFeeSats:pn(userSummary.trade_fee_sats),tradeFeePercent:parseFloat((userSummary.trade_fee_percent*100).toPrecision(3))})} <ListItemIcon>
secondary={"Trade fee"}/> <BitcoinIcon />
</ListItem> </ListItemIcon>
<ListItemText
{userSummary.is_swap ? primary={
<ListItem> pn(userSummary.is_buyer ? userSummary.received_sats : userSummary.sent_sats) +
<ListItemIcon> ' Sats'
<LinkIcon/> }
</ListItemIcon> secondary={userSummary.is_buyer ? 'BTC received' : 'BTC sent'}
<ListItemText />
primary={t("{{swapFeeSats}} Sats ({{swapFeePercent}}%)" , {swapFeeSats:pn(userSummary.swap_fee_sats), swapFeePercent:userSummary.swap_fee_percent})}
secondary={t("Onchain swap fee")}/>
<ListItemText
primary={t("{{miningFeeSats}} Sats",{miningFeeSats:pn(userSummary.mining_fee_sats)})}
secondary={t("Mining fee")}/>
</ListItem>
: null}
<ListItem> <ListItemText
<ListItemIcon> primary={t('{{tradeFeeSats}} Sats ({{tradeFeePercent}}%)', {
<LockOpenIcon color="success"/> tradeFeeSats: pn(userSummary.trade_fee_sats),
</ListItemIcon> tradeFeePercent: parseFloat(
<ListItemText (userSummary.trade_fee_percent * 100).toPrecision(3),
primary={t("{{bondSats}} Sats ({{bondPercent}}%)" , {bondSats:pn(userSummary.bond_size_sats), bondPercent:userSummary.bond_size_percent})} ),
secondary={buttonValue === 0 ? t("Maker bond") : t("Taker bond") }/> })}
<ListItemText secondary={'Trade fee'}
sx={{color:'#2e7d32'}} />
primary={<b>{t("Unlocked")}</b>}/> </ListItem>
</ListItem>
</List> {userSummary.is_swap ? (
</div>
{/* Platform Summary */}
<div style={{display: buttonValue == 1 ? '':'none'}}>
<List dense={true}>
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<AccountBalanceIcon/> <LinkIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={t("{{revenueSats}} Sats",{revenueSats:pn(platformSummary.trade_revenue_sats)})} primary={t('{{swapFeeSats}} Sats ({{swapFeePercent}}%)', {
secondary={t("Platform trade revenue")}/> swapFeeSats: pn(userSummary.swap_fee_sats),
</ListItem> swapFeePercent: userSummary.swap_fee_percent,
})}
<ListItem> secondary={t('Onchain swap fee')}
<ListItemIcon> />
<RouteIcon/> <ListItemText
</ListItemIcon> primary={t('{{miningFeeSats}} Sats', {
<ListItemText miningFeeSats: pn(userSummary.mining_fee_sats),
primary={t("{{routingFeeSats}} MiliSats",{routingFeeSats:pn(platformSummary.routing_fee_sats)})} })}
secondary={t("Platform covered routing fee")}/> secondary={t('Mining fee')}
/>
</ListItem> </ListItem>
) : null}
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<PriceChangeIcon/> <LockOpenIcon color='success' />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={`${pn(platformSummary.contract_exchange_rate.toPrecision(7))} ${currencyCode}/BTC`} primary={t('{{bondSats}} Sats ({{bondPercent}}%)', {
secondary={t("Contract exchange rate")}/> bondSats: pn(userSummary.bond_size_sats),
</ListItem> bondPercent: userSummary.bond_size_percent,
})}
<ListItem> secondary={buttonValue === 0 ? t('Maker bond') : t('Taker bond')}
<ListItemText />
primary={format(contractTimestamp, "do LLL HH:mm:ss")} <ListItemText sx={{ color: '#2e7d32' }} primary={<b>{t('Unlocked')}</b>} />
secondary={t("Timestamp")}/> </ListItem>
<ListItemIcon> </List>
<ScheduleIcon/> </div>
</ListItemIcon> {/* Platform Summary */}
<ListItemText <div style={{ display: buttonValue == 1 ? '' : 'none' }}>
primary={`${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`} <List dense={true}>
secondary={t("Completed in")}/> <ListItem>
</ListItem> <ListItemIcon>
</List> <AccountBalanceIcon />
</div> </ListItemIcon>
<ListItemText
primary={t('{{revenueSats}} Sats', {
revenueSats: pn(platformSummary.trade_revenue_sats),
})}
secondary={t('Platform trade revenue')}
/>
</ListItem>
<ListItem>
<ListItemIcon>
<RouteIcon />
</ListItemIcon>
<ListItemText
primary={t('{{routingFeeSats}} MiliSats', {
routingFeeSats: pn(platformSummary.routing_fee_sats),
})}
secondary={t('Platform covered routing fee')}
/>
</ListItem>
<ListItem>
<ListItemIcon>
<PriceChangeIcon />
</ListItemIcon>
<ListItemText
primary={`${pn(
platformSummary.contract_exchange_rate.toPrecision(7),
)} ${currencyCode}/BTC`}
secondary={t('Contract exchange rate')}
/>
</ListItem>
<ListItem>
<ListItemText
primary={format(contractTimestamp, 'do LLL HH:mm:ss')}
secondary={t('Timestamp')}
/>
<ListItemIcon>
<ScheduleIcon />
</ListItemIcon>
<ListItemText
primary={`${String(hours).padStart(2, '0')}:${String(mins).padStart(
2,
'0',
)}:${String(secs).padStart(2, '0')}`}
secondary={t('Completed in')}
/>
</ListItem>
</List>
</div>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
</Grid> </Grid>
); );
}; };
export default TradeSummary; export default TradeSummary;

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react' import React, { Component } from 'react';
import { withTranslation, Trans} from "react-i18next"; import { withTranslation, Trans } from 'react-i18next';
import {Paper, Alert, AlertTitle, Button, Link} from "@mui/material" import { Paper, Alert, AlertTitle, Button, Link } from '@mui/material';
import MediaQuery from 'react-responsive' import MediaQuery from 'react-responsive';
class UnsafeAlert extends Component { class UnsafeAlert extends Component {
constructor(props) { constructor(props) {
@ -11,86 +11,126 @@ class UnsafeAlert extends Component {
isSelfhosted: this.isSelfhosted(), isSelfhosted: this.isSelfhosted(),
}; };
} }
getHost(){ getHost() {
var url = (window.location != window.parent.location) ? this.getHost(document.referrer) : document.location.href; var url =
return url.split('/')[2] window.location != window.parent.location
? this.getHost(document.referrer)
: document.location.href;
return url.split('/')[2];
} }
isSelfhosted(){ isSelfhosted() {
var http = new XMLHttpRequest(); var http = new XMLHttpRequest();
http.open('HEAD', `${location.protocol}//${this.getHost()}/selfhosted`, false); http.open('HEAD', `${location.protocol}//${this.getHost()}/selfhosted`, false);
http.send(); http.send();
return http.status!=404; return http.status != 404;
} }
safe_urls = [ safe_urls = [
'robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion', 'robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion',
'robotestagw3dcxmd66r4rgksb4nmmr43fh77bzn2ia2eucduyeafnyd.onion', 'robotestagw3dcxmd66r4rgksb4nmmr43fh77bzn2ia2eucduyeafnyd.onion',
'robodevs7ixniseezbv7uryxhamtz3hvcelzfwpx3rvoipttjomrmpqd.onion', 'robodevs7ixniseezbv7uryxhamtz3hvcelzfwpx3rvoipttjomrmpqd.onion',
'robosats.i2p', 'robosats.i2p',
'r7r4sckft6ptmk4r2jajiuqbowqyxiwsle4iyg4fijtoordc6z7a.b32.i2p', 'r7r4sckft6ptmk4r2jajiuqbowqyxiwsle4iyg4fijtoordc6z7a.b32.i2p',
] ];
render() { render() {
const { t, i18n} = this.props; const { t, i18n } = this.props;
// If alert is hidden return null // If alert is hidden return null
if (!this.state.show){return null} if (!this.state.show) {
return null;
}
// Show selfhosted notice // Show selfhosted notice
if (this.state.isSelfhosted){ if (this.state.isSelfhosted) {
return( return (
<div> <div>
<Paper elevation={6} className="alertUnsafe"> <Paper elevation={6} className='alertUnsafe'>
<Alert severity="success" sx={{maxHeight:"120px"}} <Alert
action={<Button color="success" onClick={() => this.setState({show:false})}>{t("Hide")}</Button>} severity='success'
> sx={{ maxHeight: '120px' }}
<AlertTitle>{t("You are self-hosting RoboSats")}</AlertTitle> action={
{t("RoboSats client is served from your own node granting you the strongest security and privacy.")} <Button color='success' onClick={() => this.setState({ show: false })}>
{t('Hide')}
</Button>
}
>
<AlertTitle>{t('You are self-hosting RoboSats')}</AlertTitle>
{t(
'RoboSats client is served from your own node granting you the strongest security and privacy.',
)}
</Alert> </Alert>
</Paper> </Paper>
</div> </div>
) );
} }
// Show unsafe alert // Show unsafe alert
if (!this.safe_urls.includes(this.getHost())){ if (!this.safe_urls.includes(this.getHost())) {
return( return (
<div> <div>
<MediaQuery minWidth={800}> <MediaQuery minWidth={800}>
<Paper elevation={6} className="alertUnsafe"> <Paper elevation={6} className='alertUnsafe'>
<Alert severity="warning" sx={{maxHeight:"100px"}} <Alert
action={<Button onClick={() => this.setState({show:false})}>{t("Hide")}</Button>} severity='warning'
sx={{ maxHeight: '100px' }}
action={<Button onClick={() => this.setState({ show: false })}>{t('Hide')}</Button>}
> >
<AlertTitle>{t("You are not using RoboSats privately")}</AlertTitle> <AlertTitle>{t('You are not using RoboSats privately')}</AlertTitle>
<Trans i18nKey="desktop_unsafe_alert"> <Trans i18nKey='desktop_unsafe_alert'>
Some features are disabled for your protection (e.g. chat) and you will not be able to complete a Some features are disabled for your protection (e.g. chat) and you will not be
trade without them. To protect your privacy and fully enable RoboSats, use <Link href='https://www.torproject.org/download/' target="_blank">Tor Browser</Link> and visit the <Link href='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion' target="_blank">Onion</Link> site. able to complete a trade without them. To protect your privacy and fully enable
RoboSats, use{' '}
<Link href='https://www.torproject.org/download/' target='_blank'>
Tor Browser
</Link>{' '}
and visit the{' '}
<Link
href='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion'
target='_blank'
>
Onion
</Link>{' '}
site.
</Trans> </Trans>
</Alert> </Alert>
</Paper> </Paper>
</MediaQuery> </MediaQuery>
<MediaQuery maxWidth={799}> <MediaQuery maxWidth={799}>
<Paper elevation={6} className="alertUnsafe"> <Paper elevation={6} className='alertUnsafe'>
<Alert severity="warning" sx={{maxHeight:"120px"}}> <Alert severity='warning' sx={{ maxHeight: '120px' }}>
<AlertTitle>{t("You are not using RoboSats privately")}</AlertTitle> <AlertTitle>{t('You are not using RoboSats privately')}</AlertTitle>
<Trans i18nKey="phone_unsafe_alert"> <Trans i18nKey='phone_unsafe_alert'>
You will not be able to complete a You will not be able to complete a trade. Use{' '}
trade. Use <Link href='https://www.torproject.org/download/' target="_blank">Tor Browser</Link> and visit the <Link href='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion' target="_blank">Onion</Link> site. <Link href='https://www.torproject.org/download/' target='_blank'>
</Trans> Tor Browser
<div style={{width: '100%'}}> </Link>{' '}
</div> and visit the{' '}
<div align="center"> <Link
<Button className="hideAlertButton" onClick={() => this.setState({show:false})}>{t("Hide")}</Button> href='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion'
</div> target='_blank'
</Alert> >
Onion
</Link>{' '}
site.
</Trans>
<div style={{ width: '100%' }}></div>
<div align='center'>
<Button
className='hideAlertButton'
onClick={() => this.setState({ show: false })}
>
{t('Hide')}
</Button>
</div>
</Alert>
</Paper> </Paper>
</MediaQuery> </MediaQuery>
</div> </div>
) );
} }
} }
} }

View File

@ -1,23 +1,32 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import { withTranslation } from "react-i18next"; import { withTranslation } from 'react-i18next';
import { Button , Tooltip, Grid, Typography, TextField, ButtonGroup, CircularProgress, IconButton} from "@mui/material" import {
import { Link } from 'react-router-dom' Button,
import SmoothImage from 'react-smooth-image' Tooltip,
import { InfoDialog } from './Dialogs' Grid,
Typography,
TextField,
ButtonGroup,
CircularProgress,
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'; import SmartToyIcon from '@mui/icons-material/SmartToy';
import CasinoIcon from '@mui/icons-material/Casino'; import CasinoIcon from '@mui/icons-material/Casino';
import ContentCopy from "@mui/icons-material/ContentCopy"; import ContentCopy from '@mui/icons-material/ContentCopy';
import BoltIcon from '@mui/icons-material/Bolt'; import BoltIcon from '@mui/icons-material/Bolt';
import DownloadIcon from '@mui/icons-material/Download'; import DownloadIcon from '@mui/icons-material/Download';
import { RoboSatsNoTextIcon } from "./Icons"; import { RoboSatsNoTextIcon } from './Icons';
import { sha256 } from 'js-sha256'; import { sha256 } from 'js-sha256';
import { genBase62Token, tokenStrength } from "../utils/token"; import { genBase62Token, tokenStrength } from '../utils/token';
import { genKey } from "../utils/pgp"; import { genKey } from '../utils/pgp';
import { getCookie, writeCookie, deleteCookie } from "../utils/cookies"; import { getCookie, writeCookie, deleteCookie } from '../utils/cookies';
import { saveAsJson } from "../utils/saveFile"; import { saveAsJson } from '../utils/saveFile';
import { copyToClipboard } from "../utils/clipboard"; import { copyToClipboard } from '../utils/clipboard';
class UserGenPage extends Component { class UserGenPage extends Component {
constructor(props) { constructor(props) {
@ -25,7 +34,7 @@ class UserGenPage extends Component {
this.state = { this.state = {
openInfo: false, openInfo: false,
tokenHasChanged: false, tokenHasChanged: false,
token: "" token: '',
}; };
this.refCode = this.props.match.params.refCode; this.refCode = this.props.match.params.refCode;
@ -34,304 +43,398 @@ class UserGenPage extends Component {
componentDidMount() { componentDidMount() {
// Checks in parent HomePage if there is already a nick and token // Checks in parent HomePage if there is already a nick and token
// Displays the existing one // Displays the existing one
if (this.props.nickname != null){ if (this.props.nickname != null) {
this.setState({ this.setState({
nickname: this.props.nickname, nickname: this.props.nickname,
token: this.props.token? this.props.token : "", token: this.props.token ? this.props.token : '',
avatarUrl: '/static/assets/avatars/' + this.props.nickname + '.png', avatarUrl: '/static/assets/avatars/' + this.props.nickname + '.png',
loadingRobot: false loadingRobot: false,
}); });
} } else {
else{ var newToken = genBase62Token(36);
var newToken = genBase62Token(36)
this.setState({ this.setState({
token: newToken token: newToken,
}); });
this.getGeneratedUser(newToken); this.getGeneratedUser(newToken);
} }
} }
getGeneratedUser=(token)=>{ getGeneratedUser = (token) => {
const strength = tokenStrength(token); const strength = tokenStrength(token);
const refCode = this.refCode const refCode = this.refCode;
const requestOptions = genKey(token).then(function(key) { const requestOptions = genKey(token).then(function (key) {
return { return {
method: 'POST', method: 'POST',
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken')}, headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({ body: JSON.stringify({
token_sha256: sha256(token), token_sha256: sha256(token),
public_key: key.publicKeyArmored, public_key: key.publicKeyArmored,
encrypted_private_key: key.encryptedPrivateKeyArmored, encrypted_private_key: key.encryptedPrivateKeyArmored,
unique_values: strength.uniqueValues, unique_values: strength.uniqueValues,
counts: strength.counts, counts: strength.counts,
length: token.length, length: token.length,
ref_code: refCode, ref_code: refCode,
}) }),
}} };
); });
console.log(requestOptions);
console.log(requestOptions)
requestOptions.then((options) => requestOptions.then((options) =>
fetch("/api/user/",options) fetch('/api/user/', options)
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { console.log(data) & .then((data) => {
this.setState({ console.log(data) &
this.setState({
nickname: data.nickname, nickname: data.nickname,
bit_entropy: data.token_bits_entropy, bit_entropy: data.token_bits_entropy,
avatarUrl: '/static/assets/avatars/' + data.nickname + '.png', avatarUrl: '/static/assets/avatars/' + data.nickname + '.png',
shannon_entropy: data.token_shannon_entropy, shannon_entropy: data.token_shannon_entropy,
bad_request: data.bad_request, bad_request: data.bad_request,
found: data.found, found: data.found,
loadingRobot:false, loadingRobot: false,
stealthInvoices: data.wants_stealth, stealthInvoices: data.wants_stealth,
}) }) &
& // Add nick and token to App state (token only if not a bad request)
// Add nick and token to App state (token only if not a bad request) (data.bad_request
(data.bad_request ? this.props.setAppState({ ? this.props.setAppState({
nickname: data.nickname, nickname: data.nickname,
avatarLoaded: false, avatarLoaded: false,
activeOrderId: data.active_order_id ? data.active_order_id : null, activeOrderId: data.active_order_id ? data.active_order_id : null,
referralCode: data.referral_code, referralCode: data.referral_code,
earnedRewards: data.earned_rewards, earnedRewards: data.earned_rewards,
lastOrderId: data.last_order_id ? data.last_order_id : null, lastOrderId: data.last_order_id ? data.last_order_id : null,
stealthInvoices: data.wants_stealth, stealthInvoices: data.wants_stealth,
}) })
: : this.props.setAppState({
(this.props.setAppState({ nickname: data.nickname,
nickname: data.nickname, token: token,
token: token, avatarLoaded: false,
avatarLoaded: false, activeOrderId: data.active_order_id ? data.active_order_id : null,
activeOrderId: data.active_order_id ? data.active_order_id : null, lastOrderId: data.last_order_id ? data.last_order_id : null,
lastOrderId: data.last_order_id ? data.last_order_id : null, referralCode: data.referral_code,
referralCode: data.referral_code, earnedRewards: data.earned_rewards,
earnedRewards: data.earned_rewards, stealthInvoices: data.wants_stealth,
stealthInvoices: data.wants_stealth, }) &
})) & writeCookie("robot_token",token) writeCookie('robot_token', token) &
& writeCookie("pub_key",data.public_key.split('\n').join('\\')) writeCookie('pub_key', data.public_key.split('\n').join('\\')) &
& writeCookie("enc_priv_key",data.encrypted_private_key.split('\n').join('\\'))) writeCookie('enc_priv_key', data.encrypted_private_key.split('\n').join('\\'))) &
& // If the robot has been found (recovered) we assume the token is backed up
// If the robot has been found (recovered) we assume the token is backed up (data.found ? this.props.setAppState({ copiedToken: true }) : null);
(data.found ? this.props.setAppState({copiedToken:true}) : null) }),
})
); );
} };
delGeneratedUser() { delGeneratedUser() {
const requestOptions = { const requestOptions = {
method: 'DELETE', method: 'DELETE',
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken')}, headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
}; };
fetch("/api/user", requestOptions) fetch('/api/user', requestOptions).then((response) => response.json());
.then((response) => response.json());
deleteCookie("sessionid"); deleteCookie('sessionid');
deleteCookie("robot_token"); deleteCookie('robot_token');
deleteCookie("pub_key"); deleteCookie('pub_key');
deleteCookie("enc_priv_key"); deleteCookie('enc_priv_key');
} }
handleClickNewRandomToken=()=>{ handleClickNewRandomToken = () => {
var token = genBase62Token(36); var token = genBase62Token(36);
this.setState({ this.setState({
token: token, token: token,
tokenHasChanged: true, tokenHasChanged: true,
}); });
this.props.setAppState({copiedToken: true}) this.props.setAppState({ copiedToken: true });
} };
handleChangeToken=(e)=>{ handleChangeToken = (e) => {
this.setState({ this.setState({
token: e.target.value.split(' ').join(''), token: e.target.value.split(' ').join(''),
tokenHasChanged: true, tokenHasChanged: true,
}) });
} };
handleClickSubmitToken=()=>{ handleClickSubmitToken = () => {
this.delGeneratedUser(); this.delGeneratedUser();
this.getGeneratedUser(this.state.token); this.getGeneratedUser(this.state.token);
this.setState({loadingRobot: true, tokenHasChanged: false}); this.setState({ loadingRobot: true, tokenHasChanged: false });
this.props.setAppState({avatarLoaded: false, this.props.setAppState({
nickname: null, avatarLoaded: false,
token: null, nickname: null,
copiedToken: false, token: null,
copiedToken: false,
lastOrderId: null, lastOrderId: null,
activeOrderId: null}); activeOrderId: null,
} });
};
handleClickOpenInfo = () => { handleClickOpenInfo = () => {
this.setState({openInfo: true}); this.setState({ openInfo: true });
}; };
handleCloseInfo = () => { handleCloseInfo = () => {
this.setState({openInfo: false}); this.setState({ openInfo: false });
}; };
createJsonFile = () => { createJsonFile = () => {
return ({ return {
"token":getCookie('robot_token'), token: getCookie('robot_token'),
"token_shannon_entropy": this.state.shannon_entropy, token_shannon_entropy: this.state.shannon_entropy,
"token_bit_entropy": this.state.bit_entropy, token_bit_entropy: this.state.bit_entropy,
"public_key": getCookie('pub_key').split('\\').join('\n'), public_key: getCookie('pub_key').split('\\').join('\n'),
"encrypted_private_key": getCookie('enc_priv_key').split('\\').join('\n'), encrypted_private_key: getCookie('enc_priv_key').split('\\').join('\n'),
}) };
} };
render() { render() {
const { t, i18n} = this.props; const { t, i18n } = this.props;
const fontSize = this.props.theme.typography.fontSize; const fontSize = this.props.theme.typography.fontSize;
const fontSizeFactor = fontSize / 14; // to scale sizes, default fontSize is 14 const fontSizeFactor = fontSize / 14; // to scale sizes, default fontSize is 14
return ( return (
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item> <Grid item>
<div className='clickTrough'/> <div className='clickTrough' />
</Grid> </Grid>
<Grid item xs={12} align="center" sx={{width:370 * fontSizeFactor, height: 260 * fontSizeFactor}}> <Grid
{!this.state.loadingRobot && this.state.avatarUrl ? item
xs={12}
align='center'
sx={{ width: 370 * fontSizeFactor, height: 260 * fontSizeFactor }}
>
{!this.state.loadingRobot && this.state.avatarUrl ? (
<div> <div>
<Grid item xs={12} align="center"> <Grid item xs={12} align='center'>
<Typography component="h5" variant="h5"> <Typography component='h5' variant='h5'>
<b>{this.state.nickname && getCookie("sessionid") ? <b>
<div style={{display:'flex', alignItems:'center', justifyContent:'center', flexWrap:'wrap', height: 45 * fontSizeFactor}}> {this.state.nickname && getCookie('sessionid') ? (
<BoltIcon sx={{ color: "#fcba03", height: 33 * fontSizeFactor, width: 33 * fontSizeFactor}}/> <div
<a>{this.state.nickname}</a> style={{
<BoltIcon sx={{ color: "#fcba03", height: 33 * fontSizeFactor, width: 33 * fontSizeFactor}}/> display: 'flex',
</div> alignItems: 'center',
: ""}</b> justifyContent: 'center',
flexWrap: 'wrap',
height: 45 * fontSizeFactor,
}}
>
<BoltIcon
sx={{
color: '#fcba03',
height: 33 * fontSizeFactor,
width: 33 * fontSizeFactor,
}}
/>
<a>{this.state.nickname}</a>
<BoltIcon
sx={{
color: '#fcba03',
height: 33 * fontSizeFactor,
width: 33 * fontSizeFactor,
}}
/>
</div>
) : (
''
)}
</b>
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} align="center"> <Grid item xs={12} align='center'>
<Tooltip enterTouchDelay={0} title={t("This is your trading avatar")}> <Tooltip enterTouchDelay={0} title={t('This is your trading avatar')}>
<div style={{ maxWidth: 200 * fontSizeFactor, maxHeight: 200 * fontSizeFactor}}> <div style={{ maxWidth: 200 * fontSizeFactor, maxHeight: 200 * fontSizeFactor }}>
<SmoothImage <SmoothImage
src={this.state.avatarUrl} src={this.state.avatarUrl}
imageStyles={{borderRadius: "50%", imageStyles={{
border: "2px solid #555", borderRadius: '50%',
filter: "drop-shadow(1px 1px 1px #000000)", border: '2px solid #555',
height: `${195*fontSizeFactor}px`, filter: 'drop-shadow(1px 1px 1px #000000)',
width: `${200*fontSizeFactor}px`}} height: `${195 * fontSizeFactor}px`,
/> width: `${200 * fontSizeFactor}px`,
</div> }}
/>
</div>
</Tooltip> </Tooltip>
<br/> <br />
</Grid> </Grid>
</div> </div>
: <CircularProgress sx={{position: 'relative', top: 100, }}/>} ) : (
<CircularProgress sx={{ position: 'relative', top: 100 }} />
)}
</Grid>
{this.state.found ? (
<Grid item xs={12} align='center'>
<Typography variant='subtitle2' color='primary'>
{this.state.found ? t('A robot avatar was found, welcome back!') : null}
<br />
</Typography>
</Grid> </Grid>
{ ) : (
this.state.found ? ''
<Grid item xs={12} align="center"> )}
<Typography variant="subtitle2" color='primary'> <Grid container align='center'>
{this.state.found ? t("A robot avatar was found, welcome back!"):null}<br/> <Grid item xs={12} align='center'>
</Typography> <TextField
</Grid> sx={{ maxWidth: 280 * fontSizeFactor }}
: error={this.state.bad_request ? true : false}
"" label={t('Store your token safely')}
} required={true}
<Grid container align="center"> value={this.state.token}
<Grid item xs={12} align="center"> variant='standard'
<TextField sx={{maxWidth: 280 * fontSizeFactor}} helperText={this.state.bad_request}
error={this.state.bad_request ? true : false} size='small'
label={t("Store your token safely")} onChange={this.handleChangeToken}
required={true} onKeyPress={(e) => {
value={this.state.token} if (e.key === 'Enter') {
variant='standard' this.handleClickSubmitToken();
helperText={this.state.bad_request} }
size='small' }}
onChange={this.handleChangeToken} InputProps={{
onKeyPress={(e) => { startAdornment: (
if (e.key === 'Enter') { <div
this.handleClickSubmitToken(); style={{
} width: 50 * fontSizeFactor,
}} minWidth: 50 * fontSizeFactor,
InputProps={{ position: 'relative',
startAdornment: left: -6,
<div style={{width: 50*fontSizeFactor, minWidth: 50*fontSizeFactor, position:'relative',left:-6}}> }}
>
<Grid container> <Grid container>
<Grid item xs={6}> <Grid item xs={6}>
<Tooltip enterTouchDelay={250} title={t("Save token and PGP credentials to file")}> <Tooltip
enterTouchDelay={250}
title={t('Save token and PGP credentials to file')}
>
<span> <span>
<IconButton <IconButton
color="primary" color='primary'
disabled={!(getCookie('robot_token')==this.state.token) || !this.props.avatarLoaded} disabled={
onClick={()=> saveAsJson(this.state.nickname+'.json', this.createJsonFile())} !(getCookie('robot_token') == this.state.token) ||
!this.props.avatarLoaded
}
onClick={() =>
saveAsJson(this.state.nickname + '.json', this.createJsonFile())
}
> >
<DownloadIcon sx={{width: 22*fontSizeFactor, height: 22*fontSizeFactor}}/> <DownloadIcon
</IconButton> sx={{ width: 22 * fontSizeFactor, height: 22 * fontSizeFactor }}
/>
</IconButton>
</span> </span>
</Tooltip> </Tooltip>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}> <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}>
<IconButton <IconButton
color={this.props.copiedToken ? "inherit":"primary"} color={this.props.copiedToken ? 'inherit' : 'primary'}
disabled={!(getCookie('robot_token')==this.state.token) || !this.props.avatarLoaded} disabled={
onClick={()=> (copyToClipboard(getCookie('robot_token')) & this.props.setAppState({copiedToken:true}))} !(getCookie('robot_token') == this.state.token) ||
> !this.props.avatarLoaded
<ContentCopy sx={{width: 18*fontSizeFactor, height: 18*fontSizeFactor}}/> }
onClick={() =>
copyToClipboard(getCookie('robot_token')) &
this.props.setAppState({ copiedToken: true })
}
>
<ContentCopy
sx={{ width: 18 * fontSizeFactor, height: 18 * fontSizeFactor }}
/>
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</Grid> </Grid>
</Grid> </Grid>
</div>, </div>
endAdornment: ),
<Tooltip enterTouchDelay={250} title={t("Generate a new token")}> endAdornment: (
<Tooltip enterTouchDelay={250} title={t('Generate a new token')}>
<IconButton onClick={this.handleClickNewRandomToken}> <IconButton onClick={this.handleClickNewRandomToken}>
<CasinoIcon sx={{width: 18*fontSizeFactor, height: 18*fontSizeFactor}}/> <CasinoIcon
sx={{ width: 18 * fontSizeFactor, height: 18 * fontSizeFactor }}
/>
</IconButton> </IconButton>
</Tooltip>, </Tooltip>
}} ),
/> }}
</Grid> />
</Grid> </Grid>
<Grid item xs={12} align="center"> </Grid>
{this.state.tokenHasChanged ? <Grid item xs={12} align='center'>
<Button type="submit" size='small' onClick= {this.handleClickSubmitToken}> {this.state.tokenHasChanged ? (
<SmartToyIcon sx={{width: 18*fontSizeFactor, height: 18*fontSizeFactor}} /> <Button type='submit' size='small' onClick={this.handleClickSubmitToken}>
<span> {t("Generate Robot")}</span> <SmartToyIcon sx={{ width: 18 * fontSizeFactor, height: 18 * fontSizeFactor }} />
<span> {t('Generate Robot')}</span>
</Button> </Button>
: ) : (
<Tooltip enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t("You must enter a new token first")}> <Tooltip
enterTouchDelay={0}
enterDelay={500}
enterNextDelay={2000}
title={t('You must enter a new token first')}
>
<div> <div>
<Button disabled={true} type="submit" size='small' > <Button disabled={true} type='submit' size='small'>
<SmartToyIcon sx={{width: 18*fontSizeFactor, height: 18*fontSizeFactor}} /> <SmartToyIcon sx={{ width: 18 * fontSizeFactor, height: 18 * fontSizeFactor }} />
<span>{t("Generate Robot")}</span> <span>{t('Generate Robot')}</span>
</Button> </Button>
</div> </div>
</Tooltip> </Tooltip>
} )}
</Grid> </Grid>
<Grid item xs={12} align="center"> <Grid item xs={12} align='center'>
<ButtonGroup variant="contained" aria-label="outlined primary button group"> <ButtonGroup variant='contained' aria-label='outlined primary button group'>
<Button disabled={this.state.loadingRobot || !(this.props.token ? getCookie('robot_token')==this.props.token : true )} color='primary' to='/make/' component={Link}>{t("Make Order")}</Button> <Button
<Button color='inherit' style={{color: '#111111'}} onClick={this.handleClickOpenInfo}>{t("Info")}</Button> disabled={
<InfoDialog open={Boolean(this.state.openInfo)} maxAmount='4,000,000' onClose = {this.handleCloseInfo}/> this.state.loadingRobot ||
<Button disabled={this.state.loadingRobot || !(this.props.token ? getCookie('robot_token')==this.props.token : true )} color='secondary' to='/book/' component={Link}>{t("View Book")}</Button> !(this.props.token ? getCookie('robot_token') == this.props.token : true)
</ButtonGroup> }
</Grid> color='primary'
to='/make/'
component={Link}
>
{t('Make Order')}
</Button>
<Button color='inherit' style={{ color: '#111111' }} onClick={this.handleClickOpenInfo}>
{t('Info')}
</Button>
<InfoDialog
open={Boolean(this.state.openInfo)}
maxAmount='4,000,000'
onClose={this.handleCloseInfo}
/>
<Button
disabled={
this.state.loadingRobot ||
!(this.props.token ? getCookie('robot_token') == this.props.token : true)
}
color='secondary'
to='/book/'
component={Link}
>
{t('View Book')}
</Button>
</ButtonGroup>
</Grid>
<Grid item xs={12} align="center" sx={{width: 370*fontSizeFactor}}> <Grid item xs={12} align='center' sx={{ width: 370 * fontSizeFactor }}>
<Grid item> <Grid item>
<div style={{height: 30*fontSizeFactor}}/> <div style={{ height: 30 * fontSizeFactor }} />
</Grid>
<div style={{width: 370*fontSizeFactor, left: 30*fontSizeFactor}}>
<Grid container align="center">
<Grid item xs={0.8}/>
<Grid item xs={7.5} align="right">
<Typography component="h5" variant="h5">
{t("Simple and Private LN P2P Exchange")}
</Typography>
</Grid>
<Grid item xs={2.5} align="left">
<RoboSatsNoTextIcon color="primary"
sx={{height: 72 * fontSizeFactor, width: 72 * fontSizeFactor}}
/>
</Grid>
</Grid>
</div>
</Grid> </Grid>
<div style={{ width: 370 * fontSizeFactor, left: 30 * fontSizeFactor }}>
<Grid container align='center'>
<Grid item xs={0.8} />
<Grid item xs={7.5} align='right'>
<Typography component='h5' variant='h5'>
{t('Simple and Private LN P2P Exchange')}
</Typography>
</Grid>
<Grid item xs={2.5} align='left'>
<RoboSatsNoTextIcon
color='primary'
sx={{ height: 72 * fontSizeFactor, width: 72 * fontSizeFactor }}
/>
</Grid>
</Grid>
</div>
</Grid>
</Grid> </Grid>
); );
} }

View File

@ -1,6 +1,6 @@
import i18n from "i18next"; import i18n from 'i18next';
import LanguageDetector from "i18next-browser-languagedetector"; import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from "react-i18next"; import { initReactI18next } from 'react-i18next';
import HttpApi from 'i18next-http-backend'; import HttpApi from 'i18next-http-backend';
// import translationEN from "../../static/locales/en.json"; // import translationEN from "../../static/locales/en.json";
@ -20,49 +20,49 @@ i18n
.use(LanguageDetector) .use(LanguageDetector)
.use(initReactI18next) .use(initReactI18next)
.init({ .init({
// resources: { // resources: {
// en: {translations: translationEN}, // en: {translations: translationEN},
// es: {translations: translationES}, // es: {translations: translationES},
// ru: {translations: translationRU}, // ru: {translations: translationRU},
// de: {translations: translationDE}, // de: {translations: translationDE},
// // zh: {translations: translationZH}, // // zh: {translations: translationZH},
// pl: {translations: translationPL}, // pl: {translations: translationPL},
// fr: {translations: translationFR}, // fr: {translations: translationFR},
// ca: {translations: translationCA}, // ca: {translations: translationCA},
// it: {translations: translationIT}, // it: {translations: translationIT},
// pt: {translations: translationPT}, // pt: {translations: translationPT},
// eu: {translations: translationEU}, // eu: {translations: translationEU},
// sv: {translations: translationSV}, // sv: {translations: translationSV},
// cs: {translations: translationCS}, // cs: {translations: translationCS},
// th: {translations: translationCS}, // th: {translations: translationCS},
// }, // },
backend:{
loadPath: '/static/locales/{{lng}}.json',
allowMultiLoading: false, // set loadPath: '/locales/resources.json?lng={{lng}}&ns={{ns}}' to adapt to multiLoading
crossDomain: false,
withCredentials: false,
overrideMimeType: false,
reloadInterval: false // can be used to reload resources in a specific interval (useful in server environments)
},
fallbackLng: "en", backend: {
debug: false, loadPath: '/static/locales/{{lng}}.json',
allowMultiLoading: false, // set loadPath: '/locales/resources.json?lng={{lng}}&ns={{ns}}' to adapt to multiLoading
crossDomain: false,
withCredentials: false,
overrideMimeType: false,
reloadInterval: false, // can be used to reload resources in a specific interval (useful in server environments)
},
// have a common namespace used around the full app fallbackLng: 'en',
ns: ["translations"], debug: false,
defaultNS: "translations",
keySeparator: false, // we use content as keys // have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
interpolation: { keySeparator: false, // we use content as keys
escapeValue: false,
formatSeparator: ","
},
react: {
useSuspense: false,
}
});
export default i18n; interpolation: {
escapeValue: false,
formatSeparator: ',',
},
react: {
useSuspense: false,
},
});
export default i18n;

File diff suppressed because one or more lines are too long

View File

@ -1,86 +1,86 @@
export const paymentMethods = [ export const paymentMethods = [
{name: "Revolut",icon:'revolut'}, { name: 'Revolut', icon: 'revolut' },
{name: "CashApp",icon:'cashapp'}, { name: 'CashApp', icon: 'cashapp' },
{name: "Zelle",icon:'zelle'}, { name: 'Zelle', icon: 'zelle' },
{name: "Strike",icon:'strike'}, { name: 'Strike', icon: 'strike' },
{name: "WeChat Pay", icon: 'wechatpay'}, { name: 'WeChat Pay', icon: 'wechatpay' },
{name: "Rebellion",icon:'rebellion'}, { name: 'Rebellion', icon: 'rebellion' },
{name: "Instant SEPA", icon:'sepa'}, { name: 'Instant SEPA', icon: 'sepa' },
{name: "Interac e-Transfer",icon:'interac'}, { name: 'Interac e-Transfer', icon: 'interac' },
{name: "Wise",icon:'wise'}, { name: 'Wise', icon: 'wise' },
{name: "Venmo",icon:'venmo'}, { name: 'Venmo', icon: 'venmo' },
{name: "Faster Payments",icon:'faster'}, { name: 'Faster Payments', icon: 'faster' },
{name: "Paypal Friends & Family",icon:'paypal'}, { name: 'Paypal Friends & Family', icon: 'paypal' },
{name: "LINE Pay",icon:'linepay'}, { name: 'LINE Pay', icon: 'linepay' },
{name: "PromptPay",icon:'promptpay'}, { name: 'PromptPay', icon: 'promptpay' },
{name: "Bizum",icon:'bizum'}, { name: 'Bizum', icon: 'bizum' },
{name: "N26",icon:'n26'}, { name: 'N26', icon: 'n26' },
{name: "Tinkoff",icon:'tinkoff'}, { name: 'Tinkoff', icon: 'tinkoff' },
{name: "TWINT",icon:'twint'}, { name: 'TWINT', icon: 'twint' },
{name: "BLIK",icon:'blik'}, { name: 'BLIK', icon: 'blik' },
{name: "MBWay",icon:'mbway'}, { name: 'MBWay', icon: 'mbway' },
{name: "W1TTY",icon:'w1tty'}, { name: 'W1TTY', icon: 'w1tty' },
{name: "Verse",icon:'verse'}, { name: 'Verse', icon: 'verse' },
{name: "Paysera",icon:'paysera'}, { name: 'Paysera', icon: 'paysera' },
{name: "Amazon GiftCard",icon:'amazon'}, { name: 'Amazon GiftCard', icon: 'amazon' },
{name: "Ozon GiftCard",icon:'ozon'}, { name: 'Ozon GiftCard', icon: 'ozon' },
{name: "AliPay", icon: 'alipay'}, { name: 'AliPay', icon: 'alipay' },
{name: "GPay", icon: 'gpay'}, { name: 'GPay', icon: 'gpay' },
{name: "Bancolombia",icon:'bancolombia'}, { name: 'Bancolombia', icon: 'bancolombia' },
{name: "Pago Movil BDV",icon:'pagomovilbdv'}, { name: 'Pago Movil BDV', icon: 'pagomovilbdv' },
{name: "SPEI",icon:'spei'}, { name: 'SPEI', icon: 'spei' },
{name: "PIX",icon:'pix'}, { name: 'PIX', icon: 'pix' },
{name: "PayID",icon:'payid'}, { name: 'PayID', icon: 'payid' },
{name: "Paysafe",icon:'paysafe'}, { name: 'Paysafe', icon: 'paysafe' },
{name: "Sberbank",icon:'sberbank'}, { name: 'Sberbank', icon: 'sberbank' },
{name: "PhonePe",icon:'phonepe'}, { name: 'PhonePe', icon: 'phonepe' },
{name: "OVO",icon:'ovo'}, { name: 'OVO', icon: 'ovo' },
{name: "HalCash",icon:'halcash'}, { name: 'HalCash', icon: 'halcash' },
{name: "Vivid",icon:'vivid'}, { name: 'Vivid', icon: 'vivid' },
{name: "Google Play Gift Code",icon:'googleplay'}, { name: 'Google Play Gift Code', icon: 'googleplay' },
{name: "Apple Pay",icon:'applepay'}, { name: 'Apple Pay', icon: 'applepay' },
{name: "Steam",icon:'steam'}, { name: 'Steam', icon: 'steam' },
{name: "Nequi",icon:'nequi'}, { name: 'Nequi', icon: 'nequi' },
{name: "ShakePay",icon:'shakepay'}, { name: 'ShakePay', icon: 'shakepay' },
{name: "DaviPlata",icon:'daviplata'}, { name: 'DaviPlata', icon: 'daviplata' },
{name: "CoDi",icon:'codi'}, { name: 'CoDi', icon: 'codi' },
{name: "TaiwanPay",icon:'taiwanpay'}, { name: 'TaiwanPay', icon: 'taiwanpay' },
{name: "MaiCoin",icon:'maicoin'}, { name: 'MaiCoin', icon: 'maicoin' },
{name: "GoPay", icon: 'gopay'}, { name: 'GoPay', icon: 'gopay' },
{name: "MercadoPago",icon:'mercadopago'}, { name: 'MercadoPago', icon: 'mercadopago' },
{name: "Monero",icon:'monero'}, { name: 'Monero', icon: 'monero' },
{name: "USDT",icon:'usdt'}, { name: 'USDT', icon: 'usdt' },
{name: "Airtel Money",icon:'airtel'}, { name: 'Airtel Money', icon: 'airtel' },
{name: "MTN Money",icon:'mtn'}, { name: 'MTN Money', icon: 'mtn' },
{name: "M-Pesa",icon:'mpesa'}, { name: 'M-Pesa', icon: 'mpesa' },
{name: "UPI",icon:'upi'}, { name: 'UPI', icon: 'upi' },
{name: "MoMo",icon:'momo'}, { name: 'MoMo', icon: 'momo' },
{name: "Tigo Pesa",icon:'tigopesa'}, { name: 'Tigo Pesa', icon: 'tigopesa' },
{name: "Cash F2F",icon:'cash'}, { name: 'Cash F2F', icon: 'cash' },
{name: "Amazon USA GiftCard",icon:'amazonus'}, { name: 'Amazon USA GiftCard', icon: 'amazonus' },
{name: "Amazon DE GiftCard",icon:'amazonde'}, { name: 'Amazon DE GiftCard', icon: 'amazonde' },
{name: "Amazon AU GiftCard",icon:'amazonau'}, { name: 'Amazon AU GiftCard', icon: 'amazonau' },
{name: "Amazon SA GiftCard",icon:'amazonsa'}, { name: 'Amazon SA GiftCard', icon: 'amazonsa' },
{name: "Amazon ES GiftCard",icon:'amazones'}, { name: 'Amazon ES GiftCard', icon: 'amazones' },
{name: "Amazon CA GiftCard",icon:'amazonca'}, { name: 'Amazon CA GiftCard', icon: 'amazonca' },
{name: "Amazon CN GiftCard",icon:'amazoncn'}, { name: 'Amazon CN GiftCard', icon: 'amazoncn' },
{name: "Amazon AE GiftCard",icon:'amazonae'}, { name: 'Amazon AE GiftCard', icon: 'amazonae' },
{name: "Amazon FR GiftCard",icon:'amazonfr'}, { name: 'Amazon FR GiftCard', icon: 'amazonfr' },
{name: "Amazon NL GiftCard",icon:'amazonnl'}, { name: 'Amazon NL GiftCard', icon: 'amazonnl' },
{name: "Amazon IN GiftCard",icon:'amazonin'}, { name: 'Amazon IN GiftCard', icon: 'amazonin' },
{name: "Amazon IT GiftCard",icon:'amazonit'}, { name: 'Amazon IT GiftCard', icon: 'amazonit' },
{name: "Amazon JP GiftCard",icon:'amazonjp'}, { name: 'Amazon JP GiftCard', icon: 'amazonjp' },
{name: "Amazon MX GiftCard",icon:'amazonmx'}, { name: 'Amazon MX GiftCard', icon: 'amazonmx' },
{name: "Amazon PL GiftCard",icon:'amazonpl'}, { name: 'Amazon PL GiftCard', icon: 'amazonpl' },
{name: "Amazon UK GiftCard",icon:'amazonuk'}, { name: 'Amazon UK GiftCard', icon: 'amazonuk' },
{name: "Amazon SE GiftCard",icon:'amazonse'}, { name: 'Amazon SE GiftCard', icon: 'amazonse' },
{name: "Amazon SG GiftCard",icon:'amazonsg'}, { name: 'Amazon SG GiftCard', icon: 'amazonsg' },
{name: "Amazon TR GiftCard",icon:'amazontr'}, { name: 'Amazon TR GiftCard', icon: 'amazontr' },
]; ];
export const swapDestinations = [ export const swapDestinations = [
{name: "On-Chain BTC",icon:'onchain'}, { name: 'On-Chain BTC', icon: 'onchain' },
{name: "RBTC",icon:'rbtc'}, { name: 'RBTC', icon: 'rbtc' },
{name: "LBTC",icon:'lbtc'}, { name: 'LBTC', icon: 'lbtc' },
{name: "WBTC",icon:'wbtc'}, { name: 'WBTC', icon: 'wbtc' },
]; ];

View File

@ -1 +1 @@
import App from "./components/App"; import App from './components/App';

View File

@ -1,13 +1,13 @@
export interface Limit { export interface Limit {
code: string, code: string;
price: number, price: number;
min_amount: number, min_amount: number;
max_amount: number, max_amount: number;
max_bondless_amount: number max_bondless_amount: number;
} }
export interface LimitList { export interface LimitList {
[currencyCode: string]: Limit [currencyCode: string]: Limit;
} }
export default Limit export default Limit;

View File

@ -1,24 +1,24 @@
export interface Order { export interface Order {
id: number, id: number;
created_at: Date, created_at: Date;
expires_at: Date, expires_at: Date;
type: number, type: number;
currency: number, currency: number;
amount: string, amount: string;
base_amount?: number, base_amount?: number;
has_range: boolean, has_range: boolean;
min_amount: number, min_amount: number;
max_amount: number, max_amount: number;
payment_method: string, payment_method: string;
is_explicit: false, is_explicit: false;
premium: number, premium: number;
satoshis: number, satoshis: number;
bondless_taker: boolean, bondless_taker: boolean;
maker: number, maker: number;
escrow_duration: number, escrow_duration: number;
maker_nick: string, maker_nick: string;
price: number, price: number;
maker_status: "Active" | "Seen recently" | "Inactive" maker_status: 'Active' | 'Seen recently' | 'Inactive';
} }
export default Order export default Order;

View File

@ -1,24 +1,25 @@
export function copyToClipboard(textToCopy) { export function copyToClipboard(textToCopy) {
// navigator clipboard api needs a secure context (https) // navigator clipboard api needs a secure context (https)
// this function attempts to copy also on http contexts // this function attempts to copy also on http contexts
// useful on the http i2p site and on torified browsers // useful on the http i2p site and on torified browsers
if (navigator.clipboard && window.isSecureContext) { if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard api method' // navigator clipboard api method'
return navigator.clipboard.writeText(textToCopy); return navigator.clipboard.writeText(textToCopy);
} else { } else {
// text area method // text area method
let textArea = document.createElement("textarea"); let textArea = document.createElement('textarea');
textArea.value = textToCopy; textArea.value = textToCopy;
// make the textarea out of viewport // make the textarea out of viewport
textArea.style.position = "fixed"; textArea.style.position = 'fixed';
textArea.style.left = "-999999px"; textArea.style.left = '-999999px';
textArea.style.top = "-999999px"; textArea.style.top = '-999999px';
document.body.appendChild(textArea); document.body.appendChild(textArea);
textArea.focus(); textArea.focus();
textArea.select(); textArea.select();
return new Promise((res, rej) => { return new Promise((res, rej) => {
// here the magic happens // here the magic happens
document.execCommand('copy') ? res() : rej(); document.execCommand('copy') ? res() : rej();
textArea.remove(); textArea.remove();
}); });
}} }
}

View File

@ -5,7 +5,7 @@ export const getCookie = (name) => {
for (let i = 0; i < cookies.length; i++) { for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim(); const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want? // Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) { if (cookie.substring(0, name.length + 1) === name + '=') {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break; break;
} }
@ -14,10 +14,10 @@ export const getCookie = (name) => {
return cookieValue; return cookieValue;
}; };
export const writeCookie = (key,value) => { export const writeCookie = (key, value) => {
document.cookie=`${key}=${value};path=/;SameSite=Strict`; document.cookie = `${key}=${value};path=/;SameSite=Strict`;
} };
export const deleteCookie = (name) => { export const deleteCookie = (name) => {
document.cookie = `${name}= ; expires = Thu, 01 Jan 1970 00:00:00 GMT` document.cookie = `${name}= ; expires = Thu, 01 Jan 1970 00:00:00 GMT`;
} };

View File

@ -4,4 +4,4 @@ export const median = (arr: number[]) => {
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2; return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
}; };
export default median export default median;

View File

@ -1,12 +1,12 @@
import { import {
generateKey, generateKey,
readKey, readKey,
readPrivateKey, readPrivateKey,
decryptKey, decryptKey,
encrypt, encrypt,
decrypt, decrypt,
createMessage, createMessage,
readMessage readMessage,
} from 'openpgp/lightweight'; } from 'openpgp/lightweight';
import { sha256 } from 'js-sha256'; import { sha256 } from 'js-sha256';
@ -16,60 +16,69 @@ export async function genKey(highEntropyToken) {
const keyPair = await generateKey({ const keyPair = await generateKey({
type: 'ecc', // Type of the key, defaults to ECC type: 'ecc', // Type of the key, defaults to ECC
curve: 'curve25519', // ECC curve name, defaults to curve25519 curve: 'curve25519', // ECC curve name, defaults to curve25519
userIDs: [{name: 'RoboSats ID '+ sha256(sha256(highEntropyToken))}], //Ideally it would be the avatar nickname, but the nickname is generated only after submission. The second SHA256 can be converted into the Nickname using nick_generator package. userIDs: [{ name: 'RoboSats ID ' + sha256(sha256(highEntropyToken)) }], //Ideally it would be the avatar nickname, but the nickname is generated only after submission. The second SHA256 can be converted into the Nickname using nick_generator package.
passphrase: highEntropyToken, passphrase: highEntropyToken,
format: 'armored', format: 'armored',
date: d.setDate(d.getDate()-1) // One day of offset. Helps reducing errors due to client's system time being in the future. date: d.setDate(d.getDate() - 1), // One day of offset. Helps reducing errors due to client's system time being in the future.
}) });
return {publicKeyArmored: keyPair.publicKey, encryptedPrivateKeyArmored: keyPair.privateKey} return { publicKeyArmored: keyPair.publicKey, encryptedPrivateKeyArmored: keyPair.privateKey };
}; }
// Encrypt and sign a message // Encrypt and sign a message
export async function encryptMessage(plaintextMessage, ownPublicKeyArmored, peerPublicKeyArmored, privateKeyArmored, passphrase) { export async function encryptMessage(
plaintextMessage,
ownPublicKeyArmored,
peerPublicKeyArmored,
privateKeyArmored,
passphrase,
) {
const ownPublicKey = await readKey({ armoredKey: ownPublicKeyArmored }); const ownPublicKey = await readKey({ armoredKey: ownPublicKeyArmored });
const peerPublicKey = await readKey({ armoredKey: peerPublicKeyArmored }); const peerPublicKey = await readKey({ armoredKey: peerPublicKeyArmored });
const privateKey = await decryptKey({ const privateKey = await decryptKey({
privateKey: await readPrivateKey({ armoredKey: privateKeyArmored }), privateKey: await readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase passphrase,
}); });
const d = new Date(); const d = new Date();
const encryptedMessage = await encrypt({ const encryptedMessage = await encrypt({
message: await createMessage({ text: plaintextMessage }), // input as Message object, message must be string message: await createMessage({ text: plaintextMessage }), // input as Message object, message must be string
encryptionKeys: [ ownPublicKey, peerPublicKey ], encryptionKeys: [ownPublicKey, peerPublicKey],
signingKeys: privateKey, // optional signingKeys: privateKey, // optional
date: d.setDate(d.getDate()-1) // One day of offset, avoids verification issue due to clock mismatch date: d.setDate(d.getDate() - 1), // One day of offset, avoids verification issue due to clock mismatch
}); });
return encryptedMessage; // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----' return encryptedMessage; // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
}; }
// Decrypt and check signature of a message // Decrypt and check signature of a message
export async function decryptMessage(encryptedMessage, publicKeyArmored, privateKeyArmored, passphrase) { export async function decryptMessage(
encryptedMessage,
publicKeyArmored,
privateKeyArmored,
passphrase,
) {
const publicKey = await readKey({ armoredKey: publicKeyArmored }); const publicKey = await readKey({ armoredKey: publicKeyArmored });
const privateKey = await decryptKey({ const privateKey = await decryptKey({
privateKey: await readPrivateKey({ armoredKey: privateKeyArmored }), privateKey: await readPrivateKey({ armoredKey: privateKeyArmored }),
passphrase passphrase,
}); });
const message = await readMessage({ const message = await readMessage({
armoredMessage: encryptedMessage // parse armored message armoredMessage: encryptedMessage, // parse armored message
}); });
const { data: decrypted, signatures } = await decrypt({ const { data: decrypted, signatures } = await decrypt({
message, message,
verificationKeys: publicKey, // optional verificationKeys: publicKey, // optional
decryptionKeys: privateKey decryptionKeys: privateKey,
}); });
// check signature validity (signed messages only) // check signature validity (signed messages only)
try { try {
await signatures[0].verified; // throws on invalid signature await signatures[0].verified; // throws on invalid signature
console.log('Signature is valid'); console.log('Signature is valid');
return {decryptedMessage: decrypted, validSignature: true} return { decryptedMessage: decrypted, validSignature: true };
} catch (e) { } catch (e) {
return {decryptedMessage: decrypted, validSignature: false}; return { decryptedMessage: decrypted, validSignature: false };
} }
}; }

View File

@ -1,45 +1,45 @@
import { pn, amountToString } from "./prettyNumbers"; import { pn, amountToString } from './prettyNumbers';
describe("prettyNumbers", () => { describe('prettyNumbers', () => {
test("pn()", () => { test('pn()', () => {
[ [
{input: null, output: undefined}, { input: null, output: undefined },
{input: undefined, output: undefined}, { input: undefined, output: undefined },
{input: 0, output: "0"}, { input: 0, output: '0' },
{input: 1, output: "1"}, { input: 1, output: '1' },
{input: 2, output: "2"}, { input: 2, output: '2' },
{input: 10, output: "10"}, { input: 10, output: '10' },
{input: 11, output: "11"}, { input: 11, output: '11' },
{input: 11.0, output: "11"}, { input: 11.0, output: '11' },
{input: 12.0, output: "12"}, { input: 12.0, output: '12' },
{input: 100.50, output: "100.5"}, { input: 100.5, output: '100.5' },
{input: 224.56, output: "224.56"}, { input: 224.56, output: '224.56' },
{input: 1567, output: "1,567"}, { input: 1567, output: '1,567' },
{input: 15678, output: "15,678"}, { input: 15678, output: '15,678' },
{input: 2984.99, output: "2,984.99"}, { input: 2984.99, output: '2,984.99' },
{input: 100000.00, output: "100,000"}, { input: 100000.0, output: '100,000' },
].forEach((it) => { ].forEach((it) => {
const response = pn(it.input); const response = pn(it.input);
expect(response).toBe(it.output); expect(response).toBe(it.output);
}); });
}); });
}) });
describe("amountToString", () => { describe('amountToString', () => {
test("pn()", () => { test('pn()', () => {
[ [
{input: null, output: "NaN"}, { input: null, output: 'NaN' },
{input: undefined, output: "NaN"}, { input: undefined, output: 'NaN' },
{input: ["", false, 50, 150] , output: "0"}, { input: ['', false, 50, 150], output: '0' },
{input: ["100.00", false, 50, 150] , output: "100"}, { input: ['100.00', false, 50, 150], output: '100' },
{input: ["100.00", true, undefined, undefined] , output: "NaN-NaN"}, { input: ['100.00', true, undefined, undefined], output: 'NaN-NaN' },
{input: ["100.00", true, undefined, 150] , output: "NaN-150"}, { input: ['100.00', true, undefined, 150], output: 'NaN-150' },
{input: ["100.00", true, 50, undefined] , output: "50-NaN"}, { input: ['100.00', true, 50, undefined], output: '50-NaN' },
{input: ["100.00", true, 50, 150] , output: "50-150"}, { input: ['100.00', true, 50, 150], output: '50-150' },
].forEach((it) => { ].forEach((it) => {
const params: any[] = it.input || [] const params: any[] = it.input || [];
const response = amountToString(params[0],params[1],params[2],params[3]); const response = amountToString(params[0], params[1], params[2], params[3]);
expect(response).toBe(it.output); expect(response).toBe(it.output);
}); });
}); });
}) });

View File

@ -3,21 +3,27 @@ export const pn = (value?: number | null): string | undefined => {
return; return;
} }
const parts = value.toString().split("."); const parts = value.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join("."); return parts.join('.');
}; };
export const amountToString: (amount: string, has_range: boolean , min_amount: number, max_amount: number) => string = export const amountToString: (
(amount, has_range, min_amount, max_amount) => { amount: string,
if (has_range){ has_range: boolean,
return pn(parseFloat(Number(min_amount).toPrecision(4))) + min_amount: number,
'-' + max_amount: number,
pn(parseFloat(Number(max_amount).toPrecision(4))) ) => string = (amount, has_range, min_amount, max_amount) => {
if (has_range) {
return (
pn(parseFloat(Number(min_amount).toPrecision(4))) +
'-' +
pn(parseFloat(Number(max_amount).toPrecision(4)))
);
} }
return pn(parseFloat(Number(amount).toPrecision(4))) || "" return pn(parseFloat(Number(amount).toPrecision(4))) || '';
} };
export default pn export default pn;

View File

@ -1,22 +1,22 @@
/* function to save DATA as text from browser /* function to save DATA as text from browser
* @param {String} file -- file name to save to * @param {String} file -- file name to save to
* @param {filename} data -- object to save * @param {filename} data -- object to save
*/ */
export const saveAsJson = (filename, dataObjToWrite) => { export const saveAsJson = (filename, dataObjToWrite) => {
const blob = new Blob([JSON.stringify(dataObjToWrite, null, 2)], { type: "text/json" }); const blob = new Blob([JSON.stringify(dataObjToWrite, null, 2)], { type: 'text/json' });
const link = document.createElement("a"); const link = document.createElement('a');
link.download = filename; link.download = filename;
link.href = window.URL.createObjectURL(blob); link.href = window.URL.createObjectURL(blob);
link.dataset.downloadurl = ["text/json", link.download, link.href].join(":"); link.dataset.downloadurl = ['text/json', link.download, link.href].join(':');
const evt = new MouseEvent("click", { const evt = new MouseEvent('click', {
view: window, view: window,
bubbles: true, bubbles: true,
cancelable: true, cancelable: true,
}); });
link.dispatchEvent(evt); link.dispatchEvent(evt);
link.remove() link.remove();
}; };

View File

@ -1,17 +1,19 @@
// sort of cryptographically strong function to generate Base62 token client-side // sort of cryptographically strong function to generate Base62 token client-side
export function genBase62Token(length){ export function genBase62Token(length) {
return window.btoa(Array.from( return window
window.crypto.getRandomValues( .btoa(
new Uint8Array(length * 2))) Array.from(window.crypto.getRandomValues(new Uint8Array(length * 2)))
.map((b) => String.fromCharCode(b)) .map((b) => String.fromCharCode(b))
.join("")).replace(/[+/]/g, "") .join(''),
.substring(0, length); )
.replace(/[+/]/g, '')
.substring(0, length);
} }
export function tokenStrength(token) { export function tokenStrength(token) {
const characters = token.split("").reduce(function(obj, s){ const characters = token.split('').reduce(function (obj, s) {
obj[s] = (obj[s] || 0) + 1; obj[s] = (obj[s] || 0) + 1;
return obj; return obj;
}, {}); }, {});
return {uniqueValues:Object.keys(characters).length,counts:Object.values(characters)} return { uniqueValues: Object.keys(characters).length, counts: Object.values(characters) };
} }

View File

@ -1,18 +1,18 @@
import { requestProvider, WeblnProvider } from "webln"; import { requestProvider, WeblnProvider } from 'webln';
export const getWebln = async (): Promise<WeblnProvider> => { export const getWebln = async (): Promise<WeblnProvider> => {
const resultPromise = new Promise<WeblnProvider>(async (resolve, reject) => { const resultPromise = new Promise<WeblnProvider>(async (resolve, reject) => {
try { try {
const webln = await requestProvider() const webln = await requestProvider();
if (webln) { if (webln) {
webln.enable() webln.enable();
resolve(webln) resolve(webln);
} }
} catch (err) { } catch (err) {
console.log("Coulnd't connect to Webln") console.log("Coulnd't connect to Webln");
reject() reject();
} }
}) });
return resultPromise return resultPromise;
} };