From c731db3a6a5f097a6ff34e32d38e96e7e9a606ea Mon Sep 17 00:00:00 2001 From: strmci Date: Fri, 13 Feb 2026 11:02:33 +0100 Subject: [PATCH] frontend: align send-to-self tx display with other txs Keep the first row in BTC/sats and switch the second row to fiat for consistency. Since the sent amount is no longer shown on the right for send-to-self transactions, the left-side label now includes amount to keep it visible. --- CHANGELOG.md | 1 + .../components/amount/conversion-amount.tsx | 25 +++---- .../transactions/transaction.module.css | 7 +- .../components/transactions/transaction.tsx | 69 +++++++++++++++---- frontends/web/src/locales/en/app.json | 4 +- frontends/web/tests/send.test.ts | 7 +- 6 files changed, 77 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 678ddcf4cc..a9309b3960 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - iOS: Add haptic feedback on toggle component - Apply rounded corners in several places and components of the app - Send: enable rotating currencies in send window. +- Show the fee's fiat value in send-to-self txs for consistency with others, and include the send-to-self amount in the left-side label ## v4.50.1 - Fix a bug that would delay showing watch-only accounts. diff --git a/frontends/web/src/components/amount/conversion-amount.tsx b/frontends/web/src/components/amount/conversion-amount.tsx index 434f9bd3f8..0ded90f895 100644 --- a/frontends/web/src/components/amount/conversion-amount.tsx +++ b/frontends/web/src/components/amount/conversion-amount.tsx @@ -3,7 +3,6 @@ import { useContext } from 'react'; import type { TAmountWithConversions, TTransactionType } from '@/api/account'; import { RatesContext } from '@/contexts/RatesContext'; -import { Arrow } from '@/components/transactions/components/arrows'; import { Amount } from '@/components/amount/amount'; import { getTxSign } from '@/utils/transaction'; import styles from './conversion-amount.module.css'; @@ -17,7 +16,7 @@ type TConversionAmountProps = { const btcUnits: Readonly = ['BTC', 'TBTC', 'sat', 'tsat']; /** - * Renders a formattted conversion amount optionally with send-to-self icon or estimate symbol + * Renders a formatted conversion amount, optionally with an estimate symbol. */ export const ConversionAmount = ({ amount, @@ -25,33 +24,27 @@ export const ConversionAmount = ({ type, }: TConversionAmountProps) => { const { defaultCurrency } = useContext(RatesContext); - const conversion = amount?.conversions && amount?.conversions[defaultCurrency]; const sign = getTxSign(type); const estimatedPrefix = '\u2248'; // ≈ - const sendToSelf = type === 'send_to_self'; const recv = type === 'receive'; - const amountToShow = recv || sendToSelf ? amount : deductedAmount; - const conversionUnit = sendToSelf ? amountToShow.unit : defaultCurrency; + const amountToShow = recv ? amount : deductedAmount; + const conversionUnit = defaultCurrency; + const conversion = amountToShow?.conversions && amountToShow?.conversions[defaultCurrency]; - // we skip the estimated conversion prefix when the Tx is send to self, or both coin and conversion are in BTC units. - const skipEstimatedPrefix = sendToSelf || (btcUnits.includes(conversionUnit) && btcUnits.includes(amountToShow.unit)); + // we skip the estimated conversion prefix when both coin and conversion are in BTC units. + const skipEstimatedPrefix = btcUnits.includes(conversionUnit) && btcUnits.includes(amountToShow.unit); return ( - {(conversion || sendToSelf) && amountToShow ? ( + {conversion && amountToShow ? ( <> - {sendToSelf && ( - - - - )} {amountToShow.estimated && !skipEstimatedPrefix && ( {estimatedPrefix}{' '} )} - {conversion && conversion !== '0' && !sendToSelf ? sign : null} + {conversion !== '0' ? sign : null} diff --git a/frontends/web/src/components/transactions/transaction.module.css b/frontends/web/src/components/transactions/transaction.module.css index de7569705d..a2a2a6d818 100644 --- a/frontends/web/src/components/transactions/transaction.module.css +++ b/frontends/web/src/components/transactions/transaction.module.css @@ -190,6 +190,8 @@ color: var(--color-default); font-size: var(--size-default); line-height: 1.25; + max-width: 100%; + text-overflow: ellipsis; } .txDateLong { @@ -228,8 +230,7 @@ } .addresses { - opacity: 0; - pointer-events: none; + display: none; } .txNoteWithAddress { @@ -239,4 +240,4 @@ .iconLoupe { width: 28px; vertical-align: text-bottom; -} \ No newline at end of file +} diff --git a/frontends/web/src/components/transactions/transaction.tsx b/frontends/web/src/components/transactions/transaction.tsx index 96eca8cc7c..3148695aba 100644 --- a/frontends/web/src/components/transactions/transaction.tsx +++ b/frontends/web/src/components/transactions/transaction.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -import { useTranslation } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import type { TAmountWithConversions, TTransactionStatus, TTransactionType, TTransaction } from '@/api/account'; import { useMediaQuery } from '@/hooks/mediaquery'; import { Loupe } from '@/components/icon/icon'; @@ -44,6 +44,7 @@ export const Transaction = ({ @@ -151,10 +155,13 @@ const Amounts = ({ const displayAmount = recv ? amount : deductedAmount; return ( - + `} + data-testid="tx-amounts" + > {displayAmount.amount !== '0' && getTxSign(type)} ( + + {values[0]} + {values.length > 1 && ( + + {' '} + (+{values.length - 1}) + + )} + +); + const Date = ({ time, }: TDateProps) => { @@ -192,23 +215,50 @@ const Date = ({ type TAddresses = { addresses: TTransaction['addresses']; + amount: TAmountWithConversions; status: TTransactionStatus; type: TTransactionType; }; const Addresses = ({ addresses, + amount, status, type, }: TAddresses) => { const { t } = useTranslation(); const isMobile = useMediaQuery('(max-width: 768px)'); + + if (type === 'send_to_self') { + const labelKey = status === 'failed' + ? 'transaction.tx.send_to_self_failed' + : 'transaction.tx.send_to_self'; + return ( + + + + ), + }} + /> + + {' '} + + + ); + } + const label = isMobile ? (type === 'receive' ? t('generic.received') : t('generic.sent')) : (type === 'receive' ? t('transaction.tx.receive', { context: status }) : t('transaction.tx.send', { context: status }) - // send_to_self will currently show the send message ); return ( @@ -216,15 +266,8 @@ const Addresses = ({ {label} - - {addresses[0]} - {addresses.length > 1 && ( - - {' '} - (+{addresses.length - 1}) - - )} - + {' '} + ); }; diff --git a/frontends/web/src/locales/en/app.json b/frontends/web/src/locales/en/app.json index 60fadbc706..0d2658e065 100644 --- a/frontends/web/src/locales/en/app.json +++ b/frontends/web/src/locales/en/app.json @@ -1961,7 +1961,9 @@ "receive_pending": "Received to", "send_complete": "Sent to", "send_failed": "Failed sending to", - "send_pending": "Sent to" + "send_pending": "Sent to", + "send_to_self": "Sent to self", + "send_to_self_failed": "Failed sending to self" }, "vsize": "Virtual size", "weight": "Weight" diff --git a/frontends/web/tests/send.test.ts b/frontends/web/tests/send.test.ts index 585c4307b1..a5031973ac 100644 --- a/frontends/web/tests/send.test.ts +++ b/frontends/web/tests/send.test.ts @@ -200,11 +200,12 @@ test('Send BTC', async ({ page, host, frontendPort, servewalletPort }, testInfo) await page.getByTestId('close-button').click(); // Verify that the values displayed are correctly - const shownDetractedAmount = await newTx.getByTestId('amountBlocks').nth(0).textContent(); - const shownSentToSelfAmount = await newTx.getByTestId('amountBlocks').nth(1).textContent(); + const labelAmount = await newTx.getByTestId('amountBlocks').first().textContent(); + const amountsColumn = newTx.getByTestId('tx-amounts'); + const shownDetractedAmount = await amountsColumn.getByTestId('amountBlocks').nth(0).textContent(); + expect(labelAmount).toBe(amount); expect(shownDetractedAmount).toBe(fee); - expect(shownSentToSelfAmount).toBe(amount); });