Skip to content

Commit

Permalink
ui(send): show considered UTXOs before performing transaction (#807)
Browse files Browse the repository at this point in the history
  • Loading branch information
amitx13 authored Aug 20, 2024
1 parent 4cfe385 commit 96844d9
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 55 deletions.
43 changes: 41 additions & 2 deletions src/components/PaymentConfirmModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PropsWithChildren, useMemo } from 'react'
import { PropsWithChildren, useMemo, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import * as rb from 'react-bootstrap'
import Sprite from './Sprite'
Expand All @@ -10,6 +10,9 @@ import { AmountSats, BitcoinAddress } from '../libs/JmWalletApi'
import { jarInitial } from './jars/Jar'
import { isValidNumber } from '../utils'
import styles from './PaymentConfirmModal.module.css'
import { Utxos } from '../context/WalletContext'
import { SelectableUtxo, UtxoListDisplay } from './Send/ShowUtxos'
import Divider from './Divider'

const feeRange: (txFee: TxFee, txFeeFactor: number) => [number, number] = (txFee, txFeeFactor) => {
if (txFee.unit !== 'sats/kilo-vbyte') {
Expand Down Expand Up @@ -55,6 +58,37 @@ const useMiningFeeText = ({ tx_fees, tx_fees_factor }: Pick<FeeValues, 'tx_fees'
}, [t, tx_fees, tx_fees_factor])
}

type ReviewConsideredUtxosProps = {
utxos: SelectableUtxo[]
}
const ReviewConsideredUtxos = ({ utxos }: ReviewConsideredUtxosProps) => {
const { t } = useTranslation()
const settings = useSettings()
const [isOpen, setIsOpen] = useState<boolean>(false)

return (
<rb.Row className="mt-2">
<rb.Col xs={4} md={3} className="text-end">
<strong>{t('show_utxos.considered_utxos')}</strong>
</rb.Col>
<rb.Col xs={8} md={9}>
<Divider toggled={isOpen} onToggle={() => setIsOpen((current) => !current)} />
</rb.Col>
<rb.Collapse in={isOpen}>
<rb.Col xs={12} className="mt-2">
<UtxoListDisplay
utxos={utxos}
settings={settings}
onToggle={() => {
// No-op since these UTXOs are only for review and are not selectable
}}
/>
</rb.Col>
</rb.Collapse>
</rb.Row>
)
}

interface PaymentDisplayInfo {
sourceJarIndex?: JarIndex
destination: BitcoinAddress | string
Expand All @@ -64,6 +98,7 @@ interface PaymentDisplayInfo {
numCollaborators?: number
feeConfigValues?: FeeValues
showPrivacyInfo?: boolean
consideredUtxos?: Utxos
}

interface PaymentConfirmModalProps extends ConfirmModalProps {
Expand All @@ -80,6 +115,7 @@ export function PaymentConfirmModal({
numCollaborators,
feeConfigValues,
showPrivacyInfo = true,
consideredUtxos = [],
},
children,
...confirmModalProps
Expand All @@ -97,7 +133,7 @@ export function PaymentConfirmModal({

return (
<ConfirmModal {...confirmModalProps}>
<rb.Container className="mt-2">
<rb.Container className="mt-2" fluid>
{showPrivacyInfo && (
<rb.Row className="mt-2 mb-3">
<rb.Col xs={12} className="text-center">
Expand Down Expand Up @@ -207,6 +243,9 @@ export function PaymentConfirmModal({
</rb.Col>
</rb.Row>
)}
{consideredUtxos.length !== 0 && (
<ReviewConsideredUtxos utxos={consideredUtxos.map((it) => ({ ...it, checked: false, selectable: false }))} />
)}
{children && (
<rb.Row>
<rb.Col xs={12}>{children}</rb.Col>
Expand Down
5 changes: 3 additions & 2 deletions src/components/Send/ShowUtxos.module.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.utxoListDisplayHeight {
max-height: 17.6rem;
max-height: 15.7rem;
}

.row.row-normal {
Expand Down Expand Up @@ -31,6 +31,7 @@
height: 24px;
}

.checkbox:checked {
.checkbox:checked,
.checkbox:indeterminate {
accent-color: var(--bs-black);
}
54 changes: 28 additions & 26 deletions src/components/Send/ShowUtxos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,29 @@ interface UtxoRowProps {
utxo: SelectableUtxoTableRowData
onToggle: (utxo: SelectableUtxoTableRowData) => void
settings: Settings
showBackgroundColor: boolean
walletInfo: WalletInfo
t: TFunction
// TODO: remove
showBackgroundColor?: boolean
}

interface UtxoListDisplayProps {
utxos: SelectableUtxo[]
onToggle: (utxo: SelectableUtxo) => void
settings: Settings
showBackgroundColor: boolean
// TODO: remove
showBackgroundColor?: boolean
}

const UtxoRow = ({ utxo, onToggle, showBackgroundColor, settings, walletInfo, t }: UtxoRowProps) => {
const UtxoRow = ({ utxo, onToggle, settings, walletInfo, t }: UtxoRowProps) => {
const displayAddress = useMemo(() => shortenStringMiddle(utxo.address, 24), [utxo.address])
const tags = useMemo(() => utxoTags(utxo, walletInfo, t), [utxo, walletInfo, t])

return (
<Row
item={utxo}
className={classNames(styles.row, styles[`row-${tags[0].color || 'normal'}`], {
className={classNames(styles.row, styles[`row-${tags[0]?.color || 'normal'}`], {
[styles['row-frozen']]: utxo.frozen,
'bg-transparent': !showBackgroundColor,
'cursor-pointer': utxo.selectable,
'cursor-not-allowed': !utxo.selectable,
})}
Expand Down Expand Up @@ -110,25 +111,29 @@ const UtxoRow = ({ utxo, onToggle, showBackgroundColor, settings, walletInfo, t

type SelectableUtxoTableRowData = SelectableUtxo & Pick<TableTypes.TableNode, 'id'>

const UtxoListDisplay = ({ utxos, onToggle, settings, showBackgroundColor = true }: UtxoListDisplayProps) => {
const DEFAULT_UTXO_LIST_THEME = {
Table: `
--data-table-library_grid-template-columns: 2.5rem 2.5rem 17rem 3rem 12rem 1fr};
`,
BaseCell: `
padding: 0.35rem 0.25rem !important;
margin: 0.15rem 0px !important;
`,
Cell: `
&:nth-of-type(3) {
text-align: left;
}
&:nth-of-type(5) {
text-align: right;
}
`,
}

const UtxoListDisplay = ({ utxos, onToggle, settings }: UtxoListDisplayProps) => {
const { t } = useTranslation()
const walletInfo = useCurrentWalletInfo()

const TABLE_THEME = {
Table: `
--data-table-library_grid-template-columns: 2.5rem 2.5rem 17rem 3rem 12rem 1fr};
`,
BaseCell: `
padding: 0.35rem 0.25rem !important;
margin: 0.15rem 0px !important;
`,
Cell: `
&:nth-of-type(5) {
text-align: right;
}
`,
}
const tableTheme = useTheme(TABLE_THEME)
const tableTheme = useTheme(DEFAULT_UTXO_LIST_THEME)

const tableData: TableTypes.Data<SelectableUtxoTableRowData> = useMemo(
() => ({
Expand All @@ -155,7 +160,6 @@ const UtxoListDisplay = ({ utxos, onToggle, settings, showBackgroundColor = true
key={index}
utxo={utxo}
onToggle={onToggle}
showBackgroundColor={showBackgroundColor}
settings={settings}
walletInfo={walletInfo}
t={t}
Expand All @@ -169,7 +173,7 @@ const UtxoListDisplay = ({ utxos, onToggle, settings, showBackgroundColor = true
)
}

type SelectableUtxo = Utxo & { checked: boolean; selectable: boolean }
export type SelectableUtxo = Utxo & { checked: boolean; selectable: boolean }

// TODO: rename to QuickFreezeUtxosModal?
const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: ShowUtxosProps) => {
Expand Down Expand Up @@ -241,7 +245,6 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho
)
}}
settings={settings}
showBackgroundColor={true}
/>
</rb.Row>
{upperUtxos.length > 0 && lowerUtxos.length > 0 && (
Expand All @@ -261,7 +264,6 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho
)
}}
settings={settings}
showBackgroundColor={true}
/>
</rb.Row>
</rb.Collapse>
Expand Down Expand Up @@ -290,4 +292,4 @@ const ShowUtxos = ({ isOpen, onCancel, onConfirm, isLoading, utxos, alert }: Sho
)
}

export { ShowUtxos }
export { ShowUtxos, UtxoListDisplay }
23 changes: 0 additions & 23 deletions src/components/Send/SourceJarSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ export const SourceJarSelector = ({
const reloadCurrentWalletInfo = useReloadCurrentWalletInfo()

const [showUtxos, setShowUtxos] = useState<ShowUtxosProps>()
//const [unFrozenUtxos, setUnFrozenUtxos] = useState<Utxos>([])
//const [frozenUtxos, setFrozenUtxos] = useState<Utxos>([])

const jarBalances = useMemo(() => {
if (!walletInfo) return []
Expand All @@ -51,27 +49,6 @@ export const SourceJarSelector = ({
)
}, [walletInfo])

/*useEffect(() => {
if (frozenUtxos.length === 0 && unFrozenUtxos.length === 0) {
return
}
const frozenUtxosToUpdate = frozenUtxos.filter((utxo: Utxo) => utxo.checked && !utxo.locktime)
const timeLockedUtxo = frozenUtxos.find((utxo: Utxo) => utxo.checked && utxo.locktime)
const allUnFrozenUnchecked = unFrozenUtxos.every((utxo: Utxo) => !utxo.checked)
if (frozenUtxos.length > 0 && timeLockedUtxo) {
setAlert({ variant: 'danger', message: `${t('show_utxos.alert_for_time_locked')} ${timeLockedUtxo.locktime}` })
} else if (
(frozenUtxos.length > 0 || unFrozenUtxos.length > 0) &&
allUnFrozenUnchecked &&
frozenUtxosToUpdate.length === 0
) {
setAlert({ variant: 'warning', message: t('show_utxos.alert_for_unfreeze_utxos'), dismissible: true })
} else {
setAlert(undefined)
}
}, [frozenUtxos, unFrozenUtxos, t, setAlert])*/

const handleUtxosFrozenState = useCallback(
async (selectedUtxos: Utxos) => {
if (!showUtxos) return
Expand Down
4 changes: 3 additions & 1 deletion src/components/Send/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { useLoadConfigValue } from '../../context/ServiceConfigContext'
import { useWaitForUtxosToBeSpent } from '../../hooks/WaitForUtxosToBeSpent'
import { routes } from '../../constants/routes'
import { JM_MINIMUM_MAKERS_DEFAULT } from '../../constants/config'

import { initialNumCollaborators } from './helpers'

const INITIAL_DESTINATION = null
Expand Down Expand Up @@ -515,6 +514,9 @@ export default function Send({ wallet }: SendProps) {
isCoinjoin: showConfirmSendModal.isCoinJoin,
numCollaborators: showConfirmSendModal.numCollaborators!,
feeConfigValues: { ...feeConfigValues, tx_fees: showConfirmSendModal.txFee },
consideredUtxos: (walletInfo?.utxosByJar[showConfirmSendModal.sourceJarIndex!] || [])
.filter((utxo) => !utxo.frozen)
.sort((a, b) => a.confirmations - b.confirmations),
}}
/>
)}
Expand Down
8 changes: 8 additions & 0 deletions src/components/jar_details/UtxoList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ const TABLE_THEME = {
`,
BaseCell: `
padding: 0.25rem 0.25rem !important;
input[type="checkbox"] {
width: 16px;
height: 16px;
}
input:checked, input:indeterminate {
accent-color: var(--bs-black);
}
&:nth-of-type(1) {
text-align: center;
}
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@
},
"show_utxos": {
"select_utxos": "Select UTXOs",
"selected_utxos": "Selected UTXOs",
"considered_utxos": "Considered 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."
Expand Down

0 comments on commit 96844d9

Please sign in to comment.