diff --git a/src/components/CurrencyInputPanel/FiatValue.tsx b/src/components/CurrencyInputPanel/FiatValue.tsx index 0e7625e162..c0897b0466 100644 --- a/src/components/CurrencyInputPanel/FiatValue.tsx +++ b/src/components/CurrencyInputPanel/FiatValue.tsx @@ -6,7 +6,7 @@ import { MouseoverTooltip } from 'components/Tooltip' import { useMemo } from 'react' import styled from 'styled-components' import { ThemedText } from 'theme' -import { formatPriceImpact, NumberType, useFormatter } from 'utils/formatNumbers' +import { NumberType, useFormatter } from 'utils/formatNumbers' import { warningSeverity } from 'utils/prices' const FiatLoadingBubble = styled(LoadingBubble)` @@ -22,7 +22,7 @@ export function FiatValue({ fiatValue: { data?: number; isLoading: boolean } priceImpact?: Percent }) { - const { formatNumber } = useFormatter() + const { formatNumber, formatPriceImpact } = useFormatter() const priceImpactColor = useMemo(() => { if (!priceImpact) return undefined diff --git a/src/components/swap/AdvancedSwapDetails.tsx b/src/components/swap/AdvancedSwapDetails.tsx index 7721ef58d5..d0957b3426 100644 --- a/src/components/swap/AdvancedSwapDetails.tsx +++ b/src/components/swap/AdvancedSwapDetails.tsx @@ -9,7 +9,7 @@ import { ZERO_PERCENT } from 'constants/misc' import useNativeCurrency from 'lib/hooks/useNativeCurrency' import { ClassicTrade, InterfaceTrade } from 'state/routing/types' import { getTransactionCount, isClassicTrade } from 'state/routing/utils' -import { formatPriceImpact, NumberType, useFormatter } from 'utils/formatNumbers' +import { NumberType, useFormatter } from 'utils/formatNumbers' import { ExternalLink, Separator, ThemedText } from '../../theme' import Column from '../Column' @@ -47,7 +47,7 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }: const { chainId } = useWeb3React() const nativeCurrency = useNativeCurrency(chainId) const txCount = getTransactionCount(trade) - const { formatNumber, formatCurrencyAmount } = useFormatter() + const { formatCurrencyAmount, formatNumber, formatPriceImpact } = useFormatter() const supportsGasEstimate = chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) @@ -194,6 +194,8 @@ function TokenTaxLineItem({ type: 'input' | 'output' syncing: boolean }) { + const { formatPriceImpact } = useFormatter() + if (syncing) return null const [currency, percentage] = diff --git a/src/components/swap/PendingModalContent/TradeSummary.tsx b/src/components/swap/PendingModalContent/TradeSummary.tsx index 41977382f0..5365cf85cd 100644 --- a/src/components/swap/PendingModalContent/TradeSummary.tsx +++ b/src/components/swap/PendingModalContent/TradeSummary.tsx @@ -4,10 +4,12 @@ import { ArrowRight } from 'react-feather' import { InterfaceTrade } from 'state/routing/types' import { useTheme } from 'styled-components' import { ThemedText } from 'theme' -import { formatReviewSwapCurrencyAmount } from 'utils/formatNumbers' +import { useFormatter } from 'utils/formatNumbers' export function TradeSummary({ trade }: { trade: Pick }) { const theme = useTheme() + const { formatReviewSwapCurrencyAmount } = useFormatter() + return ( diff --git a/src/components/swap/PriceImpactModal.tsx b/src/components/swap/PriceImpactModal.tsx index ef454966a2..74e0948dd1 100644 --- a/src/components/swap/PriceImpactModal.tsx +++ b/src/components/swap/PriceImpactModal.tsx @@ -6,7 +6,7 @@ import Row from 'components/Row' import { AlertTriangle } from 'react-feather' import styled from 'styled-components' import { CloseIcon, ThemedText } from 'theme' -import { formatPriceImpact } from 'utils/formatNumbers' +import { useFormatter } from 'utils/formatNumbers' import Modal from '../Modal' @@ -37,6 +37,8 @@ interface PriceImpactModalProps { } export default function PriceImpactModal({ priceImpact, onDismiss, onContinue }: PriceImpactModalProps) { + const { formatPriceImpact } = useFormatter() + return ( diff --git a/src/components/swap/PriceImpactWarning.tsx b/src/components/swap/PriceImpactWarning.tsx index 5388b031fa..f478635ea8 100644 --- a/src/components/swap/PriceImpactWarning.tsx +++ b/src/components/swap/PriceImpactWarning.tsx @@ -3,7 +3,7 @@ import { Percent } from '@uniswap/sdk-core' import { OutlineCard } from 'components/Card' import styled, { useTheme } from 'styled-components' import { opacify } from 'theme/utils' -import formatPriceImpact from 'utils/formatPriceImpact' +import { useFormatter } from 'utils/formatNumbers' import { ThemedText } from '../../theme' import { AutoColumn } from '../Column' @@ -20,6 +20,7 @@ interface PriceImpactWarningProps { } export default function PriceImpactWarning({ priceImpact }: PriceImpactWarningProps) { + const { formatPriceImpact } = useFormatter() const theme = useTheme() return ( diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx index 684e80899b..91fca8416a 100644 --- a/src/components/swap/SwapModalFooter.tsx +++ b/src/components/swap/SwapModalFooter.tsx @@ -16,8 +16,8 @@ import { getTransactionCount, isClassicTrade } from 'state/routing/utils' import { useRouterPreference, useUserSlippageTolerance } from 'state/user/hooks' import styled, { DefaultTheme, useTheme } from 'styled-components' import { ExternalLink, ThemedText } from 'theme' -import { formatPriceImpact, NumberType, useFormatter } from 'utils/formatNumbers' -import { formatTransactionAmount, priceToPreciseFloat } from 'utils/formatNumbers' +import { FormatterRule, NumberType, SIX_SIG_FIGS_NO_COMMAS, useFormatter } from 'utils/formatNumbers' +import { priceToPreciseFloat } from 'utils/formatNumbers' import getRoutingDiagramEntries from 'utils/getRoutingDiagramEntries' import { formatSwapButtonClickEventProperties } from 'utils/loggingFormatters' import { getPriceImpactColor } from 'utils/prices' @@ -28,6 +28,8 @@ import { GasBreakdownTooltip } from './GasBreakdownTooltip' import { SwapCallbackError, SwapShowAcceptChanges } from './styled' import { Label } from './SwapModalHeaderAmount' +const sixFigsFormatterRules: FormatterRule[] = [{ upperBound: Infinity, formatterOptions: SIX_SIG_FIGS_NO_COMMAS }] + const DetailsContainer = styled(Column)` padding: 0 8px; ` @@ -78,11 +80,14 @@ export default function SwapModalFooter({ const theme = useTheme() const { chainId } = useWeb3React() const nativeCurrency = useNativeCurrency(chainId) - const { formatNumber } = useFormatter() + const { formatCurrencyAmount, formatNumber, formatPriceImpact } = useFormatter() const label = `${trade.executionPrice.baseCurrency?.symbol} ` const labelInverted = `${trade.executionPrice.quoteCurrency?.symbol}` - const formattedPrice = formatTransactionAmount(priceToPreciseFloat(trade.executionPrice)) + const formattedPrice = formatNumber({ + input: priceToPreciseFloat(trade.executionPrice), + type: NumberType.TokenTx, + }) const txCount = getTransactionCount(trade) return ( @@ -164,8 +169,14 @@ export default function SwapModalFooter({ {trade.tradeType === TradeType.EXACT_INPUT - ? `${trade.minimumAmountOut(allowedSlippage).toSignificant(6)} ${trade.outputAmount.currency.symbol}` - : `${trade.maximumAmountIn(allowedSlippage).toSignificant(6)} ${trade.inputAmount.currency.symbol}`} + ? `${formatCurrencyAmount({ + amount: trade.minimumAmountOut(allowedSlippage), + type: sixFigsFormatterRules, + })} ${trade.outputAmount.currency.symbol}` + : `${formatCurrencyAmount({ + amount: trade.maximumAmountIn(allowedSlippage), + type: sixFigsFormatterRules, + })} ${trade.inputAmount.currency.symbol}`} @@ -223,6 +234,8 @@ export default function SwapModalFooter({ } function TokenTaxLineItem({ trade, type }: { trade: ClassicTrade; type: 'input' | 'output' }) { + const { formatPriceImpact } = useFormatter() + const [currency, percentage] = type === 'input' ? [trade.inputAmount.currency, trade.inputTax] : [trade.outputAmount.currency, trade.outputTax] diff --git a/src/components/swap/SwapModalHeaderAmount.tsx b/src/components/swap/SwapModalHeaderAmount.tsx index 29882e4402..a968a67d5f 100644 --- a/src/components/swap/SwapModalHeaderAmount.tsx +++ b/src/components/swap/SwapModalHeaderAmount.tsx @@ -10,7 +10,6 @@ import { Field } from 'state/swap/actions' import styled from 'styled-components' import { BREAKPOINTS, ThemedText } from 'theme' import { NumberType, useFormatter } from 'utils/formatNumbers' -import { formatReviewSwapCurrencyAmount } from 'utils/formatNumbers' export const Label = styled(ThemedText.BodySmall)<{ cursor?: string }>` cursor: ${({ cursor }) => cursor}; @@ -45,7 +44,7 @@ interface AmountProps { } export function SwapModalHeaderAmount({ tooltipText, label, amount, usdAmount, field, currency }: AmountProps) { - const { formatNumber } = useFormatter() + const { formatNumber, formatReviewSwapCurrencyAmount } = useFormatter() return ( diff --git a/src/components/swap/TradePrice.tsx b/src/components/swap/TradePrice.tsx index 7ff0b0065d..0c207da54e 100644 --- a/src/components/swap/TradePrice.tsx +++ b/src/components/swap/TradePrice.tsx @@ -5,7 +5,7 @@ import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { useCallback, useMemo, useState } from 'react' import styled from 'styled-components' import { ThemedText } from 'theme' -import { formatPrice, NumberType, useFormatter } from 'utils/formatNumbers' +import { NumberType, useFormatter } from 'utils/formatNumbers' interface TradePriceProps { price: Price @@ -28,7 +28,7 @@ const StyledPriceContainer = styled.button` ` export default function TradePrice({ price }: TradePriceProps) { - const { formatNumber } = useFormatter() + const { formatNumber, formatPrice } = useFormatter() const [showInverted, setShowInverted] = useState(false) @@ -37,11 +37,11 @@ export default function TradePrice({ price }: TradePriceProps) { const formattedPrice = useMemo(() => { try { - return formatPrice(showInverted ? price : price.invert(), NumberType.TokenTx) + return formatPrice({ price: showInverted ? price : price.invert(), type: NumberType.TokenTx }) } catch { return '0' } - }, [price, showInverted]) + }, [formatPrice, price, showInverted]) const label = showInverted ? `${price.quoteCurrency?.symbol}` : `${price.baseCurrency?.symbol} ` const labelInverted = showInverted ? `${price.baseCurrency?.symbol} ` : `${price.quoteCurrency?.symbol}` diff --git a/src/pages/Pool/PositionPage.tsx b/src/pages/Pool/PositionPage.tsx index e3f3c882a8..c09b1f30e7 100644 --- a/src/pages/Pool/PositionPage.tsx +++ b/src/pages/Pool/PositionPage.tsx @@ -37,7 +37,7 @@ import { ExternalLink, HideExtraSmall, HideSmall, StyledRouterLink, ThemedText } import { currencyId } from 'utils/currencyId' import { WrongChainError } from 'utils/errors' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' -import { formatPrice, NumberType } from 'utils/formatNumbers' +import { NumberType, useFormatter } from 'utils/formatNumbers' import { formatTickPrice } from 'utils/formatTickPrice' import { unwrappedToken } from 'utils/unwrappedToken' @@ -179,6 +179,8 @@ function CurrentPriceCard({ currencyQuote?: Currency currencyBase?: Currency }) { + const { formatPrice } = useFormatter() + if (!pool || !currencyQuote || !currencyBase) { return null } @@ -190,7 +192,7 @@ function CurrentPriceCard({ Current price - {formatPrice(inverted ? pool.token1Price : pool.token0Price, NumberType.TokenTx)} + {formatPrice({ price: inverted ? pool.token1Price : pool.token0Price, type: NumberType.TokenTx })} diff --git a/src/utils/formatNumbers.test.ts b/src/utils/formatNumbers.test.ts index b81fe3abaa..e50a44b07e 100644 --- a/src/utils/formatNumbers.test.ts +++ b/src/utils/formatNumbers.test.ts @@ -8,7 +8,6 @@ import { formatPriceImpact, formatReviewSwapCurrencyAmount, formatSlippage, - formatTransactionAmount, formatUSDPrice, NumberType, priceToPreciseFloat, @@ -513,53 +512,6 @@ describe('priceToPreciseFloat', () => { }) }) -describe('formatTransactionAmount', () => { - it('undefined or null', () => { - expect(formatTransactionAmount(undefined)).toEqual('') - expect(formatTransactionAmount(null)).toEqual('') - }) - it('0', () => { - expect(formatTransactionAmount(0)).toEqual('0.00') - }) - it('< 0.00001', () => { - expect(formatTransactionAmount(0.000000001)).toEqual('<0.00001') - }) - it('1 > number ≥ .00001 full precision', () => { - expect(formatTransactionAmount(0.987654321)).toEqual('0.98765') - }) - it('1 > number ≥ .00001 minimum 2 decimals', () => { - expect(formatTransactionAmount(0.9)).toEqual('0.90') - }) - it('1 > number ≥ .00001 no trailing zeros beyond 2nd decimal', () => { - expect(formatTransactionAmount(0.901000123)).toEqual('0.901') - }) - it('10,000 > number ≥ 1 round to 6 sig figs', () => { - expect(formatTransactionAmount(7654.3210789)).toEqual('7,654.32') - }) - it('10,000 > number ≥ 1 round to 6 sig figs 2nd case', () => { - expect(formatTransactionAmount(76.3210789)).toEqual('76.3211') - }) - it('10,000 > number ≥ 1 no trailing zeros beyond 2nd decimal place', () => { - expect(formatTransactionAmount(7.60000054321)).toEqual('7.60') - }) - it('10,000 > number ≥ 1 always show at least 2 decimal places', () => { - expect(formatTransactionAmount(7)).toEqual('7.00') - }) - it('1M > number ≥ 10,000 few decimals', () => { - expect(formatTransactionAmount(765432.1)).toEqual('765,432.10') - }) - it('1M > number ≥ 10,000 lots of decimals', () => { - expect(formatTransactionAmount(76543.2123424)).toEqual('76,543.21') - }) - it('Number ≥ 1M', () => { - expect(formatTransactionAmount(1234567.8901)).toEqual('1,234,567.89') - }) - it('Number ≥ 1M extra long', () => { - // eslint-disable-next-line @typescript-eslint/no-loss-of-precision - expect(formatTransactionAmount(1234567890123456.789)).toEqual('1.234568e+15') - }) -}) - describe('formatReviewSwapCurrencyAmount', () => { it('should use TokenTx formatting under a default length', () => { const currencyAmount = CurrencyAmount.fromRawAmount(USDC_MAINNET, '2000000000') // 2,000 USDC diff --git a/src/utils/formatNumbers.ts b/src/utils/formatNumbers.ts index 6d490ceb93..c21d4550bc 100644 --- a/src/utils/formatNumbers.ts +++ b/src/utils/formatNumbers.ts @@ -118,7 +118,7 @@ const SIX_SIG_FIGS_TWO_DECIMALS: NumberFormatOptions = { minimumFractionDigits: 2, } -const SIX_SIG_FIGS_NO_COMMAS: NumberFormatOptions = { +export const SIX_SIG_FIGS_NO_COMMAS: NumberFormatOptions = { notation: 'standard', maximumSignificantDigits: 6, useGrouping: false, @@ -177,7 +177,7 @@ type FormatterBaseRule = { formatterOptions: NumberFormatOptions } type FormatterExactRule = { upperBound?: undefined; exact: number } & FormatterBaseRule type FormatterUpperBoundRule = { upperBound: number; exact?: undefined } & FormatterBaseRule -type FormatterRule = (FormatterExactRule | FormatterUpperBoundRule) & { hardCodedInput?: HardCodedInputFormat } +export type FormatterRule = (FormatterExactRule | FormatterUpperBoundRule) & { hardCodedInput?: HardCodedInputFormat } // these formatter objects dictate which formatter rule to use based on the interval that // the number falls into. for example, based on the rule set below, if your number @@ -349,6 +349,7 @@ export enum NumberType { NFTTokenFloorPriceTrailingZeros = 'nft-token-floor-price-trailing-zeros', } +type FormatterType = NumberType | FormatterRule[] const TYPE_TO_FORMATTER_RULES = { [NumberType.TokenNonTx]: tokenNonTxFormatter, [NumberType.TokenTx]: tokenTxFormatter, @@ -365,8 +366,8 @@ const TYPE_TO_FORMATTER_RULES = { [NumberType.NFTCollectionStats]: ntfCollectionStatsFormatter, } -function getFormatterRule(input: number, type: NumberType, conversionRate?: number): FormatterRule { - const rules = TYPE_TO_FORMATTER_RULES[type] +function getFormatterRule(input: number, type: FormatterType, conversionRate?: number): FormatterRule { + const rules = Array.isArray(type) ? type : TYPE_TO_FORMATTER_RULES[type] for (const rule of rules) { const shouldConvertInput = rule.formatterOptions.currency && conversionRate const convertedInput = shouldConvertInput ? input * conversionRate : input @@ -384,7 +385,7 @@ function getFormatterRule(input: number, type: NumberType, conversionRate?: numb interface FormatNumberOptions { input: Nullish - type?: NumberType + type?: FormatterType placeholder?: string locale?: SupportedLocale localCurrency?: SupportedLocalCurrency @@ -426,7 +427,7 @@ export function formatNumber({ interface FormatCurrencyAmountOptions { amount: Nullish> - type?: NumberType + type?: FormatterType placeholder?: string locale?: SupportedLocale localCurrency?: SupportedLocalCurrency @@ -451,10 +452,14 @@ export function formatCurrencyAmount({ }) } -export function formatPriceImpact(priceImpact: Percent | undefined): string { +export function formatPriceImpact(priceImpact: Percent | undefined, locale: SupportedLocale = DEFAULT_LOCALE): string { if (!priceImpact) return '-' - return `${priceImpact.multiply(-1).toFixed(3)}%` + return `${Number(priceImpact.multiply(-1).toFixed(3)).toLocaleString(locale, { + minimumFractionDigits: 3, + maximumFractionDigits: 3, + useGrouping: false, + })}%` } export function formatSlippage(slippage: Percent | undefined) { @@ -463,18 +468,29 @@ export function formatSlippage(slippage: Percent | undefined) { return `${slippage.toFixed(3)}%` } -export function formatPrice( - price: Nullish>, - type: NumberType = NumberType.FiatTokenPrice -): string { +interface FormatPriceProps { + price: Nullish> + type: FormatterType + locale?: SupportedLocale + localCurrency?: SupportedLocalCurrency + conversionRate?: number +} + +export function formatPrice({ + price, + type = NumberType.FiatTokenPrice, + locale = DEFAULT_LOCALE, + localCurrency = DEFAULT_LOCAL_CURRENCY, + conversionRate, +}: FormatPriceProps): string { if (price === null || price === undefined) { return '-' } - return formatNumber({ input: parseFloat(price.toSignificant()), type }) + return formatNumber({ input: parseFloat(price.toSignificant()), type, locale, localCurrency, conversionRate }) } -export function formatNumberOrString(price: Nullish, type: NumberType): string { +export function formatNumberOrString(price: Nullish, type: FormatterType): string { if (price === null || price === undefined) return '-' if (typeof price === 'string') return formatNumber({ input: parseFloat(price), type }) return formatNumber({ input: price, type }) @@ -510,50 +526,15 @@ export const priceToPreciseFloat = (price: Price | undefined return floatForLargerNumbers } -/** - * Returns a numerical amount of any token formatted in human readable string for use in template. - * - * For transaction review numbers, such as token quantities, NFT price (token-denominated), - * network fees, transaction history items. Adheres to guidelines defined here: - * https://www.notion.so/uniswaplabs/Number-standards-fbb9f533f10e4e22820722c2f66d23c0 - * @param num numerical value denominated in any token - * @param maxDigits the maximum number of digits that should be shown for the quantity - */ -export const formatTransactionAmount = (num: number | undefined | null, maxDigits = 9) => { - if (num === 0) return '0.00' - if (!num) return '' - if (num < 0.00001) { - return '<0.00001' - } - if (num >= 0.00001 && num < 1) { - return `${Number(num.toFixed(5)).toLocaleString(DEFAULT_LOCALE, { - minimumFractionDigits: 2, - maximumFractionDigits: 5, - })}` - } - if (num >= 1 && num < 10000) { - return `${Number(num.toPrecision(6)).toLocaleString(DEFAULT_LOCALE, { - minimumFractionDigits: 2, - maximumFractionDigits: 6, - })}` - } - if (num >= 10000 && num < 1000000) { - return `${Number(num.toFixed(2)).toLocaleString(DEFAULT_LOCALE, { minimumFractionDigits: 2 })}` - } - // For very large numbers, switch to scientific notation and show as much precision - // as permissible by maxDigits param. - if (num >= Math.pow(10, maxDigits - 1)) { - return `${num.toExponential(maxDigits - 3)}` - } - return `${Number(num.toFixed(2)).toLocaleString(DEFAULT_LOCALE, { minimumFractionDigits: 2 })}` -} - const MAX_AMOUNT_STR_LENGTH = 9 -export function formatReviewSwapCurrencyAmount(amount: CurrencyAmount): string { - let formattedAmount = formatCurrencyAmount({ amount, type: NumberType.TokenTx }) +export function formatReviewSwapCurrencyAmount( + amount: CurrencyAmount, + locale: SupportedLocale = DEFAULT_LOCALE +): string { + let formattedAmount = formatCurrencyAmount({ amount, type: NumberType.TokenTx, locale }) if (formattedAmount.length > MAX_AMOUNT_STR_LENGTH) { - formattedAmount = formatCurrencyAmount({ amount, type: NumberType.SwapTradeAmount }) + formattedAmount = formatCurrencyAmount({ amount, type: NumberType.SwapTradeAmount, locale }) } return formattedAmount } @@ -582,24 +563,24 @@ export function useFormatterLocales(): { function handleFallbackCurrency( selectedCurrency: SupportedLocalCurrency, previousSelectedCurrency: SupportedLocalCurrency | undefined, + previousConversionRate: number | undefined, shouldFallbackToUSD: boolean, shouldFallbackToPrevious: boolean ) { if (shouldFallbackToUSD) return DEFAULT_LOCAL_CURRENCY - if (shouldFallbackToPrevious) return previousSelectedCurrency + if (shouldFallbackToPrevious) return previousConversionRate ? previousSelectedCurrency : DEFAULT_LOCAL_CURRENCY return selectedCurrency } // Constructs an object that injects the correct locale and local currency into each of the above formatter functions. export function useFormatter() { - const activeLocalCurrency = useActiveLocalCurrency() const { formatterLocale, formatterLocalCurrency } = useFormatterLocales() - const activeLocalCurrencyIsUSD = activeLocalCurrency === GqlCurrency.Usd + const formatterLocalCurrencyIsUSD = formatterLocalCurrency === GqlCurrency.Usd const { data: localCurrencyConversionRate, isLoading: localCurrencyConversionRateIsLoading } = - useLocalCurrencyConversionRate(activeLocalCurrency, activeLocalCurrencyIsUSD) + useLocalCurrencyConversionRate(formatterLocalCurrency, formatterLocalCurrencyIsUSD) - const previousSelectedCurrency = usePrevious(activeLocalCurrency) + const previousSelectedCurrency = usePrevious(formatterLocalCurrency) const previousConversionRate = usePrevious(localCurrencyConversionRate) const shouldFallbackToPrevious = !localCurrencyConversionRate && localCurrencyConversionRateIsLoading @@ -607,6 +588,7 @@ export function useFormatter() { const currencyToFormatWith = handleFallbackCurrency( formatterLocalCurrency, previousSelectedCurrency, + previousConversionRate, shouldFallbackToUSD, shouldFallbackToPrevious ) @@ -614,8 +596,9 @@ export function useFormatter() { ? previousConversionRate : localCurrencyConversionRate + type LocalesType = 'locale' | 'localCurrency' | 'conversionRate' const formatNumberWithLocales = useCallback( - (options: Omit) => + (options: Omit) => formatNumber({ ...options, locale: formatterLocale, @@ -626,7 +609,7 @@ export function useFormatter() { ) const formatCurrencyAmountWithLocales = useCallback( - (options: Omit) => + (options: Omit) => formatCurrencyAmount({ ...options, locale: formatterLocale, @@ -636,11 +619,41 @@ export function useFormatter() { [currencyToFormatWith, formatterLocale, localCurrencyConversionRateToFormatWith] ) + const formatPriceWithLocales = useCallback( + (options: Omit) => + formatPrice({ + ...options, + locale: formatterLocale, + localCurrency: currencyToFormatWith, + conversionRate: localCurrencyConversionRateToFormatWith, + }), + [currencyToFormatWith, formatterLocale, localCurrencyConversionRateToFormatWith] + ) + + const formatPriceImpactWithLocales = useCallback( + (priceImpact: Percent | undefined) => formatPriceImpact(priceImpact, formatterLocale), + [formatterLocale] + ) + + const formatReviewSwapCurrencyAmountWithLocales = useCallback( + (amount: CurrencyAmount) => formatReviewSwapCurrencyAmount(amount, formatterLocale), + [formatterLocale] + ) + return useMemo( () => ({ - formatNumber: formatNumberWithLocales, formatCurrencyAmount: formatCurrencyAmountWithLocales, + formatNumber: formatNumberWithLocales, + formatPrice: formatPriceWithLocales, + formatPriceImpact: formatPriceImpactWithLocales, + formatReviewSwapCurrencyAmount: formatReviewSwapCurrencyAmountWithLocales, }), - [formatCurrencyAmountWithLocales, formatNumberWithLocales] + [ + formatCurrencyAmountWithLocales, + formatNumberWithLocales, + formatPriceImpactWithLocales, + formatPriceWithLocales, + formatReviewSwapCurrencyAmountWithLocales, + ] ) } diff --git a/src/utils/formatPriceImpact.test.ts b/src/utils/formatPriceImpact.test.ts deleted file mode 100644 index aba7ccc096..0000000000 --- a/src/utils/formatPriceImpact.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Percent } from '@uniswap/sdk-core' - -import formatPriceImpact from './formatPriceImpact' - -describe('formatPriceImpact', () => { - it('formats price impact', () => { - expect(formatPriceImpact(new Percent(5, 10_000))).toEqual('-0.05%') - }) - // While there's theoretically no such thing as "positive price impact", this can show up - // due to a bug in routing-api, so it's still tested for - it('formats price impact when given a negative value', () => { - expect(formatPriceImpact(new Percent(-5, 10_000))).toEqual('0.05%') - }) -}) diff --git a/src/utils/formatPriceImpact.ts b/src/utils/formatPriceImpact.ts deleted file mode 100644 index b13b3e1ff2..0000000000 --- a/src/utils/formatPriceImpact.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Percent } from '@uniswap/sdk-core' - -export default function formatPriceImpact(priceImpact: Percent) { - return `${priceImpact.multiply(-1).toFixed(2)}%` -} diff --git a/src/utils/formatTickPrice.ts b/src/utils/formatTickPrice.ts index 9b6e37a595..072594f9c2 100644 --- a/src/utils/formatTickPrice.ts +++ b/src/utils/formatTickPrice.ts @@ -20,5 +20,5 @@ export function formatTickPrice({ price, atLimit, direction, placeholder, number return placeholder } - return formatPrice(price, numberType ?? NumberType.TokenNonTx) + return formatPrice({ price, type: numberType ?? NumberType.TokenNonTx }) }