diff --git a/app/components/UI/Ramp/Aggregator/Views/OrdersList/__snapshots__/OrdersList.test.tsx.snap b/app/components/UI/Ramp/Aggregator/Views/OrdersList/__snapshots__/OrdersList.test.tsx.snap index 5091ad05fb1..7ea9855e1a1 100644 --- a/app/components/UI/Ramp/Aggregator/Views/OrdersList/__snapshots__/OrdersList.test.tsx.snap +++ b/app/components/UI/Ramp/Aggregator/Views/OrdersList/__snapshots__/OrdersList.test.tsx.snap @@ -127,7 +127,7 @@ exports[`OrdersList renders buy only correctly when pressing buy filter 1`] = ` { "account": "0xe64dD0AB5ad7e8C5F2bf6Ce75C34e187af8b920A", "createdAt": 0, - "cryptoAmount": 0, + "cryptoAmount": "...", "cryptoCurrencySymbol": "ETH", "fiatAmount": undefined, "fiatCurrencyCode": "USD", @@ -1336,7 +1336,7 @@ exports[`OrdersList renders buy only correctly when pressing buy filter 1`] = ` } testID="orders-list-crypto-amount-buy-6" > - 0 + ... ETH @@ -1505,7 +1505,7 @@ exports[`OrdersList renders correctly 1`] = ` { "account": "0xe64dD0AB5ad7e8C5F2bf6Ce75C34e187af8b920A", "createdAt": 0, - "cryptoAmount": 0, + "cryptoAmount": "...", "cryptoCurrencySymbol": "ETH", "fiatAmount": undefined, "fiatCurrencyCode": "USD", @@ -2864,7 +2864,7 @@ exports[`OrdersList renders correctly 1`] = ` } testID="orders-list-crypto-amount-buy-7" > - 0 + ... ETH @@ -4979,7 +4979,7 @@ exports[`OrdersList resets filter to all after other filter was set 2`] = ` { "account": "0xe64dD0AB5ad7e8C5F2bf6Ce75C34e187af8b920A", "createdAt": 0, - "cryptoAmount": 0, + "cryptoAmount": "...", "cryptoCurrencySymbol": "ETH", "fiatAmount": undefined, "fiatCurrencyCode": "USD", @@ -6338,7 +6338,7 @@ exports[`OrdersList resets filter to all after other filter was set 2`] = ` } testID="orders-list-crypto-amount-buy-7" > - 0 + ... ETH diff --git a/app/components/UI/Ramp/Views/OrderDetails/OrderContent.test.tsx b/app/components/UI/Ramp/Views/OrderDetails/OrderContent.test.tsx index f4c86a0f6fc..caabda17194 100644 --- a/app/components/UI/Ramp/Views/OrderDetails/OrderContent.test.tsx +++ b/app/components/UI/Ramp/Views/OrderDetails/OrderContent.test.tsx @@ -90,13 +90,14 @@ describe('OrderContent', () => { const pendingOrder: RampsOrder = { ...mockOrder, fiatAmount: 0, + cryptoAmount: 0, status: RampsOrderStatus.Pending, }; renderOrder(pendingOrder); expect(screen.toJSON()).toMatchSnapshot(); }); - it('shows ellipsis for token amount when cryptoAmount is 0 or missing', () => { + it('shows placeholder for token amount when cryptoAmount is 0 or missing', () => { const orderWithZeroCrypto: RampsOrder = { ...mockOrder, cryptoAmount: 0, @@ -285,7 +286,7 @@ describe('OrderContent', () => { expect(tokenAmount).toHaveTextContent('0.0₅614 ETH'); }); - it('shows "..." when cryptoAmount is missing', () => { + it('shows placeholder when cryptoAmount is missing', () => { const noAmountOrder: RampsOrder = { ...mockOrder, cryptoAmount: undefined as unknown as number, @@ -295,14 +296,32 @@ describe('OrderContent', () => { expect(tokenAmount).toHaveTextContent('... ETH'); }); - it('renders "0" when cryptoAmount is zero', () => { + it('shows placeholder when cryptoAmount is zero', () => { const zeroAmountOrder: RampsOrder = { ...mockOrder, cryptoAmount: 0, }; renderOrder(zeroAmountOrder); const tokenAmount = screen.getByTestId('ramps-order-details-token-amount'); - expect(tokenAmount).toHaveTextContent('0 ETH'); + expect(tokenAmount).toHaveTextContent('... ETH'); + }); + + it('shows placeholder amounts for terminal orders with no amounts', () => { + const failedOrder: RampsOrder = { + ...mockOrder, + cryptoAmount: 0, + fiatAmount: 0, + totalFeesFiat: 0, + status: RampsOrderStatus.Failed, + }; + + renderOrder(failedOrder); + + expect(screen.getByText('Failed')).toBeOnTheScreen(); + expect( + screen.getByTestId('ramps-order-details-token-amount'), + ).toHaveTextContent('... ETH'); + expect(screen.getAllByText('...')).toHaveLength(2); }); it('does not render info row when statusDescription is absent', () => { diff --git a/app/components/UI/Ramp/Views/OrderDetails/OrderContent.tsx b/app/components/UI/Ramp/Views/OrderDetails/OrderContent.tsx index 2843e9d9712..abb5fc9491d 100644 --- a/app/components/UI/Ramp/Views/OrderDetails/OrderContent.tsx +++ b/app/components/UI/Ramp/Views/OrderDetails/OrderContent.tsx @@ -26,7 +26,6 @@ import BadgeWrapper, { import { AvatarSize } from '../../../../../component-library/components/Avatars/Avatar'; import I18n, { strings } from '../../../../../../locales/i18n'; import { toDateFormat } from '../../../../../util/date'; -import { renderFiat } from '../../../../../util/number'; import { formatSubscriptNotation } from '../../../../../util/number/subscriptNotation'; import { formatWithThreshold } from '../../../../../util/assets'; import { getNetworkImageSource } from '../../../../../util/networks'; @@ -41,6 +40,14 @@ import BankDetailRow from '../../Deposit/components/BankDetailRow/BankDetailRow' import Routes from '../../../../../constants/navigation/Routes'; import { RampsOrderDetailsSelectorsIDs } from './OrderDetails.testIds'; +const AMOUNT_PLACEHOLDER = '...'; +const TERMINAL_STATUSES = new Set([ + RampsOrderStatus.Completed, + RampsOrderStatus.Failed, + RampsOrderStatus.Cancelled, + RampsOrderStatus.IdExpired, +]); + const localStyles = StyleSheet.create({ badgeWrapperCenter: { alignSelf: 'center', @@ -168,7 +175,16 @@ const OrderContent: React.FC = ({ } }; - const isLoading = !order.fiatAmount; + const fiatCurrencyCode = order.fiatCurrency?.symbol ?? ''; + const cryptoSymbol = order.cryptoCurrency?.symbol ?? ''; + + const hasAmounts = Boolean( + fiatCurrencyCode && + ((order.fiatAmount != null && Number(order.fiatAmount) > 0) || + (order.cryptoAmount != null && Number(order.cryptoAmount) > 0)), + ); + const isTerminal = TERMINAL_STATUSES.has(order.status); + const isLoading = !hasAmounts && !isTerminal; const handleClose = useCallback(() => { trackEvent( @@ -207,10 +223,6 @@ const OrderContent: React.FC = ({ trackEvent, ]); - const fiatDenomSymbol = order.fiatCurrency?.denomSymbol ?? ''; - const fiatCurrencyCode = order.fiatCurrency?.symbol ?? ''; - const cryptoSymbol = order.cryptoCurrency?.symbol ?? ''; - const normalizeChainIdForBadge = (chainId: string): string => { if (!chainId || chainId.includes(':') || chainId.startsWith('0x')) { return chainId; @@ -332,7 +344,7 @@ const OrderContent: React.FC = ({ fontWeight={FontWeight.Bold} twClassName="mt-6 text-center" > - {order.cryptoAmount != null + {order.cryptoAmount != null && Number(order.cryptoAmount) > 0 ? (formatSubscriptNotation( parseFloat(String(order.cryptoAmount)), ) ?? @@ -345,7 +357,7 @@ const OrderContent: React.FC = ({ maximumFractionDigits: 5, }, )) - : '...'}{' '} + : AMOUNT_PLACEHOLDER}{' '} {cryptoSymbol} @@ -475,12 +487,19 @@ const OrderContent: React.FC = ({ ) : ( - {fiatDenomSymbol} - {renderFiat( - Number(order.totalFeesFiat ?? 0), - fiatCurrencyCode, - fiatDecimals, - )} + {hasAmounts + ? formatWithThreshold( + Number(order.totalFeesFiat ?? 0), + 0, + I18n.locale, + { + style: 'currency', + currency: fiatCurrencyCode, + minimumFractionDigits: fiatDecimals, + maximumFractionDigits: fiatDecimals, + }, + ) + : AMOUNT_PLACEHOLDER} )} @@ -501,12 +520,19 @@ const OrderContent: React.FC = ({ ) : ( - {fiatDenomSymbol} - {renderFiat( - Number(order.fiatAmount ?? 0), - fiatCurrencyCode, - fiatDecimals, - )} + {hasAmounts + ? formatWithThreshold( + Number(order.fiatAmount ?? 0), + 0, + I18n.locale, + { + style: 'currency', + currency: fiatCurrencyCode, + minimumFractionDigits: fiatDecimals, + maximumFractionDigits: fiatDecimals, + }, + ) + : AMOUNT_PLACEHOLDER} )} diff --git a/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderContent.test.tsx.snap b/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderContent.test.tsx.snap index ddbffbb2581..2f20bd21c42 100644 --- a/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderContent.test.tsx.snap +++ b/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderContent.test.tsx.snap @@ -472,8 +472,7 @@ exports[`OrderContent renders completed state correctly 1`] = ` ] } > - $ - 2.5 USD + $2.50 - $ - 100 USD + $100.00 - 0.05 + ... ETH @@ -1095,7 +1093,7 @@ exports[`OrderContent renders loading state when order has no amount 1`] = ` `; -exports[`OrderContent shows ellipsis for token amount when cryptoAmount is 0 or missing 1`] = ` +exports[`OrderContent shows placeholder for token amount when cryptoAmount is 0 or missing 1`] = ` - 0 + ... ETH @@ -1567,8 +1565,7 @@ exports[`OrderContent shows ellipsis for token amount when cryptoAmount is 0 or ] } > - $ - 2.5 USD + $2.50 - $ - 100 USD + $100.00 { expect(result).toMatchSnapshot(); }); - it('defaults cryptoAmount to 0 when undefined', () => { - const fiatOrder = createMockFiatOrder({ cryptoAmount: undefined }); - const result = fiatOrderToDisplayOrder(fiatOrder); - expect(result.cryptoAmount).toBe(0); + it('uses placeholder when cryptoAmount is undefined or zero', () => { + expect( + fiatOrderToDisplayOrder( + createMockFiatOrder({ cryptoAmount: undefined }), + ).cryptoAmount, + ).toBe('...'); + expect( + fiatOrderToDisplayOrder(createMockFiatOrder({ cryptoAmount: 0 })) + .cryptoAmount, + ).toBe('...'); }); }); @@ -141,6 +147,23 @@ describe('displayOrder', () => { const result = rampsOrderToDisplayOrder(order); expect(result.createdAt).toBe(0); }); + + it('uses placeholder when cryptoAmount is 0 or missing', () => { + expect( + rampsOrderToDisplayOrder(createMockRampsOrder({ cryptoAmount: 0 })) + .cryptoAmount, + ).toBe('...'); + expect( + rampsOrderToDisplayOrder( + createMockRampsOrder({ cryptoAmount: undefined }), + ).cryptoAmount, + ).toBe('...'); + expect( + rampsOrderToDisplayOrder( + createMockRampsOrder({ cryptoAmount: null as unknown as string }), + ).cryptoAmount, + ).toBe('...'); + }); }); describe('mergeDisplayOrders', () => { diff --git a/app/components/UI/Ramp/utils/displayOrder.ts b/app/components/UI/Ramp/utils/displayOrder.ts index bf51aede63d..ad111e7b051 100644 --- a/app/components/UI/Ramp/utils/displayOrder.ts +++ b/app/components/UI/Ramp/utils/displayOrder.ts @@ -5,6 +5,8 @@ import { } from '../../../../reducers/fiatOrders'; import { FIAT_ORDER_PROVIDERS } from '../../../../constants/on-ramp'; +const AMOUNT_PLACEHOLDER = '...'; + export interface DisplayOrder { id: string; source: 'legacy' | 'v2'; @@ -37,7 +39,10 @@ export function fiatOrderToDisplayOrder(order: FiatOrder): DisplayOrder { createdAt: toEpochMs(order.createdAt), fiatAmount: order.amount, fiatCurrencyCode: order.currency, - cryptoAmount: order.cryptoAmount ?? 0, + cryptoAmount: + order.cryptoAmount != null && Number(order.cryptoAmount) > 0 + ? order.cryptoAmount + : AMOUNT_PLACEHOLDER, cryptoCurrencySymbol: order.cryptocurrency, network: order.network, status: order.state, @@ -65,7 +70,10 @@ export function rampsOrderToDisplayOrder(order: RampsOrder): DisplayOrder { createdAt: toEpochMs(order.createdAt), fiatAmount: order.fiatAmount, fiatCurrencyCode: order.fiatCurrency?.symbol ?? '', - cryptoAmount: order.cryptoAmount, + cryptoAmount: + order.cryptoAmount != null && Number(order.cryptoAmount) > 0 + ? order.cryptoAmount + : AMOUNT_PLACEHOLDER, cryptoCurrencySymbol: order.cryptoCurrency?.symbol ?? '', network: order.network?.chainId ?? '', status: RAMPS_STATUS_TO_DISPLAY[order.status] ?? 'PENDING',