Skip to content

Commit

Permalink
US-2157: Round USD conversions (#890)
Browse files Browse the repository at this point in the history
* do not show less than a cent if balance is zero

* round usd conversions in transaction summary

* make all TransactionSummaryScreenProps consistent

* create functions for formatting token and usd values

* add some other test cases

* add formatUsdValueWithDollarSign function

* use formatUsdValue and formatTokenValue

* remove zero as special case

* format fee value

* remove precison of 18 decimals places

* move formatting numbers into TransactionSummaryComponent

* change to formatFiatValue

* fix bitcoin transaction status

* remove log

* handle NaN values

* fetch usd token prices first
  • Loading branch information
rodrigoncalves committed Apr 12, 2024
1 parent d5a4313 commit 5e83d41
Show file tree
Hide file tree
Showing 14 changed files with 274 additions and 120 deletions.
6 changes: 3 additions & 3 deletions src/components/BasicRow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface BasicRowProps {
amount?: string
status?: StatusTextProps['status']
error?: string
usdAmount?: number
usdAmount?: string
style?: StyleProp<ViewStyle>
symbol?: string
}
Expand Down Expand Up @@ -110,14 +110,14 @@ export const BasicRow = ({
)}
</View>
<View style={styles.usdAmountView}>
{usdAmount !== undefined && (
{usdAmount && (
<Typography
accessibilityLabel={`usdAmount-${index}`}
type="labelLight"
numberOfLines={1}
ellipsizeMode="tail"
style={styles.usdText}>
{!usdAmount && '< '}${usdAmount ? usdAmount.toFixed(2) : '0.01'}
{usdAmount}
</Typography>
)}
</View>
Expand Down
31 changes: 11 additions & 20 deletions src/components/token/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import { ContactCard } from 'screens/contacts/components'
import { TokenImage, TokenSymbol } from 'screens/home/TokenImage'
import { noop, sharedColors, sharedStyles, testIDs } from 'shared/constants'
import { ContactWithAddressRequired } from 'shared/types'
import { castStyle, formatTokenValues } from 'shared/utils'
import { castStyle, formatTokenValue, formatFiatValue } from 'shared/utils'

import { DollarIcon } from '../icons/DollarIcon'
import { EyeIcon } from '../icons/EyeIcon'

export interface CurrencyValue {
symbol: TokenSymbol | string
symbolType: 'usd' | 'icon'
balance: string
balance: number | string
}

interface Props {
Expand Down Expand Up @@ -70,8 +70,8 @@ export const TokenBalance = ({
firstValue.symbol?.toUpperCase() === 'TRIF'

const firstValueBalance = editable
? firstValue.balance
: formatTokenValues(firstValue.balance)
? firstValue.balance.toString()
: formatTokenValue(firstValue.balance)

const onCopyAddress = useCallback(() => {
if (contact) {
Expand Down Expand Up @@ -106,7 +106,7 @@ export const TokenBalance = ({
)}
<TextInput
onChangeText={handleAmountChange}
value={hide ? '\u002A\u002A\u002A\u002A' : firstValueBalance}
value={hide ? '\u002A\u002A\u002A\u002A\u002A' : firstValueBalance}
keyboardType="numeric"
accessibilityLabel={'Amount.Input'}
placeholder="0"
Expand All @@ -123,23 +123,13 @@ export const TokenBalance = ({
<TokenImage symbol={secondValue.symbol} />
</View>
)}
{secondValue?.symbolType === 'usd' && (
<>
{secondValue.symbol === '<' && (
<Typography type="body1" style={styles.subTitle}>
{'<'}
</Typography>
)}
<DollarIcon size={16} color={sharedColors.labelLight} />
</>
)}
{!isNaN(Number(secondValue?.balance)) && (
{secondValue && (
<Typography type="body1" style={styles.subTitle}>
{hide
? '\u002A\u002A\u002A\u002A\u002A\u002A'
: secondValue
? formatTokenValues(secondValue.balance)
: ''}
? '\u002A\u002A\u002A\u002A\u002A'
: secondValue.symbolType === 'usd'
? formatFiatValue(secondValue.balance)
: formatTokenValue(secondValue.balance)}
</Typography>
)}
{error && (
Expand Down Expand Up @@ -235,6 +225,7 @@ const styles = StyleSheet.create({
borderRadius: 10,
width: 20,
height: 20,
marginRight: 4,
}),
subTitle: castStyle.text({
color: sharedColors.subTitle,
Expand Down
2 changes: 1 addition & 1 deletion src/redux/slices/transactionsSlice/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface IBitcoinTransaction {

export interface TokenFeeValueObject {
tokenValue: string
usdValue: string
usdValue: number | string
symbol?: TokenSymbol | string
}

Expand Down
84 changes: 40 additions & 44 deletions src/screens/activity/ActivityRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import { StyleProp, ViewStyle } from 'react-native'
import { ZERO_ADDRESS } from '@rsksmart/rif-relay-light-sdk'

import { roundBalance, shortAddress } from 'lib/utils'
import { shortAddress } from 'lib/utils'

import { isMyAddress } from 'components/address/lib'
import { StatusEnum } from 'components/BasicRow'
Expand All @@ -15,7 +15,9 @@ import { ActivityMainScreenProps } from 'shared/types'
import { useAppSelector } from 'store/storeUtils'
import { getContactByAddress } from 'store/slices/contactsSlice'
import { ActivityRowPresentationObject } from 'store/slices/transactionsSlice'
import { formatTokenValue, formatFiatValue } from 'shared/utils'
import { Wallet, useWallet } from 'shared/wallet'
import { TransactionStatus } from 'store/shared/types'

const getStatus = (status: string) => {
switch (status) {
Expand Down Expand Up @@ -53,7 +55,7 @@ export const ActivityBasicRow = ({
timeHumanFormatted,
from = '',
to = '',
price,
price: usdValue,
id,
} = activityDetails
const { address: walletAddress } = useWallet()
Expand All @@ -76,68 +78,62 @@ export const ActivityBasicRow = ({
label = t('wallet_deployment_label')
}

// USD Balance
const usdBalance = roundBalance(price, 2)
const txSummary: TransactionSummaryScreenProps = useMemo(() => {
const totalUsd = isNaN(usdValue) ? '' : usdValue + Number(fee.usdValue)
const feeUsd = isNaN(+fee.usdValue) ? '' : fee.usdValue
const usdAmount = isNaN(usdValue) ? '' : usdValue

const txSummary: TransactionSummaryScreenProps = useMemo(
() => ({
const totalToken =
symbol === fee.symbol
? Number(value) + Number(fee.tokenValue)
: Number(value)

return {
transaction: {
tokenValue: {
symbol,
symbolType: 'icon',
balance: value,
},
usdValue: {
symbol: usdBalance ? '$' : '<',
symbol: '$',
symbolType: 'usd',
balance: usdBalance ? usdBalance : '0.01',
balance: usdAmount,
},
totalToken:
symbol === fee.symbol
? Number(value) + Number(fee.tokenValue)
: Number(value),
totalUsd: Number(value) + Number(fee.usdValue),
status,
fee: {
...fee,
symbol: fee.symbol || symbol,
usdValue: fee.usdValue,
tokenValue: fee.tokenValue,
usdValue: feeUsd,
},
totalToken,
totalUsd,
status: status.toUpperCase() as TransactionStatus,
amIReceiver,
from,
to,
time: timeHumanFormatted,
hashId: id,
},
contact: contact || { address },
}),
[
address,
amIReceiver,
contact,
fee,
from,
to,
status,
symbol,
timeHumanFormatted,
usdBalance,
value,
id,
],
)

const amount = useMemo(() => {
if (symbol.startsWith('BTC')) {
return value
}
const num = Number(value)
let rounded = roundBalance(num, 4)
if (!rounded) {
rounded = roundBalance(num, 8)
}
return rounded.toString()
}, [value, symbol])
}, [
fee,
symbol,
value,
usdValue,
status,
amIReceiver,
from,
to,
timeHumanFormatted,
id,
contact,
address,
])

const amount = symbol.startsWith('BTC') ? value : formatTokenValue(value)
const isUnknownToken = !usdValue && Number(value) > 0
const usdAmount = isUnknownToken ? '' : formatFiatValue(usdValue)

const handlePress = useCallback(() => {
if (txSummary) {
Expand All @@ -158,7 +154,7 @@ export const ActivityBasicRow = ({
status={getStatus(status)}
avatar={{ name: 'A' }}
secondaryLabel={timeHumanFormatted}
usdAmount={price === 0 ? undefined : usdBalance}
usdAmount={usdAmount}
contact={contact}
/>
</AppTouchable>
Expand Down
4 changes: 2 additions & 2 deletions src/screens/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
} from 'storage/MainStorage'
import { selectTransactions } from 'store/slices/transactionsSlice'
import { sharedColors } from 'shared/constants'
import { castStyle } from 'shared/utils'
import { castStyle, formatFiatValue } from 'shared/utils'
import { ActivityBasicRow } from 'screens/activity/ActivityRow'
import { useWallet } from 'shared/wallet'

Expand Down Expand Up @@ -187,7 +187,7 @@ export const HomeScreen = ({
setSelectedTokenBalanceUsd({
symbolType: 'usd',
symbol,
balance: usdBalance.toFixed(2),
balance: formatFiatValue(usdBalance),
})
}
}, [selectedToken])
Expand Down
4 changes: 2 additions & 2 deletions src/screens/rnsManager/SearchDomainScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
ProfileStatus,
} from 'navigation/profileNavigator/types'
import { sharedColors, sharedStyles } from 'shared/constants'
import { castStyle, formatTokenValues } from 'shared/utils'
import { castStyle, formatTokenValue } from 'shared/utils'
import { colors } from 'src/styles'
import {
recoverAlias,
Expand Down Expand Up @@ -99,7 +99,7 @@ export const SearchDomainScreen = ({ navigation }: Props) => {
const years = watch('years')
const hasErrors = Object.keys(errors).length > 0

const selectedDomainPriceInUsd = formatTokenValues(
const selectedDomainPriceInUsd = formatTokenValue(
rifToken.price * Number(selectedDomainPrice),
)

Expand Down
11 changes: 6 additions & 5 deletions src/screens/send/TransactionForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { defaultIconSize, sharedColors, testIDs } from 'shared/constants'
import {
bitcoinFeeMap,
castStyle,
formatTokenValue,
getAllowedFees,
getDefaultFeeEOA,
getDefaultFeeRelay,
Expand Down Expand Up @@ -219,13 +220,13 @@ export const TransactionForm = ({
setValue('amount', balanceToSet)
setSecondBalance(prev => ({
...prev,
balance: balanceToSet.toString(),
balance: balanceToSet,
}))
} else {
setValue('amount', numberAmount)
setSecondBalance(prev => ({
...prev,
balance: convertTokenToUSD(numberAmount, tokenQuote).toFixed(2),
balance: convertTokenToUSD(numberAmount, tokenQuote),
}))
}
},
Expand Down Expand Up @@ -499,9 +500,9 @@ export const TransactionForm = ({
</Typography>
)}
<AppButton
title={`${t('transaction_form_button_send')} ${amount} ${
selectedToken.symbol
}`}
title={`${t('transaction_form_button_send')} ${formatTokenValue(
amount,
)} ${selectedToken.symbol}`}
onPress={handleSubmit(handleConfirmClick)}
accessibilityLabel={'Send'}
disabled={
Expand Down
18 changes: 5 additions & 13 deletions src/screens/transactionSummary/TransactionSummaryComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ import {
sharedColors,
sharedStyles,
} from 'shared/constants'
import { castStyle, formatTokenValues } from 'shared/utils'
import { castStyle, formatTokenValue, formatFiatValue } from 'shared/utils'
import { AppButton, AppTouchable, Typography } from 'components/index'
import { useAppSelector } from 'store/storeUtils'
import { isMyAddress } from 'components/address/lib'
import { DollarIcon } from 'components/icons/DollarIcon'
import { FullScreenSpinner } from 'components/fullScreenSpinner'
import { getContactByAddress } from 'store/slices/contactsSlice'
import { getWalletSetting } from 'core/config'
Expand Down Expand Up @@ -175,20 +174,19 @@ export const TransactionSummaryComponent = ({
size={12}
/>
<Typography type={'body2'} style={[sharedStyles.textCenter]}>
{formatTokenValues(fee.tokenValue)} {fee.symbol}
{formatTokenValue(fee.tokenValue)} {fee.symbol}
</Typography>
</View>
</View>

<View style={styles.dollarAmountWrapper}>
<DollarIcon size={14} color={sharedColors.labelLight} />
<Typography
type={'body2'}
style={[
sharedStyles.textRight,
{ color: sharedColors.labelLight },
]}>
{formatTokenValues(fee.usdValue)}
{formatFiatValue(fee.usdValue)}
</Typography>
</View>
</>
Expand All @@ -209,27 +207,21 @@ export const TransactionSummaryComponent = ({
<View style={sharedStyles.row}>
<TokenImage symbol={tokenValue.symbol} size={12} transparent />
<Typography type={'body2'} style={[sharedStyles.textCenter]}>
{formatTokenValues(totalToken)} {tokenValue.symbol}{' '}
{formatTokenValue(totalToken)} {tokenValue.symbol}{' '}
{tokenValue.symbol !== fee.symbol &&
!amIReceiver &&
t('transaction_summary_plus_fees')}
</Typography>
</View>
</View>
<View style={styles.dollarAmountWrapper}>
{usdValue.symbol === '<' && Number(totalUsd) <= 0.01 && (
<Typography type="body1" color={sharedColors.labelLight}>
{'<'}
</Typography>
)}
<DollarIcon size={14} color={sharedColors.labelLight} />
<Typography
type={'body2'}
style={[
sharedStyles.textRight,
{ color: sharedColors.labelLight },
]}>
{formatTokenValues(totalUsd)}
{formatFiatValue(totalUsd)}
</Typography>
</View>
{/* arrive value */}
Expand Down
2 changes: 1 addition & 1 deletion src/screens/transactionSummary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface TransactionSummaryScreenProps {
fee: TokenFeeValueObject
time: string
totalToken: number
totalUsd: number
totalUsd: number | string
hashId?: string
status?: TransactionStatus
amIReceiver?: boolean
Expand Down
Loading

0 comments on commit 5e83d41

Please sign in to comment.