diff --git a/frontends/web/src/components/amount/conversion-amount.module.css b/frontends/web/src/components/amount/conversion-amount.module.css new file mode 100644 index 0000000000..67989a34aa --- /dev/null +++ b/frontends/web/src/components/amount/conversion-amount.module.css @@ -0,0 +1,23 @@ +.txConversionAmount { + font-variant: tabular-nums; +} + +.txPrefix, +.txUnit { + color: var(--color-secondary); + font-size: 14px; + line-height: 1.285714; +} + +.txConversionAmount .txUnit { + font-size: 12px; +} + +.txSmallInlineIcon img { + max-height: 15px; + max-width: 15px; + vertical-align: text-bottom; +} +.txConversionAmount .txSmallInlineIcon { + padding-right: var(--space-eight); +} diff --git a/frontends/web/src/components/amount/conversion-amount.tsx b/frontends/web/src/components/amount/conversion-amount.tsx new file mode 100644 index 0000000000..ca65c6000a --- /dev/null +++ b/frontends/web/src/components/amount/conversion-amount.tsx @@ -0,0 +1,73 @@ +/** + * Copyright 2025 Shift Crypto AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useContext } from 'react'; +import type { IAmount, 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'; + +type TConversionAmountProps = { + amount: IAmount; + type: TTransactionType; +} + +const btcUnits: Readonly = ['BTC', 'TBTC', 'sat', 'tsat']; + +/** + * Renders a formattted conversion amount optionally with send-to-self icon or estimate symbol + */ +export const ConversionAmount = ({ + amount, + 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 conversionUnit = sendToSelf ? amount.unit : 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(amount.unit)); + + return ( + + {sendToSelf && ( + + + + )} + {amount.estimated && !skipEstimatedPrefix && ( + + {estimatedPrefix} + {' '} + + )} + {conversion && !sendToSelf ? sign : null} + + + {' '} + {conversionUnit} + + + ); +}; diff --git a/frontends/web/src/components/transactions/details.tsx b/frontends/web/src/components/transactions/details.tsx index e5ff684433..ca608b7162 100644 --- a/frontends/web/src/components/transactions/details.tsx +++ b/frontends/web/src/components/transactions/details.tsx @@ -19,7 +19,7 @@ import type { AccountCode, ITransaction } from '@/api/account'; import { getTransaction } from '@/api/account'; import { usePrevious } from '@/hooks/previous'; import { TxDetailsDialog } from './components/details-dialog'; -import { getTxSign } from './utils'; +import { getTxSign } from '@/utils/transaction'; type TProps = { accountCode: AccountCode; diff --git a/frontends/web/src/components/transactions/transaction.module.css b/frontends/web/src/components/transactions/transaction.module.css index 65dac9256b..697aa9e3de 100644 --- a/frontends/web/src/components/transactions/transaction.module.css +++ b/frontends/web/src/components/transactions/transaction.module.css @@ -85,9 +85,6 @@ padding-bottom: 4px; } } -.txConversionAmount { - font-variant: tabular-nums; -} .txAmount-receive { color: var(--color-darkgreen); @@ -96,25 +93,6 @@ color: var(--color-green); } -.txPrefix, -.txUnit { - color: var(--color-secondary); - font-size: 14px; - line-height: 1.285714; -} -.txConversionAmount .txUnit { - font-size: 12px; -} - -.txSmallInlineIcon img { - max-height: 15px; - max-width: 15px; - vertical-align: text-bottom; -} -.txConversionAmount .txSmallInlineIcon { - padding-right: var(--space-eight); -} - .txNote { color: var(--color-secondary); display: block; diff --git a/frontends/web/src/components/transactions/transaction.tsx b/frontends/web/src/components/transactions/transaction.tsx index 8454714a96..14ff87a2fe 100644 --- a/frontends/web/src/components/transactions/transaction.tsx +++ b/frontends/web/src/components/transactions/transaction.tsx @@ -14,17 +14,16 @@ * limitations under the License. */ -import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; import type { IAmount, TTransactionStatus, TTransactionType, ITransaction } from '@/api/account'; -import { RatesContext } from '@/contexts/RatesContext'; import { useMediaQuery } from '@/hooks/mediaquery'; import { Loupe } from '@/components/icon/icon'; import { parseTimeLong, parseTimeShort } from '@/utils/date'; import { ProgressRing } from '@/components/progressRing/progressRing'; import { Amount } from '@/components/amount/amount'; +import { ConversionAmount } from '@/components/amount/conversion-amount'; import { Arrow } from './components/arrows'; -import { getTxSign } from './utils'; +import { getTxSign } from '@/utils/transaction'; import styles from './transaction.module.css'; type TTransactionProps = ITransaction & { @@ -150,56 +149,6 @@ const Status = ({ ); }; -type TConversionAmountProps = { - amount: IAmount; - type: TTransactionType; -} - -const btcUnits: Readonly = ['BTC', 'TBTC', 'sat', 'tsat']; - -/** - * Renders a formattted conversion amount optionally with send-to-self icon or estimate symbol - */ -export const ConversionAmount = ({ - amount, - 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 conversionUnit = sendToSelf ? amount.unit : 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(amount.unit)); - - return ( - - {sendToSelf && ( - - - - )} - {amount.estimated && !skipEstimatedPrefix && ( - - {estimatedPrefix} - {' '} - - )} - {conversion && !sendToSelf ? sign : null} - - - {' '} - {conversionUnit} - - - ); -}; - type TAmountsProps = { amount: IAmount; fee: IAmount; diff --git a/frontends/web/src/components/transactions/utils.ts b/frontends/web/src/utils/transaction.ts similarity index 100% rename from frontends/web/src/components/transactions/utils.ts rename to frontends/web/src/utils/transaction.ts