mirror of
https://github.com/RoboSats/robosats.git
synced 2024-12-13 19:06:26 +00:00
Add showPGP per message, copy per message, create messageCard
This commit is contained in:
parent
83564df25a
commit
508151eae5
@ -110,7 +110,6 @@ class ChatRoomConsumer(AsyncWebsocketConsumer):
|
|||||||
|
|
||||||
async def receive(self, text_data):
|
async def receive(self, text_data):
|
||||||
text_data_json = json.loads(text_data)
|
text_data_json = json.loads(text_data)
|
||||||
print(text_data)
|
|
||||||
message = text_data_json["message"]
|
message = text_data_json["message"]
|
||||||
|
|
||||||
peer_connected = await self.is_peer_connected()
|
peer_connected = await self.is_peer_connected()
|
||||||
|
@ -20,7 +20,7 @@ import { saveAsJson } from "../../utils/saveFile";
|
|||||||
import KeyIcon from '@mui/icons-material/Key';
|
import KeyIcon from '@mui/icons-material/Key';
|
||||||
import ContentCopy from "@mui/icons-material/ContentCopy";
|
import ContentCopy from "@mui/icons-material/ContentCopy";
|
||||||
import ForumIcon from '@mui/icons-material/Forum';
|
import ForumIcon from '@mui/icons-material/Forum';
|
||||||
import { ExportIcon } from '../Icons';
|
import { ExportIcon, NewTabIcon } from '../Icons';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -53,7 +53,7 @@ const AuditPGPDialog = ({
|
|||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<DialogTitle >
|
<DialogTitle >
|
||||||
{t("Do not trust, verify!")}
|
{t("Don't trust, verify")}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@ -63,7 +63,7 @@ const AuditPGPDialog = ({
|
|||||||
<Grid container spacing={1} align="center">
|
<Grid container spacing={1} align="center">
|
||||||
|
|
||||||
<Grid item align="center" xs={12}>
|
<Grid item align="center" xs={12}>
|
||||||
<Button component={Link} target="_blank" href="https://learn.robosats.com/docs/pgp-encryption">{t("Learn how to verify")}</Button>
|
<Button component={Link} target="_blank" href="https://learn.robosats.com/docs/pgp-encryption">{t("Learn how to verify")} <NewTabIcon sx={{width:16,height:16}}/></Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item align="center" xs={12}>
|
<Grid item align="center" xs={12}>
|
||||||
|
@ -12,6 +12,7 @@ import CheckIcon from '@mui/icons-material/Check';
|
|||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import ContentCopy from "@mui/icons-material/ContentCopy";
|
import ContentCopy from "@mui/icons-material/ContentCopy";
|
||||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||||
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
import KeyIcon from '@mui/icons-material/Key';
|
import KeyIcon from '@mui/icons-material/Key';
|
||||||
import { ExportIcon } from './Icons';
|
import { ExportIcon } from './Icons';
|
||||||
|
|
||||||
@ -30,6 +31,9 @@ class Chat extends Component {
|
|||||||
connected: false,
|
connected: false,
|
||||||
peer_connected: false,
|
peer_connected: false,
|
||||||
audit: false,
|
audit: false,
|
||||||
|
showPGP: new Array,
|
||||||
|
waitingEcho: false,
|
||||||
|
lastSent: '---BLANK---',
|
||||||
};
|
};
|
||||||
|
|
||||||
rws = new ReconnectingWebSocket('ws://' + window.location.host + '/ws/chat/' + this.props.orderId + '/');
|
rws = new ReconnectingWebSocket('ws://' + window.location.host + '/ws/chat/' + this.props.orderId + '/');
|
||||||
@ -93,6 +97,8 @@ class Chat extends Component {
|
|||||||
.then((decryptedData) =>
|
.then((decryptedData) =>
|
||||||
this.setState((state) =>
|
this.setState((state) =>
|
||||||
({
|
({
|
||||||
|
waitingEcho: this.state.waitingEcho == true ? (decryptedData.decryptedMessage == this.state.lastSent ? false: true ) : false,
|
||||||
|
lastSent: decryptedData.decryptedMessage == this.state.lastSent ? '----BLANK----': this.state.lastSent,
|
||||||
messages: [...state.messages,
|
messages: [...state.messages,
|
||||||
{
|
{
|
||||||
encryptedMessage: dataFromServer.message.split('\\').join('\n'),
|
encryptedMessage: dataFromServer.message.split('\\').join('\n'),
|
||||||
@ -129,6 +135,7 @@ class Chat extends Component {
|
|||||||
|
|
||||||
onButtonClicked = (e) => {
|
onButtonClicked = (e) => {
|
||||||
if(this.state.value!=''){
|
if(this.state.value!=''){
|
||||||
|
this.setState({waitingEcho:true, lastSent:this.state.value});
|
||||||
encryptMessage(this.state.value, this.state.own_pub_key, this.state.peer_pub_key, this.state.own_enc_priv_key, this.state.token)
|
encryptMessage(this.state.value, this.state.own_pub_key, this.state.peer_pub_key, this.state.own_enc_priv_key, this.state.token)
|
||||||
.then((encryptedMessage) =>
|
.then((encryptedMessage) =>
|
||||||
console.log("Sending Encrypted MESSAGE "+encryptedMessage) &
|
console.log("Sending Encrypted MESSAGE "+encryptedMessage) &
|
||||||
@ -137,7 +144,7 @@ class Chat extends Component {
|
|||||||
message: encryptedMessage.split('\n').join('\\'),
|
message: encryptedMessage.split('\n').join('\\'),
|
||||||
nick: this.props.ur_nick,
|
nick: this.props.ur_nick,
|
||||||
})
|
})
|
||||||
) & this.setState({value: ""})
|
) & this.setState({value: "", waitingEcho: false})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -154,6 +161,60 @@ class Chat extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messageCard = (props) => {
|
||||||
|
const { t } = this.props;
|
||||||
|
return(
|
||||||
|
<Card elevation={5} align="left" >
|
||||||
|
<CardHeader sx={{color: '#333333'}}
|
||||||
|
avatar={
|
||||||
|
<Badge variant="dot" overlap="circular" badgeContent="" color={props.userConnected ? "success" : "error"}>
|
||||||
|
<Avatar className="flippedSmallAvatar"
|
||||||
|
alt={props.message.userNick}
|
||||||
|
src={window.location.origin +'/static/assets/avatars/' + props.message.userNick + '.png'}
|
||||||
|
/>
|
||||||
|
</Badge>
|
||||||
|
}
|
||||||
|
style={{backgroundColor: props.cardColor}}
|
||||||
|
title={
|
||||||
|
<Tooltip placement="top" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t(props.message.validSignature ? "Verified signature by {{nickname}}": "Invalid signature! Not sent by {{nickname}}",{"nickname": props.message.userNick})}>
|
||||||
|
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap', position:'relative',left:-5, width:210}}>
|
||||||
|
<div style={{width:168,display:'flex',alignItems:'center', flexWrap:'wrap'}}>
|
||||||
|
{props.message.userNick}
|
||||||
|
{props.message.validSignature ?
|
||||||
|
<CheckIcon sx={{height:16}} color="success"/>
|
||||||
|
:
|
||||||
|
<CloseIcon sx={{height:16}} color="error"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div style={{width:20}}>
|
||||||
|
<IconButton sx={{height:18,width:18}}
|
||||||
|
onClick={()=>
|
||||||
|
this.setState(prevState => {
|
||||||
|
const newShowPGP = [...prevState.showPGP];
|
||||||
|
newShowPGP[props.index] = !newShowPGP[props.index];
|
||||||
|
return {showPGP: newShowPGP};
|
||||||
|
})}>
|
||||||
|
<VisibilityIcon color={this.state.showPGP[props.index]? "primary":"inherit"} sx={{height:16,width:16,color:this.state.showPGP[props.index]? "primary":"#333333"}}/>
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
<div style={{width:20}}>
|
||||||
|
<Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}>
|
||||||
|
<IconButton sx={{height:18,width:18}}
|
||||||
|
onClick={()=> navigator.clipboard.writeText(this.state.showPGP[props.index] ? props.message.encryptedMessage : props.message.plainTextMessage)}>
|
||||||
|
<ContentCopy sx={{height:16,width:16,color:'#333333'}}/>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
subheader={this.state.showPGP[props.index] ? props.message.encryptedMessage : props.message.plainTextMessage}
|
||||||
|
subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '200px', color: '#444444', fontSize: this.state.showPGP[props.index]? 11 : null }}}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { t } = this.props;
|
const { t } = this.props;
|
||||||
return (
|
return (
|
||||||
@ -162,7 +223,7 @@ class Chat extends Component {
|
|||||||
<Grid item xs={0.3}/>
|
<Grid item xs={0.3}/>
|
||||||
<Grid item xs={5.5}>
|
<Grid item xs={5.5}>
|
||||||
<Paper elevation={1} style={this.state.connected ? {backgroundColor: '#e8ffe6'}: {backgroundColor: '#FFF1C5'}}>
|
<Paper elevation={1} style={this.state.connected ? {backgroundColor: '#e8ffe6'}: {backgroundColor: '#FFF1C5'}}>
|
||||||
<Typography variant='caption' sx={{color: '#111111'}}>
|
<Typography variant='caption' sx={{color: '#333333'}}>
|
||||||
{t("You")+": "}{this.state.connected ? t("connected"): t("disconnected")}
|
{t("You")+": "}{this.state.connected ? t("connected"): t("disconnected")}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
@ -170,7 +231,7 @@ class Chat extends Component {
|
|||||||
<Grid item xs={0.4}/>
|
<Grid item xs={0.4}/>
|
||||||
<Grid item xs={5.5}>
|
<Grid item xs={5.5}>
|
||||||
<Paper elevation={1} style={this.state.peer_connected ? {backgroundColor: '#e8ffe6'}: {backgroundColor: '#FFF1C5'}}>
|
<Paper elevation={1} style={this.state.peer_connected ? {backgroundColor: '#e8ffe6'}: {backgroundColor: '#FFF1C5'}}>
|
||||||
<Typography variant='caption' sx={{color: '#111111'}}>
|
<Typography variant='caption' sx={{color: '#333333'}}>
|
||||||
{t("Peer")+": "}{this.state.peer_connected ? t("connected"): t("disconnected")}
|
{t("Peer")+": "}{this.state.peer_connected ? t("connected"): t("disconnected")}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
@ -180,72 +241,101 @@ class Chat extends Component {
|
|||||||
<Paper elevation={1} style={{ height: '300px', maxHeight: '300px' , width: '280px' ,overflow: 'auto', backgroundColor: '#F7F7F7' }}>
|
<Paper elevation={1} style={{ height: '300px', maxHeight: '300px' , width: '280px' ,overflow: 'auto', backgroundColor: '#F7F7F7' }}>
|
||||||
{this.state.messages.map((message, index) =>
|
{this.state.messages.map((message, index) =>
|
||||||
<li style={{listStyleType:"none"}} key={index}>
|
<li style={{listStyleType:"none"}} key={index}>
|
||||||
<Card elevation={5} align="left" >
|
|
||||||
{/* If message sender is not our nick, gray color, if it is our nick, green color */}
|
{/* If message sender is not our nick, gray color, if it is our nick, green color */}
|
||||||
{message.userNick == this.props.ur_nick ?
|
{message.userNick == this.props.ur_nick ?
|
||||||
<CardHeader sx={{color: '#111111'}}
|
<this.messageCard message={message} index={index} cardColor={'#eeeeee'} userConnected={this.state.connected}/>
|
||||||
avatar={
|
|
||||||
<Badge variant="dot" overlap="circular" badgeContent="" color={this.state.connected ? "success" : "error"}>
|
|
||||||
<Avatar className="flippedSmallAvatar"
|
|
||||||
alt={message.userNick}
|
|
||||||
src={window.location.origin +'/static/assets/avatars/' + message.userNick + '.png'}
|
|
||||||
/>
|
|
||||||
</Badge>
|
|
||||||
}
|
|
||||||
style={{backgroundColor: '#eeeeee'}}
|
|
||||||
title={
|
|
||||||
<Tooltip placement="top" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t(message.validSignature ? "Verified signature by {{nickname}}": "Invalid signature! Not sent by {{nickname}}",{"nickname": message.userNick})}>
|
|
||||||
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap'}}>
|
|
||||||
{message.userNick}
|
|
||||||
{message.validSignature ?
|
|
||||||
<CheckIcon sx={{height:16}} color="success"/>
|
|
||||||
:
|
:
|
||||||
<CloseIcon sx={{height:16}} color="error"/>
|
<this.messageCard message={message} index={index} cardColor={'#fafafa'} userConnected={this.state.peer_connected}/>
|
||||||
}
|
}
|
||||||
<div style={{width:20}}>
|
{/* // <CardHeader sx={{color: '#333333'}}
|
||||||
<IconButton sx={{height:16}}><VisibilityIcon sx={{height:16}}/></IconButton>
|
// avatar={
|
||||||
</div>
|
// <Badge variant="dot" overlap="circular" badgeContent="" color={this.state.connected ? "success" : "error"}>
|
||||||
<div style={{width:20}}>
|
// <Avatar className="flippedSmallAvatar"
|
||||||
<IconButton sx={{height:16}}><ContentCopy sx={{height:16}}/></IconButton>
|
// alt={message.userNick}
|
||||||
</div>
|
// src={window.location.origin +'/static/assets/avatars/' + message.userNick + '.png'}
|
||||||
</div>
|
// />
|
||||||
</Tooltip>
|
// </Badge>
|
||||||
}
|
// }
|
||||||
subheader={this.state.audit ? message.encryptedMessage : message.plainTextMessage}
|
// style={{backgroundColor: '#eeeeee'}}
|
||||||
subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '200px', color: '#444444'}}}
|
// title={
|
||||||
/>
|
// <Tooltip placement="top" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t(message.validSignature ? "Verified signature by {{nickname}}": "Invalid signature! Not sent by {{nickname}}",{"nickname": message.userNick})}>
|
||||||
:
|
// <div style={{display:'flex',alignItems:'center', flexWrap:'wrap', position:'relative',left:-5, width:210}}>
|
||||||
<CardHeader sx={{color: '#111111'}}
|
// <div style={{width:168,display:'flex',alignItems:'center', flexWrap:'wrap'}}>
|
||||||
avatar={
|
// {message.userNick}
|
||||||
<Badge variant="dot" overlap="circular" badgeContent="" color={this.state.peer_connected ? "success" : "error"}>
|
// {message.validSignature ?
|
||||||
<Avatar className="flippedSmallAvatar"
|
// <CheckIcon sx={{height:16}} color="success"/>
|
||||||
alt={message.userNick}
|
// :
|
||||||
src={window.location.origin +'/static/assets/avatars/' + message.userNick + '.png'}
|
// <CloseIcon sx={{height:16}} color="error"/>
|
||||||
/>
|
// }
|
||||||
</Badge>
|
// </div>
|
||||||
}
|
// <div style={{width:20}}>
|
||||||
style={{backgroundColor: '#fafafa'}}
|
// <IconButton sx={{height:18,width:18}}
|
||||||
title={
|
// onClick={()=>
|
||||||
<Tooltip placement="top" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t(message.validSignature ? "Verified signature by {{nickname}}": "Invalid signature! Not sent by {{nickname}}",{"nickname": message.userNick})}>
|
// this.setState(prevState => {
|
||||||
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap'}}>
|
// const newShowPGP = [...prevState.showPGP];
|
||||||
{message.userNick}
|
// newShowPGP[index] = !newShowPGP[index];
|
||||||
{message.validSignature ?
|
// return {showPGP: newShowPGP};
|
||||||
<CheckIcon sx={{height:16}} color="success"/>
|
// })}>
|
||||||
:
|
// <VisibilityIcon color={this.state.showPGP[index]? "primary":"inherit"} sx={{height:16,width:16,color:this.state.showPGP[index]? "primary":"#333333"}}/>
|
||||||
<CloseIcon sx={{height:16}} color="error"/>
|
// </IconButton>
|
||||||
}
|
// </div>
|
||||||
<div style={{width:20}}>
|
// <div style={{width:20}}>
|
||||||
<IconButton sx={{height:16}}><VisibilityIcon sx={{height:16}}/></IconButton>
|
// <Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}>
|
||||||
</div>
|
// <IconButton sx={{height:18,width:18}}
|
||||||
<div style={{width:20}}>
|
// onClick={()=> navigator.clipboard.writeText(this.state.showPGP[index] ? message.encryptedMessage : message.plainTextMessage)}>
|
||||||
<IconButton sx={{height:16}}><ContentCopy sx={{height:16}}/></IconButton>
|
// <ContentCopy sx={{height:16,width:16,color:'#333333'}}/>
|
||||||
</div>
|
// </IconButton>
|
||||||
</div>
|
// </Tooltip>
|
||||||
</Tooltip>}
|
// </div>
|
||||||
subheader={this.state.audit ? message.encryptedMessage : message.plainTextMessage}
|
// </div>
|
||||||
subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '200px', color: '#444444'}}}
|
// </Tooltip>
|
||||||
/>}
|
// }
|
||||||
</Card>
|
// subheader={this.state.showPGP[index] ? message.encryptedMessage : message.plainTextMessage}
|
||||||
|
// subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '200px', color: '#444444', fontSize: this.state.showPGP[index]? 11 : null }}}
|
||||||
|
// />
|
||||||
|
// :
|
||||||
|
// <CardHeader sx={{color: '#333333'}}
|
||||||
|
// avatar={
|
||||||
|
// <Badge variant="dot" overlap="circular" badgeContent="" color={this.state.peer_connected ? "success" : "error"}>
|
||||||
|
// <Avatar className="flippedSmallAvatar"
|
||||||
|
// alt={message.userNick}
|
||||||
|
// src={window.location.origin +'/static/assets/avatars/' + message.userNick + '.png'}
|
||||||
|
// />
|
||||||
|
// </Badge>
|
||||||
|
// }
|
||||||
|
// style={{backgroundColor: '#fafafa'}}
|
||||||
|
// title={
|
||||||
|
// <Tooltip placement="top" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t(message.validSignature ? "Verified signature by {{nickname}}": "Invalid signature! Not sent by {{nickname}}",{"nickname": message.userNick})}>
|
||||||
|
// <div style={{display:'flex',alignItems:'center', flexWrap:'wrap', position:'relative',left:-5, width:210}}>
|
||||||
|
// <div style={{width:168,display:'flex',alignItems:'center', flexWrap:'wrap'}}>
|
||||||
|
// {message.userNick}
|
||||||
|
// {message.validSignature ?
|
||||||
|
// <CheckIcon sx={{height:16}} color="success"/>
|
||||||
|
// :
|
||||||
|
// <CloseIcon sx={{height:16}} color="error"/>
|
||||||
|
// }
|
||||||
|
// </div>
|
||||||
|
// <div style={{width:20}}>
|
||||||
|
// <IconButton sx={{height:18,width:18}}
|
||||||
|
// onClick={()=>
|
||||||
|
// this.setState(prevState => {
|
||||||
|
// const newShowPGP = [...prevState.showPGP];
|
||||||
|
// newShowPGP[index] = !newShowPGP[index];
|
||||||
|
// return {showPGP: newShowPGP};
|
||||||
|
// })}>
|
||||||
|
// <VisibilityIcon color={this.state.showPGP[index]? "primary":"inherit"} sx={{height:16,width:16,color:this.state.showPGP[index]? "primary":"#333333"}}/>
|
||||||
|
// </IconButton>
|
||||||
|
// </div>
|
||||||
|
// <div style={{width:20}}>
|
||||||
|
// <Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}>
|
||||||
|
// <IconButton sx={{height:18,width:18}}
|
||||||
|
// onClick={()=> navigator.clipboard.writeText(this.state.showPGP[index] ? message.encryptedMessage : message.plainTextMessage)}>
|
||||||
|
// <ContentCopy sx={{height:16,width:16,color:'#333333'}}/>
|
||||||
|
// </IconButton>
|
||||||
|
// </Tooltip>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// </Tooltip> */}
|
||||||
</li>)}
|
</li>)}
|
||||||
<div style={{ float:"left", clear: "both" }} ref={(el) => { this.messagesEnd = el; }}></div>
|
<div style={{ float:"left", clear: "both" }} ref={(el) => { this.messagesEnd = el; }}></div>
|
||||||
</Paper>
|
</Paper>
|
||||||
@ -266,7 +356,16 @@ class Chat extends Component {
|
|||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item alignItems="stretch" style={{ display: "flex" }}>
|
<Grid item alignItems="stretch" style={{ display: "flex" }}>
|
||||||
<Button sx={{'width':68}} disabled={!this.state.connected} type="submit" variant="contained" color="primary">{t("Send")} </Button>
|
<Button sx={{'width':68}} disabled={!this.state.connected || this.state.waitingEcho} type="submit" variant="contained" color="primary">
|
||||||
|
{this.state.waitingEcho ?
|
||||||
|
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap', minWidth:68, width:68, position:"relative",left:15}}>
|
||||||
|
<div style={{width:20}}><KeyIcon sx={{width:18}}/></div>
|
||||||
|
<div style={{width:18}}><CircularProgress size={16} thickness={5}/></div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
t("Send")
|
||||||
|
}
|
||||||
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</form>
|
</form>
|
||||||
|
@ -381,7 +381,7 @@
|
|||||||
"You can also check the full guide in ":"You can also check the full guide in ",
|
"You can also check the full guide in ":"You can also check the full guide in ",
|
||||||
"How to use":"How to use",
|
"How to use":"How to use",
|
||||||
"What payment methods are accepted?":"What payment methods are accepted?",
|
"What payment methods are accepted?":"What payment methods are accepted?",
|
||||||
"All of them as long as they are fast. You can write down your preferred payment method(s). You will have to match with a peer who also accepts that method. The step to exchange fiat has a expiry time of 24 hours before a dispute is automatically open. We highly recommend using instant fiat payment rails.":"All of them as long as they are fast. You can write down your preferred payment method(s). You will have to match with a peer who also accepts that method. The step to exchange fiat has a expiry time of 24 hours before a dispute is automatically open. We highly recommend using instant fiat payment rails.",
|
"All of them as long as they are fast. You can write down your preferred payment method(s). You will have to match with a peer who also accepts that method. The step to exchange fiat has a expiry time of 24 hours before a dispute is automatically open. We highly recommend using instant fiat payment rails.":"All of them as long as they are fast. You can write down your preferred payment method(s). You will have to match with a peer who also accepts that method. The step to exchange fiat has an expiry time of 24 hours before a dispute is automatically open. We highly recommend using instant fiat payment rails.",
|
||||||
"Are there trade limits?":"Are there trade limits?",
|
"Are there trade limits?":"Are there trade limits?",
|
||||||
"Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).":"Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).",
|
"Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).":"Maximum single trade size is {{maxAmount}} Satoshis to minimize lightning routing failure. There is no limits to the number of trades per day. A robot can only have one order at a time. However, you can use multiple robots simultaneously in different browsers (remember to back up your robot tokens!).",
|
||||||
"Is RoboSats private?":"Is RoboSats private?",
|
"Is RoboSats private?":"Is RoboSats private?",
|
||||||
|
Loading…
Reference in New Issue
Block a user