Skip to content

Commit

Permalink
feat: multi currency support (#1873)
Browse files Browse the repository at this point in the history
* chore: update packages

* chore: add new headers

* feat: add new translations

* feat: add fiat market data

* feat: fetch fiat market data in app context

* chore: blacklist large things from redux store

* fix: more correct type defs and balance chart fixes

* chore: fix headers comment

* chore: consolidate to priceAtDate

* chore: only upgrade market service package

* chore: use same source of truth for mock test data as real data structure

* fix: optimizations and bug fixes

* fix: market data refetch

* chore: rename booleans for readability

* chore: tighter type def for setFiatMarketData

* chore: freeze initial price history for safety

* chore: uppercase const

* chore: consistent market data selector naming

* feat: view layer changes to support multi currency display

* feat: add currency selection to settings modal

* chore: add multi currency feature flag

* feat: balance chart changes

* chore: delete duplicate test with wrong file extension

* chore: cache fee asset selector

* Revert "chore: cache fee asset selector"

This reverts commit dfcd3d0.

* fix: revert chart loading behaviour

* fix: default fiatType to USD

* test: fix useLocaleFormatter test

* chore: delete unnecessary locale renderers

* chore: revert unnecessary changes to locale formatter

* fix: improved number formatting

* feat: currency format settings

* fix: test case fixed

* fix: improved input parsing

* chore: fix typo

* feat: walletconnect wallet (#1733)

* feat: init walletconnect integration

* chore: lint

* fix: wallet init

* fix: wallet init

* fix: add imagedelivery to headers

* chore: use package version

* chore: show/hide WalletConnect based on flag

* fix: headers for macos/ios safari

* fix: show feature flag nav item for alt host

* perf: add env var for better local development

* chore: remove unecessary code

* chore: remove package dep

* chore: add hdwallet-walletconnect alpha dependency

* fix: add walletconnect csp entries

* fix: utilize feature flag

* fix: add mobileEnabled field to WalletConnect config

* chore: run linter

* fix: remove usage of process.env

* chore: run linter

* fix: apply code review suggestions

* fix: use structured logging

* fix: apply code review suggestions

* fix: update csp for wallet logos

* chore: add flag to sample.env

* chore: yarn.lock

* docs: fleek info

* fix: img source csp

* chore: revert readme to develop

* fix: image fetched by walletconnect

* feat: WalletConnect rejection

* chore: lint

* chore: lint

* chore: update hdwallet-walletconnect dependency

* chore: upgrade hdwallet-walletconnect

* fix: set wc connect modal error to null on init

* chore: run linter

* fix: walletconnect refresh bug

* chore: upgrade hdwallet dependency

* chore: bump hdwallet dependencies

* fix: csp for walletconnect desktop logos

* chore: bump hdwallet package versions

* fix: disable trade max with walletconnect

* fix: disable sendmax with walletconnect

* chore: run linter

* chore: update hdwallet dependencies

* chore: run linter

* fix: hide fiat sendMax with WalletConnect

* fix: stylistic changes

* fix: typo

* feat: add copy to walletconnect option in selectmodal

* fix: constrain icon width for selectmodal options

* fix: update return value

Co-authored-by: pastaghost <[email protected]>
Co-authored-by: 0xdef1cafe <[email protected]>

* chore(deps): bump terser from 4.8.0 to 4.8.1 (#2197)

Bumps [terser](https://github.com/terser/terser) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat: dogecoin (#2185)

* feat: dogecoin initial

* add dogecoin

* use p2pkh accountType for dgubs
add dogecoin else if to handleSend :(
add dogecoin case to handleSendMax :( :(

* wrap doge plugin in a feature flag

* pass chainId to utxoAccountParams

* remove reference to dogecoin testnet

* web clean up

* fix: update old utility to new caip method

* chore: add REACT_APP_FEATURE_DOGECOIN=true to sample.env

* fix: update swapper logic to pass correct param

* chore: version bump doge libs

* fix: add dogecoin label to accounts page

* fix: don't show tokens under dogecoin account

Co-authored-by: 0xdef1cafe <[email protected]>
Co-authored-by: Apotheosis <[email protected]>

* fix: typo and lodash import

* fix: conflict resolved

* feat: keeping order of fiat currencies and currency formats

* fix: applying suggested changes

Co-authored-by: stackedQ <[email protected]>
Co-authored-by: Grant Steuart <[email protected]>
Co-authored-by: pastaghost <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adam Samere <[email protected]>
Co-authored-by: Apotheosis <[email protected]>
Co-authored-by: reallybeard <[email protected]>
  • Loading branch information
8 people authored Jul 25, 2022
1 parent 1352c89 commit 56ba3b5
Show file tree
Hide file tree
Showing 33 changed files with 439 additions and 166 deletions.
1 change: 1 addition & 0 deletions sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@
"settings": {
"settings": "Settings",
"currency": "Currency",
"currencyFormat": "Currency Format",
"language": "Language",
"balanceThreshold": "Balance Threshold",
"balanceThresholdTooltip": "Hide balances below this value",
Expand Down
48 changes: 29 additions & 19 deletions src/components/Amount/Amount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,28 @@ type AmountProps = {
value: number | string
prefix?: string
suffix?: string
omitDecimalTrailingZeros?: boolean
abbreviated?: boolean
maximumFractionDigits?: number
} & TextProps

export function Amount({
value,
prefix = '',
suffix = '',
maximumFractionDigits,
omitDecimalTrailingZeros = false,
abbreviated = false,
...props
}: any): React.ReactElement {
const {
number: { toString },
} = useLocaleFormatter({ fiatType: 'USD' })
} = useLocaleFormatter()

return (
<RawText {...props}>
{prefix}
{toString(value, { maximumFractionDigits })}
{toString(value, { maximumFractionDigits, omitDecimalTrailingZeros, abbreviated })}
{suffix}
</RawText>
)
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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(() => {
Expand All @@ -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 <RawText {...props}>{volume}</RawText>
}

Amount.Crypto = Crypto
Amount.Fiat = Fiat
Amount.Percent = Percent
Amount.Supply = Supply
2 changes: 1 addition & 1 deletion src/components/Approval/Approval.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const Approval = () => {
const { approveInfinite, checkApprovalNeeded, updateTrade } = useSwapper()
const {
number: { toCrypto, toFiat },
} = useLocaleFormatter({ fiatType: 'USD' })
} = useLocaleFormatter()
const {
state: { isConnected },
dispatch,
Expand Down
2 changes: 1 addition & 1 deletion src/components/AssetHeader/AssetChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 6 additions & 2 deletions src/components/AssetHeader/AssetMarketData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const AssetMarketData: React.FC<AssetMarketDataProps> = ({ assetId }) =>
<Text translation='assets.assetDetails.assetHeader.maxTotalSupply' />
</StatLabel>
<StatValue isLoaded={isLoaded}>
<Amount.Supply value={marketData?.maxSupply ?? 0} />
<Amount value={marketData?.maxSupply ?? 0} abbreviated omitDecimalTrailingZeros />
</StatValue>
</StatRow>
)}
Expand All @@ -114,7 +114,11 @@ export const AssetMarketData: React.FC<AssetMarketDataProps> = ({ assetId }) =>
<Text translation='assets.assetDetails.assetHeader.availableSupply' />
</StatLabel>
<StatValue isLoaded={isLoaded}>
<Amount.Supply value={marketData?.supply} />
<Amount
value={Math.round(Number(marketData?.supply ?? 0))}
abbreviated
omitDecimalTrailingZeros
/>
</StatValue>
</StatRow>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/DeFi/components/AssetInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const AssetInput: React.FC<AssetInputProps> = ({
}) => {
const {
number: { localeParts },
} = useLocaleFormatter({ fiatType: 'USD' })
} = useLocaleFormatter()
const translate = useTranslate()
const amountRef = useRef<string | null>(null)
const [isFiat, setIsFiat] = useState<boolean>(false)
Expand Down
2 changes: 1 addition & 1 deletion src/components/Graph/PrimaryChart/PrimaryChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
7 changes: 4 additions & 3 deletions src/components/Modals/Send/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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<SendInput>({
Expand All @@ -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,
},
})

Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/components/Modals/Settings/BalanceThresholdInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }))
}
Expand Down
82 changes: 82 additions & 0 deletions src/components/Modals/Settings/CurrencyFormat.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<SlideTransition>
<IconButton
variant='ghost'
icon={<ArrowBackIcon />}
aria-label={translate('common.back')}
position='absolute'
top={2}
left={3}
fontSize='xl'
size='sm'
isRound
onClick={goBack}
/>
<ModalHeader textAlign='center'>{translate('modals.settings.currencyFormat')}</ModalHeader>
<>
<ModalBody
alignItems='center'
justifyContent='center'
textAlign='center'
maxHeight='400'
overflowY='auto'
overflowX='hidden'
>
{formats.map(currencyFormat => {
const active = currencyFormat === currentCurrencyFormat
const buttonProps = active
? {
disabled: true,
_disabled: { opacity: 1 },
}
: {
pl: 8,
variant: 'ghost',
onClick: () => dispatch(setCurrencyFormat({ currencyFormat })),
}
return (
<Button
mb={2}
width='full'
justifyContent='flexStart'
key={currencyFormat}
{...buttonProps}
>
<Flex alignItems='center' textAlign='left'>
{active && <Icon as={FaCheck} color='blue.500' />}
<Flex ml={4}>
<RawText>{currencyFormatsRepresenter[currencyFormat]}</RawText>
</Flex>
</Flex>
</Button>
)
})}
</ModalBody>
</>
</SlideTransition>
)
}
87 changes: 87 additions & 0 deletions src/components/Modals/Settings/FiatCurrencies.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<SlideTransition>
<IconButton
variant='ghost'
icon={<ArrowBackIcon />}
aria-label={translate('common.back')}
position='absolute'
top={2}
left={3}
fontSize='xl'
size='sm'
isRound
onClick={goBack}
/>
<ModalHeader textAlign='center'>{translate('modals.settings.currency')}</ModalHeader>
<>
<ModalBody
alignItems='center'
justifyContent='center'
textAlign='center'
maxHeight='400'
overflowY='auto'
overflowX='hidden'
>
{allFiatCurrencies.map(currency => {
const active = currency === selectedCurrency
const buttonProps = active
? {
disabled: true,
_disabled: { opacity: 1 },
}
: {
pl: 8,
variant: 'ghost',
onClick: () => dispatch(setSelectedCurrency({ currency })),
}
return (
<Button
width='full'
justifyContent='flexStart'
key={currency}
mb={2}
{...buttonProps}
>
<Flex alignItems='center' textAlign='left'>
{active && <Icon as={FaCheck} color='blue.500' />}
<Flex ml={4}>
<RawText>{currency}</RawText>
<RawText mx={2}>-</RawText>
<Text translation={`modals.settings.currencies.${currency}`} />
</Flex>
</Flex>
</Button>
)
})}
</ModalBody>
</>
</SlideTransition>
)
}
Loading

0 comments on commit 56ba3b5

Please sign in to comment.