Skip to content

Commit 22e733c

Browse files
committed
Exotic Currency symbols must appear before the amount value
1 parent f1119aa commit 22e733c

File tree

8 files changed

+177
-26
lines changed

8 files changed

+177
-26
lines changed

src/containers/Vault/VaultHeader/index.tsx

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import { MPT_ROUTE } from '../../App/routes'
1010
import SocketContext from '../../shared/SocketContext'
1111
import { getMPTIssuance } from '../../../rippled/lib/rippled'
1212
import { parseVaultWebsite } from '../utils'
13-
import { shortenVaultID, shortenAccount } from '../../shared/utils'
13+
import {
14+
shortenVaultID,
15+
shortenAccount,
16+
getCurrencySymbol,
17+
isCurrencyExoticSymbol,
18+
} from '../../shared/utils'
1419
import './styles.scss'
1520
import { useAnalytics } from '../../shared/analytics'
1621
import { parseAmount } from '../../shared/NumberFormattingUtils'
@@ -53,9 +58,6 @@ const WITHDRAWAL_POLICIES: { [key: number]: string } = {
5358
1: 'first_come_first_served',
5459
}
5560

56-
const getAssetCurrency = (asset: VaultData['Asset']): string =>
57-
asset?.currency === 'XRP' ? '\uE900' : asset?.currency || ''
58-
5961
export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
6062
const { t } = useTranslation()
6163
const { trackException } = useAnalytics()
@@ -93,7 +95,9 @@ export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
9395

9496
// Returns 'USD' when showing USD values, otherwise the vault's asset currency
9597
const getDisplayCurrencyLabel = (): string =>
96-
displayCurrency === 'USD' ? 'USD' : getAssetCurrency(asset)
98+
displayCurrency === 'USD'
99+
? 'USD'
100+
: getCurrencySymbol(asset?.currency ?? asset?.mpt_issuance_id)
97101

98102
// Fetch MPTokenIssuance to get the DomainID (vault credential)
99103
const { data: mptIssuanceData } = useQuery(
@@ -242,8 +246,8 @@ export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
242246
<TokenTableRow
243247
label={t('asset')}
244248
value={
245-
asset?.currency === 'XRP' ? (
246-
getAssetCurrency(asset)
249+
isCurrencyExoticSymbol(asset?.currency) ? (
250+
getCurrencySymbol(asset?.currency)
247251
) : (
248252
<Currency
249253
currency={
@@ -280,9 +284,14 @@ export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
280284
return '--'
281285
// Note: As per the NumberFormat policy, prices in the range of [10_000, 1M] do not display decimal values
282286
// Very large prices (greater than 1M must have two decimal places)
283-
if (Number(amount) < 1000000 && Number(amount) >= 10000)
287+
if (Number(amount) < 1000000 && Number(amount) >= 10000) {
288+
if (isCurrencyExoticSymbol(asset?.currency))
289+
return `${getDisplayCurrencyLabel()} ${parseAmount(amount, 0)}`
284290
return `${parseAmount(amount, 0)} ${getDisplayCurrencyLabel()}`
291+
}
285292

293+
if (isCurrencyExoticSymbol(asset?.currency))
294+
return `${getDisplayCurrencyLabel()} ${parseAmount(amount, 2)}`
286295
return `${parseAmount(amount, 2)} ${getDisplayCurrencyLabel()}`
287296
})()}
288297
/>
@@ -294,7 +303,9 @@ export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
294303
const parsedAmt = parseAmount(assetsMaximum, 2)
295304
if (['0', '0.00', '0.0000'].includes(parsedAmt)) return '--'
296305

297-
return `${parsedAmt} ${getAssetCurrency(asset)}`
306+
if (isCurrencyExoticSymbol(asset?.currency))
307+
return `${getCurrencySymbol(asset?.currency)} ${parsedAmt}`
308+
return `${parsedAmt} ${getCurrencySymbol(asset?.currency ?? asset?.mpt_issuance_id)}`
298309
})()}
299310
/>
300311
<TokenTableRow
@@ -306,15 +317,19 @@ export const VaultHeader = ({ data, vaultId, displayCurrency }: Props) => {
306317
value={(() => {
307318
const parsedAmt = parseAmount(assetsAvailable ?? '0', 2)
308319
if (['0', '0.00', '0.0000'].includes(parsedAmt)) return '--'
309-
return `${parsedAmt} ${getAssetCurrency(asset)}`
320+
if (isCurrencyExoticSymbol(asset?.currency))
321+
return `${getCurrencySymbol(asset?.currency)} ${parsedAmt}`
322+
return `${parsedAmt} ${getCurrencySymbol(asset?.currency ?? asset?.mpt_issuance_id)}`
310323
})()}
311324
/>
312325
<TokenTableRow
313326
label={t('unrealized_loss')}
314327
value={(() => {
315328
const parsedAmt = parseAmount(lossUnrealized ?? '0', 2)
316329
if (['0', '0.00', '0.0000'].includes(parsedAmt)) return '--'
317-
return `${parsedAmt} ${getAssetCurrency(asset)}`
330+
if (isCurrencyExoticSymbol(asset?.currency))
331+
return `${getCurrencySymbol(asset?.currency)} ${parsedAmt}`
332+
return `${parsedAmt} ${getCurrencySymbol(asset?.currency ?? asset?.mpt_issuance_id)}`
318333
})()}
319334
/>
320335
</tbody>

src/containers/Vault/VaultHeader/test/VaultHeader.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,8 @@ describe('VaultHeader Component', () => {
459459

460460
// Numbers >= 1,000,000 should display with M suffix
461461
// Verify exact formatted values: 12,500,000 -> "12.5M XRP", 5,000,000 -> "5M XRP"
462-
expect(screen.getByText('12.50M \uE900')).toBeInTheDocument()
463-
expect(screen.getByText('5.00M \uE900')).toBeInTheDocument()
462+
expect(screen.getByText('\uE900 12.50M')).toBeInTheDocument()
463+
expect(screen.getByText('\uE900 5.00M')).toBeInTheDocument()
464464
})
465465

466466
it('formats thousands with K suffix', () => {
@@ -483,8 +483,8 @@ describe('VaultHeader Component', () => {
483483

484484
// Numbers >= 1,000 but < 1,000,000 should display with K suffix
485485
// Verify exact formatted values: 250,000 -> "250K XRP", 75,000 -> "75K XRP"
486-
expect(screen.getByText('250.00K \uE900')).toBeInTheDocument()
487-
expect(screen.getByText('75.00K \uE900')).toBeInTheDocument()
486+
expect(screen.getByText('\uE900 250.00K')).toBeInTheDocument()
487+
expect(screen.getByText('\uE900 75.00K')).toBeInTheDocument()
488488
})
489489

490490
it('displays small numbers without suffix', () => {
@@ -506,7 +506,7 @@ describe('VaultHeader Component', () => {
506506

507507
// Numbers < 1,000 should display as-is without K/M suffix
508508
// Verify exact formatted value: 500 -> "500 XRP"
509-
expect(screen.getByText('500.00 \uE900')).toBeInTheDocument()
509+
expect(screen.getByText('\uE900 500.00')).toBeInTheDocument()
510510
})
511511

512512
it('includes currency code in formatted amounts', () => {
@@ -957,7 +957,7 @@ describe('VaultHeader Component', () => {
957957
)
958958

959959
expect(screen.getByText('Max Total Supply')).toBeInTheDocument()
960-
expect(screen.getByText(/10.00M \uE900/)).toBeInTheDocument()
960+
expect(screen.getByText(/\uE900 10.00M/)).toBeInTheDocument()
961961
})
962962

963963
it('displays "No Limit" when AssetsMaximum is not set', () => {
@@ -1009,7 +1009,7 @@ describe('VaultHeader Component', () => {
10091009

10101010
expect(screen.getByText('Total Value Locked (TVL)')).toBeInTheDocument()
10111011
// Verify exact TVL value: 5,000,000 -> "5M XRP"
1012-
expect(screen.getByText('5.00M \uE900')).toBeInTheDocument()
1012+
expect(screen.getByText('\uE900 5.00M')).toBeInTheDocument()
10131013
})
10141014

10151015
it('displays TVL for RLUSD vaults', () => {
@@ -1142,7 +1142,7 @@ describe('VaultHeader Component', () => {
11421142

11431143
// 1,000,000 XRP * 2.5 = 2,500,000 USD = "2.50M USD"
11441144
// formatAmount joins [prefix, formattedNum, currency] with spaces
1145-
expect(screen.getByText('2.50M USD')).toBeInTheDocument()
1145+
expect(screen.getByText('USD 2.50M')).toBeInTheDocument()
11461146
})
11471147

11481148
it('displays RLUSD TVL as USD with 1:1 conversion when displayCurrency is "usd"', () => {

src/containers/Vault/VaultLoans/BrokerDetails.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import { formatRate, LSF_LOAN_DEFAULT } from './utils'
55
import { BrokerLoansTable } from './BrokerLoansTable'
66
import WarningIcon from '../../shared/images/warning.svg'
77
import { parseAmount } from '../../shared/NumberFormattingUtils'
8-
import { shortenMPTID, getCurrencySymbol } from '../../shared/utils'
8+
import {
9+
shortenMPTID,
10+
getCurrencySymbol,
11+
isCurrencyExoticSymbol,
12+
} from '../../shared/utils'
913

1014
// TODO: Use types from xrpl.js instead of hand-writing it.
1115
interface LoanBrokerData {
@@ -69,14 +73,21 @@ export const BrokerDetails = ({
6973
}
7074

7175
const finalDisplayAmount = convertedAmount ?? amount
72-
if (finalDisplayAmount !== undefined)
76+
if (finalDisplayAmount !== undefined) {
77+
if (
78+
inputAsset?.currency &&
79+
isCurrencyExoticSymbol(inputAsset?.currency)
80+
) {
81+
return `${getCurrencySymbol(inputAsset?.currency)} ${parseAmount(finalDisplayAmount, 2)}`
82+
}
7383
return (
7484
`${parseAmount(finalDisplayAmount, 2)}` +
7585
` ${
76-
getCurrencySymbol(inputAsset?.currency) ??
86+
inputAsset?.currency ??
7787
`MPT (${shortenMPTID(inputAsset?.mpt_issuance_id)})`
7888
}`
7989
)
90+
}
8091
return '--'
8192
}
8293

@@ -144,6 +155,10 @@ export const BrokerDetails = ({
144155
}
145156
displayCurrency={displayCurrency}
146157
asset={asset}
158+
isCurrencySpecialSymbol={
159+
asset?.currency !== undefined &&
160+
isCurrencyExoticSymbol(asset?.currency)
161+
}
147162
/>
148163

149164
{hasDefaultedLoan && (

src/containers/Vault/VaultLoans/BrokerLoansTable.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ interface Props {
2020
currency?: string
2121
displayCurrency: string
2222
asset?: AssetInfo
23+
isCurrencySpecialSymbol?: boolean
2324
}
2425

2526
export const BrokerLoansTable = ({
2627
loans,
2728
currency = '',
2829
displayCurrency,
2930
asset,
31+
isCurrencySpecialSymbol = false,
3032
}: Props) => {
3133
const { t } = useTranslation()
3234
const [currentPage, setCurrentPage] = useState(1)
@@ -123,6 +125,7 @@ export const BrokerLoansTable = ({
123125
currency={currency}
124126
displayCurrency={displayCurrency}
125127
asset={asset}
128+
isCurrencySpecialSymbol={isCurrencySpecialSymbol}
126129
/>
127130
))}
128131
</div>

src/containers/Vault/VaultLoans/LoanRow.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
truncateId,
1313
} from './utils'
1414
import ExpandIcon from '../../shared/images/down_arrow.svg'
15+
import { getCurrencySymbol } from '../../shared/utils'
1516

1617
export interface LoanData {
1718
index: string
@@ -47,13 +48,15 @@ interface Props {
4748
currency?: string
4849
displayCurrency: string
4950
asset?: AssetInfo
51+
isCurrencySpecialSymbol?: boolean
5052
}
5153

5254
export const LoanRow = ({
5355
loan,
5456
currency = '',
5557
displayCurrency,
5658
asset,
59+
isCurrencySpecialSymbol = false,
5760
}: Props) => {
5861
const { t } = useTranslation()
5962
const language = useLanguage()
@@ -78,6 +81,8 @@ export const LoanRow = ({
7881
}
7982

8083
const prefix = displayCurrency === 'USD' ? '$' : ''
84+
if (isCurrencySpecialSymbol)
85+
return `${getCurrencySymbol(currency)} ${prefix}${parseAmount(displayNum, 1, language)}`
8186
return `${prefix}${parseAmount(displayNum, 1, language)} ${currency}`
8287
}
8388

@@ -97,6 +102,8 @@ export const LoanRow = ({
97102
}
98103

99104
const prefix = displayCurrency === 'USD' ? '$' : ''
105+
if (isCurrencySpecialSymbol)
106+
return `${getCurrencySymbol(currency)} ${prefix}${parseAmount(displayNum, 1, language)}`
100107
return `${prefix}${parseAmount(displayNum, 1, language)} ${currency}`
101108
}
102109

src/containers/Vault/VaultLoans/test/BrokerLoansTable.test.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import i18n from '../../../../i18n/testConfigEnglish'
2121
import { BrokerLoansTable } from '../BrokerLoansTable'
2222
import { LoanData } from '../LoanRow'
2323
import { LSF_LOAN_DEFAULT, LSF_LOAN_IMPAIRED } from '../utils'
24+
import { isCurrencyExoticSymbol } from '../../../shared/utils'
2425

2526
// Default test props
2627
const defaultDisplayCurrency = 'XRP'
@@ -960,6 +961,41 @@ describe('BrokerLoansTable Component', () => {
960961
expect(screen.queryByText(/USD/)).not.toBeInTheDocument()
961962
})
962963

964+
it(`Render the BrokerLoans table with BTC exotic currency`, () => {
965+
const loans = [
966+
createMockLoan({
967+
index: 'LOAN_BTC_1',
968+
PrincipalOutstanding: '5000',
969+
TotalValueOutstanding: '5250',
970+
}),
971+
]
972+
973+
const btcAsset = { currency: 'BTC', issuer: 'rTestIssuer' }
974+
975+
const { container } = render(
976+
<TestWrapper>
977+
<BrokerLoansTable
978+
loans={loans}
979+
currency={btcAsset.currency}
980+
displayCurrency={btcAsset.currency}
981+
asset={btcAsset}
982+
isCurrencySpecialSymbol={isCurrencyExoticSymbol(btcAsset.currency)}
983+
/>
984+
</TestWrapper>,
985+
)
986+
987+
// Table should render with loan row
988+
expect(container.querySelector('.loan-row')).toBeInTheDocument()
989+
990+
// Currency should appear in the amount columns
991+
const elementsWithCurrency = screen.getAllByText(/\u20BF 5,250.00/)
992+
expect(elementsWithCurrency.length).toBeGreaterThan(0)
993+
994+
// Verify XRP and USD do not appear - ensures EUR is used throughout
995+
expect(screen.queryByText(/XRP/)).not.toBeInTheDocument()
996+
expect(screen.queryByText(/USD/)).not.toBeInTheDocument()
997+
})
998+
963999
it('defaults to empty string when currency not provided', () => {
9641000
const loans = [createMockLoan()]
9651001

0 commit comments

Comments
 (0)