From 6d2ec4b08fba3fb2f88088247ed45e8be6becc7b Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 12:18:29 +0200 Subject: [PATCH 01/21] refactor(send): use util function to shorten address --- src/components/Send/ShowUtxos.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 03eacd75b..c2b8cf64a 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -13,9 +13,10 @@ import Balance from '../Balance' import { ConfirmModal } from '../Modal' import Sprite from '../Sprite' import { utxoTags } from '../jar_details/UtxoList' +import { UtxoList } from './SourceJarSelector' +import { shortenStringMiddle } from '../../utils' import mainStyles from '../MainWalletView.module.css' import styles from './ShowUtxos.module.css' -import { UtxoList } from './SourceJarSelector' interface ShowUtxosProps { isOpen: boolean @@ -55,9 +56,6 @@ interface DividerProps { className?: string } -// Utility function to format Bitcoin address -const formatAddress = (address: string) => `${address.slice(0, 10)}...${address.slice(-8)}` - // Utility function to format the confirmations const formatConfirmations = (conf: number) => { if (conf === 0) return { symbol: 'confs-0', confirmations: conf } @@ -106,7 +104,7 @@ const UtxoRow = memo( }: UtxoRowProps) => { const { address: utxoAddress, confirmations, value, checked, frozen } = utxo - const address = useMemo(() => formatAddress(utxoAddress), [utxoAddress]) + const address = useMemo(() => shortenStringMiddle(utxoAddress, 16), [utxoAddress]) const conf = useMemo(() => formatConfirmations(confirmations), [confirmations]) const valueString = useMemo(() => satsToBtc(value).toString(), [value]) const tag = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t]) From 8d4868b5e474143d3b935f1c05936c851c05bfcf Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 14:57:30 +0200 Subject: [PATCH 02/21] refactor(Send): rectify utxos fallback icon --- public/sprite.svg | 2 +- src/components/Send/ShowUtxos.tsx | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/public/sprite.svg b/public/sprite.svg index c520136c1..61caf4245 100644 --- a/public/sprite.svg +++ b/public/sprite.svg @@ -364,7 +364,7 @@ - + diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index c2b8cf64a..bffbb4acf 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -75,9 +75,10 @@ const satsToBtc = (sats: number) => (sats / 100000000).toFixed(8) const utxoIcon = (tag: string, isFrozen: boolean) => { if (isFrozen && tag === 'bond') return 'timelock' if (isFrozen) return 'snowflake' - if (tag === 'deposit' || tag === 'non-cj-change' || tag === 'reused') return 'Unmixed' if (tag === 'bond') return 'timelock' - return 'mixed' + if (tag === 'cj-out') return 'mixed' + if (tag === 'deposit' || tag === 'non-cj-change' || tag === 'reused') return 'unmixed' + return 'unmixed' // fallback } // Utility function to allot classes @@ -111,7 +112,7 @@ const UtxoRow = memo( const { icon, rowAndTagClass } = useMemo(() => { if (tag.length === 0) { - return { icon: 'Unmixed', rowAndTagClass: { row: styles.depositUtxo, tag: styles.utxoTagDeposit } } + return { icon: 'unmixed', rowAndTagClass: { row: styles.depositUtxo, tag: styles.utxoTagDeposit } } } return { icon: utxoIcon(tag[0].tag, isFrozen), rowAndTagClass: allotClasses(tag[0].tag, isFrozen) } }, [tag, isFrozen]) From 82365198864164578ca0c03f7613d31454242616 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 15:27:22 +0200 Subject: [PATCH 03/21] refactor(balance): split styles for balance color and spacing --- src/components/Balance.module.css | 36 +++++++++++++++---------------- src/components/Balance.tsx | 18 ++++++++-------- src/components/Send/ShowUtxos.tsx | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/components/Balance.module.css b/src/components/Balance.module.css index 013532ecd..d3051b06b 100644 --- a/src/components/Balance.module.css +++ b/src/components/Balance.module.css @@ -18,7 +18,7 @@ --jam-balance-deemphasize-color: #1153b5; } -.balance { +.balanceColor { color: var(--jam-balance-color); } @@ -53,32 +53,32 @@ justify-content: center; } -.bitcoinAmount .fractionalPart :nth-child(3)::before, -.bitcoinAmount .fractionalPart :nth-child(6)::before { +.bitcoinAmountSpacing .fractionalPart :nth-child(3)::before, +.bitcoinAmountSpacing .fractionalPart :nth-child(6)::before { content: '\202F'; } /** Integer Part **/ -.bitcoinAmount[data-integer-part-is-zero="true"] .integerPart, +.bitcoinAmountColor[data-integer-part-is-zero="true"] .integerPart, /** Decimal Point **/ -.bitcoinAmount[data-integer-part-is-zero="true"] .decimalPoint, -.bitcoinAmount[data-fractional-part-starts-with-zero="true"] .decimalPoint, +.bitcoinAmountColor[data-integer-part-is-zero="true"] .decimalPoint, +.bitcoinAmountColor[data-fractional-part-starts-with-zero="true"] .decimalPoint, /** Fractional Part **/ -.bitcoinAmount[data-integer-part-is-zero="false"] .fractionalPart, -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]), -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"], -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"], -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], -.bitcoinAmount[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], +.bitcoinAmountColor[data-integer-part-is-zero="false"] .fractionalPart, +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]), +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"], +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"], +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], +.bitcoinAmountColor[data-integer-part-is-zero="true"] .fractionalPart :nth-child(1):is(span[data-digit="0"]) + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"] + span[data-digit="0"], /** Symbol */ -.bitcoinAmount[data-raw-value="0"] + .bitcoinSymbol { +.bitcoinAmountColor[data-raw-value="0"] + .bitcoinSymbol { color: var(--jam-balance-deemphasize-color); } -.satsAmount[data-raw-value='0'], -.satsAmount[data-raw-value='0'] + .satsSymbol { +.satsAmountColor[data-raw-value='0'], +.satsAmountColor[data-raw-value='0'] + .satsSymbol { color: var(--jam-balance-deemphasize-color); } diff --git a/src/components/Balance.tsx b/src/components/Balance.tsx index 645ee00a0..abf9143c3 100644 --- a/src/components/Balance.tsx +++ b/src/components/Balance.tsx @@ -39,7 +39,7 @@ interface BalanceComponentProps { symbol?: JSX.Element showSymbol?: boolean frozen?: boolean - isColorChange?: boolean + colored?: boolean frozenSymbol?: boolean } @@ -47,7 +47,7 @@ const BalanceComponent = ({ symbol, showSymbol = true, frozen = false, - isColorChange = false, + colored = true, frozenSymbol = true, children, }: PropsWithChildren) => { @@ -55,7 +55,7 @@ const BalanceComponent = ({ {children} @@ -69,7 +69,7 @@ const DECIMAL_POINT_CHAR = '.' type BitcoinBalanceProps = Omit & { value: number } -const BitcoinBalance = ({ value, ...props }: BitcoinBalanceProps) => { +const BitcoinBalance = ({ value, colored = true, ...props }: BitcoinBalanceProps) => { const numberString = formatBtc(value) const [integerPart, fractionalPart] = numberString.split(DECIMAL_POINT_CHAR) @@ -78,10 +78,10 @@ const BitcoinBalance = ({ value, ...props }: BitcoinBalanceProps) => { const fractionalPartStartsWithZero = fractionPartArray[0] === '0' return ( - + { type SatsBalanceProps = Omit & { value: number } -const SatsBalance = ({ value, ...props }: SatsBalanceProps) => { +const SatsBalance = ({ value, colored = true, ...props }: SatsBalanceProps) => { return ( diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index bffbb4acf..4f0de84ea 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -179,7 +179,7 @@ const UtxoRow = memo( valueString={valueString} convertToUnit={settings.unit} showBalance={true} - isColorChange={true} + colored={false} frozen={isFrozen} frozenSymbol={false} /> From bcd8989f9462e3e117665e06b1ecdff1a51b8af2 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 15:46:37 +0200 Subject: [PATCH 04/21] refactor(send): slashed-zeroes style for addresses --- src/components/Send/ShowUtxos.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 4f0de84ea..39fa54953 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -170,7 +170,7 @@ const UtxoRow = memo( - {address} + {address} @@ -224,7 +224,7 @@ const UtxoListDisplay = ({ return (
From 84e01b838e66c7ad6843b273085cd707f9c610d9 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 16:32:49 +0200 Subject: [PATCH 05/21] refactor(send): reset amount value in InnerSendForm instead of AmountInputField --- src/components/Send/AmountInputField.tsx | 21 +------------------- src/components/Send/SendForm.tsx | 25 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/components/Send/AmountInputField.tsx b/src/components/Send/AmountInputField.tsx index 522f53812..e16a89340 100644 --- a/src/components/Send/AmountInputField.tsx +++ b/src/components/Send/AmountInputField.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef } from 'react' +import { useRef } from 'react' import { useTranslation } from 'react-i18next' import * as rb from 'react-bootstrap' import { useField, useFormikContext } from 'formik' @@ -35,25 +35,6 @@ export const AmountInputField = ({ const form = useFormikContext() const ref = useRef(null) - //Effect to change the field value whenever the sourceJarBalance changes (sourceJarBalance will change when quick freeze/unfreeze is performed or different source jar is selected) - useEffect(() => { - if (!sourceJarBalance) return - - const currentValue = formatBtcDisplayValue(sourceJarBalance.calculatedAvailableBalanceInSats) - - if (field.value?.isSweep && field.value.displayValue !== currentValue) { - form.setFieldValue( - field.name, - { - value: 0, - isSweep: true, - displayValue: formatBtcDisplayValue(sourceJarBalance.calculatedAvailableBalanceInSats), - }, - true, - ) - } - }, [sourceJarBalance, field, form]) - return ( <> diff --git a/src/components/Send/SendForm.tsx b/src/components/Send/SendForm.tsx index 7eeaf130b..5d051b7ea 100644 --- a/src/components/Send/SendForm.tsx +++ b/src/components/Send/SendForm.tsx @@ -1,6 +1,6 @@ -import { useState, useMemo } from 'react' +import { useState, useMemo, useEffect } from 'react' import { Trans, useTranslation } from 'react-i18next' -import { Field, Formik, FormikErrors, FormikProps } from 'formik' +import { Field, Formik, FormikErrors, FormikProps, useField } from 'formik' import * as rb from 'react-bootstrap' import * as Api from '../../libs/JmWalletApi' import ToggleSwitch from '../ToggleSwitch' @@ -243,6 +243,9 @@ const InnerSendForm = ({ }: InnerSendFormProps) => { const { t } = useTranslation() const serviceInfo = useServiceInfo() + const amountField = useField('amount') + const amountMeta = amountField[1] + const amountHelper = amountField[2] const jarBalances = useMemo(() => { if (!walletInfo) return [] @@ -261,12 +264,26 @@ const InnerSendForm = ({ return buildCoinjoinRequirementSummary(sourceJarUtxos) }, [sourceJarUtxos]) - const sourceJarBalance = - props.values.sourceJarIndex !== undefined ? jarBalances[props.values.sourceJarIndex] : undefined + const sourceJarBalance = useMemo( + () => (props.values.sourceJarIndex !== undefined ? jarBalances[props.values.sourceJarIndex] : undefined), + [jarBalances, props.values.sourceJarIndex], + ) const showCoinjoinPreconditionViolationAlert = !isLoading && !disabled && props.values.isCoinJoin && sourceJarCoinjoinPreconditionSummary?.isFulfilled === false + //Effect to change the field value whenever the sourceJarBalance changes (sourceJarBalance will change when quick freeze/unfreeze is performed or different source jar is selected) + useEffect(() => { + if (!sourceJarBalance) return + amountHelper.setValue( + amountMeta.initialValue || { + value: null, + isSweep: false, + }, + true, + ) + }, [sourceJarBalance, amountHelper, amountMeta.initialValue]) + return ( <> From 1f3e5e2c4a67b7a6ad67df3c2a0d71b375447153 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 16:39:52 +0200 Subject: [PATCH 06/21] refactor(send): remove unnecessary function --- src/components/Send/ShowUtxos.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 39fa54953..3ed2d74cd 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -68,9 +68,6 @@ const formatConfirmations = (conf: number) => { return { symbol: 'confs-full', confirmations: conf } } -// Utility function to convert Satoshi to Bitcoin -const satsToBtc = (sats: number) => (sats / 100000000).toFixed(8) - // Utility function to Identifies Icons const utxoIcon = (tag: string, isFrozen: boolean) => { if (isFrozen && tag === 'bond') return 'timelock' @@ -107,7 +104,6 @@ const UtxoRow = memo( const address = useMemo(() => shortenStringMiddle(utxoAddress, 16), [utxoAddress]) const conf = useMemo(() => formatConfirmations(confirmations), [confirmations]) - const valueString = useMemo(() => satsToBtc(value).toString(), [value]) const tag = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t]) const { icon, rowAndTagClass } = useMemo(() => { @@ -176,7 +172,7 @@ const UtxoRow = memo( Date: Mon, 22 Jul 2024 16:41:14 +0200 Subject: [PATCH 07/21] refactor(send): fix sats value display color --- src/components/Balance.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Balance.tsx b/src/components/Balance.tsx index abf9143c3..82ec691a8 100644 --- a/src/components/Balance.tsx +++ b/src/components/Balance.tsx @@ -107,7 +107,7 @@ type SatsBalanceProps = Omit & { value: number const SatsBalance = ({ value, colored = true, ...props }: SatsBalanceProps) => { return ( - + Date: Mon, 22 Jul 2024 17:34:04 +0200 Subject: [PATCH 08/21] fix(send): loading state indicator of quick freeze/unfreeze --- src/components/Send/SourceJarSelector.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/Send/SourceJarSelector.tsx b/src/components/Send/SourceJarSelector.tsx index af6e9ccb5..d41ee2127 100644 --- a/src/components/Send/SourceJarSelector.tsx +++ b/src/components/Send/SourceJarSelector.tsx @@ -102,22 +102,21 @@ export const SourceJarSelector = ({ .map((utxo) => ({ utxo: utxo.utxo, freeze: true })) try { + setIsUtxosLoading(true) const res = await Promise.all([ ...frozenUtxosToUpdate.map((utxo) => Api.postFreeze({ ...wallet, signal: abortCtrl.signal }, utxo)), ...unFrozenUtxosToUpdate.map((utxo) => Api.postFreeze({ ...wallet, signal: abortCtrl.signal }, utxo)), ]) if (res.length !== 0) { - setIsUtxosLoading(true) await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal }) } setShowUtxos(undefined) + setIsUtxosLoading(false) } catch (err: any) { - if (!abortCtrl.signal.aborted) { - setAlert({ variant: 'danger', message: err.message, dismissible: true }) - } - } finally { + if (abortCtrl.signal.aborted) return + setAlert({ variant: 'danger', message: err.message, dismissible: true }) setIsUtxosLoading(false) } }, [frozenUtxos, unFrozenUtxos, wallet, reloadCurrentWalletInfo]) From 5f8b8765cf8a856caae15ba8c4a08f9f1f2b00b9 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 17:53:28 +0200 Subject: [PATCH 09/21] chore(send): jarIndex type as JarIndex instead of String --- src/components/Send/SourceJarSelector.tsx | 25 +++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/components/Send/SourceJarSelector.tsx b/src/components/Send/SourceJarSelector.tsx index d41ee2127..7e40a2e68 100644 --- a/src/components/Send/SourceJarSelector.tsx +++ b/src/components/Send/SourceJarSelector.tsx @@ -21,8 +21,8 @@ export type SourceJarSelectorProps = { } interface ShowUtxosProps { - jarIndex?: string - isOpen?: boolean + jarIndex: JarIndex + isOpen: boolean } export type UtxoList = Utxo[] @@ -41,8 +41,8 @@ export const SourceJarSelector = ({ const form = useFormikContext() const reloadCurrentWalletInfo = useReloadCurrentWalletInfo() - const [showUtxos, setShowUtxos] = useState(undefined) - const [alert, setAlert] = useState(undefined) + const [showUtxos, setShowUtxos] = useState() + const [alert, setAlert] = useState() const [isUtxosLoading, setIsUtxosLoading] = useState(false) const [unFrozenUtxos, setUnFrozenUtxos] = useState([]) const [frozenUtxos, setFrozenUtxos] = useState([]) @@ -55,16 +55,15 @@ export const SourceJarSelector = ({ }, [walletInfo]) useEffect(() => { - if (showUtxos?.jarIndex && walletInfo?.utxosByJar) { - const data = Object.entries(walletInfo.utxosByJar).find(([key]) => key === showUtxos.jarIndex) - const utxos: any = data ? data[1] : [] + if (walletInfo?.utxosByJar && showUtxos && showUtxos.jarIndex >= 0) { + const utxos = walletInfo.utxosByJar[showUtxos.jarIndex] const frozenUtxoList = utxos - .filter((utxo: any) => utxo.frozen) - .map((utxo: any) => ({ ...utxo, id: utxo.utxo, checked: false })) + .filter((utxo) => utxo.frozen) + .map((utxo) => ({ ...utxo, id: utxo.utxo, checked: false })) const unFrozenUtxosList = utxos - .filter((utxo: any) => !utxo.frozen) - .map((utxo: any) => ({ ...utxo, id: utxo.utxo, checked: true })) + .filter((utxo) => !utxo.frozen) + .map((utxo) => ({ ...utxo, id: utxo.utxo, checked: true })) setFrozenUtxos(frozenUtxoList) setUnFrozenUtxos(unFrozenUtxosList) @@ -133,7 +132,7 @@ export const SourceJarSelector = ({
{showUtxos?.isOpen && ( { setShowUtxos(undefined) @@ -171,7 +170,7 @@ export const SourceJarSelector = ({ it.calculatedTotalBalanceInSats > 0 ) { setShowUtxos({ - jarIndex: it.accountIndex.toString(), + jarIndex: it.accountIndex, isOpen: true, }) } From 67a7603b695b2e37d11e3ab422aa1312c609fbf4 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Mon, 22 Jul 2024 17:56:26 +0200 Subject: [PATCH 10/21] refactor(send): remove unnecessary type UtxoList --- src/components/Send/ShowUtxos.tsx | 11 +++++------ src/components/Send/SourceJarSelector.tsx | 8 +++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 3ed2d74cd..6f610c83b 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -6,14 +6,13 @@ import classNames from 'classnames' import { Table, Body, Row, Cell } from '@table-library/react-table-library/table' import { useTheme } from '@table-library/react-table-library/theme' import * as TableTypes from '@table-library/react-table-library/types/table' -import { WalletInfo, Utxo, useCurrentWalletInfo } from '../../context/WalletContext' +import { WalletInfo, Utxo, useCurrentWalletInfo, Utxos } from '../../context/WalletContext' import { useSettings, Settings } from '../../context/SettingsContext' import Alert from '../Alert' import Balance from '../Balance' import { ConfirmModal } from '../Modal' import Sprite from '../Sprite' import { utxoTags } from '../jar_details/UtxoList' -import { UtxoList } from './SourceJarSelector' import { shortenStringMiddle } from '../../utils' import mainStyles from '../MainWalletView.module.css' import styles from './ShowUtxos.module.css' @@ -24,10 +23,10 @@ interface ShowUtxosProps { onConfirm: () => void alert: SimpleAlert | undefined isLoading: boolean - frozenUtxos: UtxoList - unFrozenUtxos: UtxoList - setFrozenUtxos: (arg: UtxoList) => void - setUnFrozenUtxos: (arg: UtxoList) => void + frozenUtxos: Utxos + unFrozenUtxos: Utxos + setFrozenUtxos: (arg: Utxos) => void + setUnFrozenUtxos: (arg: Utxos) => void } interface UtxoRowProps { diff --git a/src/components/Send/SourceJarSelector.tsx b/src/components/Send/SourceJarSelector.tsx index 7e40a2e68..73118cb7d 100644 --- a/src/components/Send/SourceJarSelector.tsx +++ b/src/components/Send/SourceJarSelector.tsx @@ -3,7 +3,7 @@ import { useField, useFormikContext } from 'formik' import * as rb from 'react-bootstrap' import { jarFillLevel, SelectableJar } from '../jars/Jar' import { noop } from '../../utils' -import { WalletInfo, CurrentWallet, useReloadCurrentWalletInfo, Utxo } from '../../context/WalletContext' +import { WalletInfo, CurrentWallet, useReloadCurrentWalletInfo, Utxo, Utxos } from '../../context/WalletContext' import styles from './SourceJarSelector.module.css' import { ShowUtxos } from './ShowUtxos' import { useTranslation } from 'react-i18next' @@ -25,8 +25,6 @@ interface ShowUtxosProps { isOpen: boolean } -export type UtxoList = Utxo[] - export const SourceJarSelector = ({ name, label, @@ -44,8 +42,8 @@ export const SourceJarSelector = ({ const [showUtxos, setShowUtxos] = useState() const [alert, setAlert] = useState() const [isUtxosLoading, setIsUtxosLoading] = useState(false) - const [unFrozenUtxos, setUnFrozenUtxos] = useState([]) - const [frozenUtxos, setFrozenUtxos] = useState([]) + const [unFrozenUtxos, setUnFrozenUtxos] = useState([]) + const [frozenUtxos, setFrozenUtxos] = useState([]) const jarBalances = useMemo(() => { if (!walletInfo) return [] From 5ae4ce0687c189d8f5d823915b1e346a803066cb Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Tue, 6 Aug 2024 16:47:32 +0200 Subject: [PATCH 11/21] refactor(send): Confirmations component --- src/components/Send/ShowUtxos.tsx | 82 +++++++++++------------ src/components/Send/SourceJarSelector.tsx | 2 +- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 6f610c83b..0749f4ba8 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -55,18 +55,6 @@ interface DividerProps { className?: string } -// Utility function to format the confirmations -const formatConfirmations = (conf: number) => { - if (conf === 0) return { symbol: 'confs-0', confirmations: conf } - if (conf === 1) return { symbol: 'confs-1', confirmations: conf } - if (conf === 2) return { symbol: 'confs-2', confirmations: conf } - if (conf === 3) return { symbol: 'confs-3', confirmations: conf } - if (conf === 4) return { symbol: 'confs-4', confirmations: conf } - if (conf === 5) return { symbol: 'confs-5', confirmations: conf } - if (conf > 9999) return { symbol: 'confs-full', confirmations: '9999+' } - return { symbol: 'confs-full', confirmations: conf } -} - // Utility function to Identifies Icons const utxoIcon = (tag: string, isFrozen: boolean) => { if (isFrozen && tag === 'bond') return 'timelock' @@ -87,6 +75,45 @@ const allotClasses = (tag: string, isFrozen: boolean) => { return { row: styles.depositUtxo, tag: styles.utxoTagDeposit } } +interface ConfirmationFormat { + symbol: string + display: string + confirmations: number +} + +const formatConfirmations = (confirmations: number): ConfirmationFormat => ({ + symbol: `confs-${confirmations >= 6 ? 'full' : confirmations}`, + display: confirmations > 9999 ? `${Number(9999).toLocaleString()}+` : confirmations.toLocaleString(), + confirmations, +}) + +const Confirmations = ({ value }: { value: ConfirmationFormat }) => + value.confirmations > 9999 ? ( + {value.confirmations.toLocaleString()}} + > +
+ + {value.display} +
+
+ ) : ( +
+ + {value.display} +
+ ) + const UtxoRow = memo( ({ utxo, @@ -102,7 +129,7 @@ const UtxoRow = memo( const { address: utxoAddress, confirmations, value, checked, frozen } = utxo const address = useMemo(() => shortenStringMiddle(utxoAddress, 16), [utxoAddress]) - const conf = useMemo(() => formatConfirmations(confirmations), [confirmations]) + const confFormat = useMemo(() => formatConfirmations(confirmations), [confirmations]) const tag = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t]) const { icon, rowAndTagClass } = useMemo(() => { @@ -112,33 +139,6 @@ const UtxoRow = memo( return { icon: utxoIcon(tag[0].tag, isFrozen), rowAndTagClass: allotClasses(tag[0].tag, isFrozen) } }, [tag, isFrozen]) - const ConfirmationCell = () => - confirmations > 9999 ? ( - {confirmations}} - > -
- - {conf.confirmations} -
-
- ) : ( -
- - {conf.confirmations} -
- ) - return ( {address} - + { - if (walletInfo?.utxosByJar && showUtxos && showUtxos.jarIndex >= 0) { + if (walletInfo?.utxosByJar && showUtxos?.jarIndex !== undefined) { const utxos = walletInfo.utxosByJar[showUtxos.jarIndex] const frozenUtxoList = utxos From a5464dab479517a620dacf8fc4d7572b63c81f81 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Wed, 7 Aug 2024 14:58:31 +0200 Subject: [PATCH 12/21] refactor(send): make onToggle in ShowUtxos mandatory --- src/components/Send/ShowUtxos.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 0749f4ba8..2f26b3d4f 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -32,7 +32,7 @@ interface ShowUtxosProps { interface UtxoRowProps { utxo: Utxo utxoIndex: number - onToggle?: (index: number, isFrozen: boolean) => void + onToggle: (index: number, isFrozen: boolean) => void isFrozen: boolean settings: Settings showRadioButton: boolean @@ -43,7 +43,7 @@ interface UtxoRowProps { interface UtxoListDisplayProps { utxos: Array - onToggle?: (index: number, isFrozen: boolean) => void + onToggle: (index: number, isFrozen: boolean) => void settings: Settings showRadioButton: boolean showBackgroundColor: boolean @@ -145,7 +145,7 @@ const UtxoRow = memo( className={classNames(rowAndTagClass.row, 'cursor-pointer', { 'bg-transparent': !showBackgroundColor, })} - onClick={() => onToggle && onToggle(utxoIndex, frozen)} + onClick={() => onToggle(utxoIndex, frozen)} > {showRadioButton && ( @@ -154,7 +154,7 @@ const UtxoRow = memo( type="checkbox" checked={checked} onChange={() => { - onToggle && onToggle(utxoIndex, isFrozen) + onToggle(utxoIndex, isFrozen) }} className={classNames(isFrozen ? styles.squareFrozenToggleButton : styles.squareToggleButton, { [styles.selected]: checked, From e0ed6f8f5262c0e101ddbe0d4b02a4ab6df2ebbc Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Fri, 9 Aug 2024 14:22:36 +0200 Subject: [PATCH 13/21] refactor(send): provide selected utxos in confirm callback --- src/components/Send/ShowUtxos.tsx | 148 +++++++++------------- src/components/Send/SourceJarSelector.tsx | 120 ++++++++---------- src/i18n/locales/en/translation.json | 5 +- 3 files changed, 117 insertions(+), 156 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 2f26b3d4f..f03acf460 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, memo, useMemo } from 'react' +import { useState, useEffect, memo, useMemo } from 'react' import * as rb from 'react-bootstrap' import { useTranslation } from 'react-i18next' import type { TFunction } from 'i18next' @@ -19,21 +19,16 @@ import styles from './ShowUtxos.module.css' interface ShowUtxosProps { isOpen: boolean - onCancel: () => void - onConfirm: () => void - alert: SimpleAlert | undefined isLoading: boolean - frozenUtxos: Utxos - unFrozenUtxos: Utxos - setFrozenUtxos: (arg: Utxos) => void - setUnFrozenUtxos: (arg: Utxos) => void + utxos: Utxos + alert?: SimpleAlert + onCancel: () => void + onConfirm: (selectedUtxos: Utxos) => void } interface UtxoRowProps { - utxo: Utxo - utxoIndex: number - onToggle: (index: number, isFrozen: boolean) => void - isFrozen: boolean + utxo: SelectableUtxo + onToggle: (utxo: SelectableUtxo) => void settings: Settings showRadioButton: boolean showBackgroundColor: boolean @@ -42,8 +37,8 @@ interface UtxoRowProps { } interface UtxoListDisplayProps { - utxos: Array - onToggle: (index: number, isFrozen: boolean) => void + utxos: SelectableUtxo[] + onToggle: (utxo: SelectableUtxo) => void settings: Settings showRadioButton: boolean showBackgroundColor: boolean @@ -115,29 +110,17 @@ const Confirmations = ({ value }: { value: ConfirmationFormat }) => ) const UtxoRow = memo( - ({ - utxo, - utxoIndex, - onToggle, - isFrozen, - showRadioButton, - showBackgroundColor, - settings, - walletInfo, - t, - }: UtxoRowProps) => { - const { address: utxoAddress, confirmations, value, checked, frozen } = utxo - - const address = useMemo(() => shortenStringMiddle(utxoAddress, 16), [utxoAddress]) - const confFormat = useMemo(() => formatConfirmations(confirmations), [confirmations]) + ({ utxo, onToggle, showRadioButton, showBackgroundColor, settings, walletInfo, t }: UtxoRowProps) => { + const address = useMemo(() => shortenStringMiddle(utxo.address, 16), [utxo.address]) + const confFormat = useMemo(() => formatConfirmations(utxo.confirmations), [utxo.confirmations]) const tag = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t]) const { icon, rowAndTagClass } = useMemo(() => { if (tag.length === 0) { return { icon: 'unmixed', rowAndTagClass: { row: styles.depositUtxo, tag: styles.utxoTagDeposit } } } - return { icon: utxoIcon(tag[0].tag, isFrozen), rowAndTagClass: allotClasses(tag[0].tag, isFrozen) } - }, [tag, isFrozen]) + return { icon: utxoIcon(tag[0].tag, utxo.frozen), rowAndTagClass: allotClasses(tag[0].tag, utxo.frozen) } + }, [tag, utxo.frozen]) return ( onToggle(utxoIndex, frozen)} + onClick={() => onToggle(utxo)} > {showRadioButton && ( { - onToggle(utxoIndex, isFrozen) + onToggle(utxo) }} - className={classNames(isFrozen ? styles.squareFrozenToggleButton : styles.squareToggleButton, { - [styles.selected]: checked, + className={classNames(utxo.frozen ? styles.squareFrozenToggleButton : styles.squareToggleButton, { + [styles.selected]: utxo.checked, })} /> @@ -171,11 +154,11 @@ const UtxoRow = memo( @@ -213,9 +196,6 @@ const UtxoListDisplay = ({ } const tableTheme = useTheme(TABLE_THEME) - //Default sort is by date the older ones at the bottom, newer ones at the top. - utxos.sort((a, b) => a.confirmations - b.confirmations) - return (
- {(utxosList: TableTypes.TableProps) => ( + {(utxosList: TableTypes.TableProps) => ( {walletInfo && - utxosList.map((utxo: Utxo, index: number) => { + utxosList.map((utxo: SelectableUtxo, index: number) => { return ( { ) } -const ShowUtxos = ({ - isOpen, - onCancel, - onConfirm, - alert, - isLoading, - frozenUtxos, - unFrozenUtxos, - setFrozenUtxos, - setUnFrozenUtxos, -}: ShowUtxosProps) => { +type SelectableUtxo = Utxo & { checked: boolean } + +const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: ShowUtxosProps) => { const { t } = useTranslation() const settings = useSettings() - const [showFrozenUtxos, setShowFrozenUtxos] = useState(false) + const [showFrozenUtxos, setShowFrozenUtxos] = useState(false) - // Handler to toggle UTXO selection - const handleUtxoCheckedState = useCallback( - (utxoIndex: number, isFrozen: boolean) => { - if (!isFrozen) { - const utxos = unFrozenUtxos.map((utxo: Utxo, i: number) => - i === utxoIndex ? { ...utxo, checked: !utxo.checked } : utxo, - ) - setUnFrozenUtxos(utxos) - } else { - const utxos = frozenUtxos.map((utxo: Utxo, i: number) => - i === utxoIndex ? { ...utxo, checked: !utxo.checked } : utxo, - ) - setFrozenUtxos(utxos) - } - }, - [frozenUtxos, unFrozenUtxos, setUnFrozenUtxos, setFrozenUtxos], + const [upperUtxos, setUpperUtxos] = useState( + utxos + .filter((it) => !it.frozen) + .map((it) => ({ ...it, checked: true })) + .sort((a, b) => a.confirmations - b.confirmations), + ) + const [lowerUtxos, setLowerUtxos] = useState( + utxos + .filter((it) => it.frozen) + .map((it) => ({ ...it, checked: false })) + .sort((a, b) => a.confirmations - b.confirmations), + ) + + const selectedUtxos = useMemo( + () => [...upperUtxos, ...lowerUtxos].filter((it) => it.checked), + [upperUtxos, lowerUtxos], ) //Effect to hide the Divider line when there is no unFrozen-UTXOs present useEffect(() => { - if (unFrozenUtxos.length === 0 && frozenUtxos.length > 0) { + if (upperUtxos.length === 0 && lowerUtxos.length > 0) { setShowFrozenUtxos(true) } - }, [unFrozenUtxos.length, frozenUtxos.length]) + }, [upperUtxos.length, lowerUtxos.length]) return ( onConfirm(selectedUtxos)} + disabled={isLoading} isShown={isOpen} title={t('show_utxos.show_utxo_title')} size="lg" @@ -329,23 +299,27 @@ const ShowUtxos = ({ {!isLoading ? ( <>
- {unFrozenUtxos.length !== 0 + {upperUtxos.length !== 0 ? t('show_utxos.show_utxo_subtitle') : t('show_utxos.show_utxo_subtitle_when_allutxos_are_frozen')}
{alert && ( - + )} { + setUpperUtxos((current) => + current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), + ) + }} settings={settings} showRadioButton={true} showBackgroundColor={true} /> - {frozenUtxos.length > 0 && unFrozenUtxos.length > 0 && ( + {upperUtxos.length > 0 && lowerUtxos.length > 0 && ( { + setLowerUtxos((current) => + current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), + ) + }} settings={settings} showRadioButton={true} showBackgroundColor={true} diff --git a/src/components/Send/SourceJarSelector.tsx b/src/components/Send/SourceJarSelector.tsx index 6e5a94f28..a6e8e516b 100644 --- a/src/components/Send/SourceJarSelector.tsx +++ b/src/components/Send/SourceJarSelector.tsx @@ -1,9 +1,9 @@ -import { useState, useMemo, useCallback, useEffect } from 'react' +import { useState, useMemo, useCallback } from 'react' import { useField, useFormikContext } from 'formik' import * as rb from 'react-bootstrap' import { jarFillLevel, SelectableJar } from '../jars/Jar' import { noop } from '../../utils' -import { WalletInfo, CurrentWallet, useReloadCurrentWalletInfo, Utxo, Utxos } from '../../context/WalletContext' +import { WalletInfo, CurrentWallet, useReloadCurrentWalletInfo, Utxos } from '../../context/WalletContext' import styles from './SourceJarSelector.module.css' import { ShowUtxos } from './ShowUtxos' import { useTranslation } from 'react-i18next' @@ -21,8 +21,9 @@ export type SourceJarSelectorProps = { } interface ShowUtxosProps { - jarIndex: JarIndex - isOpen: boolean + utxos: Utxos + isLoading: boolean + alert?: SimpleAlert } export const SourceJarSelector = ({ @@ -40,10 +41,8 @@ export const SourceJarSelector = ({ const reloadCurrentWalletInfo = useReloadCurrentWalletInfo() const [showUtxos, setShowUtxos] = useState() - const [alert, setAlert] = useState() - const [isUtxosLoading, setIsUtxosLoading] = useState(false) - const [unFrozenUtxos, setUnFrozenUtxos] = useState([]) - const [frozenUtxos, setFrozenUtxos] = useState([]) + //const [unFrozenUtxos, setUnFrozenUtxos] = useState([]) + //const [frozenUtxos, setFrozenUtxos] = useState([]) const jarBalances = useMemo(() => { if (!walletInfo) return [] @@ -52,23 +51,7 @@ export const SourceJarSelector = ({ ) }, [walletInfo]) - useEffect(() => { - if (walletInfo?.utxosByJar && showUtxos?.jarIndex !== undefined) { - const utxos = walletInfo.utxosByJar[showUtxos.jarIndex] - - const frozenUtxoList = utxos - .filter((utxo) => utxo.frozen) - .map((utxo) => ({ ...utxo, id: utxo.utxo, checked: false })) - const unFrozenUtxosList = utxos - .filter((utxo) => !utxo.frozen) - .map((utxo) => ({ ...utxo, id: utxo.utxo, checked: true })) - - setFrozenUtxos(frozenUtxoList) - setUnFrozenUtxos(unFrozenUtxosList) - } - }, [walletInfo, showUtxos?.jarIndex, t]) - - useEffect(() => { + /*useEffect(() => { if (frozenUtxos.length === 0 && unFrozenUtxos.length === 0) { return } @@ -87,36 +70,44 @@ export const SourceJarSelector = ({ } else { setAlert(undefined) } - }, [frozenUtxos, unFrozenUtxos, t, setAlert]) - - const handleUtxosFrozenState = useCallback(async () => { - const abortCtrl = new AbortController() - const frozenUtxosToUpdate = frozenUtxos - .filter((utxo) => utxo.checked && !utxo.locktime) - .map((utxo) => ({ utxo: utxo.utxo, freeze: false })) - const unFrozenUtxosToUpdate = unFrozenUtxos - .filter((utxo) => !utxo.checked) - .map((utxo) => ({ utxo: utxo.utxo, freeze: true })) - - try { - setIsUtxosLoading(true) - const res = await Promise.all([ - ...frozenUtxosToUpdate.map((utxo) => Api.postFreeze({ ...wallet, signal: abortCtrl.signal }, utxo)), - ...unFrozenUtxosToUpdate.map((utxo) => Api.postFreeze({ ...wallet, signal: abortCtrl.signal }, utxo)), - ]) - - if (res.length !== 0) { - await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal }) - } + }, [frozenUtxos, unFrozenUtxos, t, setAlert])*/ - setShowUtxos(undefined) - setIsUtxosLoading(false) - } catch (err: any) { - if (abortCtrl.signal.aborted) return - setAlert({ variant: 'danger', message: err.message, dismissible: true }) - setIsUtxosLoading(false) - } - }, [frozenUtxos, unFrozenUtxos, wallet, reloadCurrentWalletInfo]) + const handleUtxosFrozenState = useCallback( + async (selectedUtxos: Utxos) => { + if (!showUtxos) return + + const abortCtrl = new AbortController() + + const selectedUtxosIds = selectedUtxos.map((it) => it.utxo) + const frozenUtxosToUnfreeze = selectedUtxos.filter((utxo) => utxo.frozen) + const unfrozenUtxosToFreeze = showUtxos.utxos + .filter((utxo) => !utxo.frozen) + .filter((it) => !selectedUtxosIds.includes(it.utxo)) + + try { + setShowUtxos({ ...showUtxos, isLoading: true, alert: undefined }) + + const res = await Promise.all([ + ...frozenUtxosToUnfreeze.map((utxo) => + Api.postFreeze({ ...wallet, signal: abortCtrl.signal }, { utxo: utxo.utxo, freeze: false }), + ), + ...unfrozenUtxosToFreeze.map((utxo) => + Api.postFreeze({ ...wallet, signal: abortCtrl.signal }, { utxo: utxo.utxo, freeze: true }), + ), + ]) + + if (res.length !== 0) { + await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal }) + } + + setShowUtxos(undefined) + } catch (err: any) { + if (abortCtrl.signal.aborted) return + setShowUtxos({ ...showUtxos, isLoading: false, alert: { variant: 'danger', message: err.message } }) + } + }, + [showUtxos, wallet, reloadCurrentWalletInfo], + ) return ( <> @@ -128,19 +119,14 @@ export const SourceJarSelector = ({ ) : (
- {showUtxos?.isOpen && ( + {showUtxos && ( { - setShowUtxos(undefined) - }} - alert={alert} - isLoading={isUtxosLoading} - frozenUtxos={frozenUtxos} - unFrozenUtxos={unFrozenUtxos} - setFrozenUtxos={setFrozenUtxos} - setUnFrozenUtxos={setUnFrozenUtxos} + onCancel={() => setShowUtxos(undefined)} /> )} {jarBalances.map((it) => { @@ -159,7 +145,7 @@ export const SourceJarSelector = ({ walletInfo.balanceSummary.calculatedTotalBalanceInSats, )} variant={it.accountIndex === field.value ? variant : undefined} - onClick={(jarIndex: number) => { + onClick={(jarIndex) => { form.setFieldValue(field.name, jarIndex, true) if ( it.accountIndex === field.value && @@ -168,8 +154,8 @@ export const SourceJarSelector = ({ it.calculatedTotalBalanceInSats > 0 ) { setShowUtxos({ - jarIndex: it.accountIndex, - isOpen: true, + utxos: walletInfo.utxosByJar[it.accountIndex], + isLoading: false, }) } }} diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index fcbdf99f4..00a3de510 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -706,9 +706,6 @@ "selected_utxos": "Selected UTXOs", "show_utxo_title": "Select UTXOs to be considered", "show_utxo_subtitle": "The following UTXOs are considered in the transaction. Every unselected UTXO will be frozen and can be unfrozen later on.", - "show_utxo_subtitle_when_allutxos_are_frozen": "The following UTXOs are frozen. Please select them to be considered in the transaction.", - "alert_for_unfreeze_utxos": "At least one UTXO is required to perform a transaction", - "alert_for_time_locked": "Selected UTXO is Time Locked till", - "alert_for_empty_utxos": "Please Unfreeze UTXOs to send" + "show_utxo_subtitle_when_allutxos_are_frozen": "The following UTXOs are frozen. Please select them to be considered in the transaction." } } From d6743f12b445ec09dfd18c5889a0d166e50a99f1 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Sun, 11 Aug 2024 15:30:27 +0200 Subject: [PATCH 14/21] refactor(send): handle timelocked utxos --- src/components/Send/ShowUtxos.tsx | 138 ++++++++++++++++-------------- 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index f03acf460..668c9fd65 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -30,7 +30,6 @@ interface UtxoRowProps { utxo: SelectableUtxo onToggle: (utxo: SelectableUtxo) => void settings: Settings - showRadioButton: boolean showBackgroundColor: boolean walletInfo: WalletInfo t: TFunction @@ -109,66 +108,65 @@ const Confirmations = ({ value }: { value: ConfirmationFormat }) =>
) -const UtxoRow = memo( - ({ utxo, onToggle, showRadioButton, showBackgroundColor, settings, walletInfo, t }: UtxoRowProps) => { - const address = useMemo(() => shortenStringMiddle(utxo.address, 16), [utxo.address]) - const confFormat = useMemo(() => formatConfirmations(utxo.confirmations), [utxo.confirmations]) - const tag = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t]) +const UtxoRow = memo(({ utxo, onToggle, showBackgroundColor, settings, walletInfo, t }: UtxoRowProps) => { + const address = useMemo(() => shortenStringMiddle(utxo.address, 16), [utxo.address]) + const confFormat = useMemo(() => formatConfirmations(utxo.confirmations), [utxo.confirmations]) + const tag = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t]) - const { icon, rowAndTagClass } = useMemo(() => { - if (tag.length === 0) { - return { icon: 'unmixed', rowAndTagClass: { row: styles.depositUtxo, tag: styles.utxoTagDeposit } } - } - return { icon: utxoIcon(tag[0].tag, utxo.frozen), rowAndTagClass: allotClasses(tag[0].tag, utxo.frozen) } - }, [tag, utxo.frozen]) + const { icon, rowAndTagClass } = useMemo(() => { + if (tag.length === 0) { + return { icon: 'unmixed', rowAndTagClass: { row: styles.depositUtxo, tag: styles.utxoTagDeposit } } + } + return { icon: utxoIcon(tag[0].tag, utxo.frozen), rowAndTagClass: allotClasses(tag[0].tag, utxo.frozen) } + }, [tag, utxo.frozen]) - return ( - onToggle(utxo)} - > - {showRadioButton && ( - - { - onToggle(utxo) - }} - className={classNames(utxo.frozen ? styles.squareFrozenToggleButton : styles.squareToggleButton, { - [styles.selected]: utxo.checked, - })} - /> - - )} - - - - {address} - - - - - utxo.selectable && onToggle(utxo)} + > + + {utxo.selectable && ( + utxo.selectable && onToggle(utxo)} + className={classNames(utxo.frozen ? styles.squareFrozenToggleButton : styles.squareToggleButton, { + [styles.selected]: utxo.checked, + })} /> - - -
{tag.length ? tag[0].tag : ''}
-
-
- ) - }, -) + )} + + + + + {address} + + + + + + + +
{tag.length ? tag[0].tag : ''}
+
+ + ) +}) const UtxoListDisplay = ({ utxos, @@ -213,7 +211,6 @@ const UtxoListDisplay = ({ key={index} utxo={utxo} onToggle={onToggle} - showRadioButton={showRadioButton} showBackgroundColor={showBackgroundColor} settings={settings} walletInfo={walletInfo} @@ -251,7 +248,7 @@ const Divider = ({ isState, setIsState, className }: DividerProps) => { ) } -type SelectableUtxo = Utxo & { checked: boolean } +type SelectableUtxo = Utxo & { checked: boolean; selectable: boolean } const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: ShowUtxosProps) => { const { t } = useTranslation() @@ -261,15 +258,24 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho const [upperUtxos, setUpperUtxos] = useState( utxos .filter((it) => !it.frozen) - .map((it) => ({ ...it, checked: true })) + .filter((it) => !it.locktime) + .map((it) => ({ ...it, checked: true, selectable: true })) .sort((a, b) => a.confirmations - b.confirmations), ) - const [lowerUtxos, setLowerUtxos] = useState( - utxos + const [lowerUtxos, setLowerUtxos] = useState(() => { + const frozenNonTimelockedUtxos = utxos .filter((it) => it.frozen) - .map((it) => ({ ...it, checked: false })) - .sort((a, b) => a.confirmations - b.confirmations), - ) + .filter((it) => !it.locktime) + .map((it) => ({ ...it, checked: false, selectable: true })) + .sort((a, b) => a.confirmations - b.confirmations) + + const timelockedUtxos = utxos + .filter((it) => it.locktime !== undefined) + .map((it) => ({ ...it, checked: false, selectable: false })) + .sort((a, b) => a.confirmations - b.confirmations) + + return [...frozenNonTimelockedUtxos, ...timelockedUtxos] + }) const selectedUtxos = useMemo( () => [...upperUtxos, ...lowerUtxos].filter((it) => it.checked), From 4a5129ebdc40fb1a16486455bdb7cbb1064ca8c8 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Sun, 11 Aug 2024 15:54:28 +0200 Subject: [PATCH 15/21] refator(send): use rb.Collapse for frozen utxos in modal --- src/components/Send/ShowUtxos.tsx | 69 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 668c9fd65..a2f14841a 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, memo, useMemo } from 'react' +import { useState, useEffect, useMemo } from 'react' import * as rb from 'react-bootstrap' import { useTranslation } from 'react-i18next' import type { TFunction } from 'i18next' @@ -44,8 +44,8 @@ interface UtxoListDisplayProps { } interface DividerProps { - isState: boolean - setIsState: (arg: boolean) => void + toggled: boolean + onToggle: (current: boolean) => void className?: string } @@ -108,7 +108,7 @@ const Confirmations = ({ value }: { value: ConfirmationFormat }) => ) -const UtxoRow = memo(({ utxo, onToggle, showBackgroundColor, settings, walletInfo, t }: UtxoRowProps) => { +const UtxoRow = ({ utxo, onToggle, showBackgroundColor, settings, walletInfo, t }: UtxoRowProps) => { const address = useMemo(() => shortenStringMiddle(utxo.address, 16), [utxo.address]) const confFormat = useMemo(() => formatConfirmations(utxo.confirmations), [utxo.confirmations]) const tag = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t]) @@ -166,7 +166,7 @@ const UtxoRow = memo(({ utxo, onToggle, showBackgroundColor, settings, walletInf ) -}) +} const UtxoListDisplay = ({ utxos, @@ -225,21 +225,14 @@ const UtxoListDisplay = ({ ) } -const Divider = ({ isState, setIsState, className }: DividerProps) => { - //Effect for getting back to it's original state when components unMounts - useEffect(() => { - return () => { - setIsState(false) - } - }, [setIsState]) - +const Divider = ({ toggled, onToggle, className }: DividerProps) => { return (

-
@@ -314,29 +307,11 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho
)} - { - setUpperUtxos((current) => - current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), - ) - }} - settings={settings} - showRadioButton={true} - showBackgroundColor={true} - /> - {upperUtxos.length > 0 && lowerUtxos.length > 0 && ( - - )} - {showFrozenUtxos && ( + { - setLowerUtxos((current) => + setUpperUtxos((current) => current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), ) }} @@ -344,7 +319,29 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho showRadioButton={true} showBackgroundColor={true} /> + + {upperUtxos.length > 0 && lowerUtxos.length > 0 && ( + setShowFrozenUtxos((current) => !current)} + className={`mt-4 ${showFrozenUtxos && 'mb-4'}`} + /> )} + + + { + setLowerUtxos((current) => + current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), + ) + }} + settings={settings} + showRadioButton={true} + showBackgroundColor={true} + /> + + ) : (
From d548f872740ff823dc48dcc745494667fc1a4434 Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Sun, 11 Aug 2024 16:32:34 +0200 Subject: [PATCH 16/21] chore(ui): externalize Divider component --- src/components/Divider.module.css | 32 +++++++++++++++++++++++ src/components/Divider.tsx | 27 +++++++++++++++++++ src/components/MainWalletView.module.css | 33 ------------------------ src/components/MainWalletView.tsx | 23 ++++++----------- src/components/Send/ShowUtxos.tsx | 24 +---------------- 5 files changed, 68 insertions(+), 71 deletions(-) create mode 100644 src/components/Divider.module.css create mode 100644 src/components/Divider.tsx diff --git a/src/components/Divider.module.css b/src/components/Divider.module.css new file mode 100644 index 000000000..814b9c424 --- /dev/null +++ b/src/components/Divider.module.css @@ -0,0 +1,32 @@ +.dividerContainer { + display: flex; + justify-content: space-between; + align-items: center; +} + +.dividerContainer .dividerLine { + margin: 0; + width: 50%; + flex-grow: 0; + flex-shrink: 1; +} + +.dividerContainer .dividerButton { + display: flex; + justify-content: center; + align-items: center; + margin: 0 1rem; + flex-shrink: 0; + flex-grow: 1; + color: var(--bs-body-color); + cursor: pointer; + background-color: transparent; + border: 1px solid var(--bs-body-color); + border-radius: 50%; + width: 2rem; + height: 2rem; +} + +.dividerContainer .dividerButton:disabled { + cursor: not-allowed; +} diff --git a/src/components/Divider.tsx b/src/components/Divider.tsx new file mode 100644 index 000000000..317f83040 --- /dev/null +++ b/src/components/Divider.tsx @@ -0,0 +1,27 @@ +import * as rb from 'react-bootstrap' +import classNames from 'classnames' +import Sprite from './Sprite' +import styles from './Divider.module.css' + +type DividerProps = rb.ColProps & { + toggled: boolean + onToggle: (current: boolean) => void + disabled?: boolean + className?: string +} + +export default function Divider({ toggled, onToggle, disabled, className, ...colProps }: DividerProps) { + return ( + + +
+
+ +
+
+
+
+ ) +} diff --git a/src/components/MainWalletView.module.css b/src/components/MainWalletView.module.css index 893522a16..746af3fcd 100644 --- a/src/components/MainWalletView.module.css +++ b/src/components/MainWalletView.module.css @@ -27,36 +27,3 @@ width: 100%; height: 3.5rem; } - -.jarsDividerContainer { - display: flex; - justify-content: space-between; - align-items: center; -} - -.jarsDividerContainer .dividerLine { - margin: 0; - width: 50%; - flex-grow: 0; - flex-shrink: 1; -} - -.jarsDividerContainer .dividerButton { - display: flex; - justify-content: center; - align-items: center; - margin: 0 1rem; - flex-shrink: 0; - flex-grow: 1; - color: var(--bs-body-color); - cursor: pointer; - background-color: transparent; - border: 1px solid var(--bs-body-color); - border-radius: 50%; - width: 2rem; - height: 2rem; -} - -.jarsDividerContainer .dividerButton:disabled { - cursor: not-allowed; -} diff --git a/src/components/MainWalletView.tsx b/src/components/MainWalletView.tsx index efadf1d18..dc74df223 100644 --- a/src/components/MainWalletView.tsx +++ b/src/components/MainWalletView.tsx @@ -13,6 +13,7 @@ import { ExtendedLink } from './ExtendedLink' import { JarDetailsOverlay } from './jar_details/JarDetailsOverlay' import { Jars } from './Jars' import styles from './MainWalletView.module.css' +import Divider from './Divider' interface WalletHeaderProps { walletName: string @@ -226,21 +227,13 @@ export default function MainWalletView({ wallet }: MainWalletViewProps) {
- - -
-
- -
-
-
-
+ setShowJars((current) => !current)} + disabled={serviceInfo?.rescanning} + xs={showJars ? 12 : 10} + md={showJars ? 12 : 8} + /> ) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index a2f14841a..5f3891892 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -10,11 +10,11 @@ import { WalletInfo, Utxo, useCurrentWalletInfo, Utxos } from '../../context/Wal import { useSettings, Settings } from '../../context/SettingsContext' import Alert from '../Alert' import Balance from '../Balance' +import Divider from '../Divider' import { ConfirmModal } from '../Modal' import Sprite from '../Sprite' import { utxoTags } from '../jar_details/UtxoList' import { shortenStringMiddle } from '../../utils' -import mainStyles from '../MainWalletView.module.css' import styles from './ShowUtxos.module.css' interface ShowUtxosProps { @@ -43,12 +43,6 @@ interface UtxoListDisplayProps { showBackgroundColor: boolean } -interface DividerProps { - toggled: boolean - onToggle: (current: boolean) => void - className?: string -} - // Utility function to Identifies Icons const utxoIcon = (tag: string, isFrozen: boolean) => { if (isFrozen && tag === 'bond') return 'timelock' @@ -225,22 +219,6 @@ const UtxoListDisplay = ({ ) } -const Divider = ({ toggled, onToggle, className }: DividerProps) => { - return ( - - -
-
- -
-
-
-
- ) -} - type SelectableUtxo = Utxo & { checked: boolean; selectable: boolean } const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: ShowUtxosProps) => { From b4022e6741a3efb4e96c0d1253b6c73067b8b41f Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Sun, 11 Aug 2024 17:03:22 +0200 Subject: [PATCH 17/21] chore(send): prevent flickering when frozen utxos appear --- src/components/Send/ShowUtxos.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 5f3891892..3f3d1d6fb 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -224,7 +224,6 @@ type SelectableUtxo = Utxo & { checked: boolean; selectable: boolean } const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: ShowUtxosProps) => { const { t } = useTranslation() const settings = useSettings() - const [showFrozenUtxos, setShowFrozenUtxos] = useState(false) const [upperUtxos, setUpperUtxos] = useState( utxos @@ -252,13 +251,7 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho () => [...upperUtxos, ...lowerUtxos].filter((it) => it.checked), [upperUtxos, lowerUtxos], ) - - //Effect to hide the Divider line when there is no unFrozen-UTXOs present - useEffect(() => { - if (upperUtxos.length === 0 && lowerUtxos.length > 0) { - setShowFrozenUtxos(true) - } - }, [upperUtxos.length, lowerUtxos.length]) + const [showFrozenUtxos, setShowFrozenUtxos] = useState(upperUtxos.length === 0 && lowerUtxos.length > 0) return (
- {upperUtxos.length !== 0 + {upperUtxos.length > 0 ? t('show_utxos.show_utxo_subtitle') : t('show_utxos.show_utxo_subtitle_when_allutxos_are_frozen')}
From c790207961e61a65435e2d11178640540864b4ac Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Sun, 11 Aug 2024 17:57:39 +0200 Subject: [PATCH 18/21] refactor(modal): custom component for quick freeze utxos modal --- src/components/Modal.module.css | 10 +- src/components/Modal.tsx | 48 ++++--- src/components/Send/ShowUtxos.tsx | 119 ++++++++++-------- .../settings/FeeConfigModal.module.css | 1 - src/components/settings/FeeConfigModal.tsx | 2 +- 5 files changed, 95 insertions(+), 85 deletions(-) diff --git a/src/components/Modal.module.css b/src/components/Modal.module.css index 40ca36445..6c2dee561 100644 --- a/src/components/Modal.module.css +++ b/src/components/Modal.module.css @@ -8,7 +8,7 @@ box-shadow: 0px 0px 24px rgba(0, 0, 0, 0.25) !important; } -.modal-header { +.modalHeader { display: flex !important; justify-content: center !important; background-color: transparent !important; @@ -16,20 +16,20 @@ padding: 1.25rem 1.25rem 0 1.25rem !important; } -.modal-title { +.modalTitle { font-size: 1.3rem !important; font-weight: 600 !important; color: var(--bs-body-color) !important; } -.modal-body { +.modalBody { text-align: center !important; font-size: 1rem !important; font-weight: 400 !important; padding: 0.25rem 1.25rem 1rem 1.25rem !important; } -.modal-footer { +.modalFooter { display: flex !important; justify-content: center !important; gap: 1rem; @@ -37,7 +37,7 @@ padding: 1rem 1.25rem 1.25rem 1.25rem !important; } -.modal-footer :global .btn { +.modalFooter :global .btn { --bs-btn-border-color: var(--bs-border-color); flex-grow: 1; min-height: 2.8rem; diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 40e7c4b36..cbf87fafd 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -1,19 +1,18 @@ import { ReactNode, PropsWithChildren } from 'react' import * as rb from 'react-bootstrap' import { useTranslation } from 'react-i18next' -import styles from './Modal.module.css' import Sprite from './Sprite' +import styles from './Modal.module.css' + +type BaseModalProps = Pick & + Pick & { + isShown: boolean + title: ReactNode | string + onCancel: () => void + headerClassName?: rb.ModalHeaderProps['className'] + titleClassName?: rb.ModalTitleProps['className'] + } -type BaseModalProps = { - isShown: boolean - title: ReactNode | string - onCancel: () => void - backdrop?: rb.ModalProps['backdrop'] - size?: rb.ModalProps['size'] - showCloseButton?: boolean - headerClassName?: string - titleClassName?: string -} const BaseModal = ({ isShown, title, @@ -21,9 +20,10 @@ const BaseModal = ({ onCancel, size, backdrop = 'static', - showCloseButton = false, - headerClassName, - titleClassName, + closeButton = false, + className = styles.modal, + headerClassName = styles.modalHeader, + titleClassName = styles.modalTitle, }: PropsWithChildren) => { return ( - - {title} + + {title} {children} @@ -59,8 +59,8 @@ const InfoModal = ({ }: PropsWithChildren) => { return ( - {children} - + {children} + onSubmit()}> {submitButtonText} @@ -72,7 +72,6 @@ const InfoModal = ({ export type ConfirmModalProps = BaseModalProps & { onConfirm: () => void disabled?: boolean - confirmVariant?: string } const ConfirmModal = ({ @@ -80,15 +79,14 @@ const ConfirmModal = ({ onCancel, onConfirm, disabled = false, - confirmVariant = 'outline-dark', ...baseModalProps }: PropsWithChildren) => { const { t } = useTranslation() return ( - {children} - + {children} + onCancel()} @@ -97,7 +95,7 @@ const ConfirmModal = ({
{t('modal.confirm_button_reject')}
- onConfirm()} disabled={disabled}> + onConfirm()} disabled={disabled}> {t('modal.confirm_button_accept')}
@@ -105,4 +103,4 @@ const ConfirmModal = ({ ) } -export { InfoModal, ConfirmModal } +export { BaseModal, InfoModal, ConfirmModal } diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 3f3d1d6fb..9a6bbd43d 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useMemo } from 'react' +import { useState, useMemo } from 'react' import * as rb from 'react-bootstrap' import { useTranslation } from 'react-i18next' import type { TFunction } from 'i18next' @@ -11,7 +11,7 @@ import { useSettings, Settings } from '../../context/SettingsContext' import Alert from '../Alert' import Balance from '../Balance' import Divider from '../Divider' -import { ConfirmModal } from '../Modal' +import { BaseModal } from '../Modal' import Sprite from '../Sprite' import { utxoTags } from '../jar_details/UtxoList' import { shortenStringMiddle } from '../../utils' @@ -221,6 +221,7 @@ const UtxoListDisplay = ({ type SelectableUtxo = Utxo & { checked: boolean; selectable: boolean } +// TODO: rename to QuickFreezeUtxosModal? const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: ShowUtxosProps) => { const { t } = useTranslation() const settings = useSettings() @@ -254,56 +255,38 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho const [showFrozenUtxos, setShowFrozenUtxos] = useState(upperUtxos.length === 0 && lowerUtxos.length > 0) return ( - onConfirm(selectedUtxos)} - disabled={isLoading} + - {!isLoading ? ( - <> -
- {upperUtxos.length > 0 - ? t('show_utxos.show_utxo_subtitle') - : t('show_utxos.show_utxo_subtitle_when_allutxos_are_frozen')} + + {isLoading ? ( +
+
- {alert && ( + ) : ( + <> +
+ {upperUtxos.length > 0 + ? t('show_utxos.show_utxo_subtitle') + : t('show_utxos.show_utxo_subtitle_when_allutxos_are_frozen')} +
+ {alert && ( + + + + )} - - - )} - - { - setUpperUtxos((current) => - current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), - ) - }} - settings={settings} - showRadioButton={true} - showBackgroundColor={true} - /> - - {upperUtxos.length > 0 && lowerUtxos.length > 0 && ( - setShowFrozenUtxos((current) => !current)} - className={`mt-4 ${showFrozenUtxos && 'mb-4'}`} - /> - )} - - { - setLowerUtxos((current) => + setUpperUtxos((current) => current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), ) }} @@ -312,16 +295,46 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho showBackgroundColor={true} /> - - - ) : ( -
-
- )} - + {upperUtxos.length > 0 && lowerUtxos.length > 0 && ( + setShowFrozenUtxos((current) => !current)} + className={`mt-4 ${showFrozenUtxos && 'mb-4'}`} + /> + )} + + + { + setLowerUtxos((current) => + current.map((it) => (it.utxo !== utxo.utxo ? it : { ...it, checked: !utxo.checked })), + ) + }} + settings={settings} + showRadioButton={true} + showBackgroundColor={true} + /> + + + + )} +
+ + onCancel()} + className="d-flex justify-content-center align-items-center flex-grow-1" + > + +
{t('modal.confirm_button_reject')}
+
+ onConfirm(selectedUtxos)} disabled={isLoading}> + {t('modal.confirm_button_accept')} + +
+ ) } -export { ShowUtxos, Divider, UtxoListDisplay, UtxoRow } +export { ShowUtxos } diff --git a/src/components/settings/FeeConfigModal.module.css b/src/components/settings/FeeConfigModal.module.css index faf340e8b..b16cbd893 100644 --- a/src/components/settings/FeeConfigModal.module.css +++ b/src/components/settings/FeeConfigModal.module.css @@ -33,7 +33,6 @@ .modalFooter .buttonContainer :global .btn { flex-grow: 1; - min-height: 2.8rem; font-weight: 500; border-color: none !important; } diff --git a/src/components/settings/FeeConfigModal.tsx b/src/components/settings/FeeConfigModal.tsx index 581be1bcd..d38604774 100644 --- a/src/components/settings/FeeConfigModal.tsx +++ b/src/components/settings/FeeConfigModal.tsx @@ -10,9 +10,9 @@ import { useUpdateConfigValues } from '../../context/ServiceConfigContext' import { isDebugFeatureEnabled } from '../../constants/debugFeatures' import ToggleSwitch from '../ToggleSwitch' import { isValidNumber, factorToPercentage, percentageToFactor } from '../../utils' -import styles from './FeeConfigModal.module.css' import BitcoinAmountInput, { AmountValue, toAmountValue } from '../BitcoinAmountInput' import { JM_MAX_SWEEP_FEE_CHANGE_DEFAULT } from '../../constants/config' +import styles from './FeeConfigModal.module.css' const __dev_allowFeeValuesReset = isDebugFeatureEnabled('allowFeeValuesReset') From 6bcf8cd66050c82f28ca822fba1ec40c1a70d9ee Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Sun, 11 Aug 2024 18:09:56 +0200 Subject: [PATCH 19/21] refactor(send): remove showRadioButton property from UtxosList component --- src/components/Send/ShowUtxos.tsx | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 9a6bbd43d..c15b4e30c 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -39,7 +39,6 @@ interface UtxoListDisplayProps { utxos: SelectableUtxo[] onToggle: (utxo: SelectableUtxo) => void settings: Settings - showRadioButton: boolean showBackgroundColor: boolean } @@ -162,27 +161,19 @@ const UtxoRow = ({ utxo, onToggle, showBackgroundColor, settings, walletInfo, t ) } -const UtxoListDisplay = ({ - utxos, - onToggle, - settings, - showRadioButton = true, - showBackgroundColor = true, -}: UtxoListDisplayProps) => { +const UtxoListDisplay = ({ utxos, onToggle, settings, showBackgroundColor = true }: UtxoListDisplayProps) => { const { t } = useTranslation() const walletInfo = useCurrentWalletInfo() - //Table theme to manage view const TABLE_THEME = { Table: ` - font-size: ${showRadioButton ? '1rem' : '0.87rem'}; - --data-table-library_grid-template-columns: ${showRadioButton ? '3.5rem 2.5rem 12rem 2fr 3fr 10rem ' : '2.5rem 10rem 5fr 3fr 7.5rem'}; + --data-table-library_grid-template-columns: 3.5rem 2.5rem 12rem 2fr 3fr 10rem; @media only screen and (min-width: 768px) { - --data-table-library_grid-template-columns: ${showRadioButton ? '3.5rem 2.5rem 14rem 5fr 3fr 10rem' : '2.5rem 11rem 5fr 3fr 7.5rem'}; + --data-table-library_grid-template-columns: 3.5rem 2.5rem 14rem 5fr 3fr 10rem}; } `, BaseCell: ` - padding:${showRadioButton ? '0.5rem' : '0.55rem'} 0.35rem !important; + padding: 0.35rem 0.25rem !important; margin: 0.15rem 0px !important; `, } @@ -291,7 +282,6 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho ) }} settings={settings} - showRadioButton={true} showBackgroundColor={true} /> @@ -312,7 +302,6 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho ) }} settings={settings} - showRadioButton={true} showBackgroundColor={true} /> From 5372ef002471d8e9d11be5ea67097456efef2e4e Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Sun, 11 Aug 2024 18:26:11 +0200 Subject: [PATCH 20/21] refactor: remove id and checked prop from type Utxo --- src/components/Send/ShowUtxos.tsx | 33 +++++++++++++++++-------- src/components/jar_details/UtxoList.tsx | 2 +- src/context/WalletContext.tsx | 4 +-- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index c15b4e30c..32c1bed73 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -27,8 +27,8 @@ interface ShowUtxosProps { } interface UtxoRowProps { - utxo: SelectableUtxo - onToggle: (utxo: SelectableUtxo) => void + utxo: SelectableUtxoTableRowData + onToggle: (utxo: SelectableUtxoTableRowData) => void settings: Settings showBackgroundColor: boolean walletInfo: WalletInfo @@ -161,6 +161,11 @@ const UtxoRow = ({ utxo, onToggle, showBackgroundColor, settings, walletInfo, t ) } +type SelectableUtxoTableRowData = SelectableUtxo & { + // TODO: add "tags" here and remove from "Utxo" type + // tags?: { tag: string; color: string }[] +} & Pick + const UtxoListDisplay = ({ utxos, onToggle, settings, showBackgroundColor = true }: UtxoListDisplayProps) => { const { t } = useTranslation() const walletInfo = useCurrentWalletInfo() @@ -179,18 +184,26 @@ const UtxoListDisplay = ({ utxos, onToggle, settings, showBackgroundColor = true } const tableTheme = useTheme(TABLE_THEME) + const tableData: TableTypes.Data = useMemo( + () => ({ + nodes: utxos.map( + (utxo: Utxo) => + ({ + ...utxo, + id: utxo.utxo, + }) as SelectableUtxoTableRowData, + ), + }), + [utxos], + ) + return (
-
- {(utxosList: TableTypes.TableProps) => ( +
+ {(utxosList: TableTypes.TableProps) => ( {walletInfo && - utxosList.map((utxo: SelectableUtxo, index: number) => { + utxosList.map((utxo: SelectableUtxoTableRowData, index: number) => { return ( { return utxo as Utxo } -interface UtxoTableRow extends Utxo { +interface UtxoTableRow extends Utxo, TableTypes.TableNode { _icon: JSX.Element _tags: Tag[] _confs: JSX.Element diff --git a/src/context/WalletContext.tsx b/src/context/WalletContext.tsx index 5632f7975..080df1ae4 100644 --- a/src/context/WalletContext.tsx +++ b/src/context/WalletContext.tsx @@ -53,8 +53,7 @@ export type Utxo = { // `locktime` in format "yyyy-MM-dd 00:00:00" // NOTE: it is unparsable with safari Date constructor locktime?: string - id: string - checked?: boolean + // TODO: remove 'tags' prop tags?: { tag: string; color: string }[] } @@ -195,7 +194,6 @@ export const groupByJar = (utxos: Utxos): UtxosByJar => { return utxos.reduce((res, utxo) => { const { mixdepth } = utxo res[mixdepth] = res[mixdepth] || [] - utxo.id = utxo.utxo res[mixdepth].push(utxo) return res }, {} as UtxosByJar) From 128608c57994b689a58df518467bc09aa3f814db Mon Sep 17 00:00:00 2001 From: theborakompanioni Date: Tue, 13 Aug 2024 10:32:47 +0200 Subject: [PATCH 21/21] chore: align button styles in modals --- src/components/JarSelectorModal.tsx | 10 ++++++++-- src/components/Modal.tsx | 2 +- src/components/Send/ShowUtxos.module.css | 4 ---- src/components/Send/ShowUtxos.tsx | 13 +++++++++---- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/components/JarSelectorModal.tsx b/src/components/JarSelectorModal.tsx index 12045b339..0083db38e 100644 --- a/src/components/JarSelectorModal.tsx +++ b/src/components/JarSelectorModal.tsx @@ -91,9 +91,15 @@ export default function JarSelectorModal({ - {t('modal.confirm_button_reject')} + +
{t('modal.confirm_button_reject')}
- + {isConfirming ? ( <> diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index cbf87fafd..0a1c60624 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -95,7 +95,7 @@ const ConfirmModal = ({
{t('modal.confirm_button_reject')}
- onConfirm()} disabled={disabled}> + onConfirm()} disabled={disabled}> {t('modal.confirm_button_accept')}
diff --git a/src/components/Send/ShowUtxos.module.css b/src/components/Send/ShowUtxos.module.css index 38998a9df..97d512a17 100644 --- a/src/components/Send/ShowUtxos.module.css +++ b/src/components/Send/ShowUtxos.module.css @@ -18,10 +18,6 @@ color: #eb5757 !important; } -.subTitle { - color: #777777 !important; -} - .utxoTagDeposit { color: #999999; border: 1px solid #bbbbbb; diff --git a/src/components/Send/ShowUtxos.tsx b/src/components/Send/ShowUtxos.tsx index 32c1bed73..8714de224 100755 --- a/src/components/Send/ShowUtxos.tsx +++ b/src/components/Send/ShowUtxos.tsx @@ -276,11 +276,11 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho ) : ( <> -
+ {upperUtxos.length > 0 ? t('show_utxos.show_utxo_subtitle') : t('show_utxos.show_utxo_subtitle_when_allutxos_are_frozen')} -
+ {alert && ( @@ -326,12 +326,17 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho onCancel()} - className="d-flex justify-content-center align-items-center flex-grow-1" + className="d-flex flex-1 justify-content-center align-items-center" >
{t('modal.confirm_button_reject')}
- onConfirm(selectedUtxos)} disabled={isLoading}> + onConfirm(selectedUtxos)} + disabled={isLoading} + className="d-flex flex-1 justify-content-center align-items-center" + > {t('modal.confirm_button_accept')}