From b25d59ba38181611e3975e0677f355e3c2fffd13 Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Wed, 2 Nov 2022 10:32:32 -0700 Subject: [PATCH] Add Lock Invoice box --- .../src/components/TradeBox/BondStatus.tsx | 44 +++++ .../components/TradeBox/LockInvoiceBox.tsx | 148 ++++++++++++++++ frontend/src/components/TradeBox/index.tsx | 158 +++--------------- frontend/src/components/TradeBox/stepXofY.ts | 47 ++++++ 4 files changed, 262 insertions(+), 135 deletions(-) create mode 100644 frontend/src/components/TradeBox/BondStatus.tsx create mode 100644 frontend/src/components/TradeBox/LockInvoiceBox.tsx create mode 100644 frontend/src/components/TradeBox/stepXofY.ts diff --git a/frontend/src/components/TradeBox/BondStatus.tsx b/frontend/src/components/TradeBox/BondStatus.tsx new file mode 100644 index 00000000..e8534262 --- /dev/null +++ b/frontend/src/components/TradeBox/BondStatus.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Box, Typography } from '@mui/material'; +import { Lock, LockOpen, Balance } from '@mui/icons-material'; + +interface BondStatusProps { + status: 'locked' | 'settled' | 'returned' | 'hide'; + isMaker: boolean; +} + +const BondStatus = ({ status, isMaker }: BondStatusProps): JSX.Element => { + const { t } = useTranslation(); + + let Icon = Lock; + if (status === 'returned') { + Icon = LockOpen; + } else if (status === 'settled') { + Icon = Balance; + } + + if (status === 'hide') { + return <>; + } else { + return ( + + +
+ + {t(`Your ${isMaker ? 'maker' : 'taker'} bond is ${status}`)} +
+
+
+ ); + } +}; + +export default BondStatus; diff --git a/frontend/src/components/TradeBox/LockInvoiceBox.tsx b/frontend/src/components/TradeBox/LockInvoiceBox.tsx new file mode 100644 index 00000000..a7ff7ac0 --- /dev/null +++ b/frontend/src/components/TradeBox/LockInvoiceBox.tsx @@ -0,0 +1,148 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + Button, + Grid, + Link, + Typography, + TextField, + Tooltip, + useTheme, + Divider, +} from '@mui/material'; +import { AccountBalanceWallet, ContentCopy } from '@mui/icons-material'; +import { NewTabIcon } from '../Icons'; +import QRCode from 'react-qr-code'; +import { Order } from '../../models'; +import { systemClient } from '../../services/System'; +import currencyDict from '../../../static/assets/currencies.json'; +import stepXofY from './stepXofY'; +import { pn } from '../../utils'; + +interface LockInvoiceBoxProps { + order: Order; + concept: 'bond' | 'escrow'; +} + +export const LockInvoiceBox = ({ order, concept }: LockInvoiceBoxProps): JSX.Element => { + const { t } = useTranslation(); + const theme = useTheme(); + const currencyCode = currencyDict[order.currency.toString()]; + + const invoice = concept === 'bond' ? order.bond_invoice : order.escrow_invoice; + const amountSats = concept === 'bond' ? order.bond_satoshis : order.escrow_satoshis; + const helperText = + concept === 'bond' + ? t( + 'This is a hold invoice, it will freeze in your wallet. It will be charged only if you cancel or lose a dispute.', + ) + : t( + 'This is a hold invoice, it will freeze in your wallet. It will be released to the buyer once you confirm to have received the {{currencyCode}}.', + { currencyCode }, + ); + + const Title = function () { + let text = `Lock {{amountSats}} Sats to ${order.is_maker ? 'PUBLISH' : 'TAKE'} order`; + if (concept === 'escrow') { + text = 'Lock {{amountSats}} Sats as collateral'; + } + return ( + + + {t(text, { + amountSats: pn(amountSats), + })} + + {` ${stepXofY(order)}`} + + ); + }; + const CompatibleWalletsButton = function () { + return ( + + ); + }; + + const depositHoursMinutes = function () { + const hours = parseInt(order.escrow_duration / 3600); + const minutes = parseInt((order.escrow_duration - hours * 3600) / 60); + const dict = { deposit_timer_hours: hours, deposit_timer_minutes: minutes }; + return dict; + }; + + const ExpirationWarning = function () { + return ( + + {t( + 'You risk losing your bond if you do not lock the collateral. Total time available is {{deposit_timer_hours}}h {{deposit_timer_minutes}}m.', + depositHoursMinutes(), + )} + + ); + }; + + return ( + + + + </Grid> + + <Divider /> + + <Grid item xs={12}> + {concept === 'bond' ? <CompatibleWalletsButton /> : <ExpirationWarning />} + </Grid> + + <Grid item xs={12}> + <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}> + <QRCode + bgColor={'rgba(255, 255, 255, 0)'} + fgColor={theme.palette.text.primary} + value={invoice} + size={theme.typography.fontSize * 21.8} + onClick={() => { + systemClient.copyToClipboard(invoice); + }} + /> + </Tooltip> + + <Tooltip disableHoverListener enterTouchDelay={0} title={t('Copied!')}> + <Button + size='small' + color='inherit' + onClick={() => { + systemClient.copyToClipboard(invoice); + }} + > + <ContentCopy /> + {t('Copy to clipboard')} + </Button> + </Tooltip> + </Grid> + + <Grid item xs={12}> + <TextField + hiddenLabel + variant='standard' + size='small' + defaultValue={invoice} + disabled={true} + helperText={helperText} + color='secondary' + /> + </Grid> + </Grid> + ); +}; + +export default LockInvoiceBox; diff --git a/frontend/src/components/TradeBox/index.tsx b/frontend/src/components/TradeBox/index.tsx index bf909cc0..8ea9e8cc 100644 --- a/frontend/src/components/TradeBox/index.tsx +++ b/frontend/src/components/TradeBox/index.tsx @@ -26,6 +26,7 @@ import { DialogContent, DialogContentText, DialogTitle, + dividerClasses, } from '@mui/material'; import { LoadingButton } from '@mui/lab'; import QRCode from 'react-qr-code'; @@ -35,6 +36,7 @@ import TradeSummary from './TradeSummary'; import { systemClient } from '../../services/System'; import { apiClient } from '../../services/api'; import { ConfirmDisputeDialog, ConfirmFiatReceivedDialog } from './Dialogs'; +import BondStatus from './BondStatus'; // Icons import { @@ -120,50 +122,6 @@ const defaultLightning: LightningFormProps = { badLnproxy: '', }; -const stepXofY = function (order: Order) { - // set y value - let x = null; - let y = null; - - if (order.is_maker) { - y = 5; - } else if (order.is_taker) { - y = 4; - } - - // set x values - if (order.is_maker) { - if (order.status === 0) { - x = 1; - } else if ([1, 2, 3].includes(order.status)) { - x = 2; - } else if ([6, 7, 8].includes(order.status)) { - x = 3; - } else if (order.status === 9) { - x = 4; - } else if (order.status === 10) { - x = 5; - } - } else if (order.is_taker) { - if (order.status === 3) { - x = 1; - } else if ([6, 7, 8].includes(order.status)) { - x = 2; - } else if (order.status === 9) { - x = 3; - } else if (order.status === 10) { - x = 4; - } - } - - // Return "(x/y)" - if (x != null && y != null) { - return `(${x}/${y})`; - } else { - return ''; - } -}; - interface TradeBoxProps { order: Order; setOrder: (state: Order) => void; @@ -217,6 +175,11 @@ const TradeBox = ({ order, setOrder }: TradeBoxProps): JSX.Element => { onClose={() => setOpen(closeAll)} onAgreeClick={onClickAgreeOpenDispute} /> + + <StepContent /> + <Divider /> + <BondStatus /> + <ConfirmFiatReceivedDialog open={open.confirmFiatReceived} order={order} @@ -229,17 +192,13 @@ const TradeBox = ({ order, setOrder }: TradeBoxProps): JSX.Element => { }; export default TradeBox; + // class TradeBox extends Component { // showQRInvoice = () => { // const { t } = this.props; // return ( // <Grid container spacing={1}> -// {/* <Grid item xs={12} align="center"> -// <Typography variant="body2"> -// {t("Robots show commitment to their peers")} -// </Typography> -// </Grid> */} // <Grid item xs={12} align='center'> // {this.props.data.is_maker ? ( // <Typography color='primary' variant='subtitle1'> @@ -305,77 +264,6 @@ export default TradeBox; // ); // }; -// showBondIsLocked = () => { -// const { t } = this.props; -// return ( -// <Grid item xs={12} align='center'> -// <Typography color='primary' variant='subtitle1' align='center'> -// <div -// style={{ -// display: 'flex', -// alignItems: 'center', -// justifyContent: 'center', -// flexWrap: 'wrap', -// }} -// > -// <LockIcon /> -// {this.props.data.is_maker -// ? t('Your maker bond is locked') -// : t('Your taker bond is locked')} -// </div> -// </Typography> -// </Grid> -// ); -// }; - -// showBondIsSettled = () => { -// const { t } = this.props; -// return ( -// <Grid item xs={12} align='center'> -// <Typography color='error' variant='subtitle1' align='center'> -// <div -// style={{ -// display: 'flex', -// alignItems: 'center', -// justifyContent: 'center', -// flexWrap: 'wrap', -// align: 'center', -// }} -// align='center' -// > -// <BalanceIcon /> -// {this.props.data.is_maker -// ? t('Your maker bond was settled') -// : t('Your taker bond was settled')} -// </div> -// </Typography> -// </Grid> -// ); -// }; - -// showBondIsReturned = () => { -// const { t } = this.props; -// return ( -// <Grid item xs={12} align='center'> -// <Typography color='green' variant='subtitle1' align='center'> -// <div -// style={{ -// display: 'flex', -// alignItems: 'center', -// justifyContent: 'center', -// flexWrap: 'wrap', -// }} -// > -// <LockOpenIcon /> -// {this.props.data.is_maker -// ? t('Your maker bond was unlocked') -// : t('Your taker bond was unlocked')} -// </div> -// </Typography> -// </Grid> -// ); -// }; - // showEscrowQRInvoice = () => { // const { t } = this.props; // return ( @@ -436,7 +324,7 @@ export default TradeBox; // color='secondary' // /> // </Grid> -// {this.showBondIsLocked()} +// <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -460,7 +348,7 @@ export default TradeBox; // )} // </Typography> // </Grid> -// {this.showBondIsLocked()} +// // <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -567,7 +455,7 @@ export default TradeBox; // <Divider /> // </List> // </Grid> -// {this.showBondIsLocked()} +// // <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -607,7 +495,7 @@ export default TradeBox; // <Divider /> // </List> // </Grid> -// {this.showBondIsLocked()} +// // <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -950,7 +838,7 @@ export default TradeBox; // <Divider /> // </List> -// {this.showBondIsLocked()} +// // <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // } @@ -986,7 +874,7 @@ export default TradeBox; // <Divider /> // </List> // </Grid> -// {this.showBondIsSettled()} +// // <BondStatus status={'settled'} isMaker={order.is_maker}/> // </Grid> // ); // } else { @@ -1033,7 +921,7 @@ export default TradeBox; // </Button> // </Grid> // </List> -// {this.showBondIsSettled()} +// // <BondStatus status={'settled'} isMaker={order.is_maker}/> // </Grid> // ); // } @@ -1068,7 +956,7 @@ export default TradeBox; // <Divider /> // </List> // </Grid> -// {this.showBondIsSettled()} +// // <BondStatus status={'settled'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -1089,7 +977,7 @@ export default TradeBox; // )} // </Typography> // </Grid> -// {this.showBondIsSettled()} +// // <BondStatus status={'settled'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -1110,7 +998,7 @@ export default TradeBox; // )} // </Typography> // </Grid> -// {this.showBondIsSettled()} +// // <BondStatus status={'settled'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -1142,7 +1030,7 @@ export default TradeBox; // <Divider /> // </List> // </Grid> -// {this.showBondIsLocked()} +// // <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // } @@ -1179,7 +1067,7 @@ export default TradeBox; // <Divider /> // </List> // </Grid> -// {this.showBondIsLocked()} +// // <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // } @@ -1456,7 +1344,7 @@ export default TradeBox; // {showSendButton ? this.showFiatSentButton() : ''} // {showReveiceButton ? this.showFiatReceivedButton() : ''} // </Grid> -// {this.showBondIsLocked()} +// // <BondStatus status={'locked'} isMaker={order.is_maker}/> // </Grid> // ); // }; @@ -1746,7 +1634,7 @@ export default TradeBox; // {t('Submit')} // </LoadingButton> // </Grid> -// {this.showBondIsReturned()} +// // <BondStatus status={'returned'} isMaker={order.is_maker}/> // </Grid> // ); // } else { @@ -1776,7 +1664,7 @@ export default TradeBox; // </ListItemText> // </List> // </Grid> -// {this.showBondIsReturned()} +// // <BondStatus status={'returned'} isMaker={order.is_maker}/> // </Grid> // ); // } diff --git a/frontend/src/components/TradeBox/stepXofY.ts b/frontend/src/components/TradeBox/stepXofY.ts new file mode 100644 index 00000000..98644d15 --- /dev/null +++ b/frontend/src/components/TradeBox/stepXofY.ts @@ -0,0 +1,47 @@ +import { Order } from '../../models'; + +const stepXofY = function (order: Order): string { + // set y value + let x: number | null = null; + let y: number | null = null; + + if (order.is_maker) { + y = 5; + } else if (order.is_taker) { + y = 4; + } + + // set x values + if (order.is_maker) { + if (order.status === 0) { + x = 1; + } else if ([1, 2, 3].includes(order.status)) { + x = 2; + } else if ([6, 7, 8].includes(order.status)) { + x = 3; + } else if (order.status === 9) { + x = 4; + } else if (order.status === 10) { + x = 5; + } + } else if (order.is_taker) { + if (order.status === 3) { + x = 1; + } else if ([6, 7, 8].includes(order.status)) { + x = 2; + } else if (order.status === 9) { + x = 3; + } else if (order.status === 10) { + x = 4; + } + } + + // Return "(x/y)" + if (x != null && y != null) { + return `(${x}/${y})`; + } else { + return ''; + } +}; + +export default stepXofY;