diff --git a/sample.env b/sample.env
index 1c672d2d702..fde95503572 100644
--- a/sample.env
+++ b/sample.env
@@ -31,6 +31,7 @@ REACT_APP_MIDGARD_URL=https://midgard.thorchain.info/v2
REACT_APP_FRIENDLY_CAPTCHA_SITE_KEY=FCMM7AFC0S6A8NUK
+REACT_APP_FEATURE_MULTI_CURRENCY=false
REACT_APP_FEATURE_OSMOSIS=false
REACT_APP_FEATURE_WALLETCONNECT_WALLET=false
REACT_APP_FEATURE_AVALANCHE=false
diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json
index d00fe2a0df5..5dbc2632445 100644
--- a/src/assets/translations/en/main.json
+++ b/src/assets/translations/en/main.json
@@ -695,6 +695,7 @@
"settings": {
"settings": "Settings",
"currency": "Currency",
+ "currencyFormat": "Currency Format",
"language": "Language",
"balanceThreshold": "Balance Threshold",
"balanceThresholdTooltip": "Hide balances below this value",
diff --git a/src/components/Amount/Amount.tsx b/src/components/Amount/Amount.tsx
index 615585c83ce..7e93cfab47a 100644
--- a/src/components/Amount/Amount.tsx
+++ b/src/components/Amount/Amount.tsx
@@ -10,6 +10,9 @@ type AmountProps = {
value: number | string
prefix?: string
suffix?: string
+ omitDecimalTrailingZeros?: boolean
+ abbreviated?: boolean
+ maximumFractionDigits?: number
} & TextProps
export function Amount({
@@ -17,16 +20,18 @@ export function Amount({
prefix = '',
suffix = '',
maximumFractionDigits,
+ omitDecimalTrailingZeros = false,
+ abbreviated = false,
...props
}: any): React.ReactElement {
const {
number: { toString },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
return (
{prefix}
- {toString(value, { maximumFractionDigits })}
+ {toString(value, { maximumFractionDigits, omitDecimalTrailingZeros, abbreviated })}
{suffix}
)
@@ -56,13 +61,14 @@ const Crypto = ({
maximumFractionDigits = 8,
prefix,
suffix,
+ omitDecimalTrailingZeros = false,
...props
}: CryptoAmountProps) => {
const {
number: { toCrypto, toParts },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
- const crypto = toCrypto(value, symbol, { maximumFractionDigits })
+ const crypto = toCrypto(value, symbol, { maximumFractionDigits, omitDecimalTrailingZeros })
if (!cryptoSymbolStyle) {
return (
@@ -93,12 +99,27 @@ const Crypto = ({
)
}
-const Fiat = ({ value, fiatSymbolStyle, fiatType, prefix, suffix, ...props }: FiatAmountProps) => {
+const Fiat = ({
+ value,
+ fiatSymbolStyle,
+ fiatType,
+ prefix,
+ suffix,
+ maximumFractionDigits,
+ omitDecimalTrailingZeros = false,
+ abbreviated = false,
+ ...props
+}: FiatAmountProps) => {
const {
number: { toFiat, toParts },
- } = useLocaleFormatter({ fiatType: fiatType || 'USD' })
+ } = useLocaleFormatter({ fiatType })
- const fiat = toFiat(value, { fiatType })
+ const fiat = toFiat(value, {
+ fiatType,
+ omitDecimalTrailingZeros,
+ abbreviated,
+ maximumFractionDigits,
+ })
if (!fiatSymbolStyle) {
return (
@@ -132,7 +153,7 @@ const Fiat = ({ value, fiatSymbolStyle, fiatType, prefix, suffix, ...props }: Fi
const Percent = ({ value, autoColor, options, prefix, suffix, ...props }: PercentAmountProps) => {
const {
number: { toPercent },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const formattedNumber = toPercent(value, options)
const color = useMemo(() => {
@@ -155,17 +176,6 @@ const Percent = ({ value, autoColor, options, prefix, suffix, ...props }: Percen
)
}
-const Supply = ({ value, ...props }: AmountProps) => {
- const {
- number: { toSupply },
- } = useLocaleFormatter({ fiatType: 'USD' })
-
- const volume = toSupply(value)
-
- return {volume}
-}
-
Amount.Crypto = Crypto
Amount.Fiat = Fiat
Amount.Percent = Percent
-Amount.Supply = Supply
diff --git a/src/components/Approval/Approval.tsx b/src/components/Approval/Approval.tsx
index 7bfd02e1291..d68e9478afb 100644
--- a/src/components/Approval/Approval.tsx
+++ b/src/components/Approval/Approval.tsx
@@ -42,7 +42,7 @@ export const Approval = () => {
const { approveInfinite, checkApprovalNeeded, updateTrade } = useSwapper()
const {
number: { toCrypto, toFiat },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const {
state: { isConnected },
dispatch,
diff --git a/src/components/AssetHeader/AssetChart.tsx b/src/components/AssetHeader/AssetChart.tsx
index a4c230592d2..cf61754490f 100644
--- a/src/components/AssetHeader/AssetChart.tsx
+++ b/src/components/AssetHeader/AssetChart.tsx
@@ -56,7 +56,7 @@ type AssetChartProps = {
export const AssetChart = ({ accountId, assetId, isLoaded }: AssetChartProps) => {
const {
number: { toFiat },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const [percentChange, setPercentChange] = useState(0)
const alertIconColor = useColorModeValue('blue.500', 'blue.200')
const [timeframe, setTimeframe] = useState(DEFAULT_HISTORY_TIMEFRAME)
diff --git a/src/components/AssetHeader/AssetMarketData.tsx b/src/components/AssetHeader/AssetMarketData.tsx
index 04d8af06279..88bcb7d147c 100644
--- a/src/components/AssetHeader/AssetMarketData.tsx
+++ b/src/components/AssetHeader/AssetMarketData.tsx
@@ -104,7 +104,7 @@ export const AssetMarketData: React.FC = ({ assetId }) =>
-
+
)}
@@ -114,7 +114,11 @@ export const AssetMarketData: React.FC = ({ assetId }) =>
-
+
)}
diff --git a/src/components/DeFi/components/AssetInput.tsx b/src/components/DeFi/components/AssetInput.tsx
index b8eb7f3c76a..b7e50c22793 100644
--- a/src/components/DeFi/components/AssetInput.tsx
+++ b/src/components/DeFi/components/AssetInput.tsx
@@ -71,7 +71,7 @@ export const AssetInput: React.FC = ({
}) => {
const {
number: { localeParts },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const translate = useTranslate()
const amountRef = useRef(null)
const [isFiat, setIsFiat] = useState(false)
diff --git a/src/components/Graph/PrimaryChart/PrimaryChart.tsx b/src/components/Graph/PrimaryChart/PrimaryChart.tsx
index 3f8d39a0ea4..8c1142222b6 100644
--- a/src/components/Graph/PrimaryChart/PrimaryChart.tsx
+++ b/src/components/Graph/PrimaryChart/PrimaryChart.tsx
@@ -53,7 +53,7 @@ export const PrimaryChart = ({
const {
number: { toFiat },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const [chartColor] = useToken('colors', [color])
const tooltipBg = useColorModeValue('white', colors.gray[800])
diff --git a/src/components/Modals/Send/Form.tsx b/src/components/Modals/Send/Form.tsx
index 5773561febb..ecb46e6e003 100644
--- a/src/components/Modals/Send/Form.tsx
+++ b/src/components/Modals/Send/Form.tsx
@@ -15,7 +15,7 @@ import {
import { SelectAssetRoutes } from 'components/SelectAssets/SelectAssetCommon'
import { SelectAssetRouter } from 'components/SelectAssets/SelectAssetRouter'
import { AccountSpecifier } from 'state/slices/accountSpecifiersSlice/accountSpecifiersSlice'
-import { selectMarketDataById } from 'state/slices/selectors'
+import { selectMarketDataById, selectSelectedCurrency } from 'state/slices/selectors'
import { useAppSelector } from 'state/store'
import { useFormSend } from './hooks/useFormSend/useFormSend'
@@ -50,6 +50,7 @@ export const Form = ({ asset: initialAsset, accountId }: SendFormProps) => {
const location = useLocation()
const history = useHistory()
const { handleSend } = useFormSend()
+ const selectedCurrency = useAppSelector(selectSelectedCurrency)
const marketData = useAppSelector(state => selectMarketDataById(state, initialAsset.assetId))
const methods = useForm({
@@ -63,7 +64,7 @@ export const Form = ({ asset: initialAsset, accountId }: SendFormProps) => {
cryptoAmount: '',
cryptoSymbol: initialAsset?.symbol,
fiatAmount: '',
- fiatSymbol: 'USD', // TODO: use user preferences to get default fiat currency
+ fiatSymbol: selectedCurrency,
},
})
@@ -72,7 +73,7 @@ export const Form = ({ asset: initialAsset, accountId }: SendFormProps) => {
methods.setValue(SendFormFields.CryptoAmount, '')
methods.setValue(SendFormFields.CryptoSymbol, asset.symbol)
methods.setValue(SendFormFields.FiatAmount, '')
- methods.setValue(SendFormFields.FiatSymbol, 'USD')
+ methods.setValue(SendFormFields.FiatSymbol, selectedCurrency)
methods.setValue(SendFormFields.AccountId, accountId)
history.push(SendRoutes.Address)
diff --git a/src/components/Modals/Settings/BalanceThresholdInput.tsx b/src/components/Modals/Settings/BalanceThresholdInput.tsx
index c5ac829c6a7..e371ccaed91 100644
--- a/src/components/Modals/Settings/BalanceThresholdInput.tsx
+++ b/src/components/Modals/Settings/BalanceThresholdInput.tsx
@@ -30,7 +30,7 @@ export const BalanceThresholdInput = () => {
const dispatch = useAppDispatch()
const {
number: { localeParts },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const onChange = (value: string) => {
dispatch(preferences.actions.setBalanceThreshold({ threshold: value }))
}
diff --git a/src/components/Modals/Settings/CurrencyFormat.tsx b/src/components/Modals/Settings/CurrencyFormat.tsx
new file mode 100644
index 00000000000..cf948e994ec
--- /dev/null
+++ b/src/components/Modals/Settings/CurrencyFormat.tsx
@@ -0,0 +1,82 @@
+import { ArrowBackIcon } from '@chakra-ui/icons'
+import { Button, Flex, Icon, IconButton, ModalBody, ModalHeader } from '@chakra-ui/react'
+import identity from 'lodash/identity'
+import sortBy from 'lodash/sortBy'
+import { FaCheck } from 'react-icons/fa'
+import { useTranslate } from 'react-polyglot'
+import { useHistory } from 'react-router-dom'
+import { SlideTransition } from 'components/SlideTransition'
+import { RawText } from 'components/Text'
+import { CurrencyFormats, preferences } from 'state/slices/preferencesSlice/preferencesSlice'
+import { selectCurrencyFormat } from 'state/slices/selectors'
+import { useAppDispatch, useAppSelector } from 'state/store'
+
+import { currencyFormatsRepresenter } from './SettingsCommon'
+
+export const CurrencyFormat = () => {
+ const dispatch = useAppDispatch()
+ const currentCurrencyFormat = useAppSelector(selectCurrencyFormat)
+ const translate = useTranslate()
+ const history = useHistory()
+ const { goBack } = history
+ const formats = sortBy(CurrencyFormats, identity)
+ const { setCurrencyFormat } = preferences.actions
+
+ return (
+
+ }
+ aria-label={translate('common.back')}
+ position='absolute'
+ top={2}
+ left={3}
+ fontSize='xl'
+ size='sm'
+ isRound
+ onClick={goBack}
+ />
+ {translate('modals.settings.currencyFormat')}
+ <>
+
+ {formats.map(currencyFormat => {
+ const active = currencyFormat === currentCurrencyFormat
+ const buttonProps = active
+ ? {
+ disabled: true,
+ _disabled: { opacity: 1 },
+ }
+ : {
+ pl: 8,
+ variant: 'ghost',
+ onClick: () => dispatch(setCurrencyFormat({ currencyFormat })),
+ }
+ return (
+
+ )
+ })}
+
+ >
+
+ )
+}
diff --git a/src/components/Modals/Settings/FiatCurrencies.tsx b/src/components/Modals/Settings/FiatCurrencies.tsx
new file mode 100644
index 00000000000..20aace76629
--- /dev/null
+++ b/src/components/Modals/Settings/FiatCurrencies.tsx
@@ -0,0 +1,87 @@
+import { ArrowBackIcon } from '@chakra-ui/icons'
+import { Button, Flex, Icon, IconButton, ModalBody, ModalHeader } from '@chakra-ui/react'
+import { SupportedFiatCurrencies, SupportedFiatCurrenciesList } from '@shapeshiftoss/market-service'
+import identity from 'lodash/identity'
+import sortBy from 'lodash/sortBy'
+import { FaCheck } from 'react-icons/fa'
+import { useTranslate } from 'react-polyglot'
+import { useHistory } from 'react-router-dom'
+import { SlideTransition } from 'components/SlideTransition'
+import { RawText, Text } from 'components/Text'
+import { preferences } from 'state/slices/preferencesSlice/preferencesSlice'
+import { selectSelectedCurrency } from 'state/slices/selectors'
+import { useAppDispatch, useAppSelector } from 'state/store'
+
+export const FiatCurrencies = () => {
+ const dispatch = useAppDispatch()
+ const selectedCurrency = useAppSelector(selectSelectedCurrency)
+ const translate = useTranslate()
+ const history = useHistory()
+ const { goBack } = history
+ const defaultCurrency: SupportedFiatCurrencies = 'USD'
+ const allFiatCurrencies = sortBy(SupportedFiatCurrenciesList, item =>
+ // keep default currency at the top of the list
+ item === defaultCurrency ? defaultCurrency : identity,
+ )
+ const { setSelectedCurrency } = preferences.actions
+
+ return (
+
+ }
+ aria-label={translate('common.back')}
+ position='absolute'
+ top={2}
+ left={3}
+ fontSize='xl'
+ size='sm'
+ isRound
+ onClick={goBack}
+ />
+ {translate('modals.settings.currency')}
+ <>
+
+ {allFiatCurrencies.map(currency => {
+ const active = currency === selectedCurrency
+ const buttonProps = active
+ ? {
+ disabled: true,
+ _disabled: { opacity: 1 },
+ }
+ : {
+ pl: 8,
+ variant: 'ghost',
+ onClick: () => dispatch(setSelectedCurrency({ currency })),
+ }
+ return (
+
+ )
+ })}
+
+ >
+
+ )
+}
diff --git a/src/components/Modals/Settings/Settings.tsx b/src/components/Modals/Settings/Settings.tsx
index abc8ca86652..1644e712097 100644
--- a/src/components/Modals/Settings/Settings.tsx
+++ b/src/components/Modals/Settings/Settings.tsx
@@ -5,7 +5,12 @@ import { useModal } from 'hooks/useModal/useModal'
import { SettingsRoutes } from './SettingsCommon'
import { SettingsRouter } from './SettingsRouter'
-export const entries = [SettingsRoutes.Index, SettingsRoutes.Languages]
+export const entries = [
+ SettingsRoutes.Index,
+ SettingsRoutes.Languages,
+ SettingsRoutes.FiatCurrencies,
+ SettingsRoutes.CurrencyFormat,
+]
const Settings = () => {
/**
diff --git a/src/components/Modals/Settings/SettingsCommon.ts b/src/components/Modals/Settings/SettingsCommon.ts
index 06fa79949de..c6e4d20d445 100644
--- a/src/components/Modals/Settings/SettingsCommon.ts
+++ b/src/components/Modals/Settings/SettingsCommon.ts
@@ -1,4 +1,13 @@
+import { CurrencyFormats } from 'state/slices/preferencesSlice/preferencesSlice'
+
export enum SettingsRoutes {
Index = '/settings/index',
- Languages = '/receive/languages',
+ Languages = '/settings/languages',
+ FiatCurrencies = '/settings/fiat-currencies',
+ CurrencyFormat = '/settings/currency-format',
+}
+
+export const currencyFormatsRepresenter: Record = {
+ [CurrencyFormats.DotDecimal]: '1,234.56',
+ [CurrencyFormats.CommaDecimal]: '1 234,56',
}
diff --git a/src/components/Modals/Settings/SettingsList.tsx b/src/components/Modals/Settings/SettingsList.tsx
index b6362fbb989..041aa6f7ecd 100644
--- a/src/components/Modals/Settings/SettingsList.tsx
+++ b/src/components/Modals/Settings/SettingsList.tsx
@@ -11,7 +11,7 @@ import {
useColorMode,
useColorModeValue,
} from '@chakra-ui/react'
-import { FaGreaterThanEqual } from 'react-icons/fa'
+import { FaCoins, FaDollarSign, FaGreaterThanEqual } from 'react-icons/fa'
import { IoDocumentTextOutline, IoLockClosed } from 'react-icons/io5'
import { MdChevronRight, MdLanguage } from 'react-icons/md'
import { useTranslate } from 'react-polyglot'
@@ -19,12 +19,17 @@ import { RouteComponentProps } from 'react-router-dom'
import { SlideTransition } from 'components/SlideTransition'
import { RawText } from 'components/Text'
import { useModal } from 'hooks/useModal/useModal'
-import { selectSelectedLocale } from 'state/slices/selectors'
+import {
+ selectCurrencyFormat,
+ selectFeatureFlags,
+ selectSelectedCurrency,
+ selectSelectedLocale,
+} from 'state/slices/selectors'
import { useAppSelector } from 'state/store'
import { getLocaleLabel } from '../../../assets/translations/utils'
import { BalanceThresholdInput } from './BalanceThresholdInput'
-import { SettingsRoutes } from './SettingsCommon'
+import { currencyFormatsRepresenter, SettingsRoutes } from './SettingsCommon'
import { SettingsListItem } from './SettingsListItem'
type SettingsListProps = {
@@ -37,8 +42,11 @@ export const SettingsList = ({ appHistory, ...routeProps }: SettingsListProps) =
const { toggleColorMode } = useColorMode()
const isLightMode = useColorModeValue(true, false)
const selectedLocale = useAppSelector(selectSelectedLocale)
+ const selectedCurrency = useAppSelector(selectSelectedCurrency)
+ const selectedCurrencyFormat = useAppSelector(selectCurrencyFormat)
// for both locale and currency
const selectedPreferenceValueColor = useColorModeValue('blue.500', 'blue.200')
+ const featureFlags = useAppSelector(selectFeatureFlags)
const closeModalAndNavigateTo = (linkHref: string) => {
settings.close()
@@ -60,6 +68,36 @@ export const SettingsList = ({ appHistory, ...routeProps }: SettingsListProps) =
+ {featureFlags.MultiCurrency && (
+ <>
+ routeProps.history.push(SettingsRoutes.FiatCurrencies)}
+ icon={}
+ >
+
+
+ {selectedCurrency}
+
+
+
+
+
+ routeProps.history.push(SettingsRoutes.CurrencyFormat)}
+ icon={}
+ >
+
+
+ {currencyFormatsRepresenter[selectedCurrencyFormat]}
+
+
+
+
+
+ >
+ )}
routeProps.history.push(SettingsRoutes.Languages)}
diff --git a/src/components/Modals/Settings/SettingsRouter.tsx b/src/components/Modals/Settings/SettingsRouter.tsx
index 4de63439a8f..28cf4f417ab 100644
--- a/src/components/Modals/Settings/SettingsRouter.tsx
+++ b/src/components/Modals/Settings/SettingsRouter.tsx
@@ -1,6 +1,8 @@
import { AnimatePresence } from 'framer-motion'
import { Route, RouteComponentProps, Switch, useLocation } from 'react-router-dom'
+import { CurrencyFormat } from './CurrencyFormat'
+import { FiatCurrencies } from './FiatCurrencies'
import { Languages } from './Languages'
import { SettingsRoutes } from './SettingsCommon'
import { SettingsList } from './SettingsList'
@@ -16,7 +18,9 @@ export const SettingsRouter = ({ appHistory }: { appHistory: RouteComponentProps
)}
/>
- } />
+
+
+
)
diff --git a/src/components/TokenRow/TokenRow.tsx b/src/components/TokenRow/TokenRow.tsx
index b19c4423cfa..6b52d9dbc48 100644
--- a/src/components/TokenRow/TokenRow.tsx
+++ b/src/components/TokenRow/TokenRow.tsx
@@ -44,7 +44,7 @@ export function TokenRow({
}: TokenRowProps) {
const {
number: { localeParts },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
return (
diff --git a/src/components/Trade/TradeConfirm/AssetToAsset.tsx b/src/components/Trade/TradeConfirm/AssetToAsset.tsx
index 70d4eb4d666..ea5a9b22803 100644
--- a/src/components/Trade/TradeConfirm/AssetToAsset.tsx
+++ b/src/components/Trade/TradeConfirm/AssetToAsset.tsx
@@ -36,7 +36,7 @@ export const AssetToAsset = ({
const buyAssetColor = '#2775CA'
const {
number: { toCrypto },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const gray = useColorModeValue('white', 'gray.750')
const red = useColorModeValue('white', 'red.500')
const green = useColorModeValue('white', 'green.500')
diff --git a/src/components/Trade/TradeConfirm/TradeConfirm.tsx b/src/components/Trade/TradeConfirm/TradeConfirm.tsx
index 98a7a9c51e1..17c5ef56254 100644
--- a/src/components/Trade/TradeConfirm/TradeConfirm.tsx
+++ b/src/components/Trade/TradeConfirm/TradeConfirm.tsx
@@ -51,7 +51,7 @@ export const TradeConfirm = ({ history }: RouterProps) => {
const { fiatRate } = location.state
const {
number: { toFiat },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const {
state: { isConnected },
dispatch,
diff --git a/src/components/Trade/TradeInput.tsx b/src/components/Trade/TradeInput.tsx
index 73aabad6aba..1cd193fabb8 100644
--- a/src/components/Trade/TradeInput.tsx
+++ b/src/components/Trade/TradeInput.tsx
@@ -39,7 +39,7 @@ export const TradeInput = ({ history }: RouterProps) => {
} = useFormContext>()
const {
number: { localeParts },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const [isSendMaxLoading, setIsSendMaxLoading] = useState(false)
const [quote, buyTradeAsset, sellTradeAsset, feeAssetFiatRate] = useWatch({
name: ['quote', 'buyAsset', 'sellAsset', 'feeAssetFiatRate'],
diff --git a/src/config.ts b/src/config.ts
index 184c3160bb0..2e186e861d4 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -43,6 +43,7 @@ const validators = {
REACT_APP_FRIENDLY_CAPTCHA_SITE_KEY: str(),
REACT_APP_FEATURE_YEARN: bool({ default: true }),
REACT_APP_FEATURE_OSMOSIS: bool({ default: false }),
+ REACT_APP_FEATURE_MULTI_CURRENCY: bool({ default: false }),
REACT_APP_FEATURE_WALLETCONNECT_WALLET: bool({ default: false }),
REACT_APP_FEATURE_AVALANCHE: bool({ default: false }),
REACT_APP_FEATURE_THOR: bool({ default: false }),
diff --git a/src/hooks/useBalanceChartData/useBalanceChartData.test.ts b/src/hooks/useBalanceChartData/useBalanceChartData.test.ts
index 991b90dc5f2..554898d804d 100644
--- a/src/hooks/useBalanceChartData/useBalanceChartData.test.ts
+++ b/src/hooks/useBalanceChartData/useBalanceChartData.test.ts
@@ -1,5 +1,5 @@
import { RebaseHistory } from '@shapeshiftoss/investor-foxy'
-import { HistoryTimeframe } from '@shapeshiftoss/types'
+import { HistoryData, HistoryTimeframe } from '@shapeshiftoss/types'
import { ethereum, fox } from 'test/mocks/assets'
import { ethereumTransactions, FOXSend } from 'test/mocks/txs'
import { bn } from 'lib/bignumber/bignumber'
@@ -95,9 +95,10 @@ describe('calculateBucketPrices', () => {
const txs = [FOXSend]
- const priceHistoryData: PriceHistoryData = {
+ const cryptoPriceHistoryData: PriceHistoryData = {
[foxAssetId]: [{ price: 0, date: Number() }],
}
+ const fiatPriceHistoryData: HistoryData[] = [{ price: 0, date: Number() }]
const portfolioAssets: PortfolioAssets = {
[foxAssetId]: fox,
@@ -109,7 +110,8 @@ describe('calculateBucketPrices', () => {
const calculatedBuckets = calculateBucketPrices({
assetIds,
buckets,
- priceHistoryData,
+ cryptoPriceHistoryData,
+ fiatPriceHistoryData,
portfolioAssets,
delegationTotal: '0',
})
@@ -127,9 +129,10 @@ describe('calculateBucketPrices', () => {
}
const assetIds = [ethAssetId]
const timeframe = HistoryTimeframe.YEAR
- const priceHistoryData: PriceHistoryData = {
+ const cryptoPriceHistoryData: PriceHistoryData = {
[ethAssetId]: [{ price: 0, date: Number() }],
}
+ const fiatPriceHistoryData: HistoryData[] = [{ price: 0, date: Number() }]
const portfolioAssets: PortfolioAssets = {
[ethAssetId]: ethereum,
}
@@ -140,7 +143,8 @@ describe('calculateBucketPrices', () => {
const calculatedBuckets = calculateBucketPrices({
assetIds,
buckets,
- priceHistoryData,
+ cryptoPriceHistoryData,
+ fiatPriceHistoryData,
portfolioAssets,
delegationTotal: '0',
})
diff --git a/src/hooks/useBalanceChartData/useBalanceChartData.ts b/src/hooks/useBalanceChartData/useBalanceChartData.ts
index d440802f37d..6b2adf5240c 100644
--- a/src/hooks/useBalanceChartData/useBalanceChartData.ts
+++ b/src/hooks/useBalanceChartData/useBalanceChartData.ts
@@ -30,6 +30,8 @@ import {
selectAccountSpecifiers,
selectAssets,
selectCryptoPriceHistoryTimeframe,
+ selectFiatPriceHistoriesLoadingByTimeframe,
+ selectFiatPriceHistoryTimeframe,
selectPortfolioAssets,
selectPortfolioCryptoBalancesByAccountIdAboveThreshold,
selectPriceHistoriesLoadingByAssetTimeframe,
@@ -160,14 +162,16 @@ export const bucketEvents = (
type FiatBalanceAtBucketArgs = {
bucket: Bucket
portfolioAssets: PortfolioAssets
- priceHistoryData: PriceHistoryData
+ cryptoPriceHistoryData: PriceHistoryData
+ fiatPriceHistoryData: HistoryData[]
}
type FiatBalanceAtBucket = (args: FiatBalanceAtBucketArgs) => BigNumber
const fiatBalanceAtBucket: FiatBalanceAtBucket = ({
bucket,
- priceHistoryData,
+ cryptoPriceHistoryData,
+ fiatPriceHistoryData,
portfolioAssets,
}) => {
const { balance, end } = bucket
@@ -175,15 +179,17 @@ const fiatBalanceAtBucket: FiatBalanceAtBucket = ({
const { crypto } = balance
return Object.entries(crypto).reduce((acc, [assetId, assetCryptoBalance]) => {
- const assetPriceHistoryData = priceHistoryData[assetId]
+ const assetPriceHistoryData = cryptoPriceHistoryData[assetId]
if (!assetPriceHistoryData?.length) return acc
- const price = priceAtDate({ priceHistoryData: assetPriceHistoryData, date })
const portfolioAsset = portfolioAssets[assetId]
- if (!portfolioAsset) {
- return acc
- }
+ if (!portfolioAsset) return acc
+ const price = priceAtDate({ priceHistoryData: assetPriceHistoryData, date })
+ const fiatToUsdRate = priceAtDate({ priceHistoryData: fiatPriceHistoryData, date })
const { precision } = portfolioAsset
- const assetFiatBalance = assetCryptoBalance.div(bn(10).exponentiatedBy(precision)).times(price)
+ const assetFiatBalance = assetCryptoBalance
+ .div(bn(10).exponentiatedBy(precision))
+ .times(price)
+ .times(fiatToUsdRate)
return acc.plus(assetFiatBalance)
}, bn(0))
}
@@ -192,7 +198,8 @@ type CalculateBucketPricesArgs = {
assetIds: AssetId[]
buckets: Bucket[]
portfolioAssets: PortfolioAssets
- priceHistoryData: PriceHistoryData
+ cryptoPriceHistoryData: PriceHistoryData
+ fiatPriceHistoryData: HistoryData[]
delegationTotal: string
}
@@ -200,7 +207,14 @@ type CalculateBucketPrices = (args: CalculateBucketPricesArgs) => Bucket[]
// note - this mutates buckets
export const calculateBucketPrices: CalculateBucketPrices = args => {
- const { assetIds, buckets, portfolioAssets, priceHistoryData, delegationTotal } = args
+ const {
+ assetIds,
+ buckets,
+ portfolioAssets,
+ cryptoPriceHistoryData,
+ fiatPriceHistoryData,
+ delegationTotal,
+ } = args
const startingBucket = buckets[buckets.length - 1]
@@ -266,7 +280,12 @@ export const calculateBucketPrices: CalculateBucketPrices = args => {
bucket.balance.crypto[assetId] = bnOrZero(bucket.balance.crypto[assetId]).minus(balanceDiff)
})
- bucket.balance.fiat = fiatBalanceAtBucket({ bucket, priceHistoryData, portfolioAssets })
+ bucket.balance.fiat = fiatBalanceAtBucket({
+ bucket,
+ cryptoPriceHistoryData,
+ fiatPriceHistoryData,
+ portfolioAssets,
+ })
buckets[i] = bucket
}
return buckets
@@ -361,13 +380,20 @@ export const useBalanceChartData: UseBalanceChartData = args => {
// kick off requests for all the price histories we need
useFetchPriceHistories({ assetIds, timeframe })
- const priceHistoryData = useAppSelector(state =>
+ const cryptoPriceHistoryData = useAppSelector(state =>
selectCryptoPriceHistoryTimeframe(state, timeframe),
)
- const priceHistoryDataLoading = useAppSelector(state =>
+ const cryptoPriceHistoryDataLoading = useAppSelector(state =>
selectPriceHistoriesLoadingByAssetTimeframe(state, assetIds, timeframe),
)
+ const fiatPriceHistoryData = useAppSelector(state =>
+ selectFiatPriceHistoryTimeframe(state, timeframe),
+ )
+ const fiatPriceHistoryDataLoading = useAppSelector(state =>
+ selectFiatPriceHistoriesLoadingByTimeframe(state, timeframe),
+ )
+
// loading state
useEffect(() => setBalanceChartDataLoading(true), [setBalanceChartDataLoading, timeframe])
@@ -376,8 +402,8 @@ export const useBalanceChartData: UseBalanceChartData = args => {
// data prep
const hasNoDeviceId = isNil(walletInfo?.deviceId)
const hasNoAssetIds = !assetIds.length
- const hasNoPriceHistoryData = isEmpty(priceHistoryData)
- if (hasNoDeviceId || hasNoAssetIds || priceHistoryDataLoading || hasNoPriceHistoryData) {
+ const hasNoPriceHistoryData = isEmpty(cryptoPriceHistoryData) || !fiatPriceHistoryData?.length
+ if (hasNoDeviceId || hasNoAssetIds || hasNoPriceHistoryData || cryptoPriceHistoryDataLoading) {
return setBalanceChartDataLoading(true)
}
@@ -390,7 +416,8 @@ export const useBalanceChartData: UseBalanceChartData = args => {
const calculatedBuckets = calculateBucketPrices({
assetIds,
buckets,
- priceHistoryData,
+ cryptoPriceHistoryData,
+ fiatPriceHistoryData,
portfolioAssets,
delegationTotal,
})
@@ -405,8 +432,10 @@ export const useBalanceChartData: UseBalanceChartData = args => {
assets,
assetIds,
accountIds,
- priceHistoryData,
- priceHistoryDataLoading,
+ cryptoPriceHistoryData,
+ cryptoPriceHistoryDataLoading,
+ fiatPriceHistoryData,
+ fiatPriceHistoryDataLoading,
txs,
timeframe,
balances,
diff --git a/src/hooks/useFetchPriceHistories/useFetchPriceHistories.ts b/src/hooks/useFetchPriceHistories/useFetchPriceHistories.ts
index f921ebc87b0..77eb6e617ba 100644
--- a/src/hooks/useFetchPriceHistories/useFetchPriceHistories.ts
+++ b/src/hooks/useFetchPriceHistories/useFetchPriceHistories.ts
@@ -2,7 +2,8 @@ import { AssetId } from '@shapeshiftoss/caip'
import { HistoryTimeframe } from '@shapeshiftoss/types'
import { useEffect } from 'react'
import { marketApi } from 'state/slices/marketDataSlice/marketDataSlice'
-import { useAppDispatch } from 'state/store'
+import { selectSelectedCurrency } from 'state/slices/selectors'
+import { useAppDispatch, useAppSelector } from 'state/store'
type UseFetchPriceHistoriesArgs = {
assetIds: AssetId[]
@@ -13,13 +14,19 @@ type UseFetchPriceHistories = (args: UseFetchPriceHistoriesArgs) => void
export const useFetchPriceHistories: UseFetchPriceHistories = ({ assetIds, timeframe }) => {
const dispatch = useAppDispatch()
+ const symbol = useAppSelector(selectSelectedCurrency)
+
+ const { findPriceHistoryByAssetId, findPriceHistoryByFiatSymbol } = marketApi.endpoints
useEffect(
() =>
assetIds.forEach(assetId =>
- dispatch(marketApi.endpoints.findPriceHistoryByAssetId.initiate({ assetId, timeframe })),
+ dispatch(findPriceHistoryByAssetId.initiate({ assetId, timeframe })),
),
// assetIds ref changes, prevent infinite render
// eslint-disable-next-line react-hooks/exhaustive-deps
- [JSON.stringify(assetIds), dispatch, timeframe],
+ [assetIds, dispatch, timeframe],
)
+ useEffect(() => {
+ dispatch(findPriceHistoryByFiatSymbol.initiate({ symbol, timeframe }))
+ }, [dispatch, findPriceHistoryByFiatSymbol, symbol, timeframe])
}
diff --git a/src/hooks/useLocaleFormatter/useLocaleFormatter.test.ts b/src/hooks/useLocaleFormatter/useLocaleFormatter.test.tsx
similarity index 88%
rename from src/hooks/useLocaleFormatter/useLocaleFormatter.test.ts
rename to src/hooks/useLocaleFormatter/useLocaleFormatter.test.tsx
index 024f2cc40ba..1c51b4cd063 100644
--- a/src/hooks/useLocaleFormatter/useLocaleFormatter.test.ts
+++ b/src/hooks/useLocaleFormatter/useLocaleFormatter.test.tsx
@@ -2,6 +2,8 @@ import 'lib/polyfills'
import { renderHook, RenderHookResult } from '@testing-library/react'
import { FiatTypeEnum } from 'constants/FiatTypeEnum'
+import { PropsWithChildren } from 'react'
+import { TestProviders } from 'test/TestProviders'
import { FiatParts, NumberFormatter, NumberValue, useLocaleFormatter } from './useLocaleFormatter'
@@ -14,7 +16,10 @@ function setup({
locale?: string
fiat: FiatTypeEnum
}): RenderHookResult, NumberFormatter> {
- return renderHook(() => useLocaleFormatter({ locale, fiatType: fiat }))
+ const wrapper: React.FC = ({ children }) => (
+ {children}
+ )
+ return renderHook(() => useLocaleFormatter({ locale, fiatType: fiat }), { wrapper })
}
describe('useLocaleFormatter', () => {
@@ -327,32 +332,4 @@ describe('useLocaleFormatter', () => {
},
)
})
-
- describe('toSupply', () => {
- const scenarios: [{ number: NumberValue }, string][] = [
- [{ number: 123.456 }, '123.45'],
- [{ number: 1234.567 }, '1,234.56'],
- [{ number: 12345.6789 }, '12,345'],
- [{ number: 123456.789 }, '123,456'],
- [{ number: 1234567.89123 }, '1.23M'],
- [{ number: 12345678.9123 }, '12.34M'],
- [{ number: 123456789.12345 }, '123.45M'],
- [{ number: 1234567891.2345 }, '1.23 billion'],
- [{ number: 12345678912.3456 }, '12.34 billion'],
- [{ number: 123456789123.4567 }, '123.45 billion'],
- [{ number: 1004567.89123 }, '1M'],
- [{ number: 1014567.89123 }, '1.01M'],
- [{ number: 10005678.9123 }, '10M'],
- [{ number: 123006789.12345 }, '123M'],
- [{ number: 1004567891.2345 }, '1 billion'],
- [{ number: 12005678912.3456 }, '12 billion'],
- [{ number: 123006789123.4567 }, '123 billion'],
- ]
-
- it.each(scenarios)('parses %p and returns %s', async ({ number }, expected) => {
- const { result } = setup({ locale: 'en-US', fiat: FiatTypeEnum.USD })
-
- expect(result.current.number.toSupply(number)).toEqual(expected)
- })
- })
})
diff --git a/src/hooks/useLocaleFormatter/useLocaleFormatter.ts b/src/hooks/useLocaleFormatter/useLocaleFormatter.ts
index 14061029bcf..579830d590f 100644
--- a/src/hooks/useLocaleFormatter/useLocaleFormatter.ts
+++ b/src/hooks/useLocaleFormatter/useLocaleFormatter.ts
@@ -1,6 +1,8 @@
import { useCallback, useMemo } from 'react'
import { getFiatNumberFractionDigits } from 'lib/getFiatNumberFractionDigits/getFiatNumberFractionDigits'
import { logger } from 'lib/logger'
+import { selectCurrencyFormat, selectSelectedCurrency } from 'state/slices/selectors'
+import { useAppSelector } from 'state/store'
const CRYPTO_PRECISION = 8
@@ -29,8 +31,9 @@ export type NumberFormatOptions = {
maximumFractionDigits?: number
minimumFractionDigits?: number
notation?: 'compact' | 'standard' | 'scientific' | 'engineering'
- compactDisplay?: 'short' | 'long'
fiatType?: string
+ abbreviated?: boolean
+ omitDecimalTrailingZeros?: boolean
}
export type NumberFormatter = {
@@ -44,7 +47,6 @@ export type NumberFormatter = {
toParts: (value: string) => FiatParts
toPercent: (number: NumberValue, options?: NumberFormatOptions) => string
toString: (number: NumberValue, options?: NumberFormatOptions) => string
- toSupply: (number: NumberValue, options?: NumberFormatOptions) => string
}
date: {
toDateTime: (date: DateValue, options?: Intl.DateTimeFormatOptions) => string
@@ -140,27 +142,28 @@ export const getBrowserLocales = (options = {}) => {
})[0]
}
+type useLocaleFormatterArgs = {
+ locale?: string
+ fiatType?: string
+}
+
/**
* Set of helper functions for formatting using the user's locale
* such as numbers, currencies, and dates
*/
-export const useLocaleFormatter = ({
- locale,
- fiatType = 'USD',
-}: {
- locale?: string
- fiatType: string
-}): NumberFormatter => {
- const deviceLocale = locale ?? getBrowserLocales()
-
+export const useLocaleFormatter = (args?: useLocaleFormatterArgs): NumberFormatter => {
+ const currencyFormat = useAppSelector(selectCurrencyFormat)
+ const deviceLocale = args?.locale ?? currencyFormat
+ const selectedCurrency = useAppSelector(selectSelectedCurrency)
+ const fiatTypeToUse = args?.fiatType ?? selectedCurrency
/**
* Parse a number in the current locale formatted in the selected currency.
* This will determine the thousandth group separator, decimal separator, and minor units
*/
const localeParts = useMemo((): LocaleParts => {
- return getParts(deviceLocale, fiatType)
- }, [fiatType, deviceLocale])
+ return getParts(deviceLocale, fiatTypeToUse)
+ }, [fiatTypeToUse, deviceLocale])
/**
* Parse a formatted number string into a prefix, number, and postfix
@@ -180,13 +183,13 @@ export const useLocaleFormatter = ({
* Helper function to abbreviate number to truncate rather than round fractions
* @param {number} maximumFractionDigits - truncate fraction after this number of digits. Use 0 for no fraction.
*/
- function partsReducer(maximumFractionDigits: number, fiatType?: string) {
+ function partsReducer(maximumFractionDigits: number, omitDecimalTrailingZeros?: boolean) {
return (accum: string, { type, value }: Intl.NumberFormatPart) => {
let segment = value
if (type === 'decimal' && maximumFractionDigits === 0) segment = ''
if (type === 'fraction') {
segment = value.substr(0, maximumFractionDigits)
- if (!fiatType && segment && /^0*$/.test(segment)) {
+ if (omitDecimalTrailingZeros && segment && /^0*$/.test(segment)) {
// remove trailing zeroes as well as separator character in case there are only zeroes as decimals
return accum.slice(0, -1)
}
@@ -196,37 +199,43 @@ export const useLocaleFormatter = ({
}
}
- const abbreviateNumber = (number: number, fiatType?: string, options?: NumberFormatOptions) => {
- const bounds = { min: 10000, max: 1000000 }
- const longCompactDisplayLowerBound = 1_000_000_000
- const noDecimals = bounds.min <= number && number < bounds.max
- const minDisplayValue = 0.000001
- const lessThanMin = 0 < number && minDisplayValue > number
- const formatNumber = lessThanMin ? minDisplayValue : number
- const minimumFractionDigits = noDecimals ? 0 : 2
- const maximumFractionDigits = Math.max(
- minimumFractionDigits,
- lessThanMin ? 6 : getFiatNumberFractionDigits(number),
- )
- const formatter = new Intl.NumberFormat(deviceLocale, {
- notation: number < bounds.min || noDecimals ? 'standard' : 'compact',
- compactDisplay: fiatType || number < longCompactDisplayLowerBound ? 'short' : 'long',
- style: fiatType ? 'currency' : 'decimal',
- currency: fiatType,
- minimumFractionDigits,
- maximumFractionDigits: 10,
- ...options,
- })
-
- const parts = formatter.formatToParts(formatNumber)
- return parts.reduce(partsReducer(maximumFractionDigits, fiatType), lessThanMin ? '<' : '')
- }
+ const abbreviateNumber = useCallback(
+ (number: number, fiatType?: string, options?: NumberFormatOptions) => {
+ const bounds = { min: 10000, max: 1000000 }
+ const longCompactDisplayLowerBound = 1_000_000_000
+ const noDecimals = bounds.min <= number && number < bounds.max
+ const minDisplayValue = 0.000001
+ const lessThanMin = 0 < number && minDisplayValue > number
+ const formatNumber = lessThanMin ? minDisplayValue : number
+ const minimumFractionDigits = noDecimals ? 0 : 2
+ const maximumFractionDigits = Math.max(
+ minimumFractionDigits,
+ lessThanMin ? 6 : getFiatNumberFractionDigits(number),
+ )
+ const formatter = new Intl.NumberFormat(deviceLocale, {
+ notation: number < bounds.min || noDecimals ? 'standard' : 'compact',
+ compactDisplay: fiatType || number < longCompactDisplayLowerBound ? 'short' : 'long',
+ style: fiatType ? 'currency' : 'decimal',
+ currency: fiatType,
+ minimumFractionDigits,
+ maximumFractionDigits: 10,
+ ...options,
+ })
+
+ const parts = formatter.formatToParts(formatNumber)
+ return parts.reduce(
+ partsReducer(maximumFractionDigits, options?.omitDecimalTrailingZeros),
+ lessThanMin ? '<' : '',
+ )
+ },
+ [deviceLocale],
+ )
/** If the number that is being formatted has a trailing decimal, add it back to the formatted number */
const showTrailingDecimal = useCallback(
(num: NumberValue, formattedNum: string): string => {
const parts = numberToParts(formattedNum)
- const numHasDecimal = String(num).includes('.')
+ const numHasDecimal = String(num).includes(localeParts.decimal)
const decimalWasRemoved = !parts?.number?.includes(localeParts.decimal)
if (numHasDecimal && decimalWasRemoved) {
parts.number = parts.number + localeParts.decimal
@@ -257,7 +266,7 @@ export const useLocaleFormatter = ({
symbol = 'BTC',
options?: NumberFormatOptions,
): string => {
- const fractionDigits = (String(num).split('.')?.[1] ?? '').length
+ const fractionDigits = (String(num).split(localeParts.decimal)?.[1] ?? '').length
const minimumFractionDigits =
fractionDigits < CRYPTO_PRECISION ? fractionDigits : CRYPTO_PRECISION
const crypto = numberToCrypto(num, symbol, { ...options, minimumFractionDigits })
@@ -269,7 +278,7 @@ export const useLocaleFormatter = ({
(value: NumberValue, options?: NumberFormatOptions): string => {
try {
const number = toNumber(value)
- const numberFiat = options?.fiatType || fiatType
+ const numberFiat = options?.fiatType || fiatTypeToUse
return abbreviateNumber(number, numberFiat, options)
} catch (e) {
// @TODO: figure out logging
@@ -277,7 +286,7 @@ export const useLocaleFormatter = ({
return String(value)
}
},
- [fiatType, deviceLocale], // eslint-disable-line react-hooks/exhaustive-deps
+ [abbreviateNumber, fiatTypeToUse],
)
/**
@@ -288,7 +297,7 @@ export const useLocaleFormatter = ({
(num: NumberValue, options?: NumberFormatOptions): string => {
try {
const { fraction } = localeParts
- const fractionDigits = (String(num).split('.')?.[1] ?? '').length
+ const fractionDigits = (String(num).split(localeParts.decimal)?.[1] ?? '').length
const minimumFractionDigits = Math.min(fractionDigits, fraction)
const fiat = numberToFiat(num, { ...options, minimumFractionDigits })
return showTrailingDecimal(num, fiat)
@@ -302,26 +311,7 @@ export const useLocaleFormatter = ({
return String(num)
}
},
- [localeParts, numberToFiat], // eslint-disable-line react-hooks/exhaustive-deps
- )
-
- /** Format a number as a supply display value */
- const numberToSupply = useCallback(
- (value: NumberValue, options?: NumberFormatOptions): string => {
- try {
- const number = toNumber(value)
- return abbreviateNumber(number, undefined, options)
- } catch (e) {
- // @TODO: figure out logging
- moduleLogger.error(
- e,
- { fn: 'numberToSupply' },
- 'Error formatting number to supply display value',
- )
- return String(value)
- }
- },
- [deviceLocale], // eslint-disable-line react-hooks/exhaustive-deps
+ [localeParts, numberToFiat, showTrailingDecimal],
)
const numberToPercent = (number: NumberValue, options: NumberFormatOptions = {}): string => {
@@ -335,6 +325,7 @@ export const useLocaleFormatter = ({
}
const numberToString = (number: NumberValue, options?: NumberFormatOptions): string => {
+ if (options?.abbreviated) return abbreviateNumber(toNumber(number), undefined, options)
const maximumFractionDigits = options?.maximumFractionDigits ?? 8
return toNumber(number).toLocaleString(deviceLocale, { maximumFractionDigits })
}
@@ -365,7 +356,6 @@ export const useLocaleFormatter = ({
toParts: numberToParts,
toPercent: numberToPercent,
toString: numberToString,
- toSupply: numberToSupply,
},
date: {
toDateTime,
diff --git a/src/plugins/cosmos/components/StakingInput/StakingInput.tsx b/src/plugins/cosmos/components/StakingInput/StakingInput.tsx
index f19c99d5c39..480d34dbe6c 100644
--- a/src/plugins/cosmos/components/StakingInput/StakingInput.tsx
+++ b/src/plugins/cosmos/components/StakingInput/StakingInput.tsx
@@ -54,7 +54,7 @@ export const StakingInput = ({
}: StakingInputProps & InputGroupProps) => {
const {
number: { localeParts },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
return (
diff --git a/src/plugins/cosmos/components/modals/Send/Form.tsx b/src/plugins/cosmos/components/modals/Send/Form.tsx
index 2f1f32524f9..1bf49178571 100644
--- a/src/plugins/cosmos/components/modals/Send/Form.tsx
+++ b/src/plugins/cosmos/components/modals/Send/Form.tsx
@@ -17,7 +17,7 @@ import { Address } from 'components/Modals/Send/views/Address'
import { QrCodeScanner } from 'components/Modals/Send/views/QrCodeScanner'
import { SelectAssetRouter } from 'components/SelectAssets/SelectAssetRouter'
import { AccountSpecifier } from 'state/slices/accountSpecifiersSlice/accountSpecifiersSlice'
-import { selectMarketDataById } from 'state/slices/selectors'
+import { selectMarketDataById, selectSelectedCurrency } from 'state/slices/selectors'
import { useAppSelector } from 'state/store'
import { useFormSend } from './hooks/useFormSend/useFormSend'
@@ -49,6 +49,7 @@ export const Form = ({ asset: initialAsset, accountId }: SendFormProps) => {
const location = useLocation()
const history = useHistory()
const { handleSend } = useFormSend()
+ const selectedCurrency = useAppSelector(selectSelectedCurrency)
const marketData = useAppSelector(state => selectMarketDataById(state, initialAsset.assetId))
const methods = useForm({
@@ -62,7 +63,7 @@ export const Form = ({ asset: initialAsset, accountId }: SendFormProps) => {
cryptoAmount: '',
cryptoSymbol: initialAsset?.symbol,
fiatAmount: '',
- fiatSymbol: 'USD', // TODO: use user preferences to get default fiat currency
+ fiatSymbol: selectedCurrency,
},
})
@@ -71,7 +72,7 @@ export const Form = ({ asset: initialAsset, accountId }: SendFormProps) => {
methods.setValue(SendFormFields.CryptoAmount, '')
methods.setValue(SendFormFields.CryptoSymbol, asset.symbol)
methods.setValue(SendFormFields.FiatAmount, '')
- methods.setValue(SendFormFields.FiatSymbol, 'USD')
+ methods.setValue(SendFormFields.FiatSymbol, selectedCurrency)
methods.setValue(SendFormFields.AccountId, accountId)
history.push(SendRoutes.Address)
diff --git a/src/plugins/foxPage/components/FoxChart.tsx b/src/plugins/foxPage/components/FoxChart.tsx
index 1701b0dcecc..63e3f4745b1 100644
--- a/src/plugins/foxPage/components/FoxChart.tsx
+++ b/src/plugins/foxPage/components/FoxChart.tsx
@@ -20,7 +20,7 @@ export const FoxChart: React.FC = ({ assetId }) => {
const [percentChange, setPercentChange] = useState(0)
const {
number: { toFiat },
- } = useLocaleFormatter({ fiatType: 'USD' })
+ } = useLocaleFormatter()
const translate = useTranslate()
const marketData = useAppSelector(state => selectMarketDataById(state, assetId))
const { price } = marketData || {}
diff --git a/src/plugins/foxPage/components/FoxTab.tsx b/src/plugins/foxPage/components/FoxTab.tsx
index cdd9de8237a..cc79378e73c 100644
--- a/src/plugins/foxPage/components/FoxTab.tsx
+++ b/src/plugins/foxPage/components/FoxTab.tsx
@@ -58,8 +58,14 @@ export const FoxTab: React.FC = ({
lineHeight={'1.2'}
fontSize={{ base: 'lg', md: '2xl' }}
fontWeight='semibold'
+ maximumFractionDigits={2}
+ />
+
-
diff --git a/src/state/slices/preferencesSlice/preferencesSlice.ts b/src/state/slices/preferencesSlice/preferencesSlice.ts
index 9f15563ecfa..744e4d16b04 100644
--- a/src/state/slices/preferencesSlice/preferencesSlice.ts
+++ b/src/state/slices/preferencesSlice/preferencesSlice.ts
@@ -9,6 +9,7 @@ dayjs.extend(localizedFormat)
export type FeatureFlags = {
Osmosis: boolean
+ MultiCurrency: boolean
WalletConnectWallet: boolean
Avalanche: boolean
CoinbasePay: boolean
@@ -21,16 +22,23 @@ export type FeatureFlags = {
export type Flag = keyof FeatureFlags
+export enum CurrencyFormats {
+ DotDecimal = 'en-US',
+ CommaDecimal = 'fr-FR',
+}
+
export type Preferences = {
featureFlags: FeatureFlags
selectedLocale: string
balanceThreshold: string
selectedCurrency: SupportedFiatCurrencies
+ currencyFormat: CurrencyFormats
}
const initialState: Preferences = {
featureFlags: {
Osmosis: getConfig().REACT_APP_FEATURE_OSMOSIS,
+ MultiCurrency: getConfig().REACT_APP_FEATURE_MULTI_CURRENCY,
WalletConnectWallet: getConfig().REACT_APP_FEATURE_WALLETCONNECT_WALLET,
Avalanche: getConfig().REACT_APP_FEATURE_AVALANCHE,
CoinbasePay: getConfig().REACT_APP_FEATURE_COINBASE_RAMP,
@@ -43,6 +51,7 @@ const initialState: Preferences = {
selectedLocale: simpleLocale(),
balanceThreshold: '0',
selectedCurrency: 'USD',
+ currencyFormat: CurrencyFormats.DotDecimal,
}
export const preferences = createSlice({
@@ -66,5 +75,8 @@ export const preferences = createSlice({
setBalanceThreshold(state, { payload }: { payload: { threshold: string } }) {
state.balanceThreshold = payload.threshold
},
+ setCurrencyFormat(state, { payload }: { payload: { currencyFormat: CurrencyFormats } }) {
+ state.currencyFormat = payload.currencyFormat
+ },
},
})
diff --git a/src/state/slices/preferencesSlice/selectors.ts b/src/state/slices/preferencesSlice/selectors.ts
index e3f437d33bd..272a27323e7 100644
--- a/src/state/slices/preferencesSlice/selectors.ts
+++ b/src/state/slices/preferencesSlice/selectors.ts
@@ -14,3 +14,4 @@ export const selectFeatureFlag = createCachedSelector(
export const selectSelectedLocale = (state: ReduxState) => state.preferences.selectedLocale
export const selectSelectedCurrency = (state: ReduxState) => state.preferences.selectedCurrency
export const selectBalanceThreshold = (state: ReduxState) => state.preferences.balanceThreshold
+export const selectCurrencyFormat = (state: ReduxState) => state.preferences.currencyFormat
diff --git a/src/test/mocks/store.ts b/src/test/mocks/store.ts
index 100d2e34eb6..2185b331290 100644
--- a/src/test/mocks/store.ts
+++ b/src/test/mocks/store.ts
@@ -1,5 +1,6 @@
import { ReduxState } from 'state/reducer'
import { INITIAL_PRICE_HISTORY } from 'state/slices/marketDataSlice/marketDataSlice'
+import { CurrencyFormats } from 'state/slices/preferencesSlice/preferencesSlice'
const mockApiFactory = (reducerPath: T) => ({
queries: {},
@@ -48,6 +49,7 @@ export const mockStore: ReduxState = {
preferences: {
featureFlags: {
Osmosis: false,
+ MultiCurrency: false,
WalletConnectWallet: false,
FoxPage: false,
Avalanche: false,
@@ -61,6 +63,7 @@ export const mockStore: ReduxState = {
selectedLocale: 'en',
balanceThreshold: '0',
selectedCurrency: 'USD',
+ currencyFormat: CurrencyFormats.DotDecimal,
// the following object is required by redux-persist
_persist: {
version: 0,