chore: moving language selection to own settings panel (#7169)

* chore: moving language selection to own settings panel

* auto switch when close

* updating e2e

* clickable style

* moving behind feature flag

* fixing tests

* this looks nicer

* nowrap for overflow
This commit is contained in:
Jack Short 2023-08-17 16:05:18 -04:00 committed by GitHub
parent bf1f613a4f
commit ea5af12b1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 169 additions and 50 deletions

@ -1,3 +1,5 @@
import { FeatureFlag } from 'featureFlags'
import { getTestSelector } from '../utils' import { getTestSelector } from '../utils'
describe('Wallet Dropdown', () => { describe('Wallet Dropdown', () => {
@ -21,10 +23,14 @@ describe('Wallet Dropdown', () => {
}) })
} }
function itChangesLocale() { function itChangesLocale({ featureFlag = false }: { featureFlag?: boolean } = {}) {
it('should change locale', () => { it('should change locale', () => {
cy.contains('Uniswap available in: English').should('not.exist') cy.contains('Uniswap available in: English').should('not.exist')
if (featureFlag) {
cy.get(getTestSelector('language-settings-button')).click()
}
cy.get(getTestSelector('wallet-language-item')).contains('Afrikaans').click({ force: true }) cy.get(getTestSelector('wallet-language-item')).contains('Afrikaans').click({ force: true })
cy.location('search').should('match', /\?lng=af-ZA$/) cy.location('search').should('match', /\?lng=af-ZA$/)
cy.contains('Uniswap available in: English') cy.contains('Uniswap available in: English')
@ -45,6 +51,15 @@ describe('Wallet Dropdown', () => {
itChangesLocale() itChangesLocale()
}) })
describe('should change locale with feature flag', () => {
beforeEach(() => {
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
cy.get(getTestSelector('web3-status-connected')).click()
cy.get(getTestSelector('wallet-settings')).click()
})
itChangesLocale({ featureFlag: true })
})
describe('testnet toggle', () => { describe('testnet toggle', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/swap') cy.visit('/swap')

@ -5,6 +5,7 @@ import { useCallback, useEffect, 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 SettingsMenu from './SettingsMenu' import SettingsMenu from './SettingsMenu'
const DefaultMenuWrap = styled(Column)` const DefaultMenuWrap = styled(Column)`
@ -15,6 +16,7 @@ const DefaultMenuWrap = styled(Column)`
enum MenuState { enum MenuState {
DEFAULT, DEFAULT,
SETTINGS, SETTINGS,
LANGUAGE_SETTINGS,
} }
function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) { function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) {
@ -24,9 +26,10 @@ function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) {
const [menu, setMenu] = useState<MenuState>(MenuState.DEFAULT) const [menu, setMenu] = useState<MenuState>(MenuState.DEFAULT)
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), [])
useEffect(() => { useEffect(() => {
if (!drawerOpen && menu === MenuState.SETTINGS) { if (!drawerOpen && menu !== MenuState.DEFAULT) {
// wait for the drawer to close before resetting the menu // wait for the drawer to close before resetting the menu
const timer = setTimeout(() => { const timer = setTimeout(() => {
closeSettings() closeSettings()
@ -44,7 +47,10 @@ function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) {
) : ( ) : (
<WalletModal openSettings={openSettings} /> <WalletModal openSettings={openSettings} />
))} ))}
{menu === MenuState.SETTINGS && <SettingsMenu onClose={closeSettings} />} {menu === MenuState.SETTINGS && (
<SettingsMenu onClose={closeSettings} openLanguageSettings={openLanguageSettings} />
)}
{menu === MenuState.LANGUAGE_SETTINGS && <LanguageMenu onClose={openSettings} />}
</DefaultMenuWrap> </DefaultMenuWrap>
) )
} }

@ -0,0 +1,56 @@
import { Trans } from '@lingui/macro'
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
import { useActiveLocale } from 'hooks/useActiveLocale'
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 { 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.textPrimary};
`
function LanguageMenuItem({ locale, isActive }: { locale: SupportedLocale; isActive: boolean }) {
const { to, onClick } = useLocationLinkProps(locale)
const theme = useTheme()
if (!to) return null
return (
<InternalLinkMenuItem onClick={onClick} to={to}>
<ThemedText.BodySmall data-testid="wallet-language-item">{LOCALE_LABEL[locale]}</ThemedText.BodySmall>
{isActive && <Check color={theme.accentActive} opacity={1} size={20} />}
</InternalLinkMenuItem>
)
}
export function LanguageMenuItems() {
const activeLocale = useActiveLocale()
return (
<>
{SUPPORTED_LOCALES.map((locale) => (
<LanguageMenuItem locale={locale} isActive={activeLocale === locale} key={locale} />
))}
</>
)
}
export default function LanguageMenu({ onClose }: { onClose: () => void }) {
return (
<SlideOutMenu title={<Trans>Language</Trans>} onClose={onClose}>
<LanguageMenuItems />
</SlideOutMenu>
)
}

@ -1,46 +1,27 @@
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales' import Column from 'components/Column'
import Row from 'components/Row'
import { LOCALE_LABEL } from 'constants/locales'
import { useCurrencyConversionFlagEnabled } from 'featureFlags/flags/currencyConversion'
import { useActiveLocale } from 'hooks/useActiveLocale' import { useActiveLocale } from 'hooks/useActiveLocale'
import { useLocationLinkProps } from 'hooks/useLocationLinkProps' import { ReactNode } from 'react'
import { Check } from 'react-feather' import { ChevronRight } from 'react-feather'
import { Link } from 'react-router-dom' import styled from 'styled-components'
import styled, { useTheme } from 'styled-components'
import { ClickableStyle, ThemedText } from 'theme' import { ClickableStyle, ThemedText } from 'theme'
import ThemeToggle from 'theme/components/ThemeToggle' import ThemeToggle from 'theme/components/ThemeToggle'
import { AnalyticsToggle } from './AnalyticsToggle' import { AnalyticsToggle } from './AnalyticsToggle'
import { GitVersionRow } from './GitVersionRow' import { GitVersionRow } from './GitVersionRow'
import { LanguageMenuItems } from './LanguageMenu'
import { SlideOutMenu } from './SlideOutMenu' import { SlideOutMenu } from './SlideOutMenu'
import { SmallBalanceToggle } from './SmallBalanceToggle' import { SmallBalanceToggle } from './SmallBalanceToggle'
import { TestnetsToggle } from './TestnetsToggle' import { TestnetsToggle } from './TestnetsToggle'
const InternalLinkMenuItem = styled(Link)` const Container = styled(Column)`
${ClickableStyle} height: 100%;
flex: 1;
color: ${({ theme }) => theme.textTertiary};
display: flex;
flex-direction: row;
align-items: center;
padding: 12px 0;
justify-content: space-between; justify-content: space-between;
text-decoration: none;
color: ${({ theme }) => theme.textPrimary};
` `
function LanguageMenuItem({ locale, isActive }: { locale: SupportedLocale; isActive: boolean }) {
const { to, onClick } = useLocationLinkProps(locale)
const theme = useTheme()
if (!to) return null
return (
<InternalLinkMenuItem onClick={onClick} to={to}>
<ThemedText.BodySmall data-testid="wallet-language-item">{LOCALE_LABEL[locale]}</ThemedText.BodySmall>
{isActive && <Check color={theme.accentActive} opacity={1} size={20} />}
</InternalLinkMenuItem>
)
}
const SectionTitle = styled(ThemedText.SubHeader)` const SectionTitle = styled(ThemedText.SubHeader)`
color: ${({ theme }) => theme.textSecondary}; color: ${({ theme }) => theme.textSecondary};
padding-bottom: 24px; padding-bottom: 24px;
@ -53,28 +34,81 @@ const ToggleWrapper = styled.div`
margin-bottom: 24px; margin-bottom: 24px;
` `
export default function SettingsMenu({ onClose }: { onClose: () => void }) { const SettingsButtonWrapper = styled(Row)`
${ClickableStyle}
`
const StyledChevron = styled(ChevronRight)`
color: ${({ theme }) => theme.textSecondary};
`
const LanguageLabel = styled(Row)`
white-space: nowrap;
`
const SettingsButton = ({
title,
currentState,
onClick,
testId,
}: {
title: ReactNode
currentState: ReactNode
onClick: () => void
testId?: string
}) => (
<SettingsButtonWrapper data-testid={testId} align="center" justify="space-between" onClick={onClick}>
<ThemedText.SubHeaderSmall color="textPrimary">{title}</ThemedText.SubHeaderSmall>
<LanguageLabel gap="xs" align="center" width="min-content">
<ThemedText.LabelMedium color="textPrimary">{currentState}</ThemedText.LabelMedium>
<StyledChevron size={20} />
</LanguageLabel>
</SettingsButtonWrapper>
)
export default function SettingsMenu({
onClose,
openLanguageSettings,
}: {
onClose: () => void
openLanguageSettings: () => void
}) {
const currencyConversionEnabled = useCurrencyConversionFlagEnabled()
const activeLocale = useActiveLocale() const activeLocale = useActiveLocale()
return ( return (
<SlideOutMenu title={<Trans>Settings</Trans>} onClose={onClose}> <SlideOutMenu title={<Trans>Settings</Trans>} onClose={onClose}>
<SectionTitle> <Container>
<Trans>Preferences</Trans> <div>
</SectionTitle> <SectionTitle data-testid="wallet-header">
<ToggleWrapper> <Trans>Preferences</Trans>
<ThemeToggle /> </SectionTitle>
<SmallBalanceToggle /> <ToggleWrapper>
<AnalyticsToggle /> <ThemeToggle />
<TestnetsToggle /> <SmallBalanceToggle />
</ToggleWrapper> <AnalyticsToggle />
<TestnetsToggle />
</ToggleWrapper>
{!currencyConversionEnabled && (
<>
<SectionTitle data-testid="wallet-header">
<Trans>Language</Trans>
</SectionTitle>
<LanguageMenuItems />
</>
)}
<SectionTitle data-testid="wallet-header"> {currencyConversionEnabled && (
<Trans>Language</Trans> <SettingsButton
</SectionTitle> title={<Trans>Language</Trans>}
{SUPPORTED_LOCALES.map((locale) => ( currentState={LOCALE_LABEL[activeLocale]}
<LanguageMenuItem locale={locale} isActive={activeLocale === locale} key={locale} /> onClick={openLanguageSettings}
))} testId="language-settings-button"
<GitVersionRow /> />
)}
</div>
<GitVersionRow />
</Container>
</SlideOutMenu> </SlideOutMenu>
) )
} }

@ -1,9 +1,10 @@
import Column from 'components/Column'
import { ScrollBarStyles } from 'components/Common' import { ScrollBarStyles } from 'components/Common'
import { ArrowLeft } from 'react-feather' import { ArrowLeft } from 'react-feather'
import styled from 'styled-components' import styled from 'styled-components'
import { ClickableStyle, ThemedText } from 'theme' import { ClickableStyle, ThemedText } from 'theme'
const Menu = styled.div` const Menu = styled(Column)`
width: 100%; width: 100%;
overflow: auto; overflow: auto;
margin-top: 4px; margin-top: 4px;

@ -3,3 +3,7 @@ import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
export function useCurrencyConversionFlag(): BaseVariant { export function useCurrencyConversionFlag(): BaseVariant {
return useBaseFlag(FeatureFlag.currencyConversion) return useBaseFlag(FeatureFlag.currencyConversion)
} }
export function useCurrencyConversionFlagEnabled(): boolean {
return useCurrencyConversionFlag() === BaseVariant.Enabled
}

@ -43,6 +43,9 @@ export const ThemedText = {
Hero(props: TextProps) { Hero(props: TextProps) {
return <TextWrapper fontWeight={500} fontSize={48} color="textPrimary" {...props} /> return <TextWrapper fontWeight={500} fontSize={48} color="textPrimary" {...props} />
}, },
LabelMedium(props: TextProps) {
return <TextWrapper fontWeight={500} fontSize={16} color="textPrimary" lineHeight="20px" {...props} />
},
LabelSmall(props: TextProps) { LabelSmall(props: TextProps) {
return <TextWrapper fontWeight={600} fontSize={14} color="textSecondary" {...props} /> return <TextWrapper fontWeight={600} fontSize={14} color="textSecondary" {...props} />
}, },