mirror of
https://github.com/RoboSats/robosats.git
synced 2025-02-07 05:49:04 +00:00
commit
ec1b4f2576
@ -478,6 +478,7 @@ class LNDNode:
|
|||||||
payment_request=lnpayment.invoice,
|
payment_request=lnpayment.invoice,
|
||||||
fee_limit_sat=fee_limit_sat,
|
fee_limit_sat=fee_limit_sat,
|
||||||
timeout_seconds=timeout_seconds,
|
timeout_seconds=timeout_seconds,
|
||||||
|
amp=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
routerstub = router_pb2_grpc.RouterStub(cls.channel)
|
routerstub = router_pb2_grpc.RouterStub(cls.channel)
|
||||||
@ -536,6 +537,7 @@ class LNDNode:
|
|||||||
fee_limit_sat=fee_limit_sat,
|
fee_limit_sat=fee_limit_sat,
|
||||||
timeout_seconds=timeout_seconds,
|
timeout_seconds=timeout_seconds,
|
||||||
allow_self_payment=True,
|
allow_self_payment=True,
|
||||||
|
amp=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
order = lnpayment.order_paid_LN
|
order = lnpayment.order_paid_LN
|
||||||
|
@ -50,16 +50,16 @@ class Command(BaseCommand):
|
|||||||
parts = message.split(" ")
|
parts = message.split(" ")
|
||||||
if len(parts) < 2:
|
if len(parts) < 2:
|
||||||
self.notifications.send_telegram_message(
|
self.notifications.send_telegram_message(
|
||||||
chat_id=result["message"]["from"]["id"],
|
result["message"]["from"]["id"],
|
||||||
text='You must enable the notifications bot using the RoboSats client. Click on your "Robot robot" -> "Enable Telegram" and follow the link or scan the QR code.',
|
'You must enable the notifications bot using the RoboSats client. Click on your "Robot robot" -> "Enable Telegram" and follow the link or scan the QR code.',
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
token = parts[-1]
|
token = parts[-1]
|
||||||
robot = Robot.objects.filter(telegram_token=token).first()
|
robot = Robot.objects.filter(telegram_token=token).first()
|
||||||
if not robot:
|
if not robot:
|
||||||
self.notifications.send_telegram_message(
|
self.notifications.send_telegram_message(
|
||||||
chat_id=result["message"]["from"]["id"],
|
result["message"]["from"]["id"],
|
||||||
text=f'Wops, invalid token! There is no Robot with telegram chat token "{token}"',
|
f'Wops, invalid token! There is no Robot with telegram chat token "{token}"',
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
18
api/migrations/0049_alter_currency_currency.py
Normal file
18
api/migrations/0049_alter_currency_currency.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.0.8 on 2024-08-15 18:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0048_alter_order_reference'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='currency',
|
||||||
|
name='currency',
|
||||||
|
field=models.PositiveSmallIntegerField(choices=[(1, 'USD'), (2, 'EUR'), (3, 'JPY'), (4, 'GBP'), (5, 'AUD'), (6, 'CAD'), (7, 'CHF'), (8, 'CNY'), (9, 'HKD'), (10, 'NZD'), (11, 'SEK'), (12, 'KRW'), (13, 'SGD'), (14, 'NOK'), (15, 'MXN'), (16, 'BYN'), (17, 'RUB'), (18, 'ZAR'), (19, 'TRY'), (20, 'BRL'), (21, 'CLP'), (22, 'CZK'), (23, 'DKK'), (24, 'HRK'), (25, 'HUF'), (26, 'INR'), (27, 'ISK'), (28, 'PLN'), (29, 'RON'), (30, 'ARS'), (31, 'VES'), (32, 'COP'), (33, 'PEN'), (34, 'UYU'), (35, 'PYG'), (36, 'BOB'), (37, 'IDR'), (38, 'ANG'), (39, 'CRC'), (40, 'CUP'), (41, 'DOP'), (42, 'GHS'), (43, 'GTQ'), (44, 'ILS'), (45, 'JMD'), (46, 'KES'), (47, 'KZT'), (48, 'MYR'), (49, 'NAD'), (50, 'NGN'), (51, 'AZN'), (52, 'PAB'), (53, 'PHP'), (54, 'PKR'), (55, 'QAR'), (56, 'SAR'), (57, 'THB'), (58, 'TTD'), (59, 'VND'), (60, 'XOF'), (61, 'TWD'), (62, 'TZS'), (63, 'XAF'), (64, 'UAH'), (65, 'EGP'), (66, 'LKR'), (67, 'MAD'), (68, 'AED'), (69, 'TND'), (70, 'ETB'), (71, 'GEL'), (72, 'UGX'), (73, 'RSD'), (74, 'IRT'), (75, 'BDT'), (76, 'ALL'), (77, 'DZD'), (300, 'XAU'), (1000, 'BTC')], unique=True),
|
||||||
|
),
|
||||||
|
]
|
18
api/migrations/0050_alter_order_status.py
Normal file
18
api/migrations/0050_alter_order_status.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.0.8 on 2024-08-22 08:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0049_alter_currency_currency'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='order',
|
||||||
|
name='status',
|
||||||
|
field=models.PositiveSmallIntegerField(choices=[(0, 'Waiting for maker bond'), (1, 'Public'), (2, 'Paused'), (3, 'Waiting for taker bond'), (4, 'Cancelled'), (5, 'Expired'), (6, 'Waiting for trade collateral and buyer invoice'), (7, 'Waiting only for seller trade collateral'), (8, 'Waiting only for buyer invoice'), (9, 'Sending fiat - In chatroom'), (10, 'Fiat sent - In chatroom'), (11, 'In dispute'), (12, 'Collaboratively cancelled'), (13, 'Sending satoshis to buyer'), (14, 'Successful trade'), (15, 'Failed lightning network routing'), (16, 'Wait for dispute resolution'), (17, 'Maker lost dispute'), (18, 'Taker lost dispute')], default=0),
|
||||||
|
),
|
||||||
|
]
|
@ -46,7 +46,7 @@ class Order(models.Model):
|
|||||||
DIS = 11, "In dispute"
|
DIS = 11, "In dispute"
|
||||||
CCA = 12, "Collaboratively cancelled"
|
CCA = 12, "Collaboratively cancelled"
|
||||||
PAY = 13, "Sending satoshis to buyer"
|
PAY = 13, "Sending satoshis to buyer"
|
||||||
SUC = 14, "Sucessful trade"
|
SUC = 14, "Successful trade"
|
||||||
FAI = 15, "Failed lightning network routing"
|
FAI = 15, "Failed lightning network routing"
|
||||||
WFR = 16, "Wait for dispute resolution"
|
WFR = 16, "Wait for dispute resolution"
|
||||||
MLD = 17, "Maker lost dispute"
|
MLD = 17, "Maker lost dispute"
|
||||||
|
@ -37,13 +37,13 @@ class Notifications:
|
|||||||
if robot.telegram_enabled:
|
if robot.telegram_enabled:
|
||||||
self.send_telegram_message(robot.telegram_chat_id, title, description)
|
self.send_telegram_message(robot.telegram_chat_id, title, description)
|
||||||
|
|
||||||
def save_message(self, order, robot, title, description):
|
def save_message(self, order, robot, title, description=""):
|
||||||
"""Save a message for a user"""
|
"""Save a message for a user"""
|
||||||
Notification.objects.create(
|
Notification.objects.create(
|
||||||
title=title, description=description, robot=robot, order=order
|
title=title, description=description, robot=robot, order=order
|
||||||
)
|
)
|
||||||
|
|
||||||
def send_telegram_message(self, chat_id, title, description):
|
def send_telegram_message(self, chat_id, title, description=""):
|
||||||
"""sends a message to a user with telegram notifications enabled"""
|
"""sends a message to a user with telegram notifications enabled"""
|
||||||
|
|
||||||
bot_token = config("TELEGRAM_TOKEN")
|
bot_token = config("TELEGRAM_TOKEN")
|
||||||
|
@ -112,7 +112,7 @@ class OrderViewSchema:
|
|||||||
- `11` "In dispute"
|
- `11` "In dispute"
|
||||||
- `12` "Collaboratively cancelled"
|
- `12` "Collaboratively cancelled"
|
||||||
- `13` "Sending satoshis to buyer"
|
- `13` "Sending satoshis to buyer"
|
||||||
- `14` "Sucessful trade"
|
- `14` "Successful trade"
|
||||||
- `15` "Failed lightning network routing"
|
- `15` "Failed lightning network routing"
|
||||||
- `16` "Wait for dispute resolution"
|
- `16` "Wait for dispute resolution"
|
||||||
- `17` "Maker lost dispute"
|
- `17` "Maker lost dispute"
|
||||||
|
@ -141,7 +141,7 @@ def get_devfund_pubkey(network: str) -> str:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
session = get_session()
|
session = get_session()
|
||||||
url = "https://raw.githubusercontent.com/RoboSats/robosats/main/devfund_pubey.json"
|
url = "https://raw.githubusercontent.com/RoboSats/robosats/main/devfund_pubkey.json"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = session.get(url)
|
response = session.get(url)
|
||||||
|
@ -365,7 +365,7 @@ paths:
|
|||||||
- `11` "In dispute"
|
- `11` "In dispute"
|
||||||
- `12` "Collaboratively cancelled"
|
- `12` "Collaboratively cancelled"
|
||||||
- `13` "Sending satoshis to buyer"
|
- `13` "Sending satoshis to buyer"
|
||||||
- `14` "Sucessful trade"
|
- `14` "Successful trade"
|
||||||
- `15` "Failed lightning network routing"
|
- `15` "Failed lightning network routing"
|
||||||
- `16` "Wait for dispute resolution"
|
- `16` "Wait for dispute resolution"
|
||||||
- `17` "Maker lost dispute"
|
- `17` "Maker lost dispute"
|
||||||
@ -1833,7 +1833,7 @@ components:
|
|||||||
* `11` - In dispute
|
* `11` - In dispute
|
||||||
* `12` - Collaboratively cancelled
|
* `12` - Collaboratively cancelled
|
||||||
* `13` - Sending satoshis to buyer
|
* `13` - Sending satoshis to buyer
|
||||||
* `14` - Sucessful trade
|
* `14` - Successful trade
|
||||||
* `15` - Failed lightning network routing
|
* `15` - Failed lightning network routing
|
||||||
* `16` - Wait for dispute resolution
|
* `16` - Wait for dispute resolution
|
||||||
* `17` - Maker lost dispute
|
* `17` - Maker lost dispute
|
||||||
|
24
frontend/package-lock.json
generated
24
frontend/package-lock.json
generated
@ -23,11 +23,11 @@
|
|||||||
"@nivo/core": "^0.86.0",
|
"@nivo/core": "^0.86.0",
|
||||||
"@nivo/line": "^0.86.0",
|
"@nivo/line": "^0.86.0",
|
||||||
"base-ex": "^0.8.1",
|
"base-ex": "^0.8.1",
|
||||||
"country-flag-icons": "^1.5.11",
|
"country-flag-icons": "^1.5.13",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"file-replace-loader": "^1.4.0",
|
"file-replace-loader": "^1.4.0",
|
||||||
"i18next": "^23.2.11",
|
"i18next": "^23.2.11",
|
||||||
"i18next-browser-languagedetector": "^7.2.1",
|
"i18next-browser-languagedetector": "^8.0.0",
|
||||||
"i18next-http-backend": "^2.5.0",
|
"i18next-http-backend": "^2.5.0",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"js-sha256": "^0.11.0",
|
"js-sha256": "^0.11.0",
|
||||||
@ -81,7 +81,7 @@
|
|||||||
"jest": "^29.6.1",
|
"jest": "^29.6.1",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.2",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.4.2",
|
"typescript": "^5.5.4",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
}
|
}
|
||||||
@ -6411,9 +6411,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/country-flag-icons": {
|
"node_modules/country-flag-icons": {
|
||||||
"version": "1.5.11",
|
"version": "1.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.11.tgz",
|
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.13.tgz",
|
||||||
"integrity": "sha512-B+mvFywunkRJs270k7kCBjhogvIA0uNn6GAXv6m2cPn3rrwqZzZVr2gBWcz+Cz7OGVWlcbERlYRIX0S6OGr8Bw=="
|
"integrity": "sha512-4JwHNqaKZ19doQoNcBjsoYA+I7NqCH/mC/6f5cBWvdKzcK5TMmzLpq3Z/syVHMHJuDGFwJ+rPpGizvrqJybJow=="
|
||||||
},
|
},
|
||||||
"node_modules/create-require": {
|
"node_modules/create-require": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
@ -8823,9 +8823,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/i18next-browser-languagedetector": {
|
"node_modules/i18next-browser-languagedetector": {
|
||||||
"version": "7.2.1",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
|
||||||
"integrity": "sha512-h/pM34bcH6tbz8WgGXcmWauNpQupCGr25XPp9cZwZInR9XHSjIFDYp1SIok7zSPsTOMxdvuLyu86V+g2Kycnfw==",
|
"integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.23.2"
|
"@babel/runtime": "^7.23.2"
|
||||||
}
|
}
|
||||||
@ -16730,9 +16730,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.4.2",
|
"version": "5.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
||||||
"integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==",
|
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
"jest": "^29.6.1",
|
"jest": "^29.6.1",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.2",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.4.2",
|
"typescript": "^5.5.4",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
},
|
},
|
||||||
@ -62,11 +62,11 @@
|
|||||||
"@nivo/core": "^0.86.0",
|
"@nivo/core": "^0.86.0",
|
||||||
"@nivo/line": "^0.86.0",
|
"@nivo/line": "^0.86.0",
|
||||||
"base-ex": "^0.8.1",
|
"base-ex": "^0.8.1",
|
||||||
"country-flag-icons": "^1.5.11",
|
"country-flag-icons": "^1.5.13",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"file-replace-loader": "^1.4.0",
|
"file-replace-loader": "^1.4.0",
|
||||||
"i18next": "^23.2.11",
|
"i18next": "^23.2.11",
|
||||||
"i18next-browser-languagedetector": "^7.2.1",
|
"i18next-browser-languagedetector": "^8.0.0",
|
||||||
"i18next-http-backend": "^2.5.0",
|
"i18next-http-backend": "^2.5.0",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"js-sha256": "^0.11.0",
|
"js-sha256": "^0.11.0",
|
||||||
|
@ -40,14 +40,14 @@ const OrderPage = (): JSX.Element => {
|
|||||||
const shortAlias = params.shortAlias;
|
const shortAlias = params.shortAlias;
|
||||||
const coordinator = federation.getCoordinator(shortAlias ?? '');
|
const coordinator = federation.getCoordinator(shortAlias ?? '');
|
||||||
if (coordinator) {
|
if (coordinator) {
|
||||||
const { url, basePath } = coordinator?.getEndpoint(
|
const endpoint = coordinator?.getEndpoint(
|
||||||
settings.network,
|
settings.network,
|
||||||
origin,
|
origin,
|
||||||
settings.selfhostedClient,
|
settings.selfhostedClient,
|
||||||
hostUrl,
|
hostUrl,
|
||||||
);
|
);
|
||||||
|
|
||||||
setBaseUrl(`${url}${basePath}`);
|
if (endpoint) setBaseUrl(`${endpoint?.url}${endpoint?.basePath}`);
|
||||||
|
|
||||||
const orderId = Number(params.orderId);
|
const orderId = Number(params.orderId);
|
||||||
if (
|
if (
|
||||||
|
@ -2,38 +2,45 @@ import React, { useState, useContext, useEffect } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
Grid,
|
|
||||||
LinearProgress,
|
|
||||||
Typography,
|
Typography,
|
||||||
Alert,
|
LinearProgress,
|
||||||
Select,
|
Select,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Box,
|
Box,
|
||||||
|
TextField,
|
||||||
|
SelectChangeEvent,
|
||||||
useTheme,
|
useTheme,
|
||||||
Tooltip,
|
useMediaQuery,
|
||||||
type SelectChangeEvent,
|
styled,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Bolt, Add, DeleteSweep, Logout, Download } from '@mui/icons-material';
|
import { Bolt, Add, DeleteSweep, Logout, Download, FileCopy } from '@mui/icons-material';
|
||||||
import RobotAvatar from '../../components/RobotAvatar';
|
import RobotAvatar from '../../components/RobotAvatar';
|
||||||
import TokenInput from './TokenInput';
|
import { AppContext, UseAppStoreType } from '../../contexts/AppContext';
|
||||||
import { type Slot, type Robot } from '../../models';
|
|
||||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
|
||||||
import { genBase62Token } from '../../utils';
|
import { genBase62Token } from '../../utils';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { GarageContext, UseGarageStoreType } from '../../contexts/GarageContext';
|
||||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
import { FederationContext, UseFederationStoreType } from '../../contexts/FederationContext';
|
||||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
|
||||||
|
const BUTTON_COLORS = {
|
||||||
|
primary: '#2196f3',
|
||||||
|
secondary: '#9c27b0',
|
||||||
|
text: '#ffffff',
|
||||||
|
hoverPrimary: '#4dabf5',
|
||||||
|
hoverSecondary: '#af52bf',
|
||||||
|
activePrimary: '#1976d2',
|
||||||
|
activeSecondary: '#7b1fa2',
|
||||||
|
deleteHover: '#ff6666',
|
||||||
|
};
|
||||||
|
|
||||||
|
const COLORS = {
|
||||||
|
shadow: '#000000',
|
||||||
|
};
|
||||||
|
|
||||||
interface RobotProfileProps {
|
interface RobotProfileProps {
|
||||||
robot: Robot;
|
|
||||||
setRobot: (state: Robot) => void;
|
|
||||||
setView: (state: 'welcome' | 'onboarding' | 'recovery' | 'profile') => void;
|
|
||||||
getGenerateRobot: (token: string, slot?: number) => void;
|
|
||||||
inputToken: string;
|
inputToken: string;
|
||||||
|
getGenerateRobot: (token: string) => void;
|
||||||
|
setInputToken: (token: string) => void;
|
||||||
logoutRobot: () => void;
|
logoutRobot: () => void;
|
||||||
setInputToken: (state: string) => void;
|
setView: (view: string) => void;
|
||||||
width: number;
|
|
||||||
baseUrl: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const RobotProfile = ({
|
const RobotProfile = ({
|
||||||
@ -42,7 +49,6 @@ const RobotProfile = ({
|
|||||||
setInputToken,
|
setInputToken,
|
||||||
logoutRobot,
|
logoutRobot,
|
||||||
setView,
|
setView,
|
||||||
width,
|
|
||||||
}: RobotProfileProps): JSX.Element => {
|
}: RobotProfileProps): JSX.Element => {
|
||||||
const { windowSize } = useContext<UseAppStoreType>(AppContext);
|
const { windowSize } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { garage, robotUpdatedAt, orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
const { garage, robotUpdatedAt, orderUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
|
||||||
@ -51,6 +57,7 @@ const RobotProfile = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
|
|
||||||
@ -82,278 +89,309 @@ const RobotProfile = ({
|
|||||||
).length;
|
).length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container direction='column' alignItems='center' spacing={1} padding={1} paddingTop={2}>
|
<ProfileContainer $isMobile={isMobile}>
|
||||||
<Grid
|
<InfoSection colors={COLORS} $isMobile={isMobile}>
|
||||||
item
|
<NicknameTypography variant={isMobile ? "h6" : "h5"} align="center" $isMobile={isMobile}>
|
||||||
container
|
<BoltIcon $isMobile={isMobile} />
|
||||||
direction='column'
|
{slot?.nickname}
|
||||||
alignItems='center'
|
<BoltIcon $isMobile={isMobile} />
|
||||||
spacing={1}
|
</NicknameTypography>
|
||||||
sx={{ width: '100%' }}
|
<StyledRobotAvatar
|
||||||
>
|
hashId={slot?.hashId}
|
||||||
<Grid item sx={{ height: '2.3em', position: 'relative' }}>
|
smooth={true}
|
||||||
{slot?.nickname ? (
|
placeholderType='generating'
|
||||||
<Typography align='center' component='h5' variant='h5'>
|
style={{ width: isMobile ? '80px' : '120px', height: isMobile ? '80px' : '120px' }}
|
||||||
<div
|
/>
|
||||||
style={{
|
<StatusTypography variant={isMobile ? "body2" : "body1"} align="center" $isMobile={isMobile}>
|
||||||
display: 'flex',
|
{loadingCoordinators > 0 && !robot?.activeOrderId ? t('Looking for orders!') : t('Ready to Trade')}
|
||||||
alignItems: 'center',
|
</StatusTypography>
|
||||||
justifyContent: 'center',
|
{loadingCoordinators > 0 && !robot?.activeOrderId && <StyledLinearProgress $isMobile={isMobile} />}
|
||||||
flexWrap: 'wrap',
|
<TokenBox $isMobile={isMobile}>
|
||||||
}}
|
<CustomIconButton onClick={() => {
|
||||||
>
|
logoutRobot();
|
||||||
{width < 19 ? null : (
|
setView('welcome');
|
||||||
<Bolt
|
}}>
|
||||||
sx={{
|
<StyledLogoutIcon $isMobile={isMobile} />
|
||||||
color: '#fcba03',
|
</CustomIconButton>
|
||||||
height: '1.5em',
|
<StyledTextField
|
||||||
width: '1.5em',
|
fullWidth
|
||||||
}}
|
value={inputToken}
|
||||||
/>
|
variant="standard"
|
||||||
)}
|
$isMobile={isMobile}
|
||||||
<b>{slot?.nickname}</b>
|
InputProps={{
|
||||||
{width < 19 ? null : (
|
readOnly: true,
|
||||||
<Bolt
|
disableUnderline: true,
|
||||||
sx={{
|
endAdornment: (
|
||||||
color: '#fcba03',
|
<CustomIconButton onClick={() => navigator.clipboard.writeText(inputToken)}>
|
||||||
height: '1.5em',
|
<StyledFileCopyIcon $isMobile={isMobile} />
|
||||||
width: '1.5em',
|
</CustomIconButton>
|
||||||
}}
|
),
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Typography>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<b>{t('Building your robot!')}</b>
|
|
||||||
<LinearProgress />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid item sx={{ width: `13.5em` }}>
|
|
||||||
<RobotAvatar
|
|
||||||
hashId={slot?.hashId}
|
|
||||||
smooth={true}
|
|
||||||
style={{ maxWidth: '12.5em', maxHeight: '12.5em' }}
|
|
||||||
placeholderType='generating'
|
|
||||||
imageStyle={{
|
|
||||||
transform: '',
|
|
||||||
border: '2px solid #555',
|
|
||||||
filter: 'drop-shadow(1px 1px 1px #000000)',
|
|
||||||
height: `12.4em`,
|
|
||||||
width: `12.4em`,
|
|
||||||
}}
|
}}
|
||||||
tooltip={t('This is your trading avatar')}
|
|
||||||
tooltipPosition='top'
|
|
||||||
/>
|
/>
|
||||||
{robot?.found && Boolean(slot?.lastShortAlias) ? (
|
</TokenBox>
|
||||||
<Typography align='center' variant='h6'>
|
</InfoSection>
|
||||||
{t('Welcome back!')}
|
|
||||||
</Typography>
|
<RightSection $isMobile={isMobile}>
|
||||||
|
<TitleSection>
|
||||||
|
<TitleTypography variant={isMobile ? "subtitle1" : "h6"} align="center">
|
||||||
|
{t('Robot Garage')}
|
||||||
|
</TitleTypography>
|
||||||
|
</TitleSection>
|
||||||
|
<StyledSelect
|
||||||
|
value={loading ? 'loading' : garage.currentSlot}
|
||||||
|
onChange={handleChangeSlot}
|
||||||
|
$isMobile={isMobile}
|
||||||
|
>
|
||||||
|
{loading ? (
|
||||||
|
<MenuItem key={'loading'} value={'loading'}>
|
||||||
|
<Typography variant={isMobile ? "body2" : "body1"}>{t('Building...')}</Typography>
|
||||||
|
</MenuItem>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
Object.values(garage.slots).map((slot: Slot, index: number) => (
|
||||||
|
<StyledMenuItem key={index} value={slot.token} $isMobile={isMobile}>
|
||||||
|
<MenuItemContent>
|
||||||
|
<StyledMenuItemAvatar
|
||||||
|
hashId={slot?.hashId}
|
||||||
|
smooth={true}
|
||||||
|
$isMobile={isMobile}
|
||||||
|
placeholderType='loading'
|
||||||
|
small={true}
|
||||||
|
/>
|
||||||
|
<Typography variant={isMobile ? "body2" : "body1"}>{slot?.nickname}</Typography>
|
||||||
|
</MenuItemContent>
|
||||||
|
</StyledMenuItem>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</StyledSelect>
|
||||||
|
<ButtonContainer>
|
||||||
{loadingCoordinators > 0 && !Boolean(robot?.activeOrderId) ? (
|
<StyledButton
|
||||||
<Grid>
|
$buttonColor={BUTTON_COLORS.primary}
|
||||||
<b>{t('Looking for orders!')}</b>
|
$hoverColor={BUTTON_COLORS.hoverPrimary}
|
||||||
<LinearProgress />
|
$textColor={BUTTON_COLORS.text}
|
||||||
</Grid>
|
$isMobile={isMobile}
|
||||||
) : null}
|
onClick={handleAddRobot}
|
||||||
|
|
||||||
{Boolean(robot?.activeOrderId) && Boolean(slot?.hashId) ? (
|
|
||||||
<Grid item>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
setCurrentOrderId({ id: robot?.activeOrderId, shortAlias: slot?.activeShortAlias });
|
|
||||||
navigate(
|
|
||||||
`/order/${String(slot?.activeShortAlias)}/${String(robot?.activeOrderId)}`,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Active order #{{orderID}}', { orderID: robot?.activeOrderId })}
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{Boolean(robot?.lastOrderId) && Boolean(slot?.hashId) ? (
|
|
||||||
<Grid item container direction='column' alignItems='center'>
|
|
||||||
<Grid item>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
setCurrentOrderId({ id: robot?.lastOrderId, shortAlias: slot?.activeShortAlias });
|
|
||||||
navigate(`/order/${String(slot?.lastShortAlias)}/${String(robot?.lastOrderId)}`);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Last order #{{orderID}}', { orderID: robot?.lastOrderId })}
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
<Grid item>
|
|
||||||
<Alert severity='warning'>
|
|
||||||
<Grid container direction='column' alignItems='center'>
|
|
||||||
<Grid item>
|
|
||||||
{t(
|
|
||||||
'Reusing trading identity degrades your privacy against other users, coordinators and observers.',
|
|
||||||
)}
|
|
||||||
</Grid>
|
|
||||||
<Grid item sx={{ position: 'relative', right: '1em' }}>
|
|
||||||
<Button color='success' size='small' onClick={handleAddRobot}>
|
|
||||||
<Add />
|
|
||||||
{t('Add a new Robot')}
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Alert>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{!Boolean(robot?.activeOrderId) &&
|
|
||||||
slot?.hashId &&
|
|
||||||
!Boolean(robot?.lastOrderId) &&
|
|
||||||
loadingCoordinators === 0 ? (
|
|
||||||
<Grid item>{t('No existing orders found')}</Grid>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
container
|
|
||||||
direction='row'
|
|
||||||
justifyContent='stretch'
|
|
||||||
alignItems='stretch'
|
|
||||||
sx={{ width: '100%' }}
|
|
||||||
>
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
xs={2}
|
|
||||||
sx={{ display: 'flex', justifyContent: 'stretch', alignItems: 'stretch' }}
|
|
||||||
>
|
>
|
||||||
<Tooltip enterTouchDelay={0} enterDelay={300} enterNextDelay={1000} title={t('Logout')}>
|
<StyledAddIcon $isMobile={isMobile} /> {t('ADD ROBOT')}
|
||||||
<Button
|
</StyledButton>
|
||||||
sx={{ minWidth: '2em', width: '100%' }}
|
{window.NativeRobosats === undefined && (
|
||||||
color='primary'
|
<StyledButton
|
||||||
variant='outlined'
|
$buttonColor={BUTTON_COLORS.secondary}
|
||||||
onClick={() => {
|
$hoverColor={BUTTON_COLORS.hoverSecondary}
|
||||||
logoutRobot();
|
$textColor={BUTTON_COLORS.text}
|
||||||
setView('welcome');
|
$isMobile={isMobile}
|
||||||
}}
|
onClick={() => garage.download()}
|
||||||
>
|
>
|
||||||
<Logout />
|
<StyledDownloadIcon $isMobile={isMobile} /> {t('DOWNLOAD')}
|
||||||
</Button>
|
</StyledButton>
|
||||||
</Tooltip>
|
)}
|
||||||
</Grid>
|
<StyledButton
|
||||||
<Grid item xs={10}>
|
$buttonColor="transparent"
|
||||||
<TokenInput
|
$hoverColor={BUTTON_COLORS.deleteHover}
|
||||||
inputToken={inputToken}
|
$textColor="red"
|
||||||
editable={false}
|
$isMobile={isMobile}
|
||||||
label={t('Store your token safely')}
|
onClick={() => {
|
||||||
setInputToken={setInputToken}
|
garage.delete();
|
||||||
onPressEnter={() => null}
|
logoutRobot();
|
||||||
/>
|
setView('welcome');
|
||||||
</Grid>
|
}}
|
||||||
</Grid>
|
>
|
||||||
</Grid>
|
<StyledDeleteSweepIcon $isMobile={isMobile} /> {t('DELETE GARAGE')}
|
||||||
<Grid item sx={{ width: '100%' }}>
|
</StyledButton>
|
||||||
<Box
|
</ButtonContainer>
|
||||||
sx={{
|
</RightSection>
|
||||||
backgroundColor: 'background.paper',
|
</ProfileContainer>
|
||||||
border: '1px solid',
|
|
||||||
borderRadius: '4px',
|
|
||||||
borderColor: theme.palette.mode === 'dark' ? '#434343' : '#c4c4c4',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Grid container direction='column' alignItems='center' spacing={2} padding={2}>
|
|
||||||
<Grid item sx={{ width: '100%' }}>
|
|
||||||
<Typography variant='caption'>{t('Robot Garage')}</Typography>
|
|
||||||
<Select
|
|
||||||
fullWidth
|
|
||||||
required={true}
|
|
||||||
inputProps={{
|
|
||||||
style: { textAlign: 'center' },
|
|
||||||
}}
|
|
||||||
value={loading ? 'loading' : garage.currentSlot}
|
|
||||||
onChange={handleChangeSlot}
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<MenuItem key={'loading'} value={'loading'}>
|
|
||||||
<Typography>{t('Building...')}</Typography>
|
|
||||||
</MenuItem>
|
|
||||||
) : (
|
|
||||||
Object.values(garage.slots).map((slot: Slot, index: number) => {
|
|
||||||
return (
|
|
||||||
<MenuItem key={index} value={slot.token}>
|
|
||||||
<Grid
|
|
||||||
container
|
|
||||||
direction='row'
|
|
||||||
justifyContent='flex-start'
|
|
||||||
alignItems='center'
|
|
||||||
style={{ height: '2.8em' }}
|
|
||||||
spacing={1}
|
|
||||||
>
|
|
||||||
<Grid item>
|
|
||||||
<RobotAvatar
|
|
||||||
hashId={slot?.hashId}
|
|
||||||
smooth={true}
|
|
||||||
style={{ width: '2.6em', height: '2.6em' }}
|
|
||||||
placeholderType='loading'
|
|
||||||
small={true}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item>
|
|
||||||
<Typography variant={windowSize.width < 26 ? 'caption' : undefined}>
|
|
||||||
{slot?.nickname}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
)}
|
|
||||||
</Select>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid item container direction='row' alignItems='center' justifyContent='space-evenly'>
|
|
||||||
<Grid item>
|
|
||||||
<LoadingButton loading={loading} color='primary' onClick={handleAddRobot}>
|
|
||||||
<Add /> <div style={{ width: '0.5em' }} />
|
|
||||||
{t('Add Robot')}
|
|
||||||
</LoadingButton>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{window.NativeRobosats === undefined ? (
|
|
||||||
<Grid item>
|
|
||||||
<Button
|
|
||||||
color='primary'
|
|
||||||
onClick={() => {
|
|
||||||
garage.download();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Download />
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<Grid item>
|
|
||||||
<Button
|
|
||||||
color='primary'
|
|
||||||
onClick={() => {
|
|
||||||
garage.delete();
|
|
||||||
logoutRobot();
|
|
||||||
setView('welcome');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DeleteSweep /> <div style={{ width: '0.5em' }} />
|
|
||||||
{t('Delete Garage')}
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Box>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RobotProfile;
|
// Styled components
|
||||||
|
const ProfileContainer = styled(Box)<{ $isMobile: boolean }>(({ theme, $isMobile }) => ({
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: $isMobile ? '100%' : 1000,
|
||||||
|
margin: '0 auto',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: $isMobile ? 'column' : 'row',
|
||||||
|
border: $isMobile ? '1px solid #000' : '2px solid #000',
|
||||||
|
borderRadius: '8px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
boxShadow: $isMobile ? '4px 4px 0px #000000' : '8px 8px 0px #000000',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const InfoSection = styled(Box)<{ colors: typeof COLORS; $isMobile: boolean }>(({ theme, colors, $isMobile }) => ({
|
||||||
|
flexGrow: 1,
|
||||||
|
flexBasis: $isMobile ? 'auto' : 0,
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: $isMobile ? theme.spacing(2) : theme.spacing(4),
|
||||||
|
borderBottom: $isMobile ? '1px solid #000' : 'none',
|
||||||
|
borderRight: $isMobile ? 'none' : '2px solid #000',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const NicknameTypography = styled(Typography)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: $isMobile ? '8px' : '16px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const BoltIcon = styled(Bolt)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
color: '#fcba03',
|
||||||
|
height: $isMobile ? '0.8em' : '1em',
|
||||||
|
width: $isMobile ? '0.8em' : '1em',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledRobotAvatar = styled(RobotAvatar)({
|
||||||
|
'& img': {
|
||||||
|
border: '2px solid #555',
|
||||||
|
borderRadius: '50%',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const StatusTypography = styled(Typography)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
marginBottom: $isMobile ? '8px' : '16px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledLinearProgress = styled(LinearProgress)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
width: '100%',
|
||||||
|
marginBottom: $isMobile ? '8px' : '16px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TokenBox = styled(Box)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: '100%',
|
||||||
|
border: $isMobile ? '1px solid #000' : '2px solid #000',
|
||||||
|
borderRadius: '4px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledTextField = styled(TextField)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
'& .MuiInputBase-root': {
|
||||||
|
height: $isMobile ? '36px' : '48px',
|
||||||
|
padding: $isMobile ? '2px 4px' : '4px 8px',
|
||||||
|
fontSize: $isMobile ? '0.8rem' : '1rem',
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const RightSection = styled(Box)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
flexGrow: 1,
|
||||||
|
flexBasis: $isMobile ? 'auto' : 0,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TitleSection = styled(Box)(({ theme }) => ({
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
borderBottom: `2px solid #000`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TitleTypography = styled(Typography)({
|
||||||
|
fontWeight: 'bold',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledSelect = styled(Select)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
width: '100%',
|
||||||
|
height: $isMobile ? '50px' : '80px',
|
||||||
|
borderBottom: $isMobile ? '1px solid #000' : '2px solid #000',
|
||||||
|
borderRadius: 0,
|
||||||
|
'& .MuiOutlinedInput-notchedOutline': {
|
||||||
|
border: 'none',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledMenuItem = styled(MenuItem)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
height: $isMobile ? '50px' : '80px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const MenuItemContent = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledMenuItemAvatar = styled(RobotAvatar)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
width: $isMobile ? '24px' : '30px',
|
||||||
|
height: $isMobile ? '24px' : '30px',
|
||||||
|
marginRight: '8px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ButtonContainer = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: '100%',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledButton = styled('button')<{
|
||||||
|
$buttonColor: string;
|
||||||
|
$hoverColor: string;
|
||||||
|
$textColor: string;
|
||||||
|
$isMobile: boolean;
|
||||||
|
}>(({ theme, $buttonColor, $hoverColor, $textColor, $isMobile }) => ({
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: 0,
|
||||||
|
backgroundColor: $buttonColor,
|
||||||
|
color: $textColor,
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'flex',
|
||||||
|
transition: 'background-color 0.3s ease, color 0.3s ease',
|
||||||
|
width: '100%',
|
||||||
|
height: $isMobile ? '40px' : '60px',
|
||||||
|
borderBottom: $isMobile ? '1px solid #000' : '2px solid #000',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: $hoverColor,
|
||||||
|
color: $buttonColor === 'transparent' ? '#fff' : $textColor,
|
||||||
|
},
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: $buttonColor === BUTTON_COLORS.primary ? BUTTON_COLORS.activePrimary : BUTTON_COLORS.activeSecondary,
|
||||||
|
},
|
||||||
|
'&:focus': {
|
||||||
|
outline: 'none',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const CustomIconButton = styled('button')({
|
||||||
|
background: 'transparent',
|
||||||
|
border: 'none',
|
||||||
|
color: '#1976d2',
|
||||||
|
padding: '4px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
transition: 'color 0.3s ease',
|
||||||
|
'&:hover': {
|
||||||
|
color: '#0d47a1',
|
||||||
|
},
|
||||||
|
'&:active': {
|
||||||
|
color: '#002171',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledLogoutIcon = styled(Logout)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
fontSize: $isMobile ? '1rem' : '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledFileCopyIcon = styled(FileCopy)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
fontSize: $isMobile ? '1rem' : '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledAddIcon = styled(Add)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
marginRight: '8px',
|
||||||
|
fontSize: $isMobile ? '1rem' : '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledDownloadIcon = styled(Download)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
marginRight: '8px',
|
||||||
|
fontSize: $isMobile ? '1rem' : '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledDeleteSweepIcon = styled(DeleteSweep)<{ $isMobile: boolean }>(({ $isMobile }) => ({
|
||||||
|
marginRight: '8px',
|
||||||
|
fontSize: $isMobile ? '1rem' : '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default RobotProfile;
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
Paper,
|
|
||||||
Grid,
|
Grid,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Box,
|
Box,
|
||||||
@ -129,42 +128,40 @@ const RobotPage = (): JSX.Element => {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<StyledMainBox>
|
<StyledMainBox>
|
||||||
<StyledPaper>
|
{view === 'welcome' && (
|
||||||
{view === 'welcome' && (
|
<Welcome setView={setView} getGenerateRobot={getGenerateRobot} width={1200} />
|
||||||
<Welcome setView={setView} getGenerateRobot={getGenerateRobot} width={1200} />
|
)}
|
||||||
)}
|
|
||||||
|
|
||||||
{view === 'onboarding' && (
|
{view === 'onboarding' && (
|
||||||
<Onboarding
|
<Onboarding
|
||||||
setView={setView}
|
setView={setView}
|
||||||
badToken={badToken}
|
badToken={badToken}
|
||||||
inputToken={inputToken}
|
inputToken={inputToken}
|
||||||
setInputToken={setInputToken}
|
setInputToken={setInputToken}
|
||||||
getGenerateRobot={getGenerateRobot}
|
getGenerateRobot={getGenerateRobot}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{view === 'profile' && (
|
{view === 'profile' && (
|
||||||
<RobotProfile
|
<RobotProfile
|
||||||
setView={setView}
|
setView={setView}
|
||||||
logoutRobot={logoutRobot}
|
logoutRobot={logoutRobot}
|
||||||
width={1200}
|
width={1200}
|
||||||
inputToken={inputToken}
|
inputToken={inputToken}
|
||||||
setInputToken={setInputToken}
|
setInputToken={setInputToken}
|
||||||
getGenerateRobot={getGenerateRobot}
|
getGenerateRobot={getGenerateRobot}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{view === 'recovery' && (
|
{view === 'recovery' && (
|
||||||
<Recovery
|
<Recovery
|
||||||
setView={setView}
|
setView={setView}
|
||||||
badToken={badToken}
|
badToken={badToken}
|
||||||
inputToken={inputToken}
|
inputToken={inputToken}
|
||||||
setInputToken={setInputToken}
|
setInputToken={setInputToken}
|
||||||
getRecoverRobot={getGenerateRobot}
|
getRecoverRobot={getGenerateRobot}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledPaper>
|
|
||||||
</StyledMainBox>
|
</StyledMainBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -174,11 +171,13 @@ const RobotPage = (): JSX.Element => {
|
|||||||
const StyledConnectingBox = styled(Box)({
|
const StyledConnectingBox = styled(Box)({
|
||||||
width: '100vw',
|
width: '100vw',
|
||||||
height: 'auto',
|
height: 'auto',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
});
|
});
|
||||||
|
|
||||||
const StyledTorIconBox = styled(Box)({
|
const StyledTorIconBox = styled(Box)({
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
top: '4.6em',
|
top: '4.6em',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
});
|
});
|
||||||
|
|
||||||
const StyledMainBox = styled(Box)({
|
const StyledMainBox = styled(Box)({
|
||||||
@ -188,18 +187,9 @@ const StyledMainBox = styled(Box)({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '2em',
|
padding: '2em',
|
||||||
});
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
width: '80vw',
|
|
||||||
maxWidth: '1200px',
|
|
||||||
maxHeight: '85vh',
|
|
||||||
overflow: 'auto',
|
|
||||||
overflowX: 'clip',
|
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
padding: '1em',
|
});
|
||||||
}));
|
|
||||||
|
|
||||||
export default RobotPage;
|
export default RobotPage;
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import { Button, Grid, List, ListItem, Paper, TextField, Typography } from '@mui/material';
|
import { Button, Grid, Paper, TextField, Typography, Box } from '@mui/material';
|
||||||
import SettingsForm from '../../components/SettingsForm';
|
import SettingsForm from '../../components/SettingsForm';
|
||||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||||
import FederationTable from '../../components/FederationTable';
|
import FederationTable from '../../components/FederationTable';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { FederationContext, UseFederationStoreType } from '../../contexts/FederationContext';
|
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||||
|
import { styled } from '@mui/system';
|
||||||
|
|
||||||
const SettingsPage = (): JSX.Element => {
|
const SettingsPage = (): JSX.Element => {
|
||||||
const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
|
const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
const maxHeight = (windowSize.height * 0.65)
|
|
||||||
|
const maxHeight = (windowSize.height * 0.65);
|
||||||
const [newAlias, setNewAlias] = useState<string>('');
|
const [newAlias, setNewAlias] = useState<string>('');
|
||||||
const [newUrl, setNewUrl] = useState<string>('');
|
const [newUrl, setNewUrl] = useState<string>('');
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
// Regular expression to match a valid .onion URL
|
|
||||||
const onionUrlPattern = /^((http|https):\/\/)?[a-zA-Z2-7]{16,56}\.onion$/;
|
const onionUrlPattern = /^((http|https):\/\/)?[a-zA-Z2-7]{16,56}\.onion$/;
|
||||||
|
|
||||||
const addCoordinator = () => {
|
const addCoordinator: () => void = () => {
|
||||||
if (federation.coordinators[newAlias]) {
|
if (federation.coordinators[newAlias]) {
|
||||||
setError(t('Alias already exists'));
|
setError(t('Alias already exists'));
|
||||||
} else {
|
} else {
|
||||||
@ -35,48 +37,42 @@ const SettingsPage = (): JSX.Element => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper
|
<SettingsContainer elevation={12}>
|
||||||
elevation={12}
|
|
||||||
sx={{
|
|
||||||
padding: '0.6em',
|
|
||||||
width: '20.5em',
|
|
||||||
maxHeight: `${maxHeight}em`,
|
|
||||||
overflow: 'auto',
|
|
||||||
overflowX: 'clip',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item>
|
<LeftGrid item xs={12} md={6}>
|
||||||
<SettingsForm />
|
<SettingsForm />
|
||||||
</Grid>
|
</LeftGrid>
|
||||||
<Grid item>
|
<RightGrid item xs={12} md={6}>
|
||||||
<FederationTable maxHeight={18} />
|
<FederationTableWrapper>
|
||||||
</Grid>
|
<FederationTable maxHeight={18} />
|
||||||
<Grid item>
|
</FederationTableWrapper>
|
||||||
<Typography align='center' component='h2' variant='subtitle2' color='secondary'>
|
{error && (
|
||||||
{error}
|
<ErrorTypography align='center' component='h2' variant='subtitle2' color='secondary'>
|
||||||
</Typography>
|
{error}
|
||||||
</Grid>
|
</ErrorTypography>
|
||||||
<List>
|
)}
|
||||||
<ListItem>
|
<InputContainer>
|
||||||
<TextField
|
<StyledTextField
|
||||||
id='outlined-basic'
|
id='outlined-basic'
|
||||||
label={t('Alias')}
|
label={t('Alias')}
|
||||||
variant='outlined'
|
variant='outlined'
|
||||||
size='small'
|
size='small'
|
||||||
value={newAlias}
|
value={newAlias}
|
||||||
onChange={(e) => setNewAlias(e.target.value)}
|
onChange={(e) => {
|
||||||
|
setNewAlias(e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<StyledTextField
|
||||||
id='outlined-basic'
|
id='outlined-basic'
|
||||||
label={t('URL')}
|
label={t('URL')}
|
||||||
variant='outlined'
|
variant='outlined'
|
||||||
size='small'
|
size='small'
|
||||||
value={newUrl}
|
value={newUrl}
|
||||||
onChange={(e) => setNewUrl(e.target.value)}
|
onChange={(e) => {
|
||||||
|
setNewUrl(e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<StyledButton
|
||||||
sx={{ maxHeight: 38 }}
|
|
||||||
disabled={false}
|
disabled={false}
|
||||||
onClick={addCoordinator}
|
onClick={addCoordinator}
|
||||||
variant='contained'
|
variant='contained'
|
||||||
@ -85,12 +81,83 @@ const SettingsPage = (): JSX.Element => {
|
|||||||
type='submit'
|
type='submit'
|
||||||
>
|
>
|
||||||
{t('Add')}
|
{t('Add')}
|
||||||
</Button>
|
</StyledButton>
|
||||||
</ListItem>
|
</InputContainer>
|
||||||
</List>
|
</RightGrid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</SettingsContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsPage;
|
// Styled Components
|
||||||
|
const SettingsContainer = styled(Paper)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
width: '80vw',
|
||||||
|
height: '70vh',
|
||||||
|
margin: '0 auto',
|
||||||
|
border: '2px solid #000',
|
||||||
|
borderRadius: '8px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
boxShadow: '8px 8px 0px #000',
|
||||||
|
[theme.breakpoints.down('md')]: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: '90vw',
|
||||||
|
height: 'fit-content',
|
||||||
|
marginTop: '30rem',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const LeftGrid = styled(Grid)(({ theme }) => ({
|
||||||
|
padding: '2rem',
|
||||||
|
borderRight: '2px solid #000',
|
||||||
|
[theme.breakpoints.down('md')]: {
|
||||||
|
padding: '1rem',
|
||||||
|
borderRight: 'none',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const RightGrid = styled(Grid)(({ theme }) => ({
|
||||||
|
padding: '2rem',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
[theme.breakpoints.down('md')]: {
|
||||||
|
padding: '1rem',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const FederationTableWrapper = styled(Box)({
|
||||||
|
flexGrow: 1,
|
||||||
|
'& > *': {
|
||||||
|
width: '100% !important',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const ErrorTypography = styled(Typography)({
|
||||||
|
// You can add specific styles for the error message here if needed
|
||||||
|
});
|
||||||
|
|
||||||
|
const InputContainer = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
[theme.breakpoints.down('sm')]: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledTextField = styled(TextField)(({ theme }) => ({
|
||||||
|
flexGrow: 1,
|
||||||
|
[theme.breakpoints.down('sm')]: {
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledButton = styled(Button)(({ theme }) => ({
|
||||||
|
maxHeight: 40,
|
||||||
|
[theme.breakpoints.down('sm')]: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default SettingsPage;
|
@ -14,7 +14,6 @@ import {
|
|||||||
LinearProgress,
|
LinearProgress,
|
||||||
IconButton,
|
IconButton,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
type LinearProgressProps,
|
|
||||||
styled,
|
styled,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
@ -24,7 +23,7 @@ import {
|
|||||||
type GridPaginationModel,
|
type GridPaginationModel,
|
||||||
type GridColDef,
|
type GridColDef,
|
||||||
type GridValidRowModel,
|
type GridValidRowModel,
|
||||||
GridSlotsComponent,
|
type GridSlotsComponent,
|
||||||
} from '@mui/x-data-grid';
|
} from '@mui/x-data-grid';
|
||||||
import currencyDict from '../../../static/assets/currencies.json';
|
import currencyDict from '../../../static/assets/currencies.json';
|
||||||
import { type PublicOrder } from '../../models';
|
import { type PublicOrder } from '../../models';
|
||||||
@ -831,14 +830,6 @@ const BookTable = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface GridComponentProps {
|
|
||||||
LoadingOverlay: (props: LinearProgressProps) => JSX.Element;
|
|
||||||
NoResultsOverlay?: (props: any) => JSX.Element;
|
|
||||||
NoRowsOverlay?: (props: any) => JSX.Element;
|
|
||||||
Footer?: (props: any) => JSX.Element;
|
|
||||||
Toolbar?: (props: any) => JSX.Element;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NoResultsOverlay = function (): JSX.Element {
|
const NoResultsOverlay = function (): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -1,78 +1,38 @@
|
|||||||
import React, { useCallback, useEffect, useState, useContext, useMemo } from 'react';
|
import React, { useCallback, useContext, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Box, useTheme, Checkbox, CircularProgress, Typography, Grid } from '@mui/material';
|
import { Box, Checkbox, CircularProgress, Grid, Typography } from '@mui/material';
|
||||||
import { DataGrid, type GridColDef, type GridValidRowModel } from '@mui/x-data-grid';
|
import { DataGrid, type GridColDef, type GridValidRowModel } from '@mui/x-data-grid';
|
||||||
import { type Coordinator } from '../../models';
|
import { type Coordinator } from '../../models';
|
||||||
import RobotAvatar from '../RobotAvatar';
|
import RobotAvatar from '../RobotAvatar';
|
||||||
import { Link, LinkOff } from '@mui/icons-material';
|
import { Link, LinkOff } from '@mui/icons-material';
|
||||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||||
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
||||||
import headerStyleFix from '../DataGrid/HeaderFix';
|
import { styled } from '@mui/system';
|
||||||
|
|
||||||
interface FederationTableProps {
|
interface FederationTableProps {
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
maxHeight?: number;
|
|
||||||
fillContainer?: boolean;
|
fillContainer?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FederationTable = ({
|
const FederationTable = ({ maxWidth = 90, fillContainer = false }: FederationTableProps): JSX.Element => {
|
||||||
maxWidth = 90,
|
|
||||||
maxHeight = 50,
|
|
||||||
fillContainer = false,
|
|
||||||
}: FederationTableProps): JSX.Element => {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { federation, sortedCoordinators, coordinatorUpdatedAt, federationUpdatedAt } =
|
const { federation, sortedCoordinators, coordinatorUpdatedAt } = useContext<UseFederationStoreType>(FederationContext);
|
||||||
useContext<UseFederationStoreType>(FederationContext);
|
|
||||||
const { setOpen, settings } = useContext<UseAppStoreType>(AppContext);
|
const { setOpen, settings } = useContext<UseAppStoreType>(AppContext);
|
||||||
const theme = useTheme();
|
|
||||||
const [pageSize, setPageSize] = useState<number>(0);
|
|
||||||
|
|
||||||
// all sizes in 'em'
|
|
||||||
const fontSize = theme.typography.fontSize;
|
|
||||||
const verticalHeightFrame = 3.3;
|
|
||||||
const verticalHeightRow = 3.27;
|
|
||||||
const defaultPageSize = Math.max(
|
|
||||||
Math.floor((maxHeight - verticalHeightFrame) / verticalHeightRow),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
const height = defaultPageSize * verticalHeightRow + verticalHeightFrame;
|
|
||||||
|
|
||||||
const [useDefaultPageSize, setUseDefaultPageSize] = useState(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (useDefaultPageSize) {
|
|
||||||
setPageSize(defaultPageSize);
|
|
||||||
}
|
|
||||||
}, [coordinatorUpdatedAt, federationUpdatedAt]);
|
|
||||||
|
|
||||||
const localeText = {
|
|
||||||
MuiTablePagination: { labelRowsPerPage: t('Coordinators per page:') },
|
|
||||||
noResultsOverlayLabel: t('No coordinators found.'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClickCoordinator = function (shortAlias: string): void {
|
|
||||||
setOpen((open) => {
|
|
||||||
return { ...open, coordinator: shortAlias };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const aliasObj = useCallback((width: number) => {
|
const aliasObj = useCallback((width: number) => {
|
||||||
return {
|
return {
|
||||||
field: 'longAlias',
|
field: 'longAlias',
|
||||||
headerName: t('Coordinator'),
|
headerName: t('Coordinator'),
|
||||||
width: width * fontSize,
|
width: width,
|
||||||
renderCell: (params: any) => {
|
renderCell: (params: any) => {
|
||||||
const coordinator = federation.coordinators[params.row.shortAlias];
|
const coordinator = federation.coordinators[params.row.shortAlias];
|
||||||
return (
|
return (
|
||||||
<Grid
|
<CoordinatorGrid
|
||||||
container
|
container
|
||||||
direction='row'
|
direction="row"
|
||||||
sx={{ cursor: 'pointer', position: 'relative', left: '-0.3em', width: '50em' }}
|
wrap="nowrap"
|
||||||
wrap='nowrap'
|
onClick={() => onClickCoordinator(params.row.shortAlias)}
|
||||||
onClick={() => {
|
alignItems="center"
|
||||||
onClickCoordinator(params.row.shortAlias);
|
|
||||||
}}
|
|
||||||
alignItems='center'
|
|
||||||
spacing={1}
|
spacing={1}
|
||||||
>
|
>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
@ -87,31 +47,29 @@ const FederationTable = ({
|
|||||||
<Grid item>
|
<Grid item>
|
||||||
<Typography>{params.row.longAlias}</Typography>
|
<Typography>{params.row.longAlias}</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</CoordinatorGrid>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, []);
|
}, [federation.coordinators]);
|
||||||
|
|
||||||
const enabledObj = useCallback(
|
const enabledObj = useCallback(
|
||||||
(width: number) => {
|
(width: number) => {
|
||||||
return {
|
return {
|
||||||
field: 'enabled',
|
field: 'enabled',
|
||||||
headerName: t('Enabled'),
|
headerName: t('Enabled'),
|
||||||
width: width * fontSize,
|
width: width,
|
||||||
renderCell: (params: any) => {
|
renderCell: (params: any) => {
|
||||||
return (
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={params.row.enabled}
|
checked={params.row.enabled}
|
||||||
onClick={() => {
|
onClick={() => onEnableChange(params.row.shortAlias)}
|
||||||
onEnableChange(params.row.shortAlias);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[coordinatorUpdatedAt],
|
[coordinatorUpdatedAt]
|
||||||
);
|
);
|
||||||
|
|
||||||
const upObj = useCallback(
|
const upObj = useCallback(
|
||||||
@ -119,52 +77,41 @@ const FederationTable = ({
|
|||||||
return {
|
return {
|
||||||
field: 'up',
|
field: 'up',
|
||||||
headerName: t('Up'),
|
headerName: t('Up'),
|
||||||
width: width * fontSize,
|
width: width,
|
||||||
renderCell: (params: any) => {
|
renderCell: (params: any) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<UpStatusContainer onClick={() => onClickCoordinator(params.row.shortAlias)}>
|
||||||
style={{ cursor: 'pointer' }}
|
{params.row.loadingInfo && params.row.enabled ? (
|
||||||
onClick={() => {
|
<CircularProgress thickness={2} size={24} />
|
||||||
onClickCoordinator(params.row.shortAlias);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{Boolean(params.row.loadingInfo) && Boolean(params.row.enabled) ? (
|
|
||||||
<CircularProgress thickness={0.35 * fontSize} size={1.5 * fontSize} />
|
|
||||||
) : params.row.info !== undefined ? (
|
) : params.row.info !== undefined ? (
|
||||||
<Link color='success' />
|
<Link color="success" />
|
||||||
) : (
|
) : (
|
||||||
<LinkOff color='error' />
|
<LinkOff color="error" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</UpStatusContainer>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[coordinatorUpdatedAt],
|
[coordinatorUpdatedAt]
|
||||||
);
|
);
|
||||||
|
|
||||||
const columnSpecs = {
|
const columnSpecs = {
|
||||||
alias: {
|
alias: {
|
||||||
priority: 2,
|
|
||||||
order: 1,
|
|
||||||
normal: {
|
normal: {
|
||||||
width: 12.1,
|
width: 200,
|
||||||
object: aliasObj,
|
object: aliasObj,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
up: {
|
up: {
|
||||||
priority: 3,
|
|
||||||
order: 2,
|
|
||||||
normal: {
|
normal: {
|
||||||
width: 3.5,
|
width: 70,
|
||||||
object: upObj,
|
object: upObj,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enabled: {
|
enabled: {
|
||||||
priority: 1,
|
|
||||||
order: 3,
|
|
||||||
normal: {
|
normal: {
|
||||||
width: 5,
|
width: 90,
|
||||||
object: enabledObj,
|
object: enabledObj,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -174,29 +121,17 @@ const FederationTable = ({
|
|||||||
columns: Array<GridColDef<GridValidRowModel>>;
|
columns: Array<GridColDef<GridValidRowModel>>;
|
||||||
width: number;
|
width: number;
|
||||||
} {
|
} {
|
||||||
const useSmall = maxWidth < 30;
|
|
||||||
const selectedColumns: object[] = [];
|
const selectedColumns: object[] = [];
|
||||||
let width: number = 0;
|
let width: number = 0;
|
||||||
|
|
||||||
for (const value of Object.values(columnSpecs)) {
|
for (const value of Object.values(columnSpecs)) {
|
||||||
const colWidth = Number(
|
const colWidth = value.normal.width;
|
||||||
useSmall && Boolean(value.small) ? value.small.width : value.normal.width,
|
const colObject = value.normal.object;
|
||||||
);
|
|
||||||
const colObject = useSmall && Boolean(value.small) ? value.small.object : value.normal.object;
|
|
||||||
|
|
||||||
if (width + colWidth < maxWidth || selectedColumns.length < 2) {
|
width += colWidth;
|
||||||
width = width + colWidth;
|
selectedColumns.push([colObject(colWidth), value.order]);
|
||||||
selectedColumns.push([colObject(colWidth, false), value.order]);
|
|
||||||
} else {
|
|
||||||
selectedColumns.push([colObject(colWidth, true), value.order]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort columns by column.order value
|
|
||||||
selectedColumns.sort(function (first, second) {
|
|
||||||
return first[1] - second[1];
|
|
||||||
});
|
|
||||||
|
|
||||||
const columns: Array<GridColDef<GridValidRowModel>> = selectedColumns.map(function (item) {
|
const columns: Array<GridColDef<GridValidRowModel>> = selectedColumns.map(function (item) {
|
||||||
return item[0];
|
return item[0];
|
||||||
});
|
});
|
||||||
@ -204,7 +139,7 @@ const FederationTable = ({
|
|||||||
return { columns, width: width * 0.9 };
|
return { columns, width: width * 0.9 };
|
||||||
};
|
};
|
||||||
|
|
||||||
const { columns, width } = filteredColumns();
|
const { columns } = filteredColumns();
|
||||||
|
|
||||||
const onEnableChange = function (shortAlias: string): void {
|
const onEnableChange = function (shortAlias: string): void {
|
||||||
if (federation.getCoordinator(shortAlias).enabled === true) {
|
if (federation.getCoordinator(shortAlias).enabled === true) {
|
||||||
@ -217,38 +152,65 @@ const FederationTable = ({
|
|||||||
const reorderedCoordinators = useMemo(() => {
|
const reorderedCoordinators = useMemo(() => {
|
||||||
return sortedCoordinators.reduce((coordinators, key) => {
|
return sortedCoordinators.reduce((coordinators, key) => {
|
||||||
coordinators[key] = federation.coordinators[key];
|
coordinators[key] = federation.coordinators[key];
|
||||||
|
|
||||||
return coordinators;
|
return coordinators;
|
||||||
}, {});
|
}, {});
|
||||||
}, [settings.network, federationUpdatedAt]);
|
}, [settings.network, coordinatorUpdatedAt]);
|
||||||
|
|
||||||
|
const onClickCoordinator = (shortAlias: string): void => {
|
||||||
|
setOpen((open) => {
|
||||||
|
return { ...open, coordinator: shortAlias };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<TableContainer fillContainer={fillContainer} maxWidth={maxWidth}>
|
||||||
sx={
|
<StyledDataGrid
|
||||||
fillContainer
|
|
||||||
? { width: '100%', height: '100%' }
|
|
||||||
: { width: `${width}em`, height: `${height}em`, overflow: 'auto' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DataGrid
|
|
||||||
sx={headerStyleFix}
|
|
||||||
localeText={localeText}
|
|
||||||
rowHeight={3.714 * theme.typography.fontSize}
|
|
||||||
headerHeight={3.25 * theme.typography.fontSize}
|
|
||||||
rows={Object.values(reorderedCoordinators)}
|
rows={Object.values(reorderedCoordinators)}
|
||||||
getRowId={(params: Coordinator) => params.shortAlias}
|
getRowId={(params: Coordinator) => params.shortAlias}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
checkboxSelection={false}
|
checkboxSelection={false}
|
||||||
pageSize={pageSize}
|
autoHeight
|
||||||
rowsPerPageOptions={width < 22 ? [] : [0, pageSize, defaultPageSize * 2, 50, 100]}
|
hideFooter
|
||||||
onPageSizeChange={(newPageSize) => {
|
|
||||||
setPageSize(newPageSize);
|
|
||||||
setUseDefaultPageSize(false);
|
|
||||||
}}
|
|
||||||
hideFooter={true}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</TableContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FederationTable;
|
// Styled Components
|
||||||
|
const TableContainer = styled(Box, {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'fillContainer' && prop !== 'maxWidth',
|
||||||
|
})<{ fillContainer: boolean; maxWidth: number }>(({ theme, fillContainer, maxWidth }) => ({
|
||||||
|
width: fillContainer ? '100%' : `${maxWidth}em`,
|
||||||
|
height: 'fit-content',
|
||||||
|
border: '2px solid black',
|
||||||
|
overflow: 'hidden',
|
||||||
|
borderRadius: '8px',
|
||||||
|
boxShadow: 'none',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledDataGrid = styled(DataGrid)(({ theme }) => ({
|
||||||
|
'& .MuiDataGrid-root': {
|
||||||
|
fontSize: { xs: '0.8rem', sm: '0.9rem', md: '1rem' },
|
||||||
|
},
|
||||||
|
'& .MuiDataGrid-cell': {
|
||||||
|
padding: { xs: '0.5rem', sm: '1rem' },
|
||||||
|
},
|
||||||
|
'& .MuiDataGrid-columnHeaders': {
|
||||||
|
backgroundColor: theme.palette.background.default,
|
||||||
|
borderBottom: '2px solid black',
|
||||||
|
fontSize: { xs: '0.8rem', sm: '0.9rem', md: '1rem' },
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const CoordinatorGrid = styled(Grid)({
|
||||||
|
cursor: 'pointer',
|
||||||
|
position: 'relative',
|
||||||
|
left: '-0.3em',
|
||||||
|
width: '50em',
|
||||||
|
});
|
||||||
|
|
||||||
|
const UpStatusContainer = styled('div')({
|
||||||
|
cursor: 'pointer',
|
||||||
|
});
|
||||||
|
|
||||||
|
export default FederationTable;
|
@ -90,6 +90,7 @@ const FlagWithProps = ({ code, width = '1.428em', height = '1.428em' }: Props):
|
|||||||
if (code === 'IRT') flag = <Flags.IR {...defaultProps} />;
|
if (code === 'IRT') flag = <Flags.IR {...defaultProps} />;
|
||||||
if (code === 'BDT') flag = <Flags.BD {...defaultProps} />;
|
if (code === 'BDT') flag = <Flags.BD {...defaultProps} />;
|
||||||
if (code === 'ALL') flag = <Flags.AL {...defaultProps} />;
|
if (code === 'ALL') flag = <Flags.AL {...defaultProps} />;
|
||||||
|
if (code === 'DZD') flag = <Flags.DZ {...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' />;
|
||||||
|
@ -409,9 +409,8 @@ const AutocompletePayments: React.FC<AutocompletePaymentsProps> = (props) => {
|
|||||||
))}
|
))}
|
||||||
{qttHiddenTags > 0 ? (
|
{qttHiddenTags > 0 ? (
|
||||||
<StyledChip
|
<StyledChip
|
||||||
sx={{ borderRadius: 1 }}
|
|
||||||
label={`+${qttHiddenTags}`}
|
label={`+${qttHiddenTags}`}
|
||||||
sx={{ height: '1.6rem' }}
|
sx={{ borderRadius: 1, height: '1.6rem' }}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useContext, useMemo } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import {
|
import {
|
||||||
Grid,
|
Grid,
|
||||||
Select,
|
Select,
|
||||||
|
@ -248,7 +248,7 @@ const Notifications = ({
|
|||||||
// 11: 'In dispute'
|
// 11: 'In dispute'
|
||||||
// 12: 'Collaboratively cancelled'
|
// 12: 'Collaboratively cancelled'
|
||||||
// 13: 'Sending satoshis to buyer'
|
// 13: 'Sending satoshis to buyer'
|
||||||
// 14: 'Sucessful trade'
|
// 14: 'Successful trade'
|
||||||
// 15: 'Failed lightning network routing'
|
// 15: 'Failed lightning network routing'
|
||||||
// 16: 'Wait for dispute resolution'
|
// 16: 'Wait for dispute resolution'
|
||||||
// 17: 'Maker lost dispute'
|
// 17: 'Maker lost dispute'
|
||||||
|
@ -174,8 +174,8 @@ const OrderDetails = ({
|
|||||||
|
|
||||||
const isBuyer = (order.type === 0 && order.is_maker) || (order.type === 1 && !order.is_maker);
|
const isBuyer = (order.type === 0 && order.is_maker) || (order.type === 1 && !order.is_maker);
|
||||||
const tradeFee = order.is_maker
|
const tradeFee = order.is_maker
|
||||||
? coordinator.info?.maker_fee ?? 0
|
? (coordinator.info?.maker_fee ?? 0)
|
||||||
: coordinator.info?.taker_fee ?? 0;
|
: (coordinator.info?.taker_fee ?? 0);
|
||||||
const defaultRoutingBudget = 0.001;
|
const defaultRoutingBudget = 0.001;
|
||||||
const btc_now = order.satoshis_now / 100000000;
|
const btc_now = order.satoshis_now / 100000000;
|
||||||
const rate = Number(order.max_amount ?? order.amount) / btc_now;
|
const rate = Number(order.max_amount ?? order.amount) / btc_now;
|
||||||
|
@ -1,39 +1,36 @@
|
|||||||
import React, { useContext, useEffect } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
|
import { type UseAppStoreType, AppContext } from '../../contexts/AppContext';
|
||||||
import {
|
import {
|
||||||
Grid,
|
Grid,
|
||||||
Paper,
|
|
||||||
Switch,
|
Switch,
|
||||||
useTheme,
|
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
Slider,
|
|
||||||
Typography,
|
Typography,
|
||||||
ToggleButtonGroup,
|
ToggleButtonGroup,
|
||||||
ToggleButton,
|
ToggleButton,
|
||||||
|
Box,
|
||||||
|
Slider,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import SelectLanguage from './SelectLanguage';
|
import SelectLanguage from './SelectLanguage';
|
||||||
import {
|
import {
|
||||||
Translate,
|
Translate,
|
||||||
Palette,
|
Palette,
|
||||||
LightMode,
|
|
||||||
DarkMode,
|
|
||||||
SettingsOverscan,
|
SettingsOverscan,
|
||||||
Link,
|
Link,
|
||||||
AccountBalance,
|
AccountBalance,
|
||||||
AttachMoney,
|
AttachMoney,
|
||||||
QrCode,
|
QrCode,
|
||||||
ControlPoint,
|
DarkMode,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { systemClient } from '../../services/System';
|
import { systemClient } from '../../services/System';
|
||||||
import { TorIcon } from '../Icons';
|
import { TorIcon } from '../Icons';
|
||||||
import SwapCalls from '@mui/icons-material/SwapCalls';
|
import SwapCalls from '@mui/icons-material/SwapCalls';
|
||||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
|
||||||
import { GarageContext, UseGarageStoreType } from '../../contexts/GarageContext';
|
|
||||||
import { apiClient } from '../../services/api';
|
import { apiClient } from '../../services/api';
|
||||||
|
import { styled } from '@mui/system';
|
||||||
|
|
||||||
interface SettingsFormProps {
|
interface SettingsFormProps {
|
||||||
dense?: boolean;
|
dense?: boolean;
|
||||||
@ -41,10 +38,9 @@ interface SettingsFormProps {
|
|||||||
|
|
||||||
const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
|
const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
|
||||||
const { fav, setFav, settings, setSettings } = useContext<UseAppStoreType>(AppContext);
|
const { fav, setFav, settings, setSettings } = useContext<UseAppStoreType>(AppContext);
|
||||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
|
||||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
|
||||||
const theme = useTheme();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const fontSizes = [
|
const fontSizes = [
|
||||||
{ label: 'XS', value: { basic: 12, pro: 10 } },
|
{ label: 'XS', value: { basic: 12, pro: 10 } },
|
||||||
{ label: 'S', value: { basic: 13, pro: 11 } },
|
{ label: 'S', value: { basic: 13, pro: 11 } },
|
||||||
@ -53,115 +49,74 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
|
|||||||
{ label: 'XL', value: { basic: 16, pro: 14 } },
|
{ label: 'XL', value: { basic: 16, pro: 14 } },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleToggleChange = (e, newValue) => {
|
||||||
|
if (newValue !== null) {
|
||||||
|
setFav({ ...fav, mode: newValue, currency: newValue === 'fiat' ? 0 : 1000 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNetworkChange = (e, newValue) => {
|
||||||
|
if (newValue !== null) {
|
||||||
|
setSettings({ ...settings, network: newValue });
|
||||||
|
systemClient.setItem('settings_network', newValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={2}>
|
||||||
<Grid item>
|
<Grid item xs={12}>
|
||||||
<List dense={dense}>
|
<List dense={dense}>
|
||||||
<ListItem>
|
{/* Language Settings */}
|
||||||
<ListItemIcon>
|
<StyledListItem>
|
||||||
<Translate />
|
<SettingHeader>
|
||||||
</ListItemIcon>
|
<ListItemIcon>
|
||||||
<SelectLanguage
|
<Translate />
|
||||||
|
</ListItemIcon>
|
||||||
|
<Typography variant="subtitle1">
|
||||||
|
{t('Language Settings')}
|
||||||
|
</Typography>
|
||||||
|
</SettingHeader>
|
||||||
|
<StyledSelectLanguage
|
||||||
language={settings.language}
|
language={settings.language}
|
||||||
setLanguage={(language) => {
|
setLanguage={(language) => {
|
||||||
setSettings({ ...settings, language });
|
setSettings({ ...settings, language });
|
||||||
systemClient.setItem('settings_language', language);
|
systemClient.setItem('settings_language', language);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
<ListItem>
|
{/* Appearance Settings */}
|
||||||
<ListItemIcon>
|
<StyledListItem>
|
||||||
<Palette />
|
<SettingHeader>
|
||||||
</ListItemIcon>
|
<ListItemIcon>
|
||||||
<FormControlLabel
|
<Palette />
|
||||||
labelPlacement='end'
|
</ListItemIcon>
|
||||||
label={settings.mode === 'dark' ? t('Dark') : t('Light')}
|
<Typography variant="subtitle1">
|
||||||
control={
|
{t('Appearance Settings')}
|
||||||
<Switch
|
</Typography>
|
||||||
checked={settings.mode === 'dark'}
|
</SettingHeader>
|
||||||
checkedIcon={
|
<AppearanceSettingsBox>
|
||||||
<Paper
|
<FormControlLabel
|
||||||
elevation={3}
|
labelPlacement="end"
|
||||||
sx={{
|
label={t('Dark Mode')}
|
||||||
width: '1.2em',
|
control={
|
||||||
height: '1.2em',
|
<Switch
|
||||||
borderRadius: '0.4em',
|
checked={settings.mode === 'dark'}
|
||||||
backgroundColor: 'white',
|
onChange={(e) => {
|
||||||
position: 'relative',
|
const mode = e.target.checked ? 'dark' : 'light';
|
||||||
top: `${7 - 0.5 * theme.typography.fontSize}px`,
|
setSettings({ ...settings, mode });
|
||||||
}}
|
systemClient.setItem('settings_mode', mode);
|
||||||
>
|
}}
|
||||||
<DarkMode sx={{ width: '0.8em', height: '0.8em', color: '#666' }} />
|
/>
|
||||||
</Paper>
|
}
|
||||||
}
|
/>
|
||||||
icon={
|
{settings.mode === 'dark' && (
|
||||||
<Paper
|
<QRCodeSwitch
|
||||||
elevation={3}
|
labelPlacement="end"
|
||||||
sx={{
|
label={t('QR Code Color')}
|
||||||
width: '1.2em',
|
|
||||||
height: '1.2em',
|
|
||||||
borderRadius: '0.4em',
|
|
||||||
backgroundColor: 'white',
|
|
||||||
padding: '0.07em',
|
|
||||||
position: 'relative',
|
|
||||||
top: `${7 - 0.5 * theme.typography.fontSize}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LightMode sx={{ width: '0.67em', height: '0.67em', color: '#666' }} />
|
|
||||||
</Paper>
|
|
||||||
}
|
|
||||||
onChange={(e) => {
|
|
||||||
const mode = e.target.checked ? 'dark' : 'light';
|
|
||||||
setSettings({ ...settings, mode });
|
|
||||||
systemClient.setItem('settings_mode', mode);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{settings.mode === 'dark' ? (
|
|
||||||
<>
|
|
||||||
<ListItemIcon>
|
|
||||||
<QrCode />
|
|
||||||
</ListItemIcon>
|
|
||||||
<FormControlLabel
|
|
||||||
sx={{ position: 'relative', right: '1.5em', width: '3em' }}
|
|
||||||
labelPlacement='end'
|
|
||||||
label={settings.lightQRs ? t('Light') : t('Dark')}
|
|
||||||
control={
|
control={
|
||||||
<Switch
|
<Switch
|
||||||
checked={!settings.lightQRs}
|
checked={!settings.lightQRs}
|
||||||
checkedIcon={
|
|
||||||
<Paper
|
|
||||||
elevation={3}
|
|
||||||
sx={{
|
|
||||||
width: '1.2em',
|
|
||||||
height: '1.2em',
|
|
||||||
borderRadius: '0.4em',
|
|
||||||
backgroundColor: 'white',
|
|
||||||
position: 'relative',
|
|
||||||
top: `${7 - 0.5 * theme.typography.fontSize}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DarkMode sx={{ width: '0.8em', height: '0.8em', color: '#666' }} />
|
|
||||||
</Paper>
|
|
||||||
}
|
|
||||||
icon={
|
|
||||||
<Paper
|
|
||||||
elevation={3}
|
|
||||||
sx={{
|
|
||||||
width: '1.2em',
|
|
||||||
height: '1.2em',
|
|
||||||
borderRadius: '0.4em',
|
|
||||||
backgroundColor: 'white',
|
|
||||||
padding: '0.07em',
|
|
||||||
position: 'relative',
|
|
||||||
top: `${7 - 0.5 * theme.typography.fontSize}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LightMode sx={{ width: '0.67em', height: '0.67em', color: '#666' }} />
|
|
||||||
</Paper>
|
|
||||||
}
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const lightQRs = !e.target.checked;
|
const lightQRs = !e.target.checked;
|
||||||
setSettings({ ...settings, lightQRs });
|
setSettings({ ...settings, lightQRs });
|
||||||
@ -170,17 +125,21 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
)}
|
||||||
) : (
|
</AppearanceSettingsBox>
|
||||||
<></>
|
</StyledListItem>
|
||||||
)}
|
|
||||||
</ListItem>
|
|
||||||
|
|
||||||
<ListItem>
|
{/* Font Size Settings */}
|
||||||
<ListItemIcon>
|
<StyledListItem>
|
||||||
<SettingsOverscan />
|
<SettingHeader>
|
||||||
</ListItemIcon>
|
<ListItemIcon>
|
||||||
<Slider
|
<SettingsOverscan />
|
||||||
|
</ListItemIcon>
|
||||||
|
<Typography variant="subtitle1">
|
||||||
|
{t('Font Size')}
|
||||||
|
</Typography>
|
||||||
|
</SettingHeader>
|
||||||
|
<StyledSlider
|
||||||
value={settings.fontSize}
|
value={settings.fontSize}
|
||||||
min={settings.frontend === 'basic' ? 12 : 10}
|
min={settings.frontend === 'basic' ? 12 : 10}
|
||||||
max={settings.frontend === 'basic' ? 16 : 14}
|
max={settings.frontend === 'basic' ? 16 : 14}
|
||||||
@ -190,80 +149,98 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
|
|||||||
setSettings({ ...settings, fontSize });
|
setSettings({ ...settings, fontSize });
|
||||||
systemClient.setItem(`settings_fontsize_${settings.frontend}`, fontSize.toString());
|
systemClient.setItem(`settings_fontsize_${settings.frontend}`, fontSize.toString());
|
||||||
}}
|
}}
|
||||||
valueLabelDisplay='off'
|
valueLabelDisplay="off"
|
||||||
|
track={false}
|
||||||
marks={fontSizes.map(({ label, value }) => ({
|
marks={fontSizes.map(({ label, value }) => ({
|
||||||
label: <Typography variant='caption'>{t(label)}</Typography>,
|
label: <Typography variant="caption">{t(label)}</Typography>,
|
||||||
value: settings.frontend === 'basic' ? value.basic : value.pro,
|
value: settings.frontend === 'basic' ? value.basic : value.pro,
|
||||||
}))}
|
}))}
|
||||||
track={false}
|
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
<ListItem>
|
{/* Currency Settings */}
|
||||||
<ListItemIcon>
|
<StyledListItem>
|
||||||
<AccountBalance />
|
<SettingHeader>
|
||||||
</ListItemIcon>
|
<ListItemIcon>
|
||||||
<ToggleButtonGroup
|
<AccountBalance />
|
||||||
|
</ListItemIcon>
|
||||||
|
<Typography variant="subtitle1">
|
||||||
|
{t('Currency Settings')}
|
||||||
|
</Typography>
|
||||||
|
</SettingHeader>
|
||||||
|
<StyledToggleButtonGroup
|
||||||
exclusive={true}
|
exclusive={true}
|
||||||
value={fav.mode}
|
value={fav.mode}
|
||||||
onChange={(e, mode) => {
|
onChange={handleToggleChange}
|
||||||
setFav({ ...fav, mode, currency: mode === 'fiat' ? 0 : 1000 });
|
fullWidth
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<ToggleButton value='fiat' color='primary'>
|
<StyledToggleButton value="fiat">
|
||||||
<AttachMoney />
|
<AttachMoney />
|
||||||
{t('Fiat')}
|
{t('Fiat')}
|
||||||
</ToggleButton>
|
</StyledToggleButton>
|
||||||
<ToggleButton value='swap' color='secondary'>
|
<StyledToggleButton value="swap">
|
||||||
<SwapCalls />
|
<SwapCalls />
|
||||||
{t('Swaps')}
|
{t('Swaps')}
|
||||||
</ToggleButton>
|
</StyledToggleButton>
|
||||||
</ToggleButtonGroup>
|
</StyledToggleButtonGroup>
|
||||||
</ListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
<ListItem>
|
{/* Network Settings */}
|
||||||
<ListItemIcon>
|
<StyledListItem>
|
||||||
<Link />
|
<SettingHeader>
|
||||||
</ListItemIcon>
|
<ListItemIcon>
|
||||||
<ToggleButtonGroup
|
<Link />
|
||||||
|
</ListItemIcon>
|
||||||
|
<Typography variant="subtitle1">
|
||||||
|
{t('Network Settings')}
|
||||||
|
</Typography>
|
||||||
|
</SettingHeader>
|
||||||
|
<StyledToggleButtonGroup
|
||||||
exclusive={true}
|
exclusive={true}
|
||||||
value={settings.network}
|
value={settings.network}
|
||||||
onChange={(e, network) => {
|
onChange={handleNetworkChange}
|
||||||
setSettings({ ...settings, network });
|
fullWidth
|
||||||
systemClient.setItem('settings_network', network);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<ToggleButton value='mainnet' color='primary'>
|
<StyledToggleButton value="mainnet">
|
||||||
{t('Mainnet')}
|
{t('Mainnet')}
|
||||||
</ToggleButton>
|
</StyledToggleButton>
|
||||||
<ToggleButton value='testnet' color='secondary'>
|
<StyledToggleButton value="testnet">
|
||||||
{t('Testnet')}
|
{t('Testnet')}
|
||||||
</ToggleButton>
|
</StyledToggleButton>
|
||||||
</ToggleButtonGroup>
|
</StyledToggleButtonGroup>
|
||||||
</ListItem>
|
</StyledListItem>
|
||||||
|
|
||||||
|
{/* Proxy Settings */}
|
||||||
{window.NativeRobosats !== undefined && (
|
{window.NativeRobosats !== undefined && (
|
||||||
<ListItem>
|
<StyledListItem>
|
||||||
<ListItemIcon>
|
<SettingHeader>
|
||||||
<TorIcon />
|
<ListItemIcon>
|
||||||
</ListItemIcon>
|
<TorIcon />
|
||||||
<ToggleButtonGroup
|
</ListItemIcon>
|
||||||
|
<Typography variant="subtitle1">
|
||||||
|
{t('Proxy Settings')}
|
||||||
|
</Typography>
|
||||||
|
</SettingHeader>
|
||||||
|
<StyledToggleButtonGroup
|
||||||
exclusive={true}
|
exclusive={true}
|
||||||
value={settings.useProxy}
|
value={settings.useProxy}
|
||||||
onChange={(_e, useProxy) => {
|
onChange={(_e, useProxy) => {
|
||||||
setSettings({ ...settings, useProxy });
|
if (useProxy !== null) {
|
||||||
systemClient.setItem('settings_use_proxy', String(useProxy));
|
setSettings({ ...settings, useProxy });
|
||||||
apiClient.useProxy = useProxy;
|
systemClient.setItem('settings_use_proxy', String(useProxy));
|
||||||
|
apiClient.useProxy = useProxy;
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
fullWidth
|
||||||
>
|
>
|
||||||
<ToggleButton value={true} color='primary'>
|
<StyledToggleButton value={true}>
|
||||||
{t('Build-in')}
|
{t('Built-in')}
|
||||||
</ToggleButton>
|
</StyledToggleButton>
|
||||||
<ToggleButton value={false} color='secondary'>
|
<StyledToggleButton value={false}>
|
||||||
{t('Disabled')}
|
{t('Disabled')}
|
||||||
</ToggleButton>
|
</StyledToggleButton>
|
||||||
</ToggleButtonGroup>
|
</StyledToggleButtonGroup>
|
||||||
</ListItem>
|
</StyledListItem>
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -271,4 +248,79 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): JSX.Element => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsForm;
|
// Styled Components
|
||||||
|
const StyledListItem = styled(ListItem)({
|
||||||
|
display: 'block',
|
||||||
|
});
|
||||||
|
|
||||||
|
const SettingHeader = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: '0.5em',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledSelectLanguage = styled(SelectLanguage)(({ theme }) => ({
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '8px',
|
||||||
|
border: '2px solid black',
|
||||||
|
boxShadow: '4px 4px 0px rgba(0, 0, 0, 1)',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const AppearanceSettingsBox = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: theme.spacing(2),
|
||||||
|
[theme.breakpoints.up('sm')]: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const QRCodeSwitch = styled(FormControlLabel)(({ theme }) => ({
|
||||||
|
marginLeft: 0,
|
||||||
|
[theme.breakpoints.up('sm')]: {
|
||||||
|
marginLeft: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledSlider = styled(Slider)(({ theme }) => ({
|
||||||
|
'& .MuiSlider-thumb': {
|
||||||
|
borderRadius: '8px',
|
||||||
|
border: '2px solid black',
|
||||||
|
},
|
||||||
|
'& .MuiSlider-track': {
|
||||||
|
borderRadius: '8px',
|
||||||
|
border: '2px solid black',
|
||||||
|
},
|
||||||
|
'& .MuiSlider-rail': {
|
||||||
|
borderRadius: '8px',
|
||||||
|
border: '2px solid black',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledToggleButtonGroup = styled(ToggleButtonGroup)({
|
||||||
|
width: '100%',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledToggleButton = styled(ToggleButton)(({ theme }) => ({
|
||||||
|
borderRadius: '8px',
|
||||||
|
border: '2px solid black',
|
||||||
|
boxShadow: 'none',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
width: '100%',
|
||||||
|
'&.Mui-selected': {
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
color: theme.palette.primary.contrastText,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'initial',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default SettingsForm;
|
@ -639,7 +639,7 @@ const TradeBox = ({ baseUrl, onStartAgain }: TradeBoxProps): JSX.Element => {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 14: 'Sucessful trade'
|
// 14: 'Successful trade'
|
||||||
case 14:
|
case 14:
|
||||||
baseContract.title = 'Trade finished!';
|
baseContract.title = 'Trade finished!';
|
||||||
baseContract.titleColor = 'success';
|
baseContract.titleColor = 'success';
|
||||||
|
@ -4,19 +4,17 @@ import React, {
|
|||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
type SetStateAction,
|
type SetStateAction,
|
||||||
useMemo,
|
|
||||||
useContext,
|
useContext,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import { type Order, Federation, Settings, Coordinator } from '../models';
|
import { type Order, Federation, Settings } from '../models';
|
||||||
|
|
||||||
import { federationLottery } from '../utils';
|
import { federationLottery } from '../utils';
|
||||||
|
|
||||||
import { AppContext, type UseAppStoreType } from './AppContext';
|
import { AppContext, type UseAppStoreType } from './AppContext';
|
||||||
import { GarageContext, type UseGarageStoreType } from './GarageContext';
|
import { GarageContext, type UseGarageStoreType } from './GarageContext';
|
||||||
import NativeRobosats from '../services/Native';
|
import { type Origin, type Origins } from '../models/Coordinator.model';
|
||||||
import { Origins } from '../models/Coordinator.model';
|
|
||||||
|
|
||||||
// Refresh delays (ms) according to Order status
|
// Refresh delays (ms) according to Order status
|
||||||
const defaultDelay = 5000;
|
const defaultDelay = 5000;
|
||||||
@ -35,7 +33,7 @@ const statusToDelay = [
|
|||||||
100000, // 'In dispute'
|
100000, // 'In dispute'
|
||||||
999999, // 'Collaboratively cancelled'
|
999999, // 'Collaboratively cancelled'
|
||||||
10000, // 'Sending satoshis to buyer'
|
10000, // 'Sending satoshis to buyer'
|
||||||
60000, // 'Sucessful trade'
|
60000, // 'Successful trade'
|
||||||
30000, // 'Failed lightning network routing'
|
30000, // 'Failed lightning network routing'
|
||||||
300000, // 'Wait for dispute resolution'
|
300000, // 'Wait for dispute resolution'
|
||||||
300000, // 'Maker lost dispute'
|
300000, // 'Maker lost dispute'
|
||||||
@ -175,14 +173,15 @@ export const FederationContextProvider = ({
|
|||||||
federated: false,
|
federated: false,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
};
|
};
|
||||||
|
const origins: Origins = {
|
||||||
|
clearnet: undefined,
|
||||||
|
onion: url as Origin,
|
||||||
|
i2p: undefined,
|
||||||
|
};
|
||||||
if (settings.network === 'mainnet') {
|
if (settings.network === 'mainnet') {
|
||||||
attributes.mainnet = {
|
attributes.mainnet = origins;
|
||||||
onion: url,
|
|
||||||
} as Origins;
|
|
||||||
} else {
|
} else {
|
||||||
attributes.testnet = {
|
attributes.testnet = origins;
|
||||||
onion: url,
|
|
||||||
} as Origins;
|
|
||||||
}
|
}
|
||||||
federation.addCoordinator(origin, settings, hostUrl, attributes);
|
federation.addCoordinator(origin, settings, hostUrl, attributes);
|
||||||
const newCoordinator = federation.coordinators[alias];
|
const newCoordinator = federation.coordinators[alias];
|
||||||
|
@ -210,7 +210,7 @@ export class Coordinator {
|
|||||||
|
|
||||||
generateAllMakerAvatars = async (data: [PublicOrder]): Promise<void> => {
|
generateAllMakerAvatars = async (data: [PublicOrder]): Promise<void> => {
|
||||||
for (const order of data) {
|
for (const order of data) {
|
||||||
roboidentitiesClient.generateRobohash(order.maker_hash_id, 'small');
|
void roboidentitiesClient.generateRobohash(order.maker_hash_id, 'small');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ export class Federation {
|
|||||||
settings: Settings,
|
settings: Settings,
|
||||||
hostUrl: string,
|
hostUrl: string,
|
||||||
attributes: Record<any, any>,
|
attributes: Record<any, any>,
|
||||||
) => {
|
): void => {
|
||||||
const value = {
|
const value = {
|
||||||
...coordinatorDefaultValues,
|
...coordinatorDefaultValues,
|
||||||
...attributes,
|
...attributes,
|
||||||
@ -111,7 +111,7 @@ export class Federation {
|
|||||||
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
|
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
|
||||||
this.updateEnabledCoordinators();
|
this.updateEnabledCoordinators();
|
||||||
for (const coor of Object.values(this.coordinators)) {
|
for (const coor of Object.values(this.coordinators)) {
|
||||||
coor.update(() => {
|
void coor.update(() => {
|
||||||
this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1;
|
this.exchange.onlineCoordinators = this.exchange.onlineCoordinators + 1;
|
||||||
this.onCoordinatorSaved();
|
this.onCoordinatorSaved();
|
||||||
});
|
});
|
||||||
@ -124,7 +124,7 @@ export class Federation {
|
|||||||
this.triggerHook('onCoordinatorUpdate');
|
this.triggerHook('onCoordinatorUpdate');
|
||||||
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
|
this.exchange.loadingCoordinators = Object.keys(this.coordinators).length;
|
||||||
for (const coor of Object.values(this.coordinators)) {
|
for (const coor of Object.values(this.coordinators)) {
|
||||||
coor.updateBook(() => {
|
void coor.updateBook(() => {
|
||||||
this.onCoordinatorSaved();
|
this.onCoordinatorSaved();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Coordinator, type Order } from '.';
|
import { type Coordinator, type Order } from '.';
|
||||||
import { systemClient } from '../services/System';
|
import { systemClient } from '../services/System';
|
||||||
import { saveAsJson } from '../utils';
|
import { saveAsJson } from '../utils';
|
||||||
import Slot from './Slot.model';
|
import Slot from './Slot.model';
|
||||||
@ -59,8 +59,13 @@ class Garage {
|
|||||||
const rawSlots = JSON.parse(slotsDump);
|
const rawSlots = JSON.parse(slotsDump);
|
||||||
Object.values(rawSlots).forEach((rawSlot: Record<any, any>) => {
|
Object.values(rawSlots).forEach((rawSlot: Record<any, any>) => {
|
||||||
if (rawSlot?.token) {
|
if (rawSlot?.token) {
|
||||||
this.slots[rawSlot.token] = new Slot(rawSlot.token, Object.keys(rawSlot.robots), {}, () =>
|
this.slots[rawSlot.token] = new Slot(
|
||||||
this.triggerHook('onRobotUpdate'),
|
rawSlot.token,
|
||||||
|
Object.keys(rawSlot.robots),
|
||||||
|
{},
|
||||||
|
() => {
|
||||||
|
this.triggerHook('onRobotUpdate');
|
||||||
|
},
|
||||||
);
|
);
|
||||||
Object.keys(rawSlot.robots).forEach((shortAlias) => {
|
Object.keys(rawSlot.robots).forEach((shortAlias) => {
|
||||||
const rawRobot = rawSlot.robots[shortAlias];
|
const rawRobot = rawSlot.robots[shortAlias];
|
||||||
@ -78,7 +83,7 @@ class Garage {
|
|||||||
// Slots
|
// Slots
|
||||||
getSlot: (token?: string) => Slot | null = (token) => {
|
getSlot: (token?: string) => Slot | null = (token) => {
|
||||||
const currentToken = token ?? this.currentSlot;
|
const currentToken = token ?? this.currentSlot;
|
||||||
return currentToken ? this.slots[currentToken] ?? null : null;
|
return currentToken ? (this.slots[currentToken] ?? null) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
deleteSlot: (token?: string) => void = (token) => {
|
deleteSlot: (token?: string) => void = (token) => {
|
||||||
@ -118,9 +123,9 @@ class Garage {
|
|||||||
if (!token || !shortAliases) return;
|
if (!token || !shortAliases) return;
|
||||||
|
|
||||||
if (this.getSlot(token) === null) {
|
if (this.getSlot(token) === null) {
|
||||||
this.slots[token] = new Slot(token, shortAliases, attributes, () =>
|
this.slots[token] = new Slot(token, shortAliases, attributes, () => {
|
||||||
this.triggerHook('onRobotUpdate'),
|
this.triggerHook('onRobotUpdate');
|
||||||
);
|
});
|
||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { sha256 } from 'js-sha256';
|
import { sha256 } from 'js-sha256';
|
||||||
import { Coordinator, Garage, Robot, type Order } from '.';
|
import { type Coordinator, type Garage, Robot, type Order } from '.';
|
||||||
import { roboidentitiesClient } from '../services/Roboidentities/Web';
|
import { roboidentitiesClient } from '../services/Roboidentities/Web';
|
||||||
|
|
||||||
class Slot {
|
class Slot {
|
||||||
@ -13,12 +13,12 @@ class Slot {
|
|||||||
|
|
||||||
this.hashId = sha256(sha256(this.token));
|
this.hashId = sha256(sha256(this.token));
|
||||||
this.nickname = null;
|
this.nickname = null;
|
||||||
roboidentitiesClient.generateRoboname(this.hashId).then((nickname) => {
|
void roboidentitiesClient.generateRoboname(this.hashId).then((nickname) => {
|
||||||
this.nickname = nickname;
|
this.nickname = nickname;
|
||||||
onRobotUpdate();
|
onRobotUpdate();
|
||||||
});
|
});
|
||||||
roboidentitiesClient.generateRobohash(this.hashId, 'small');
|
void roboidentitiesClient.generateRobohash(this.hashId, 'small');
|
||||||
roboidentitiesClient.generateRobohash(this.hashId, 'large');
|
void roboidentitiesClient.generateRobohash(this.hashId, 'large');
|
||||||
|
|
||||||
this.robots = shortAliases.reduce((acc: Record<string, Robot>, shortAlias: string) => {
|
this.robots = shortAliases.reduce((acc: Record<string, Robot>, shortAlias: string) => {
|
||||||
acc[shortAlias] = new Robot(robotAttributes);
|
acc[shortAlias] = new Robot(robotAttributes);
|
||||||
@ -82,7 +82,7 @@ class Slot {
|
|||||||
pubKey: defaultRobot.pubKey,
|
pubKey: defaultRobot.pubKey,
|
||||||
encPrivKey: defaultRobot.encPrivKey,
|
encPrivKey: defaultRobot.encPrivKey,
|
||||||
});
|
});
|
||||||
coordinator.fetchRobot(garage, defaultRobot.token);
|
void coordinator.fetchRobot(garage, defaultRobot.token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import RoboidentitiesClientNativeClient from './RoboidentitiesNativeClient';
|
import RoboidentitiesClientNativeClient from './RoboidentitiesNativeClient';
|
||||||
import { RoboidentitiesClient } from './type';
|
import { type RoboidentitiesClient } from './type';
|
||||||
|
|
||||||
export const roboidentitiesClient: RoboidentitiesClient = new RoboidentitiesClientNativeClient();
|
export const roboidentitiesClient: RoboidentitiesClient = new RoboidentitiesClientNativeClient();
|
||||||
|
@ -31,8 +31,8 @@ class RoboidentitiesNativeClient implements RoboidentitiesClient {
|
|||||||
type: 'robohash',
|
type: 'robohash',
|
||||||
detail: key,
|
detail: key,
|
||||||
});
|
});
|
||||||
const result = response ? Object.values(response)[0] : '';
|
const result: string = response ? Object.values(response)[0] : '';
|
||||||
const image = `data:image/png;base64,${result}`;
|
const image: string = `data:image/png;base64,${result}`;
|
||||||
this.robohashes[key] = image;
|
this.robohashes[key] = image;
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,14 @@ import { robohash } from './RobohashGenerator';
|
|||||||
|
|
||||||
class RoboidentitiesClientWebClient implements RoboidentitiesClient {
|
class RoboidentitiesClientWebClient implements RoboidentitiesClient {
|
||||||
public generateRoboname: (initialString: string) => Promise<string> = async (initialString) => {
|
public generateRoboname: (initialString: string) => Promise<string> = async (initialString) => {
|
||||||
return new Promise<string>(async (resolve, _reject) => {
|
return await new Promise<string>((resolve, _reject) => {
|
||||||
resolve(generate_roboname(initialString));
|
resolve(generate_roboname(initialString));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
public generateRobohash: (initialString: string, size: 'small' | 'large') => Promise<string> =
|
public generateRobohash: (initialString: string, size: 'small' | 'large') => Promise<string> =
|
||||||
async (initialString, size) => {
|
async (initialString, size) => {
|
||||||
return robohash.generate(initialString, size);
|
return await robohash.generate(initialString, size);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import RoboidentitiesClientWebClient from './RoboidentitiesWebClient';
|
import RoboidentitiesClientWebClient from './RoboidentitiesWebClient';
|
||||||
import { RoboidentitiesClient } from './type';
|
import { type RoboidentitiesClient } from './type';
|
||||||
|
|
||||||
export const roboidentitiesClient: RoboidentitiesClient = new RoboidentitiesClientWebClient();
|
export const roboidentitiesClient: RoboidentitiesClient = new RoboidentitiesClientWebClient();
|
||||||
|
@ -5,7 +5,7 @@ import ApiWebClient from '../ApiWebClient';
|
|||||||
class ApiNativeClient implements ApiClient {
|
class ApiNativeClient implements ApiClient {
|
||||||
public useProxy = true;
|
public useProxy = true;
|
||||||
|
|
||||||
private webClient: ApiClient = new ApiWebClient();
|
private readonly webClient: ApiClient = new ApiWebClient();
|
||||||
|
|
||||||
private readonly assetsPromises = new Map<string, Promise<string | undefined>>();
|
private readonly assetsPromises = new Map<string, Promise<string | undefined>>();
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ class ApiNativeClient implements ApiClient {
|
|||||||
|
|
||||||
public delete: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined> =
|
public delete: (baseUrl: string, path: string, auth?: Auth) => Promise<object | undefined> =
|
||||||
async (baseUrl, path, auth) => {
|
async (baseUrl, path, auth) => {
|
||||||
if (!this.useProxy) return this.webClient.delete(baseUrl, path, auth);
|
if (!this.useProxy) return await this.webClient.delete(baseUrl, path, auth);
|
||||||
return await window.NativeRobosats?.postMessage({
|
return await window.NativeRobosats?.postMessage({
|
||||||
category: 'http',
|
category: 'http',
|
||||||
type: 'delete',
|
type: 'delete',
|
||||||
@ -71,7 +71,7 @@ class ApiNativeClient implements ApiClient {
|
|||||||
body: object,
|
body: object,
|
||||||
auth?: Auth,
|
auth?: Auth,
|
||||||
) => Promise<object | undefined> = async (baseUrl, path, body, auth) => {
|
) => Promise<object | undefined> = async (baseUrl, path, body, auth) => {
|
||||||
if (!this.useProxy) return this.webClient.post(baseUrl, path, body, auth);
|
if (!this.useProxy) return await this.webClient.post(baseUrl, path, body, auth);
|
||||||
return await window.NativeRobosats?.postMessage({
|
return await window.NativeRobosats?.postMessage({
|
||||||
category: 'http',
|
category: 'http',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
@ -87,7 +87,7 @@ class ApiNativeClient implements ApiClient {
|
|||||||
path,
|
path,
|
||||||
auth,
|
auth,
|
||||||
) => {
|
) => {
|
||||||
if (!this.useProxy) return this.webClient.get(baseUrl, path, auth);
|
if (!this.useProxy) return await this.webClient.get(baseUrl, path, auth);
|
||||||
return await window.NativeRobosats?.postMessage({
|
return await window.NativeRobosats?.postMessage({
|
||||||
category: 'http',
|
category: 'http',
|
||||||
type: 'get',
|
type: 'get',
|
||||||
|
@ -16,14 +16,6 @@ export interface AggregatedInfo {
|
|||||||
version: Version;
|
version: Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
type toAdd =
|
|
||||||
| 'num_public_buy_orders'
|
|
||||||
| 'num_public_sell_orders'
|
|
||||||
| 'book_liquidity'
|
|
||||||
| 'active_robots_today'
|
|
||||||
| 'last_day_volume'
|
|
||||||
| 'lifetime_volume';
|
|
||||||
|
|
||||||
export const weightedMean = (arrValues: number[], arrWeights: number[]): number => {
|
export const weightedMean = (arrValues: number[], arrWeights: number[]): number => {
|
||||||
if (arrValues.length === 0) {
|
if (arrValues.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
"74": "IRT",
|
"74": "IRT",
|
||||||
"75": "BDT",
|
"75": "BDT",
|
||||||
"76": "ALL",
|
"76": "ALL",
|
||||||
|
"77": "DZD",
|
||||||
"300": "XAU",
|
"300": "XAU",
|
||||||
"1000": "BTC"
|
"1000": "BTC"
|
||||||
}
|
}
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "En disputa",
|
"In dispute": "En disputa",
|
||||||
"Collaboratively cancelled": "Cancel·lat col·laborativament",
|
"Collaboratively cancelled": "Cancel·lat col·laborativament",
|
||||||
"Sending satoshis to buyer": "Enviant satoshis al comprador",
|
"Sending satoshis to buyer": "Enviant satoshis al comprador",
|
||||||
"Sucessful trade": "Intercanvi exitós",
|
"Successful trade": "Intercanvi exitós",
|
||||||
"Failed lightning network routing": "L'enrrutament lightning network ha fallat",
|
"Failed lightning network routing": "L'enrrutament lightning network ha fallat",
|
||||||
"Wait for dispute resolution": "Esperant la resolució de la disputa",
|
"Wait for dispute resolution": "Esperant la resolució de la disputa",
|
||||||
"Maker lost dispute": "El creador ha perdut la disputa",
|
"Maker lost dispute": "El creador ha perdut la disputa",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "En disputa",
|
"In dispute": "En disputa",
|
||||||
"Collaboratively cancelled": "Cancelada colaborativamente",
|
"Collaboratively cancelled": "Cancelada colaborativamente",
|
||||||
"Sending satoshis to buyer": "Enviando Sats al comprador",
|
"Sending satoshis to buyer": "Enviando Sats al comprador",
|
||||||
"Sucessful trade": "Intercambio exitoso",
|
"Successful trade": "Intercambio exitoso",
|
||||||
"Failed lightning network routing": "Enrutamiento fallido en la red Lightning",
|
"Failed lightning network routing": "Enrutamiento fallido en la red Lightning",
|
||||||
"Wait for dispute resolution": "Espera a la resolución de la disputa",
|
"Wait for dispute resolution": "Espera a la resolución de la disputa",
|
||||||
"Maker lost dispute": "El creador ha perdido la disputa",
|
"Maker lost dispute": "El creador ha perdido la disputa",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "En litige",
|
"In dispute": "En litige",
|
||||||
"Collaboratively cancelled": "Annulation commune",
|
"Collaboratively cancelled": "Annulation commune",
|
||||||
"Sending satoshis to buyer": "Envoi des satoshis à l'acheteur",
|
"Sending satoshis to buyer": "Envoi des satoshis à l'acheteur",
|
||||||
"Sucessful trade": "Transaction réussie",
|
"Successful trade": "Transaction réussie",
|
||||||
"Failed lightning network routing": "Échec du routage du réseau lightning",
|
"Failed lightning network routing": "Échec du routage du réseau lightning",
|
||||||
"Wait for dispute resolution": "Attendre la résolution du litige",
|
"Wait for dispute resolution": "Attendre la résolution du litige",
|
||||||
"Maker lost dispute": "Litige perdu par l'auteur",
|
"Maker lost dispute": "Litige perdu par l'auteur",
|
||||||
|
@ -32,7 +32,7 @@ phrases = OrderedDict(
|
|||||||
("In dispute", "In dispute"),
|
("In dispute", "In dispute"),
|
||||||
("Collaboratively cancelled", "Collaboratively cancelled"),
|
("Collaboratively cancelled", "Collaboratively cancelled"),
|
||||||
("Sending satoshis to buyer", "Sending satoshis to buyer"),
|
("Sending satoshis to buyer", "Sending satoshis to buyer"),
|
||||||
("Sucessful trade", "Successful trade"),
|
("Successful trade", "Successful trade"),
|
||||||
("Failed lightning network routing", "Failed lightning network routing"),
|
("Failed lightning network routing", "Failed lightning network routing"),
|
||||||
("Wait for dispute resolution", "Wait for dispute resolution"),
|
("Wait for dispute resolution", "Wait for dispute resolution"),
|
||||||
("Maker lost dispute", "Maker lost dispute"),
|
("Maker lost dispute", "Maker lost dispute"),
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In contestazione",
|
"In dispute": "In contestazione",
|
||||||
"Collaboratively cancelled": "Annullato collaborativamente",
|
"Collaboratively cancelled": "Annullato collaborativamente",
|
||||||
"Sending satoshis to buyer": "Invio satoshi all'acquirente",
|
"Sending satoshis to buyer": "Invio satoshi all'acquirente",
|
||||||
"Sucessful trade": "Scambio completato con successo",
|
"Successful trade": "Scambio completato con successo",
|
||||||
"Failed lightning network routing": "Routing Lightning Network fallito",
|
"Failed lightning network routing": "Routing Lightning Network fallito",
|
||||||
"Wait for dispute resolution": "In attesa della risoluzione della contestazione",
|
"Wait for dispute resolution": "In attesa della risoluzione della contestazione",
|
||||||
"Maker lost dispute": "Il maker ha perso la contestazione",
|
"Maker lost dispute": "Il maker ha perso la contestazione",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "紛争中",
|
"In dispute": "紛争中",
|
||||||
"Collaboratively cancelled": "共同でキャンセルされました",
|
"Collaboratively cancelled": "共同でキャンセルされました",
|
||||||
"Sending satoshis to buyer": "買い手にSatsを送信しています",
|
"Sending satoshis to buyer": "買い手にSatsを送信しています",
|
||||||
"Sucessful trade": "成功した取引",
|
"Successful trade": "成功した取引",
|
||||||
"Failed lightning network routing": "ライトニングネットワークのルーティングに失敗しました",
|
"Failed lightning network routing": "ライトニングネットワークのルーティングに失敗しました",
|
||||||
"Wait for dispute resolution": "紛争の解決を待ってください",
|
"Wait for dispute resolution": "紛争の解決を待ってください",
|
||||||
"Maker lost dispute": "オーダーメイカーが紛争に負けました",
|
"Maker lost dispute": "オーダーメイカーが紛争に負けました",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "В диспуте",
|
"In dispute": "В диспуте",
|
||||||
"Collaboratively cancelled": "Совместно отменено",
|
"Collaboratively cancelled": "Совместно отменено",
|
||||||
"Sending satoshis to buyer": "Отправка Сатоши покупателю",
|
"Sending satoshis to buyer": "Отправка Сатоши покупателю",
|
||||||
"Sucessful trade": "Успешная торговля",
|
"Successful trade": "Успешная торговля",
|
||||||
"Failed lightning network routing": "Неудачная маршрутизация сети Lightning",
|
"Failed lightning network routing": "Неудачная маршрутизация сети Lightning",
|
||||||
"Wait for dispute resolution": "Дождитесь разрешения диспута",
|
"Wait for dispute resolution": "Дождитесь разрешения диспута",
|
||||||
"Maker lost dispute": "Мейкер проиграл диспут",
|
"Maker lost dispute": "Мейкер проиграл диспут",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "Katika mzozo",
|
"In dispute": "Katika mzozo",
|
||||||
"Collaboratively cancelled": "Kufutwa kwa ushirikiano",
|
"Collaboratively cancelled": "Kufutwa kwa ushirikiano",
|
||||||
"Sending satoshis to buyer": "Inatumwa satoshis kwa mnunuzi",
|
"Sending satoshis to buyer": "Inatumwa satoshis kwa mnunuzi",
|
||||||
"Sucessful trade": "Biashara imefanikiwa",
|
"Successful trade": "Biashara imefanikiwa",
|
||||||
"Failed lightning network routing": "Utaratibu wa mtandao wa umeme umeshindwa",
|
"Failed lightning network routing": "Utaratibu wa mtandao wa umeme umeshindwa",
|
||||||
"Wait for dispute resolution": "Kusubiri suluhisho la mzozo",
|
"Wait for dispute resolution": "Kusubiri suluhisho la mzozo",
|
||||||
"Maker lost dispute": "Mtengenezaji amepoteza mzozo",
|
"Maker lost dispute": "Mtengenezaji amepoteza mzozo",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "In dispute",
|
"In dispute": "In dispute",
|
||||||
"Collaboratively cancelled": "Collaboratively cancelled",
|
"Collaboratively cancelled": "Collaboratively cancelled",
|
||||||
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
"Sending satoshis to buyer": "Sending satoshis to buyer",
|
||||||
"Sucessful trade": "Successful trade",
|
"Successful trade": "Successful trade",
|
||||||
"Failed lightning network routing": "Failed lightning network routing",
|
"Failed lightning network routing": "Failed lightning network routing",
|
||||||
"Wait for dispute resolution": "Wait for dispute resolution",
|
"Wait for dispute resolution": "Wait for dispute resolution",
|
||||||
"Maker lost dispute": "Maker lost dispute",
|
"Maker lost dispute": "Maker lost dispute",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "正在争议中",
|
"In dispute": "正在争议中",
|
||||||
"Collaboratively cancelled": "已合作取消",
|
"Collaboratively cancelled": "已合作取消",
|
||||||
"Sending satoshis to buyer": "正在向买方发送聪",
|
"Sending satoshis to buyer": "正在向买方发送聪",
|
||||||
"Sucessful trade": "成功交易",
|
"Successful trade": "成功交易",
|
||||||
"Failed lightning network routing": "闪电路由失败",
|
"Failed lightning network routing": "闪电路由失败",
|
||||||
"Wait for dispute resolution": "等待争议解决",
|
"Wait for dispute resolution": "等待争议解决",
|
||||||
"Maker lost dispute": "挂单方失去了争议",
|
"Maker lost dispute": "挂单方失去了争议",
|
||||||
|
@ -700,7 +700,7 @@
|
|||||||
"In dispute": "正在爭議中",
|
"In dispute": "正在爭議中",
|
||||||
"Collaboratively cancelled": "已合作取消",
|
"Collaboratively cancelled": "已合作取消",
|
||||||
"Sending satoshis to buyer": "正在向買方發送聰",
|
"Sending satoshis to buyer": "正在向買方發送聰",
|
||||||
"Sucessful trade": "成功交易",
|
"Successful trade": "成功交易",
|
||||||
"Failed lightning network routing": "閃電路由失敗",
|
"Failed lightning network routing": "閃電路由失敗",
|
||||||
"Wait for dispute resolution": "等待爭議解決",
|
"Wait for dispute resolution": "等待爭議解決",
|
||||||
"Maker lost dispute": "掛單方失去了爭議",
|
"Maker lost dispute": "掛單方失去了爭議",
|
||||||
|
2229
mobile/package-lock.json
generated
2229
mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@
|
|||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/react-native": "^0.71.3",
|
"@types/react-native": "^0.71.3",
|
||||||
"@types/react-test-renderer": "^18.0.0",
|
"@types/react-test-renderer": "^18.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
"@typescript-eslint/eslint-plugin": "^8.0.1",
|
||||||
"@typescript-eslint/parser": "^5.59.6",
|
"@typescript-eslint/parser": "^5.59.6",
|
||||||
"babel-jest": "^29.7.0",
|
"babel-jest": "^29.7.0",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.39.0",
|
||||||
@ -35,13 +35,13 @@
|
|||||||
"eslint-import-resolver-typescript": "^3.6.0",
|
"eslint-import-resolver-typescript": "^3.6.0",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-n": "^15.7.0",
|
"eslint-plugin-n": "^15.7.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.6.0",
|
||||||
"eslint-plugin-react": "^7.32.2",
|
"eslint-plugin-react": "^7.35.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"metro-react-native-babel-preset": "^0.75.1",
|
"metro-react-native-babel-preset": "^0.75.1",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.3",
|
||||||
"react-test-renderer": "18.2.0",
|
"react-test-renderer": "18.2.0",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5"
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
django==5.0.6
|
django==5.0.8
|
||||||
django-admin-relation-links==0.2.5
|
django-admin-relation-links==0.2.5
|
||||||
django-celery-beat==2.6.0
|
django-celery-beat==2.6.0
|
||||||
django-celery-results==2.5.1
|
django-celery-results==2.5.1
|
||||||
@ -19,9 +19,9 @@ ring==0.10.1
|
|||||||
gunicorn==22.0.0
|
gunicorn==22.0.0
|
||||||
psycopg2==2.9.9
|
psycopg2==2.9.9
|
||||||
SQLAlchemy==2.0.16
|
SQLAlchemy==2.0.16
|
||||||
django-import-export==4.1.0
|
django-import-export==4.1.1
|
||||||
requests[socks]
|
requests[socks]
|
||||||
shapely==2.0.4
|
shapely==2.0.5
|
||||||
python-gnupg==0.5.2
|
python-gnupg==0.5.2
|
||||||
daphne==4.1.2
|
daphne==4.1.2
|
||||||
drf-spectacular==0.27.2
|
drf-spectacular==0.27.2
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
coverage==7.5.0
|
coverage==7.6.0
|
||||||
ruff==0.5.1
|
ruff==0.5.7
|
||||||
git+https://github.com/Reckless-Satoshi/drf-openapi-tester.git@soften-django-requirements
|
git+https://github.com/Reckless-Satoshi/drf-openapi-tester.git@soften-django-requirements
|
||||||
pre-commit==3.7.0
|
pre-commit==3.8.0
|
Loading…
Reference in New Issue
Block a user