From b6129bb46f33ce0b0a56dc0a19f8a80b4c5d226b Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi <90936742+Reckless-Satoshi@users.noreply.github.com> Date: Thu, 9 Mar 2023 20:10:49 +0000 Subject: [PATCH] Enhance clarity for swaps (#382) * Improve clarity of swap orders * Add descriptive send/receive amounts for swaps on Maker Page * Add descriptive send/receive amounts for swaps on OrderDetails * Collect new phrases * Small fixes --- frontend/src/basic/MakerPage/index.tsx | 30 ++-- frontend/src/basic/OrderPage/index.tsx | 7 +- .../src/components/Dialogs/Confirmation.tsx | 4 +- frontend/src/components/Dialogs/NoRobot.tsx | 8 +- .../src/components/MakerForm/MakerForm.tsx | 141 +++++++++++------- .../components/OrderDetails/TakeButton.tsx | 28 ++-- .../src/components/OrderDetails/index.tsx | 131 +++++++++++++--- .../src/components/TradeBox/Dialogs/WebLN.tsx | 2 +- .../TradeBox/Forms/LightningPayout.tsx | 27 ---- frontend/src/utils/computeSats.ts | 23 +++ frontend/src/utils/index.ts | 1 + frontend/static/locales/ca.json | 12 +- frontend/static/locales/cs.json | 12 +- frontend/static/locales/de.json | 12 +- frontend/static/locales/en.json | 12 +- frontend/static/locales/es.json | 12 +- frontend/static/locales/eu.json | 12 +- frontend/static/locales/fr.json | 12 +- frontend/static/locales/it.json | 12 +- frontend/static/locales/pl.json | 12 +- frontend/static/locales/pt.json | 12 +- frontend/static/locales/ru.json | 12 +- frontend/static/locales/sv.json | 12 +- frontend/static/locales/th.json | 12 +- frontend/static/locales/zh-SI.json | 12 +- frontend/static/locales/zh-TR.json | 12 +- 26 files changed, 408 insertions(+), 174 deletions(-) create mode 100644 frontend/src/utils/computeSats.ts diff --git a/frontend/src/basic/MakerPage/index.tsx b/frontend/src/basic/MakerPage/index.tsx index 2cf5c3d0..74ecd9bf 100644 --- a/frontend/src/basic/MakerPage/index.tsx +++ b/frontend/src/basic/MakerPage/index.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useState } from 'react'; +import React, { useContext, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useHistory } from 'react-router-dom'; import { Grid, Paper, Collapse, Typography } from '@mui/material'; @@ -32,17 +32,23 @@ const MakerPage = (): JSX.Element => { const [showMatches, setShowMatches] = useState(false); const [openNoRobot, setOpenNoRobot] = useState(false); - const matches = filterOrders({ - orders: book.orders, - baseFilter: { currency: fav.currency === 0 ? 1 : fav.currency, type: fav.type, mode: fav.mode }, - paymentMethods: maker.paymentMethods, - amountFilter: { - amount: maker.amount, - minAmount: maker.minAmount, - maxAmount: maker.maxAmount, - threshold: 0.7, - }, - }); + const matches = useMemo(() => { + return filterOrders({ + orders: book.orders, + baseFilter: { + currency: fav.currency === 0 ? 1 : fav.currency, + type: fav.type, + mode: fav.mode, + }, + paymentMethods: maker.paymentMethods, + amountFilter: { + amount: maker.amount, + minAmount: maker.minAmount, + maxAmount: maker.maxAmount, + threshold: 0.7, + }, + }); + }, [book.orders, fav, maker.amount, maker.minAmount, maker.maxAmount]); const onViewOrder = function () { setOrder(undefined); diff --git a/frontend/src/basic/OrderPage/index.tsx b/frontend/src/basic/OrderPage/index.tsx index d9558e85..2f9d5805 100644 --- a/frontend/src/basic/OrderPage/index.tsx +++ b/frontend/src/basic/OrderPage/index.tsx @@ -16,6 +16,7 @@ interface OrderPageProps { const OrderPage = ({ locationOrderId }: OrderPageProps): JSX.Element => { const { windowSize, + info, order, robot, settings, @@ -103,7 +104,7 @@ const OrderPage = ({ locationOrderId }: OrderPageProps): JSX.Element => { order={order} setOrder={setOrder} baseUrl={baseUrl} - setPage={setPage} + info={info} hasRobot={robot.avatarLoaded} /> @@ -156,7 +157,7 @@ const OrderPage = ({ locationOrderId }: OrderPageProps): JSX.Element => { order={order} setOrder={setOrder} baseUrl={baseUrl} - setPage={setPage} + info={info} hasRobot={robot.avatarLoaded} /> @@ -188,7 +189,7 @@ const OrderPage = ({ locationOrderId }: OrderPageProps): JSX.Element => { order={order} setOrder={setOrder} baseUrl={baseUrl} - setPage={setPage} + info={info} hasRobot={robot.avatarLoaded} /> diff --git a/frontend/src/components/Dialogs/Confirmation.tsx b/frontend/src/components/Dialogs/Confirmation.tsx index 27b1841e..ee72dd13 100644 --- a/frontend/src/components/Dialogs/Confirmation.tsx +++ b/frontend/src/components/Dialogs/Confirmation.tsx @@ -5,7 +5,6 @@ import { Page } from '../../basic/NavBar'; interface ConfirmationDialogProps { open: boolean; onClose: () => void; - setPage: (state: Page) => void; onClickDone: () => void; hasRobot: boolean; } @@ -14,7 +13,6 @@ const ConfirmationDialog = ({ open, onClose, hasRobot, - setPage, onClickDone, }: ConfirmationDialogProps): JSX.Element => { return hasRobot ? ( @@ -25,7 +23,7 @@ const ConfirmationDialog = ({ onClickDone={onClickDone} /> ) : ( - + ); }; diff --git a/frontend/src/components/Dialogs/NoRobot.tsx b/frontend/src/components/Dialogs/NoRobot.tsx index 98e7a677..7ee82d8a 100644 --- a/frontend/src/components/Dialogs/NoRobot.tsx +++ b/frontend/src/components/Dialogs/NoRobot.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; import { Dialog, @@ -9,15 +9,15 @@ import { Button, } from '@mui/material'; import { useHistory } from 'react-router-dom'; -import { Page } from '../../basic/NavBar'; +import { AppContext, AppContextProps } from '../../contexts/AppContext'; interface Props { open: boolean; onClose: () => void; - setPage: (state: Page) => void; } -const NoRobotDialog = ({ open, onClose, setPage }: Props): JSX.Element => { +const NoRobotDialog = ({ open, onClose }: Props): JSX.Element => { + const { setPage } = useContext(AppContext); const { t } = useTranslation(); const history = useHistory(); diff --git a/frontend/src/components/MakerForm/MakerForm.tsx b/frontend/src/components/MakerForm/MakerForm.tsx index ed504979..90171fad 100644 --- a/frontend/src/components/MakerForm/MakerForm.tsx +++ b/frontend/src/components/MakerForm/MakerForm.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from 'react'; +import React, { useContext, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { InputAdornment, @@ -25,7 +25,7 @@ import { IconButton, } from '@mui/material'; -import { LimitList, Maker, Favorites, defaultMaker } from '../../models'; +import { LimitList, defaultMaker } from '../../models'; import { LocalizationProvider, TimePicker } from '@mui/x-date-pickers'; import DateFnsUtils from '@date-io/date-fns'; @@ -36,7 +36,7 @@ import { FlagWithProps } from '../Icons'; import AutocompletePayments from './AutocompletePayments'; import AmountRange from './AmountRange'; import currencyDict from '../../../static/assets/currencies.json'; -import { amountToString, pn } from '../../utils'; +import { amountToString, computeSats, pn } from '../../utils'; import { SelfImprovement, Lock, HourglassTop, DeleteSweep, Edit } from '@mui/icons-material'; import { LoadingButton } from '@mui/lab'; @@ -63,7 +63,7 @@ const MakerForm = ({ onOrderCreated = () => null, hasRobot = true, }: MakerFormProps): JSX.Element => { - const { fav, setFav, limits, fetchLimits, maker, setMaker, setPage, baseUrl } = + const { fav, setFav, limits, info, maker, setMaker, setPage, baseUrl } = useContext(AppContext); const { t } = useTranslation(); @@ -81,23 +81,6 @@ const MakerForm = ({ const minRangeAmountMultiple = 1.6; const amountSafeThresholds = [1.03, 0.98]; - useEffect(() => { - setCurrencyCode(currencyDict[fav.currency == 0 ? 1 : fav.currency]); - if (Object.keys(limits.list).length === 0) { - fetchLimits().then((data) => { - updateAmountLimits(data, fav.currency, maker.premium); - updateCurrentPrice(data, fav.currency, maker.premium); - updateSatoshisLimits(data); - }); - } else { - updateAmountLimits(limits.list, fav.currency, maker.premium); - updateCurrentPrice(limits.list, fav.currency, maker.premium); - updateSatoshisLimits(limits.list); - - fetchLimits(); - } - }, []); - const updateAmountLimits = function (limitList: LimitList, currency: number, premium: number) { const index = currency == 0 ? 1 : currency; let minAmountLimit: number = limitList[index].min_amount * (1 + premium / 100); @@ -175,7 +158,7 @@ const MakerForm = ({ }; const handlePremiumChange = function (e: object) { - const max = 999; + const max = fav.mode === 'fiat' ? 999 : 99; const min = -100; const newPremium = Math.floor(e.target.value * Math.pow(10, 2)) / Math.pow(10, 2); let premium: number = newPremium; @@ -299,23 +282,23 @@ const MakerForm = ({ } }; - const minAmountError = function () { + const minAmountError = useMemo(() => { return ( maker.minAmount < amountLimits[0] * 0.99 || maker.maxAmount < maker.minAmount || maker.minAmount < maker.maxAmount / (maxRangeAmountMultiple + 0.15) || maker.minAmount * (minRangeAmountMultiple - 0.1) > maker.maxAmount ); - }; + }, [maker.minAmount, maker.maxAmount, amountLimits]); - const maxAmountError = function () { + const maxAmountError = useMemo(() => { return ( maker.maxAmount > amountLimits[1] * 1.01 || maker.maxAmount < maker.minAmount || maker.minAmount < maker.maxAmount / (maxRangeAmountMultiple + 0.15) || maker.minAmount * (minRangeAmountMultiple - 0.1) > maker.maxAmount ); - }; + }, [maker.minAmount, maker.maxAmount, amountLimits]); const resetRange = function (advancedOptions: boolean) { const index = fav.currency === 0 ? 1 : fav.currency; @@ -368,19 +351,51 @@ const MakerForm = ({ }); }; - const disableSubmit = function () { + const amountLabel = useMemo(() => { + const defaultRoutingBudget = 0.001; + let label = t('Amount'); + let helper = ''; + let swapSats = 0; + if (fav.mode === 'swap') { + if (fav.type === 1) { + swapSats = computeSats({ + amount: Number(maker.amount), + premium: Number(maker.premium), + fee: -info.maker_fee, + routingBudget: defaultRoutingBudget, + }); + label = t('Onchain amount to send (BTC)'); + helper = t('You receive approx {{swapSats}} LN Sats (fees might vary)', { + swapSats, + }); + } else if (fav.type === 0) { + swapSats = computeSats({ + amount: Number(maker.amount), + premium: Number(maker.premium), + fee: info.maker_fee, + }); + label = t('Onchain amount to receive (BTC)'); + helper = t('You send approx {{swapSats}} LN Sats (fees might vary)', { + swapSats, + }); + } + } + return { label, helper, swapSats }; + }, [fav, maker.amount, maker.premium, info]); + + const disableSubmit = useMemo(() => { return ( fav.type == null || (maker.amount != '' && !maker.advancedOptions && (maker.amount < amountLimits[0] || maker.amount > amountLimits[1])) || (maker.amount == null && (!maker.advancedOptions || limits.loading)) || - (maker.advancedOptions && (minAmountError() || maxAmountError())) || + (maker.advancedOptions && (minAmountError || maxAmountError)) || (maker.amount <= 0 && !maker.advancedOptions) || (maker.isExplicit && (maker.badSatoshisText != '' || maker.satoshis == '')) || (!maker.isExplicit && maker.badPremiumText != '') ); - }; + }, [maker, amountLimits, limits, fav.type]); const clearMaker = function () { setFav({ ...fav, type: null }); @@ -393,7 +408,7 @@ const MakerForm = ({ component='h2' variant='subtitle2' align='center' - color={disableSubmit() ? 'text.secondary' : 'text.primary'} + color={disableSubmit ? 'text.secondary' : 'text.primary'} > {fav.type == null ? t(fav.mode === 'fiat' ? 'Order for ' : 'Swap of ') @@ -553,7 +568,7 @@ const MakerForm = ({ - + @@ -572,7 +587,7 @@ const MakerForm = ({ - + setMaker({ ...maker, amount: e.target.value })} /> + {fav.mode === 'swap' && maker.amount != '' ? ( + + {amountLabel.helper} + + ) : null} - - - + {fav.mode === 'fiat' ? ( + + + + ) : null} @@ -914,7 +941,7 @@ const MakerForm = ({ {/* conditions to disable the make button */} - {disableSubmit() ? ( + {disableSubmit ? (