feat: currency selector (#7196)
* adding currency settings option * moving menu item to shared component * adding supported currencies * currency menu items * currency url params * currency selector e2e tests * fixing tests * currency icons * removing eslint * removing another eslint disable * renaming to local currency * more name changes * design updates * renaming file * fixing lint * Update src/components/AccountDrawer/SettingsMenu.tsx Co-authored-by: Charles Bachmeier <charles@bachmeier.io> * alphabetical ordering currencies * column padding * padding only for mobile * memoizing into switch --------- Co-authored-by: Charles Bachmeier <charles@bachmeier.io>
This commit is contained in:
parent
ea66b8b959
commit
4eda18a4d5
@ -144,4 +144,32 @@ describe('Wallet Dropdown', () => {
|
|||||||
cy.get(getTestSelector('wallet-settings')).should('not.be.visible')
|
cy.get(getTestSelector('wallet-settings')).should('not.be.visible')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('local currency', () => {
|
||||||
|
it('loads local currency from the query param', () => {
|
||||||
|
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||||
|
cy.get(getTestSelector('web3-status-connected')).click()
|
||||||
|
cy.get(getTestSelector('wallet-settings')).click()
|
||||||
|
cy.contains('USD')
|
||||||
|
|
||||||
|
cy.visit('/?cur=AUD', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||||
|
cy.contains('AUD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('loads local currency from menu', () => {
|
||||||
|
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||||
|
cy.get(getTestSelector('web3-status-connected')).click()
|
||||||
|
cy.get(getTestSelector('wallet-settings')).click()
|
||||||
|
cy.contains('USD')
|
||||||
|
|
||||||
|
cy.get(getTestSelector('local-currency-settings-button')).click()
|
||||||
|
cy.get(getTestSelector('wallet-local-currency-item')).contains('AUD').click({ force: true })
|
||||||
|
cy.location('hash').should('match', /\?cur=AUD$/)
|
||||||
|
cy.contains('AUD')
|
||||||
|
|
||||||
|
cy.get(getTestSelector('wallet-local-currency-item')).contains('USD').click({ force: true })
|
||||||
|
cy.location('hash').should('match', /\?cur=USD$/)
|
||||||
|
cy.contains('USD')
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { useWeb3React } from '@web3-react/core'
|
import { useWeb3React } from '@web3-react/core'
|
||||||
import Column from 'components/Column'
|
import Column from 'components/Column'
|
||||||
import WalletModal from 'components/WalletModal'
|
import WalletModal from 'components/WalletModal'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import AuthenticatedHeader from './AuthenticatedHeader'
|
import AuthenticatedHeader from './AuthenticatedHeader'
|
||||||
import LanguageMenu from './LanguageMenu'
|
import LanguageMenu from './LanguageMenu'
|
||||||
|
import LocalCurrencyMenu from './LocalCurrencyMenu'
|
||||||
import SettingsMenu from './SettingsMenu'
|
import SettingsMenu from './SettingsMenu'
|
||||||
|
|
||||||
const DefaultMenuWrap = styled(Column)`
|
const DefaultMenuWrap = styled(Column)`
|
||||||
@ -17,6 +18,7 @@ enum MenuState {
|
|||||||
DEFAULT,
|
DEFAULT,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
LANGUAGE_SETTINGS,
|
LANGUAGE_SETTINGS,
|
||||||
|
LOCAL_CURRENCY_SETTINGS,
|
||||||
}
|
}
|
||||||
|
|
||||||
function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) {
|
function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) {
|
||||||
@ -27,6 +29,7 @@ function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) {
|
|||||||
const openSettings = useCallback(() => setMenu(MenuState.SETTINGS), [])
|
const openSettings = useCallback(() => setMenu(MenuState.SETTINGS), [])
|
||||||
const closeSettings = useCallback(() => setMenu(MenuState.DEFAULT), [])
|
const closeSettings = useCallback(() => setMenu(MenuState.DEFAULT), [])
|
||||||
const openLanguageSettings = useCallback(() => setMenu(MenuState.LANGUAGE_SETTINGS), [])
|
const openLanguageSettings = useCallback(() => setMenu(MenuState.LANGUAGE_SETTINGS), [])
|
||||||
|
const openLocalCurrencySettings = useCallback(() => setMenu(MenuState.LOCAL_CURRENCY_SETTINGS), [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!drawerOpen && menu !== MenuState.DEFAULT) {
|
if (!drawerOpen && menu !== MenuState.DEFAULT) {
|
||||||
@ -39,20 +42,30 @@ function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) {
|
|||||||
return
|
return
|
||||||
}, [drawerOpen, menu, closeSettings])
|
}, [drawerOpen, menu, closeSettings])
|
||||||
|
|
||||||
return (
|
const SubMenu = useMemo(() => {
|
||||||
<DefaultMenuWrap>
|
switch (menu) {
|
||||||
{menu === MenuState.DEFAULT &&
|
case MenuState.DEFAULT:
|
||||||
(isAuthenticated ? (
|
return isAuthenticated ? (
|
||||||
<AuthenticatedHeader account={account} openSettings={openSettings} />
|
<AuthenticatedHeader account={account} openSettings={openSettings} />
|
||||||
) : (
|
) : (
|
||||||
<WalletModal openSettings={openSettings} />
|
<WalletModal openSettings={openSettings} />
|
||||||
))}
|
|
||||||
{menu === MenuState.SETTINGS && (
|
|
||||||
<SettingsMenu onClose={closeSettings} openLanguageSettings={openLanguageSettings} />
|
|
||||||
)}
|
|
||||||
{menu === MenuState.LANGUAGE_SETTINGS && <LanguageMenu onClose={openSettings} />}
|
|
||||||
</DefaultMenuWrap>
|
|
||||||
)
|
)
|
||||||
|
case MenuState.SETTINGS:
|
||||||
|
return (
|
||||||
|
<SettingsMenu
|
||||||
|
onClose={closeSettings}
|
||||||
|
openLanguageSettings={openLanguageSettings}
|
||||||
|
openLocalCurrencySettings={openLocalCurrencySettings}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case MenuState.LANGUAGE_SETTINGS:
|
||||||
|
return <LanguageMenu onClose={openSettings} />
|
||||||
|
case MenuState.LOCAL_CURRENCY_SETTINGS:
|
||||||
|
return <LocalCurrencyMenu onClose={openSettings} />
|
||||||
|
}
|
||||||
|
}, [account, closeSettings, isAuthenticated, menu, openLanguageSettings, openLocalCurrencySettings, openSettings])
|
||||||
|
|
||||||
|
return <DefaultMenuWrap>{SubMenu}</DefaultMenuWrap>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DefaultMenu
|
export default DefaultMenu
|
||||||
|
@ -2,36 +2,21 @@ import { Trans } from '@lingui/macro'
|
|||||||
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
|
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
|
||||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||||
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
|
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
|
||||||
import { Check } from 'react-feather'
|
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import styled, { useTheme } from 'styled-components'
|
|
||||||
import { ClickableStyle, ThemedText } from 'theme'
|
|
||||||
|
|
||||||
|
import { MenuColumn, MenuItem } from './shared'
|
||||||
import { SlideOutMenu } from './SlideOutMenu'
|
import { SlideOutMenu } from './SlideOutMenu'
|
||||||
|
|
||||||
const InternalLinkMenuItem = styled(Link)`
|
|
||||||
${ClickableStyle}
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
padding: 12px 0;
|
|
||||||
justify-content: space-between;
|
|
||||||
text-decoration: none;
|
|
||||||
color: ${({ theme }) => theme.neutral1};
|
|
||||||
`
|
|
||||||
|
|
||||||
function LanguageMenuItem({ locale, isActive }: { locale: SupportedLocale; isActive: boolean }) {
|
function LanguageMenuItem({ locale, isActive }: { locale: SupportedLocale; isActive: boolean }) {
|
||||||
const { to, onClick } = useLocationLinkProps(locale)
|
const { to, onClick } = useLocationLinkProps(locale)
|
||||||
const theme = useTheme()
|
|
||||||
|
|
||||||
if (!to) return null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InternalLinkMenuItem onClick={onClick} to={to}>
|
<MenuItem
|
||||||
<ThemedText.BodySmall data-testid="wallet-language-item">{LOCALE_LABEL[locale]}</ThemedText.BodySmall>
|
label={LOCALE_LABEL[locale]}
|
||||||
{isActive && <Check color={theme.accent1} opacity={1} size={20} />}
|
onClick={onClick}
|
||||||
</InternalLinkMenuItem>
|
to={to}
|
||||||
|
isActive={isActive}
|
||||||
|
testId="wallet-language-item"
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +35,9 @@ export function LanguageMenuItems() {
|
|||||||
export default function LanguageMenu({ onClose }: { onClose: () => void }) {
|
export default function LanguageMenu({ onClose }: { onClose: () => void }) {
|
||||||
return (
|
return (
|
||||||
<SlideOutMenu title={<Trans>Language</Trans>} onClose={onClose}>
|
<SlideOutMenu title={<Trans>Language</Trans>} onClose={onClose}>
|
||||||
|
<MenuColumn>
|
||||||
<LanguageMenuItems />
|
<LanguageMenuItems />
|
||||||
|
</MenuColumn>
|
||||||
</SlideOutMenu>
|
</SlideOutMenu>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
61
src/components/AccountDrawer/LocalCurrencyMenu.tsx
Normal file
61
src/components/AccountDrawer/LocalCurrencyMenu.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { Trans } from '@lingui/macro'
|
||||||
|
import { getLocalCurrencyIcon, SUPPORTED_LOCAL_CURRENCIES, SupportedLocalCurrency } from 'constants/localCurrencies'
|
||||||
|
import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency'
|
||||||
|
import { useLocalCurrencyLinkProps } from 'hooks/useLocalCurrencyLinkProps'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
import { MenuColumn, MenuItem } from './shared'
|
||||||
|
import { SlideOutMenu } from './SlideOutMenu'
|
||||||
|
|
||||||
|
const StyledLocalCurrencyIcon = styled.div`
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
`
|
||||||
|
|
||||||
|
function LocalCurrencyMenuItem({
|
||||||
|
localCurrency,
|
||||||
|
isActive,
|
||||||
|
}: {
|
||||||
|
localCurrency: SupportedLocalCurrency
|
||||||
|
isActive: boolean
|
||||||
|
}) {
|
||||||
|
const { to, onClick } = useLocalCurrencyLinkProps(localCurrency)
|
||||||
|
|
||||||
|
const LocalCurrencyIcon = useMemo(() => {
|
||||||
|
return <StyledLocalCurrencyIcon>{getLocalCurrencyIcon(localCurrency)}</StyledLocalCurrencyIcon>
|
||||||
|
}, [localCurrency])
|
||||||
|
|
||||||
|
if (!to) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
label={localCurrency}
|
||||||
|
logo={LocalCurrencyIcon}
|
||||||
|
isActive={isActive}
|
||||||
|
to={to}
|
||||||
|
onClick={onClick}
|
||||||
|
testId="wallet-local-currency-item"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function LocalCurrencyMenu({ onClose }: { onClose: () => void }) {
|
||||||
|
const activeLocalCurrency = useActiveLocalCurrency()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SlideOutMenu title={<Trans>Currency</Trans>} onClose={onClose}>
|
||||||
|
<MenuColumn>
|
||||||
|
{SUPPORTED_LOCAL_CURRENCIES.map((localCurrency) => (
|
||||||
|
<LocalCurrencyMenuItem
|
||||||
|
localCurrency={localCurrency}
|
||||||
|
isActive={activeLocalCurrency === localCurrency}
|
||||||
|
key={localCurrency}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</MenuColumn>
|
||||||
|
</SlideOutMenu>
|
||||||
|
)
|
||||||
|
}
|
@ -3,6 +3,7 @@ import Column from 'components/Column'
|
|||||||
import Row from 'components/Row'
|
import Row from 'components/Row'
|
||||||
import { LOCALE_LABEL } from 'constants/locales'
|
import { LOCALE_LABEL } from 'constants/locales'
|
||||||
import { useCurrencyConversionFlagEnabled } from 'featureFlags/flags/currencyConversion'
|
import { useCurrencyConversionFlagEnabled } from 'featureFlags/flags/currencyConversion'
|
||||||
|
import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency'
|
||||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import { ChevronRight } from 'react-feather'
|
import { ChevronRight } from 'react-feather'
|
||||||
@ -27,15 +28,16 @@ const SectionTitle = styled(ThemedText.SubHeader)`
|
|||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ToggleWrapper = styled.div`
|
const ToggleWrapper = styled.div<{ currencyConversionEnabled?: boolean }>`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: ${({ currencyConversionEnabled }) => (currencyConversionEnabled ? '10px' : '24px')};
|
||||||
`
|
`
|
||||||
|
|
||||||
const SettingsButtonWrapper = styled(Row)`
|
const SettingsButtonWrapper = styled(Row)`
|
||||||
${ClickableStyle}
|
${ClickableStyle}
|
||||||
|
padding: 16px 0px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const StyledChevron = styled(ChevronRight)`
|
const StyledChevron = styled(ChevronRight)`
|
||||||
@ -60,7 +62,7 @@ const SettingsButton = ({
|
|||||||
<SettingsButtonWrapper data-testid={testId} align="center" justify="space-between" onClick={onClick}>
|
<SettingsButtonWrapper data-testid={testId} align="center" justify="space-between" onClick={onClick}>
|
||||||
<ThemedText.SubHeaderSmall color="textPrimary">{title}</ThemedText.SubHeaderSmall>
|
<ThemedText.SubHeaderSmall color="textPrimary">{title}</ThemedText.SubHeaderSmall>
|
||||||
<LanguageLabel gap="xs" align="center" width="min-content">
|
<LanguageLabel gap="xs" align="center" width="min-content">
|
||||||
<ThemedText.LabelMedium color="textPrimary">{currentState}</ThemedText.LabelMedium>
|
<ThemedText.LabelSmall color="textPrimary">{currentState}</ThemedText.LabelSmall>
|
||||||
<StyledChevron size={20} />
|
<StyledChevron size={20} />
|
||||||
</LanguageLabel>
|
</LanguageLabel>
|
||||||
</SettingsButtonWrapper>
|
</SettingsButtonWrapper>
|
||||||
@ -69,12 +71,15 @@ const SettingsButton = ({
|
|||||||
export default function SettingsMenu({
|
export default function SettingsMenu({
|
||||||
onClose,
|
onClose,
|
||||||
openLanguageSettings,
|
openLanguageSettings,
|
||||||
|
openLocalCurrencySettings,
|
||||||
}: {
|
}: {
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
openLanguageSettings: () => void
|
openLanguageSettings: () => void
|
||||||
|
openLocalCurrencySettings: () => void
|
||||||
}) {
|
}) {
|
||||||
const currencyConversionEnabled = useCurrencyConversionFlagEnabled()
|
const currencyConversionEnabled = useCurrencyConversionFlagEnabled()
|
||||||
const activeLocale = useActiveLocale()
|
const activeLocale = useActiveLocale()
|
||||||
|
const activeLocalCurrency = useActiveLocalCurrency()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SlideOutMenu title={<Trans>Settings</Trans>} onClose={onClose}>
|
<SlideOutMenu title={<Trans>Settings</Trans>} onClose={onClose}>
|
||||||
@ -83,7 +88,7 @@ export default function SettingsMenu({
|
|||||||
<SectionTitle data-testid="wallet-header">
|
<SectionTitle data-testid="wallet-header">
|
||||||
<Trans>Preferences</Trans>
|
<Trans>Preferences</Trans>
|
||||||
</SectionTitle>
|
</SectionTitle>
|
||||||
<ToggleWrapper>
|
<ToggleWrapper currencyConversionEnabled={currencyConversionEnabled}>
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
<SmallBalanceToggle />
|
<SmallBalanceToggle />
|
||||||
<AnalyticsToggle />
|
<AnalyticsToggle />
|
||||||
@ -99,12 +104,20 @@ export default function SettingsMenu({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{currencyConversionEnabled && (
|
{currencyConversionEnabled && (
|
||||||
|
<Column>
|
||||||
<SettingsButton
|
<SettingsButton
|
||||||
title={<Trans>Language</Trans>}
|
title={<Trans>Language</Trans>}
|
||||||
currentState={LOCALE_LABEL[activeLocale]}
|
currentState={LOCALE_LABEL[activeLocale]}
|
||||||
onClick={openLanguageSettings}
|
onClick={openLanguageSettings}
|
||||||
testId="language-settings-button"
|
testId="language-settings-button"
|
||||||
/>
|
/>
|
||||||
|
<SettingsButton
|
||||||
|
title={<Trans>Currency</Trans>}
|
||||||
|
currentState={activeLocalCurrency}
|
||||||
|
onClick={openLocalCurrencySettings}
|
||||||
|
testId="local-currency-settings-button"
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<GitVersionRow />
|
<GitVersionRow />
|
||||||
|
57
src/components/AccountDrawer/shared.tsx
Normal file
57
src/components/AccountDrawer/shared.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import Column from 'components/Column'
|
||||||
|
import Row from 'components/Row'
|
||||||
|
import { ReactNode } from 'react'
|
||||||
|
import { Check } from 'react-feather'
|
||||||
|
import type { To } from 'react-router-dom'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import styled, { useTheme } from 'styled-components'
|
||||||
|
import { BREAKPOINTS, ClickableStyle, ThemedText } from 'theme'
|
||||||
|
|
||||||
|
const InternalLinkMenuItem = styled(Link)`
|
||||||
|
${ClickableStyle}
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 0;
|
||||||
|
justify-content: space-between;
|
||||||
|
text-decoration: none;
|
||||||
|
color: ${({ theme }) => theme.neutral1};
|
||||||
|
`
|
||||||
|
|
||||||
|
export const MenuColumn = styled(Column)`
|
||||||
|
@media screen and (max-width: ${BREAKPOINTS.sm}px) {
|
||||||
|
padding-bottom: 14px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export function MenuItem({
|
||||||
|
label,
|
||||||
|
logo,
|
||||||
|
to,
|
||||||
|
onClick,
|
||||||
|
isActive,
|
||||||
|
testId,
|
||||||
|
}: {
|
||||||
|
label: ReactNode
|
||||||
|
logo?: ReactNode
|
||||||
|
to?: To
|
||||||
|
onClick?: () => void
|
||||||
|
isActive: boolean
|
||||||
|
testId?: string
|
||||||
|
}) {
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
|
if (!to) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InternalLinkMenuItem onClick={onClick} to={to}>
|
||||||
|
<Row gap="md">
|
||||||
|
{logo && logo}
|
||||||
|
<ThemedText.BodySmall data-testid={testId}>{label}</ThemedText.BodySmall>
|
||||||
|
</Row>
|
||||||
|
{isActive && <Check color={theme.accent1} opacity={1} size={20} />}
|
||||||
|
</InternalLinkMenuItem>
|
||||||
|
)
|
||||||
|
}
|
90
src/constants/localCurrencies.tsx
Normal file
90
src/constants/localCurrencies.tsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
|
import {
|
||||||
|
AUD_ICON,
|
||||||
|
BRL_ICON,
|
||||||
|
CAD_ICON,
|
||||||
|
EUR_ICON,
|
||||||
|
GBP_ICON,
|
||||||
|
HKD_ICON,
|
||||||
|
IDR_ICON,
|
||||||
|
INR_ICON,
|
||||||
|
JPY_ICON,
|
||||||
|
NGN_ICON,
|
||||||
|
PKR_ICON,
|
||||||
|
RUB_ICON,
|
||||||
|
SGD_ICON,
|
||||||
|
THB_ICON,
|
||||||
|
TRY_ICON,
|
||||||
|
UAH_ICON,
|
||||||
|
USD_ICON,
|
||||||
|
VND_ICON,
|
||||||
|
} from './localCurrencyIcons'
|
||||||
|
|
||||||
|
export const SUPPORTED_LOCAL_CURRENCIES = [
|
||||||
|
'USD',
|
||||||
|
'AUD',
|
||||||
|
'BRL',
|
||||||
|
'CAD',
|
||||||
|
'EUR',
|
||||||
|
'GBP',
|
||||||
|
'HKD',
|
||||||
|
'IDR',
|
||||||
|
'INR',
|
||||||
|
'JPY',
|
||||||
|
'NGN',
|
||||||
|
'PKR',
|
||||||
|
'RUB',
|
||||||
|
'SGD',
|
||||||
|
'THB',
|
||||||
|
'TRY',
|
||||||
|
'UAH',
|
||||||
|
'VND',
|
||||||
|
]
|
||||||
|
|
||||||
|
export type SupportedLocalCurrency = (typeof SUPPORTED_LOCAL_CURRENCIES)[number]
|
||||||
|
|
||||||
|
export const DEFAULT_LOCAL_CURRENCY: SupportedLocalCurrency = 'USD'
|
||||||
|
|
||||||
|
export function getLocalCurrencyIcon(localCurrency: SupportedLocalCurrency, size = 20): ReactNode {
|
||||||
|
switch (localCurrency) {
|
||||||
|
case 'USD':
|
||||||
|
return <USD_ICON width={size} height={size} />
|
||||||
|
case 'EUR':
|
||||||
|
return <EUR_ICON width={size} height={size} />
|
||||||
|
case 'RUB':
|
||||||
|
return <RUB_ICON width={size} height={size} />
|
||||||
|
case 'INR':
|
||||||
|
return <INR_ICON width={size} height={size} />
|
||||||
|
case 'GBP':
|
||||||
|
return <GBP_ICON width={size} height={size} />
|
||||||
|
case 'JPY':
|
||||||
|
return <JPY_ICON width={size} height={size} />
|
||||||
|
case 'VND':
|
||||||
|
return <VND_ICON width={size} height={size} />
|
||||||
|
case 'SGD':
|
||||||
|
return <SGD_ICON width={size} height={size} />
|
||||||
|
case 'BRL':
|
||||||
|
return <BRL_ICON width={size} height={size} />
|
||||||
|
case 'HKD':
|
||||||
|
return <HKD_ICON width={size} height={size} />
|
||||||
|
case 'CAD':
|
||||||
|
return <CAD_ICON width={size} height={size} />
|
||||||
|
case 'IDR':
|
||||||
|
return <IDR_ICON width={size} height={size} />
|
||||||
|
case 'TRY':
|
||||||
|
return <TRY_ICON width={size} height={size} />
|
||||||
|
case 'NGN':
|
||||||
|
return <NGN_ICON width={size} height={size} />
|
||||||
|
case 'AUD':
|
||||||
|
return <AUD_ICON width={size} height={size} />
|
||||||
|
case 'PKR':
|
||||||
|
return <PKR_ICON width={size} height={size} />
|
||||||
|
case 'UAH':
|
||||||
|
return <UAH_ICON width={size} height={size} />
|
||||||
|
case 'THB':
|
||||||
|
return <THB_ICON width={size} height={size} />
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
721
src/constants/localCurrencyIcons.tsx
Normal file
721
src/constants/localCurrencyIcons.tsx
Normal file
File diff suppressed because one or more lines are too long
29
src/hooks/useActiveLocalCurrency.ts
Normal file
29
src/hooks/useActiveLocalCurrency.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { DEFAULT_LOCAL_CURRENCY, SUPPORTED_LOCAL_CURRENCIES, SupportedLocalCurrency } from 'constants/localCurrencies'
|
||||||
|
import { atomWithStorage, useAtomValue } from 'jotai/utils'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import useParsedQueryString from './useParsedQueryString'
|
||||||
|
|
||||||
|
export const activeLocalCurrencyAtom = atomWithStorage<SupportedLocalCurrency>(
|
||||||
|
'activeLocalCurrency',
|
||||||
|
DEFAULT_LOCAL_CURRENCY
|
||||||
|
)
|
||||||
|
|
||||||
|
function useUrlLocalCurrency() {
|
||||||
|
const parsed = useParsedQueryString()
|
||||||
|
const parsedLocalCurrency = parsed.cur
|
||||||
|
|
||||||
|
if (typeof parsedLocalCurrency !== 'string') return undefined
|
||||||
|
|
||||||
|
const lowerCaseSupportedLocalCurrency = parsedLocalCurrency.toLowerCase()
|
||||||
|
return SUPPORTED_LOCAL_CURRENCIES.find(
|
||||||
|
(localCurrency) => localCurrency.toLowerCase() === lowerCaseSupportedLocalCurrency
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useActiveLocalCurrency(): SupportedLocalCurrency {
|
||||||
|
const activeLocalCurrency = useAtomValue(activeLocalCurrencyAtom)
|
||||||
|
const urlLocalCurrency = useUrlLocalCurrency()
|
||||||
|
|
||||||
|
return useMemo(() => urlLocalCurrency ?? activeLocalCurrency, [activeLocalCurrency, urlLocalCurrency])
|
||||||
|
}
|
40
src/hooks/useLocalCurrencyLinkProps.ts
Normal file
40
src/hooks/useLocalCurrencyLinkProps.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { sendAnalyticsEvent } from 'analytics'
|
||||||
|
import { SupportedLocalCurrency } from 'constants/localCurrencies'
|
||||||
|
import useParsedQueryString from 'hooks/useParsedQueryString'
|
||||||
|
import { useAtom } from 'jotai'
|
||||||
|
import { stringify } from 'qs'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import type { To } from 'react-router-dom'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
|
import { activeLocalCurrencyAtom, useActiveLocalCurrency } from './useActiveLocalCurrency'
|
||||||
|
|
||||||
|
export function useLocalCurrencyLinkProps(localCurrency?: SupportedLocalCurrency): {
|
||||||
|
to?: To
|
||||||
|
onClick?: () => void
|
||||||
|
} {
|
||||||
|
const location = useLocation()
|
||||||
|
const qs = useParsedQueryString()
|
||||||
|
const activeLocalCurrency = useActiveLocalCurrency()
|
||||||
|
const [, updateActiveLocalCurrency] = useAtom(activeLocalCurrencyAtom)
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() =>
|
||||||
|
!localCurrency
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
to: {
|
||||||
|
...location,
|
||||||
|
search: stringify({ ...qs, cur: localCurrency }),
|
||||||
|
},
|
||||||
|
onClick: () => {
|
||||||
|
updateActiveLocalCurrency(localCurrency)
|
||||||
|
sendAnalyticsEvent('Local Currency Selected', {
|
||||||
|
previous_local_currency: activeLocalCurrency,
|
||||||
|
new_local_currency: localCurrency,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[localCurrency, location, qs, updateActiveLocalCurrency, activeLocalCurrency]
|
||||||
|
)
|
||||||
|
}
|
@ -40,9 +40,6 @@ export const ThemedText = {
|
|||||||
Hero(props: TextProps) {
|
Hero(props: TextProps) {
|
||||||
return <TextWrapper fontWeight={485} fontSize={48} color="neutral1" {...props} />
|
return <TextWrapper fontWeight={485} fontSize={48} color="neutral1" {...props} />
|
||||||
},
|
},
|
||||||
LabelMedium(props: TextProps) {
|
|
||||||
return <TextWrapper fontWeight={500} fontSize={16} color="textPrimary" lineHeight="20px" {...props} />
|
|
||||||
},
|
|
||||||
LabelSmall(props: TextProps) {
|
LabelSmall(props: TextProps) {
|
||||||
return <TextWrapper fontWeight={485} fontSize={14} color="neutral2" {...props} />
|
return <TextWrapper fontWeight={485} fontSize={14} color="neutral2" {...props} />
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user