mirror of
https://github.com/RoboSats/robosats.git
synced 2025-09-13 00:56:22 +00:00
Frontend
This commit is contained in:
@ -1075,7 +1075,7 @@ class ReviewView(APIView):
|
||||
{"bad_request": "Invalid hex pubkey"},
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
if request.user.robot.nostr_pubkey is not pubkey:
|
||||
if request.user.robot.nostr_pubkey != pubkey:
|
||||
return Response(
|
||||
{"bad_request": "Wrong hex pubkey"},
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
|
||||
125
frontend/src/basic/SettingsPage/Coordinators.tsx
Normal file
125
frontend/src/basic/SettingsPage/Coordinators.tsx
Normal file
@ -0,0 +1,125 @@
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { Button, Dialog, DialogContent, Grid, TextField, Typography } from '@mui/material';
|
||||
import FederationTable from '../../components/FederationTable';
|
||||
import { t } from 'i18next';
|
||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
|
||||
const Coordinators = (): JSX.Element => {
|
||||
const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const [newAlias, setNewAlias] = useState<string>('');
|
||||
const [newUrl, setNewUrl] = useState<string>('');
|
||||
const [error, setError] = useState<string>();
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
// Regular expression to match a valid .onion URL
|
||||
const onionUrlPattern = /^((http|https):\/\/)?[a-zA-Z2-7]{16,56}\.onion$\/?/;
|
||||
|
||||
const addCoordinator: () => void = () => {
|
||||
if (federation.getCoordinator(newAlias)) {
|
||||
setError(t('Alias already exists'));
|
||||
} else {
|
||||
if (onionUrlPattern.test(newUrl)) {
|
||||
let fullNewUrl = newUrl;
|
||||
if (!/^((http|https):\/\/)/.test(fullNewUrl)) {
|
||||
fullNewUrl = `http://${newUrl}`;
|
||||
}
|
||||
addNewCoordinator(newAlias, fullNewUrl);
|
||||
garage.syncCoordinator(federation, newAlias);
|
||||
setNewAlias('');
|
||||
setNewUrl('');
|
||||
} else {
|
||||
setError(t('Invalid Onion URL'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
<Grid container direction='column' justifyItems='center' alignItems='center'>
|
||||
<Grid item>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
color='primary'
|
||||
variant='contained'
|
||||
>
|
||||
{t('Coordinators')}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
aria-labelledby='recovery-dialog-title'
|
||||
aria-describedby='recovery-description'
|
||||
>
|
||||
<DialogContent>
|
||||
<Grid container direction='column' alignItems='center' spacing={1} padding={2}>
|
||||
<Grid item>
|
||||
<Typography variant='h5' align='center'>
|
||||
{t('Coordinators')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FederationTable fillContainer />
|
||||
</Grid>
|
||||
{error ?? (
|
||||
<Grid item xs={12}>
|
||||
<Typography align='center' component='h2' variant='subtitle2' color='secondary'>
|
||||
{error}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<Grid container direction='row' alignItems='center' spacing={1} padding={2}>
|
||||
<Grid item xs={4}>
|
||||
<TextField
|
||||
id='outlined-basic'
|
||||
label={t('Alias')}
|
||||
variant='outlined'
|
||||
size='small'
|
||||
value={newAlias}
|
||||
onChange={(e) => {
|
||||
setNewAlias(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
id='outlined-basic'
|
||||
label={t('URL')}
|
||||
variant='outlined'
|
||||
size='small'
|
||||
value={newUrl}
|
||||
onChange={(e) => {
|
||||
setNewUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={1}>
|
||||
<Button
|
||||
sx={{ maxHeight: 38 }}
|
||||
disabled={false}
|
||||
onClick={addCoordinator}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
size='small'
|
||||
type='submit'
|
||||
>
|
||||
{t('Add')}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Coordinators;
|
||||
@ -1,42 +1,12 @@
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { Box, Button, Grid, List, ListItem, Paper, TextField, Typography } from '@mui/material';
|
||||
import React, { useContext } from 'react';
|
||||
import { Grid, Paper } from '@mui/material';
|
||||
import SettingsForm from '../../components/SettingsForm';
|
||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
import FederationTable from '../../components/FederationTable';
|
||||
import { t } from 'i18next';
|
||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
import Coordinators from './Coordinators';
|
||||
|
||||
const SettingsPage = (): JSX.Element => {
|
||||
const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
|
||||
const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const maxHeight = (windowSize.height - navbarHeight) * 0.85 - 3;
|
||||
const [newAlias, setNewAlias] = useState<string>('');
|
||||
const [newUrl, setNewUrl] = 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 addCoordinator: () => void = () => {
|
||||
if (federation.getCoordinator(newAlias)) {
|
||||
setError(t('Alias already exists'));
|
||||
} else {
|
||||
if (onionUrlPattern.test(newUrl)) {
|
||||
let fullNewUrl = newUrl;
|
||||
if (!/^((http|https):\/\/)/.test(fullNewUrl)) {
|
||||
fullNewUrl = `http://${newUrl}`;
|
||||
}
|
||||
addNewCoordinator(newAlias, fullNewUrl);
|
||||
garage.syncCoordinator(federation, newAlias);
|
||||
setNewAlias('');
|
||||
setNewUrl('');
|
||||
} else {
|
||||
setError(t('Invalid Onion URL'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
elevation={12}
|
||||
@ -52,57 +22,7 @@ const SettingsPage = (): JSX.Element => {
|
||||
<Grid item xs={12}>
|
||||
<SettingsForm />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FederationTable maxHeight={18} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography align='center' component='h2' variant='subtitle2' color='secondary'>
|
||||
{error}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<List>
|
||||
<ListItem>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<TextField
|
||||
id='outlined-basic'
|
||||
label={t('Alias')}
|
||||
variant='outlined'
|
||||
size='small'
|
||||
value={newAlias}
|
||||
onChange={(e) => {
|
||||
setNewAlias(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<TextField
|
||||
id='outlined-basic'
|
||||
label={t('URL')}
|
||||
variant='outlined'
|
||||
size='small'
|
||||
value={newUrl}
|
||||
onChange={(e) => {
|
||||
setNewUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Button
|
||||
sx={{ maxHeight: 38 }}
|
||||
disabled={false}
|
||||
onClick={addCoordinator}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
size='small'
|
||||
type='submit'
|
||||
>
|
||||
{t('Add')}
|
||||
</Button>
|
||||
</Box>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Grid>
|
||||
<Coordinators />
|
||||
</Grid>
|
||||
</Paper>
|
||||
);
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
AccordionSummary,
|
||||
AlertTitle,
|
||||
ListItemButton,
|
||||
Rating,
|
||||
} from '@mui/material';
|
||||
|
||||
import {
|
||||
@ -72,6 +73,7 @@ import { systemClient } from '../../services/System';
|
||||
import type Coordinator from '../../models/Coordinator.model';
|
||||
import { type Badges } from '../../models/Coordinator.model';
|
||||
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
||||
import { verifyCoordinatorToken } from '../../utils/nostr';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@ -358,6 +360,8 @@ const CoordinatorDialog = ({ open = false, onClose, shortAlias }: Props): JSX.El
|
||||
const { clientVersion, page, settings, origin } = useContext(AppContext);
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
|
||||
const [, setRating] = useState<number[]>([0, 0]);
|
||||
const [averageRating, setAvergeRating] = useState<number>(0);
|
||||
const [expanded, setExpanded] = useState<'summary' | 'stats' | 'policies' | undefined>(undefined);
|
||||
const [coordinator, setCoordinator] = useState<Coordinator>(
|
||||
federation.getCoordinator(shortAlias ?? ''),
|
||||
@ -370,10 +374,39 @@ const CoordinatorDialog = ({ open = false, onClose, shortAlias }: Props): JSX.El
|
||||
|
||||
useEffect(() => {
|
||||
setCoordinator(federation.getCoordinator(shortAlias ?? ''));
|
||||
setRating([0, 0]);
|
||||
setAvergeRating(0);
|
||||
}, [shortAlias]);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) federation.getCoordinator(shortAlias ?? '')?.loadInfo();
|
||||
if (open) {
|
||||
const coordinator = federation.getCoordinator(shortAlias ?? '');
|
||||
if (settings.connection === 'nostr') {
|
||||
federation.roboPool.subscribeRatings(
|
||||
{
|
||||
onevent: (event) => {
|
||||
const verfied = verifyCoordinatorToken(event);
|
||||
const coordinatorPubKey = event.tags.find((t) => t[0] === 'p')?.[1];
|
||||
if (verfied && coordinatorPubKey === coordinator.nostrHexPubkey) {
|
||||
const eventRating = event.tags.find((t) => t[0] === 'rating')?.[1];
|
||||
if (eventRating) {
|
||||
setRating((prev) => {
|
||||
const sum = prev[0];
|
||||
const count = prev[1] + 1;
|
||||
prev = [sum + parseFloat(eventRating), count];
|
||||
setAvergeRating(sum / count);
|
||||
return prev;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
oneose: () => {},
|
||||
},
|
||||
[coordinator.nostrHexPubkey],
|
||||
);
|
||||
}
|
||||
coordinator?.loadInfo();
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
@ -398,6 +431,21 @@ const CoordinatorDialog = ({ open = false, onClose, shortAlias }: Props): JSX.El
|
||||
<i>{String(coordinator?.motto)}</i>
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid container direction='column' alignItems='center' padding={0}>
|
||||
<Grid item>
|
||||
<Rating
|
||||
readOnly
|
||||
precision={0.5}
|
||||
name='size-large'
|
||||
value={averageRating * 5}
|
||||
defaultValue={0}
|
||||
disabled={settings.connection !== 'nostr'}
|
||||
/>
|
||||
<Typography variant='caption' color='text.secondary'>
|
||||
{`(${parseFloat((averageRating * 10).toFixed(1))})`}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<ContactButtons {...coordinator?.contact} />
|
||||
</Grid>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { Link, LinkOff } from '@mui/icons-material';
|
||||
import { Box, Checkbox, CircularProgress, Grid, Typography, useTheme } from '@mui/material';
|
||||
import { Box, Checkbox, CircularProgress, Grid, Rating, Typography, useTheme } from '@mui/material';
|
||||
import { DataGrid, type GridColDef, type GridValidRowModel } from '@mui/x-data-grid';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
@ -8,6 +8,7 @@ import { FederationContext, type UseFederationStoreType } from '../../contexts/F
|
||||
import { type Coordinator } from '../../models';
|
||||
import headerStyleFix from '../DataGrid/HeaderFix';
|
||||
import RobotAvatar from '../RobotAvatar';
|
||||
import { verifyCoordinatorToken } from '../../utils/nostr';
|
||||
|
||||
interface FederationTableProps {
|
||||
maxWidth?: number;
|
||||
@ -22,9 +23,16 @@ const FederationTable = ({
|
||||
}: FederationTableProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const { federation, federationUpdatedAt } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { setOpen } = useContext<UseAppStoreType>(AppContext);
|
||||
const { setOpen, windowSize, settings } = useContext<UseAppStoreType>(AppContext);
|
||||
const theme = useTheme();
|
||||
const [pageSize, setPageSize] = useState<number>(0);
|
||||
const [ratings, setRatings] = useState<Record<string, number[]>>(
|
||||
federation.getCoordinators().reduce((acc, coord) => {
|
||||
if (coord.nostrHexPubkey) acc[coord.nostrHexPubkey] = [0, 0];
|
||||
return acc;
|
||||
}, {}),
|
||||
);
|
||||
const [useDefaultPageSize, setUseDefaultPageSize] = useState(true);
|
||||
|
||||
// all sizes in 'em'
|
||||
const fontSize = theme.typography.fontSize;
|
||||
@ -35,8 +43,11 @@ const FederationTable = ({
|
||||
1,
|
||||
);
|
||||
const height = defaultPageSize * verticalHeightRow + verticalHeightFrame;
|
||||
const mobile = windowSize.width < 44;
|
||||
|
||||
const [useDefaultPageSize, setUseDefaultPageSize] = useState(true);
|
||||
useEffect(() => {
|
||||
loadRatings();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (useDefaultPageSize) {
|
||||
@ -44,6 +55,29 @@ const FederationTable = ({
|
||||
}
|
||||
}, [federationUpdatedAt]);
|
||||
|
||||
const loadRatings: () => void = () => {
|
||||
if (settings.connection !== 'nostr') return;
|
||||
|
||||
federation.roboPool.subscribeRatings({
|
||||
onevent: (event) => {
|
||||
const verfied = verifyCoordinatorToken(event);
|
||||
const coordinatorPubKey = event.tags.find((t) => t[0] === 'p')?.[1];
|
||||
if (verfied && coordinatorPubKey) {
|
||||
const rating = event.tags.find((t) => t[0] === 'rating')?.[1];
|
||||
if (rating) {
|
||||
setRatings((prev) => {
|
||||
const sum = prev[coordinatorPubKey][0];
|
||||
const count = prev[coordinatorPubKey][1];
|
||||
prev[coordinatorPubKey] = [sum + parseFloat(rating), count + 1];
|
||||
return prev;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
oneose: () => {},
|
||||
});
|
||||
};
|
||||
|
||||
const localeText = {
|
||||
MuiTablePagination: { labelRowsPerPage: t('Coordinators per page:') },
|
||||
noResultsOverlayLabel: t('No coordinators found.'),
|
||||
@ -55,11 +89,11 @@ const FederationTable = ({
|
||||
});
|
||||
};
|
||||
|
||||
const aliasObj = useCallback((width: number) => {
|
||||
const aliasObj = useCallback((_width: number) => {
|
||||
return {
|
||||
field: 'longAlias',
|
||||
headerName: t('Coordinator'),
|
||||
width: width * fontSize,
|
||||
headerName: mobile ? '' : t('Rating'),
|
||||
width: mobile ? 60 : 190,
|
||||
renderCell: (params: any) => {
|
||||
const coordinator = federation.getCoordinator(params.row.shortAlias);
|
||||
return (
|
||||
@ -83,15 +117,67 @@ const FederationTable = ({
|
||||
small={true}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography>{params.row.longAlias}</Typography>
|
||||
</Grid>
|
||||
{!mobile ? (
|
||||
<Grid item>
|
||||
<Typography>{params.row.longAlias}</Typography>
|
||||
</Grid>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
|
||||
const ratingObj = useCallback(
|
||||
(width: number) => {
|
||||
return {
|
||||
field: 'rating',
|
||||
headerName: t('Rating'),
|
||||
width: mobile ? 60 : 170,
|
||||
renderCell: (params: any) => {
|
||||
const coordinator = federation.getCoordinator(params.row.shortAlias);
|
||||
const coordinatorRating = ratings[coordinator.nostrHexPubkey];
|
||||
|
||||
if (!coordinatorRating) return <></>;
|
||||
|
||||
const average =
|
||||
coordinatorRating && coordinatorRating[1] > 0
|
||||
? coordinatorRating[0] / coordinatorRating[1]
|
||||
: 0;
|
||||
return (
|
||||
<>
|
||||
{mobile ? (
|
||||
<Grid container direction='column' alignItems='center' style={{ paddingTop: 10 }}>
|
||||
<Typography>{`${parseFloat((average * 10).toFixed(1))}`}</Typography>
|
||||
</Grid>
|
||||
) : (
|
||||
<>
|
||||
<Rating
|
||||
readOnly
|
||||
precision={0.5}
|
||||
name='size-large'
|
||||
value={average * 5}
|
||||
defaultValue={0}
|
||||
disabled={settings.connection !== 'nostr'}
|
||||
onClick={() => {
|
||||
onClickCoordinator(params.row.shortAlias);
|
||||
}}
|
||||
/>
|
||||
<Typography variant='caption' color='text.secondary'>
|
||||
{`(${parseFloat((average * 10).toFixed(1))})`}
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
[federationUpdatedAt],
|
||||
);
|
||||
|
||||
const enabledObj = useCallback(
|
||||
(width: number) => {
|
||||
return {
|
||||
@ -151,9 +237,17 @@ const FederationTable = ({
|
||||
object: aliasObj,
|
||||
},
|
||||
},
|
||||
rating: {
|
||||
priority: 2,
|
||||
order: 2,
|
||||
normal: {
|
||||
width: 12.1,
|
||||
object: ratingObj,
|
||||
},
|
||||
},
|
||||
up: {
|
||||
priority: 3,
|
||||
order: 2,
|
||||
order: 3,
|
||||
normal: {
|
||||
width: 3.5,
|
||||
object: upObj,
|
||||
@ -161,7 +255,7 @@ const FederationTable = ({
|
||||
},
|
||||
enabled: {
|
||||
priority: 1,
|
||||
order: 3,
|
||||
order: 4,
|
||||
normal: {
|
||||
width: 5,
|
||||
object: enabledObj,
|
||||
|
||||
@ -48,6 +48,7 @@ export const SuccessfulPrompt = ({
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
|
||||
const [coordinatorToken, setCoordinatorToken] = useState<string>();
|
||||
const [hostRating, setHostRating] = useState<number>();
|
||||
|
||||
const rateHostPlatform = function (): void {
|
||||
@ -56,12 +57,22 @@ export const SuccessfulPrompt = ({
|
||||
const slot = garage.getSlot();
|
||||
const coordinatorPubKey = federation.getCoordinator(order.shortAlias)?.nostrHexPubkey;
|
||||
|
||||
if (!slot?.nostrPubKey || !slot.nostrSecKey || !coordinatorPubKey || !order.id) return;
|
||||
if (
|
||||
!coordinatorToken ||
|
||||
!slot?.nostrPubKey ||
|
||||
!slot.nostrSecKey ||
|
||||
!coordinatorPubKey ||
|
||||
!order.id
|
||||
) {
|
||||
setHostRating(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const eventTemplate: Event = {
|
||||
kind: 31986,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [
|
||||
['sig', coordinatorToken],
|
||||
['d', `${order.shortAlias}:${order.id}`],
|
||||
['p', coordinatorPubKey],
|
||||
['rating', String(hostRating / 5)],
|
||||
@ -76,6 +87,13 @@ export const SuccessfulPrompt = ({
|
||||
federation.roboPool.sendEvent(signedEvent);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const slot = garage.getSlot();
|
||||
if (slot?.nostrPubKey) {
|
||||
slot.getRobot(order.shortAlias)?.loadReviewToken(federation, setCoordinatorToken);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
rateHostPlatform();
|
||||
}, [hostRating]);
|
||||
@ -91,7 +109,7 @@ export const SuccessfulPrompt = ({
|
||||
>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant='body2' align='center'>
|
||||
{t('Rate your peer')} <b>{order.is_maker ? order.taker_nick : order.maker_nick}</b>
|
||||
{t('Rate your trade experience')}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
@ -108,9 +126,6 @@ export const SuccessfulPrompt = ({
|
||||
<Grid item xs={12}>
|
||||
<Typography variant='body2' align='center'>
|
||||
{t('Rate your host')} <b>{federation.getCoordinator(order.shortAlias)?.longAlias}</b>{' '}
|
||||
<Typography variant='button' align='center'>
|
||||
{t('BETA')}
|
||||
</Typography>
|
||||
<Tooltip title={t('You need to enable nostr to rate your coordinator.')}>
|
||||
<Info sx={{ width: 15 }} />
|
||||
</Tooltip>
|
||||
|
||||
@ -120,7 +120,7 @@ const getSettings = (): Settings => {
|
||||
} else {
|
||||
settings = view === 'pro' ? new SettingsPro() : new Settings();
|
||||
}
|
||||
|
||||
console.log(settings.connection);
|
||||
return settings;
|
||||
};
|
||||
|
||||
|
||||
@ -123,6 +123,31 @@ class Robot {
|
||||
|
||||
this.stealthInvoices = wantsStealth;
|
||||
};
|
||||
|
||||
loadReviewToken = (
|
||||
federation: Federation,
|
||||
onDataLoad: (token: string) => void = () => {},
|
||||
): void => {
|
||||
if (!federation) return;
|
||||
|
||||
const coordinator = federation.getCoordinator(this.shortAlias);
|
||||
const body = {
|
||||
pubkey: this.nostrPubKey,
|
||||
};
|
||||
|
||||
apiClient
|
||||
.post(coordinator.url, `${coordinator.basePath}/api/review/`, body, {
|
||||
tokenSHA256: this.tokenSHA256,
|
||||
})
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
onDataLoad(data.token);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default Robot;
|
||||
|
||||
@ -44,10 +44,10 @@ class BaseSettings {
|
||||
: i18n.resolvedLanguage.substring(0, 2);
|
||||
|
||||
const connection = systemClient.getItem('settings_connection');
|
||||
this.connection = connection && connection !== '' ? connection : 'api';
|
||||
this.connection = connection && connection !== '' ? connection : this.connection;
|
||||
|
||||
const networkCookie = systemClient.getItem('settings_network');
|
||||
this.network = networkCookie && networkCookie !== '' ? networkCookie : 'mainnet';
|
||||
this.network = networkCookie && networkCookie !== '' ? networkCookie : this.network;
|
||||
this.host = getHost();
|
||||
|
||||
const [client] = window.RobosatsSettings.split('-');
|
||||
@ -68,7 +68,7 @@ class BaseSettings {
|
||||
public language?: Language;
|
||||
public freezeViewports: boolean = false;
|
||||
public network: 'mainnet' | 'testnet' = 'mainnet';
|
||||
public connection: 'api' | 'nostr' = 'api';
|
||||
public connection: 'api' | 'nostr' = 'nostr';
|
||||
public host?: string;
|
||||
public unsafeClient: boolean = false;
|
||||
public selfhostedClient: boolean = false;
|
||||
|
||||
@ -131,6 +131,30 @@ class RoboPool {
|
||||
this.sendMessage(JSON.stringify(requestSuccess));
|
||||
};
|
||||
|
||||
subscribeRatings = (events: RoboPoolEvents, coordinators?: string[]): void => {
|
||||
const pubkeys =
|
||||
coordinators ??
|
||||
[...Object.values(defaultFederation), ...Object.values(thirdParties)]
|
||||
.map((f) => f.nostrHexPubkey)
|
||||
.filter((item) => item !== undefined);
|
||||
|
||||
const requestRatings = [
|
||||
'REQ',
|
||||
'subscribeRatings',
|
||||
{ kinds: [31986], '#p': pubkeys, since: 1745509494 },
|
||||
];
|
||||
|
||||
this.messageHandlers.push((_url: string, messageEvent: MessageEvent) => {
|
||||
const jsonMessage = JSON.parse(messageEvent.data);
|
||||
if (jsonMessage[0] === 'EVENT') {
|
||||
events.onevent(jsonMessage[2]);
|
||||
} else if (jsonMessage[0] === 'EOSE') {
|
||||
events.oneose();
|
||||
}
|
||||
});
|
||||
this.sendMessage(JSON.stringify(requestRatings));
|
||||
};
|
||||
|
||||
sendEvent = (event: Event): void => {
|
||||
const message = ['EVENT', event];
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { type Event } from 'nostr-tools';
|
||||
import { schnorr } from '@noble/curves/secp256k1';
|
||||
import { type PublicOrder } from '../models';
|
||||
import { fromUnixTime } from 'date-fns';
|
||||
import Geohash from 'latlon-geohash';
|
||||
@ -106,4 +107,16 @@ const eventToPublicOrder = (event: Event): { dTag: string; publicOrder: PublicOr
|
||||
return { dTag: dTag[1], publicOrder };
|
||||
};
|
||||
|
||||
export const verifyCoordinatorToken: (event: Event) => boolean = (event) => {
|
||||
const d = event.tags.find((t) => t[0] === 'd')?.[1];
|
||||
const orderId = d?.split(':')?.[1];
|
||||
const signature = event.tags.find((t) => t[0] === 'sig')?.[1];
|
||||
const hash = `${event.pubkey}${orderId ?? ''}`;
|
||||
const coordinatorPubKey = event.tags.find((t) => t[0] === 'p')?.[1];
|
||||
if (signature && coordinatorPubKey) {
|
||||
return schnorr.verify(signature, hash, coordinatorPubKey);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export default eventToPublicOrder;
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connectant a TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connexió xifrada i anònima mitjançant TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "Això garanteix la màxima privadesa, però és possible que sentis que l'aplicació es comporta lenta. Si es perd la connexió, reinicia l'aplicació.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinadors per pàgina:",
|
||||
"Enabled": "Habilitat",
|
||||
"No coordinators found.": "No s'han trobat coordinadors.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Pujar",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "El client RoboSats és servit pel teu propi node, gaudeixes de la major seguretat i privacitat.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats està intentant pagar la teva factura de Lightning. Recorda que els nodes Lightning han d'estar en línia per rebre pagaments.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renovar",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats millora amb més usuaris i liquiditat. Ensenya-li RoboSats a un amic bitcoiner!",
|
||||
"Sending coins to": "Enviant monedes a",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connecting to TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connection encrypted and anonymized using TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats client is served from your own node granting you the strongest security and privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats se snaží zaplatit tvůj lightning invoice. Nezapomeň, že lightning nody musí být online, aby mohl přijímat platby.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats bude lepší s větší likviditou a uživateli. Pověz svým přátelům o Robosats!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connecting to TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connection encrypted and anonymized using TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats client is served from your own node granting you the strongest security and privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats versucht deine Lightning-Invoice zu bezahlen. Denk daran, dass deine Lightning-Node erreichbar sein muss, um die Zahlung zu erhalten.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats wird noch besser mit mehr Nutzern und Liquidität. Erzähl einem Bitcoin-Freund von uns!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connecting to TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connection encrypted and anonymized using TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats client is served from your own node granting you the strongest security and privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Conectando con TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Conexión encriptada y anonimizada usando TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "Esto asegura máxima privacidad, aunque quizá observe algo de lentitud. Si se corta la conexión, reinicie la aplicación.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "El cliente RoboSats es servido por tu propio nodo, gozas de la mayor seguridad y privacidad.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats está intentando pagar tu factura de Lightning. Recuerda que los nodos Lightning deben estar en línea para recibir pagos.",
|
||||
"Taking too long?": "¿Tarda demasiado?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renovar",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats mejora con más liquidez y usuarios. ¡Háblale a un amigo bitcoiner sobre RoboSats!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connecting to TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connection encrypted and anonymized using TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats webgunea zure nodotik zerbitzatzen da beraz segurtasun eta pribatutasun sendoena eskaintzen dizu.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats zure Lightning faktura ordaintzen saiatzen ari da. Gogoratu lightning nodoak online egon behar direla ordainketak jaso ahal izateko.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats hobetu egiten da likidezia eta erabiltzaile gehiagorekin. Aipatu Robosats lagun bitcoiner bati!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connexion au réseau TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connexion chiffré et anonymisée utilisant TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "Cela garantit une confidentialité maximale, mais l'application peut sembler lente. Si la connexion est perdue, redémarrez l'application.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "Le client RoboSats est servi à partir de votre propre nœud, ce qui vous garantit une sécurité et une confidentialité optimales.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats tente de payer votre facture lightning. Rappelez-vous que les nœuds lightning doivent être en ligne pour recevoir des paiements.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renouveler",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats s'améliore avec plus de liquidité et d'utilisateurs. Parlez de Robosats à un ami bitcoiner!",
|
||||
"Sending coins to": "Envoi coins à",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connessione a TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connessione criptata e anonimizzata mediante TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "Questo garantisce la massima privacy, ma l'app potrebbe risultare lenta. Se si perde la connessione, riavviare l'app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "Il client RoboSats è servito dal proprio nodo, garantendo la massima sicurezza e privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats sta provando a pagare la tua fattura lightning. Ricorda che i nodi lightning devono essere online per ricevere pagamenti.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Rinnova",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats migliora se ha più liquidità ed utenti. Parla di Robosats ai tuoi amici bitcoiner!",
|
||||
"Sending coins to": "Invio monete a",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Torネットワークに接続中",
|
||||
"Connection encrypted and anonymized using TOR.": "接続はTORを使って暗号化され、匿名化されています。",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "これにより最大限のプライバシーが確保されますが、アプリの動作が遅いと感じることがあります。接続が切断された場合は、アプリを再起動してください。",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSatsクライアントは、あなた自身のノードから提供され、最高のセキュリティとプライバシーが保証されます。",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSatsはあなたのライトニングインボイスを支払おうとしています。支払いを受け取るには、ライトニングノードがオンラインである必要があることを忘れないでください。",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "更新する",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSatsはより多くの流動性とユーザーでより良くなります。ビットコイナーのお友達にRoboSatsについて話してください!",
|
||||
"Sending coins to": "コインを送信する先",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connecting to TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connection encrypted and anonymized using TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats client is served from your own node granting you the strongest security and privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats próbuje zapłacić fakturę za błyskawicę. Pamiętaj, że węzły pioruna muszą być online, aby otrzymywać płatności.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats staje się lepszy dzięki większej płynności i użytkownikom. Powiedz znajomemu bitcoinerowi o Robosats!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Conectando ao TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Conexão criptografada e anonimizada usando TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "Isso garante privacidade máxima, entretanto, você pode sentir que o aplicativo fique lento. Se a conexão for perdida, reinicie-o.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats client is served from your own node granting you the strongest security and privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats está tentando pagar sua lightning invoice. Lembre-se de que os nós lightning devem estar online para receber pagamentos.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats fica melhor com mais liquidez e usuários. Conte a um amigo bitcoiner sobre Robosats!",
|
||||
"Sending coins to": "Enviando moedas para",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Подключение к TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Соединение зашифровано и анонимизировано с помощью TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "Это обеспечивает максимальную конфиденциальность, однако вы можете почувствовать, что приложение работает медленно. Если соединение потеряно, перезапустите приложение.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "Клиент RoboSats обслуживается с вашего собственного нода, что обеспечивает максимальную безопасность и конфиденциальность.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats пытается оплатить Ваш Lightning инвойс. Помните, что ноды Lightning должны быть подключены к сети, чтобы получать платежи.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats становится лучше с большей ликвидностью и пользователями. Расскажите другу-биткойнеру о Robosat!",
|
||||
"Sending coins to": "Отправка монет на",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connecting to TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connection encrypted and anonymized using TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats client is served from your own node granting you the strongest security and privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats försöker betala din lightning-faktura. Kom ihåg att lightning-noder måste vara online för att kunna mottaga betalningar.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats blir bättre med mer likviditet och fler användare. Berätta om RoboSats för en Bitcoiner-vän!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Kuunganisha kwa TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Unganisho limefichwa na kufanywa kuwa na siri kwa kutumia TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "Hii inahakikisha faragha ya juu kabisa, hata hivyo unaweza kuhisi programu inafanya kazi polepole. Ikiwa mawasiliano yamepotea, anza tena programu.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "Mteja wa RoboSats unatolewa kutoka kwenye node yako mwenyewe ikikupa usalama na faragha imara kabisa.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats inajaribu kulipa ankara yako ya umeme. Kumbuka kuwa nodi za umeme lazima ziwe mtandaoni ili kupokea malipo.",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats inaboreshwa na utoshelevu zaidi na watumiaji. Mwambie rafiki yako wa Bitcoin kuhusu RoboSats!",
|
||||
"Sending coins to": "Inatuma sarafu kwa",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "Connecting to TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "Connection encrypted and anonymized using TOR.",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats client is served from your own node granting you the strongest security and privacy.",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats กำลังจ่ายเหรียญให้ lightning invoice ของท่าน lightning nodes จะต้องออนไลน์เพื่อรับเหรียญ",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "Renew",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats จะดีขึ้นเมื่อมีสภาพคล่องและผู้ใช้งานมากขึ้น ช่วยกันชวนเพื่อนของคุณมาใช้ Robosats!",
|
||||
"Sending coins to": "Sending coins to",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "正在连线 TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "连接已用 TOR 加密和匿名化。",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "这确保最高的隐秘程度,但你可能会觉得应用程序运作缓慢。如果丢失连接,请重启应用。",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats 客户端已由你自己的节点提供服务,为你提供最强的安全性和隐私性。",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats 正在尝试支付你的闪电发票。请注意,闪电节点必须在线才能接收付款。",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "延续",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats 会随着更多的流动性和更高的用户数量而变得更好。把 RoboSats 推荐给你的比特币朋友吧!",
|
||||
"Sending coins to": "将比特币发送到",
|
||||
|
||||
@ -68,10 +68,11 @@
|
||||
"Connecting to TOR": "正在連線 TOR",
|
||||
"Connection encrypted and anonymized using TOR.": "連接已用 TOR 加密和匿名化。",
|
||||
"This ensures maximum privacy, however you might feel the app behaves slow. If connection is lost, restart the app.": "這確保最高的隱密程度,但你可能會覺得應用程序運作緩慢。如果丟失連接,請重啟應用。",
|
||||
"#12": "Phrases in basic/SettingsPage/index.tsx",
|
||||
"#12": "Phrases in basic/SettingsPage/Coordinators.tsx",
|
||||
"Add": "Add",
|
||||
"Alias": "Alias",
|
||||
"Alias already exists": "Alias already exists",
|
||||
"Coordinators": "Coordinators",
|
||||
"Invalid Onion URL": "Invalid Onion URL",
|
||||
"URL": "URL",
|
||||
"#13": "Phrases in components/BookTable/BookControl.tsx",
|
||||
@ -343,6 +344,7 @@
|
||||
"Coordinators per page:": "Coordinators per page:",
|
||||
"Enabled": "Enabled",
|
||||
"No coordinators found.": "No coordinators found.",
|
||||
"Rating": "Rating",
|
||||
"Up": "Up",
|
||||
"#36": "Phrases in components/HostAlert/SelfhostedAlert.tsx",
|
||||
"RoboSats client is served from your own node granting you the strongest security and privacy.": "RoboSats客戶端已由你自己的節點提供服務,為你提供最強的安全性和隱私性。",
|
||||
@ -679,9 +681,8 @@
|
||||
"RoboSats is trying to pay your lightning invoice. Remember that lightning nodes must be online in order to receive payments.": "RoboSats 正在嘗試支付你的閃電發票。請注意,閃電節點必須在線才能接收付款。",
|
||||
"Taking too long?": "Taking too long?",
|
||||
"#82": "Phrases in components/TradeBox/Prompts/Successful.tsx",
|
||||
"BETA": "BETA",
|
||||
"Rate your host": "Rate your host",
|
||||
"Rate your peer": "Rate your peer",
|
||||
"Rate your trade experience": "Rate your trade experience",
|
||||
"Renew": "延續",
|
||||
"RoboSats gets better with more liquidity and users. Tell a bitcoiner friend about Robosats!": "RoboSats 會隨著更多的流動性和更高的用戶数量而變得更好。把 RoboSats 推薦給你的比特幣朋友吧!",
|
||||
"Sending coins to": "將比特幣發送到",
|
||||
|
||||
@ -1 +1 @@
|
||||
aa19b79461dbd92673900cd50f51934ec648f8dbb79cb2e3e59929e798d41e86
|
||||
4b809260d59c8109a9de49b373253432c09a10fe87aad9386b2c958fb00e0b94
|
||||
@ -1 +1 @@
|
||||
b905e7adcee82cc7fe3ba05c8f0922c9098a872f71db4ba70c216e4396d73be8
|
||||
1934f637425f7a881020d013b0b5996eac937b864de48bc8114b0d86b78ca9c9
|
||||
Reference in New Issue
Block a user