-
-
Notifications
You must be signed in to change notification settings - Fork 273
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(suite-native): select coin modal UI
- Loading branch information
Showing
16 changed files
with
421 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
suite-native/module-trading/src/components/buy/AmountCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React from 'react'; | ||
|
||
import { Card, HStack } from '@suite-native/atoms'; | ||
|
||
import { SelectNetworkButton } from '../general/SelectNetworkButton'; | ||
import { NetworksSheet } from '../general/NetworksSheet'; | ||
import { useTokensSheetControls } from '../../hooks/useTokensSheetControls'; | ||
|
||
export const AmountCard = () => { | ||
const { | ||
showTokensSheet, | ||
isTokensSheetVisible, | ||
hideTokensSheet, | ||
setSelectedNetwork, | ||
selectedNetwork, | ||
} = useTokensSheetControls(); | ||
|
||
return ( | ||
<Card> | ||
<HStack> | ||
<SelectNetworkButton onPress={showTokensSheet} selectedNetwork={selectedNetwork} /> | ||
</HStack> | ||
<NetworksSheet | ||
isVisible={isTokensSheetVisible} | ||
onClose={hideTokensSheet} | ||
onNetworkSelect={setSelectedNetwork} | ||
/> | ||
</Card> | ||
); | ||
}; |
30 changes: 30 additions & 0 deletions
30
suite-native/module-trading/src/components/buy/__tests__/AmountCard.comp.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { render, fireEvent } from '@suite-native/test-utils'; | ||
|
||
import { AmountCard } from '../AmountCard'; | ||
|
||
describe('AmountCard', () => { | ||
it('should display Select coin button', () => { | ||
const { getByText, queryByText } = render(<AmountCard />); | ||
|
||
expect(getByText('Select coin')).toBeDefined(); | ||
expect(queryByText('Tokens')).toBeNull(); | ||
}); | ||
|
||
it('should display NetworksSheet after button click', () => { | ||
const { getByText } = render(<AmountCard />); | ||
|
||
fireEvent.press(getByText('Select coin')); | ||
|
||
expect(getByText('Tokens')).toBeDefined(); | ||
}); | ||
|
||
it('should display selected network from NetworksSheet', () => { | ||
const { getByText, queryByText } = render(<AmountCard />); | ||
|
||
fireEvent.press(getByText('Select coin')); | ||
fireEvent.press(getByText('BTC')); | ||
|
||
expect(queryByText('Tokens')).toBeNull(); | ||
expect(getByText('BTC')).toBeDefined(); | ||
}); | ||
}); |
62 changes: 62 additions & 0 deletions
62
suite-native/module-trading/src/components/general/NetworkButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { Pressable, StyleSheet } from 'react-native'; | ||
import Animated from 'react-native-reanimated'; | ||
|
||
import { LinearGradient } from 'expo-linear-gradient'; | ||
|
||
import { hexToRgba } from '@suite-common/suite-utils'; | ||
import { useFormatters } from '@suite-common/formatters'; | ||
import { NetworkSymbol } from '@suite-common/wallet-config'; | ||
import { Text } from '@suite-native/atoms'; | ||
import { CryptoIcon, Icon } from '@suite-native/icons'; | ||
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; | ||
import { nativeSpacings } from '@trezor/theme'; | ||
import { getNetworkSymbolColorBold } from '@suite-native/theme'; | ||
|
||
export type AssetButtonProps = { | ||
symbol: NetworkSymbol; | ||
onPress: () => void; | ||
caret?: boolean; | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
button: { | ||
height: 36, | ||
padding: nativeSpacings.sp4, // TODO 5? | ||
paddingRight: nativeSpacings.sp8, // TODO 12? | ||
flexDirection: 'row', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
gap: nativeSpacings.sp8, // TODO 6? | ||
}, | ||
}); | ||
|
||
const gradientBackgroundStyle = prepareNativeStyle(utils => ({ | ||
borderRadius: utils.borders.radii.round, | ||
borderWidth: 1, | ||
borderColor: 'rgba(0, 0, 0, 0.06)', | ||
})); | ||
|
||
const AnimatedPressable = Animated.createAnimatedComponent(Pressable); | ||
|
||
export const NetworkButton = ({ symbol, onPress, caret }: AssetButtonProps) => { | ||
const { DisplaySymbolFormatter } = useFormatters(); | ||
const { applyStyle } = useNativeStyles(); | ||
const symbolColor = getNetworkSymbolColorBold(symbol); | ||
|
||
return ( | ||
<LinearGradient | ||
colors={[hexToRgba(symbolColor, 0.3), hexToRgba(symbolColor, 0.01)]} | ||
style={applyStyle(gradientBackgroundStyle)} | ||
start={{ x: 0, y: 0.5 }} | ||
end={{ x: 1, y: 0.5 }} | ||
> | ||
<AnimatedPressable onPress={onPress} style={styles.button}> | ||
<CryptoIcon symbol={symbol} size="small" /> | ||
<Text color="textSubdued" variant="callout"> | ||
<DisplaySymbolFormatter value={symbol} areAmountUnitsEnabled={false} /> | ||
</Text> | ||
{caret && <Icon name="caretDown" color="textSubdued" size="medium" />} | ||
</AnimatedPressable> | ||
</LinearGradient> | ||
); | ||
}; |
38 changes: 38 additions & 0 deletions
38
suite-native/module-trading/src/components/general/NetworksSheet.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { NetworkSymbol } from '@suite-common/wallet-config/libDev/src'; | ||
import { BottomSheet, Button, SearchInput, VStack } from '@suite-native/atoms'; | ||
|
||
import { PopularNetworks } from './PopularNetworks'; | ||
|
||
export type NetworksSheetProps = { | ||
isVisible: boolean; | ||
onClose: () => void; | ||
onNetworkSelect: (symbol: NetworkSymbol) => void; | ||
}; | ||
|
||
export const NetworksSheet = ({ isVisible, onClose, onNetworkSelect }: NetworksSheetProps) => { | ||
const onNetworkSelectCallback = (symbol: NetworkSymbol) => { | ||
onNetworkSelect(symbol); | ||
onClose(); | ||
}; | ||
|
||
return ( | ||
<BottomSheet | ||
isVisible={isVisible} | ||
onClose={onClose} | ||
title="Tokens" | ||
isCloseDisplayed={false} | ||
> | ||
<VStack spacing="sp16"> | ||
<SearchInput onChange={() => {}} /> | ||
|
||
<PopularNetworks | ||
symbols={['btc', 'eth', 'sol', 'base']} | ||
onNetworkSelect={onNetworkSelectCallback} | ||
/> | ||
<Button colorScheme="tertiaryElevation0" onPress={onClose}> | ||
Close | ||
</Button> | ||
</VStack> | ||
</BottomSheet> | ||
); | ||
}; |
38 changes: 38 additions & 0 deletions
38
suite-native/module-trading/src/components/general/PopularNetworks.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { NetworkSymbol } from '@suite-common/wallet-config'; | ||
import { HStack, Text, VStack } from '@suite-native/atoms'; | ||
import { Translation } from '@suite-native/intl'; | ||
|
||
import { NetworkButton } from './NetworkButton'; | ||
|
||
export type PopularNetworksProps = { | ||
symbols: NetworkSymbol[]; | ||
onNetworkSelect: (symbol: NetworkSymbol) => void; | ||
maxNetworkSymbols?: number; | ||
}; | ||
|
||
const DEFAULT_MAX_NETWORK_SYMBOLS = 4; | ||
|
||
export const PopularNetworks = ({ | ||
symbols, | ||
onNetworkSelect, | ||
maxNetworkSymbols = DEFAULT_MAX_NETWORK_SYMBOLS, | ||
}: PopularNetworksProps) => { | ||
const limitedSymbols = symbols.slice(0, maxNetworkSymbols); | ||
|
||
return ( | ||
<VStack> | ||
<Text> | ||
<Translation id="moduleTrading.networksSheet.popularTitle" /> | ||
</Text> | ||
<HStack justifyContent="space-between"> | ||
{limitedSymbols.map(symbol => ( | ||
<NetworkButton | ||
key={symbol} | ||
symbol={symbol} | ||
onPress={() => onNetworkSelect(symbol)} | ||
/> | ||
))} | ||
</HStack> | ||
</VStack> | ||
); | ||
}; |
29 changes: 29 additions & 0 deletions
29
suite-native/module-trading/src/components/general/SelectNetworkButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { NetworkSymbol } from '@suite-common/wallet-config'; | ||
import { Button, buttonSchemeToColorsMap } from '@suite-native/atoms'; | ||
import { Translation } from '@suite-native/intl'; | ||
import { Icon } from '@suite-native/icons'; | ||
|
||
import { NetworkButton } from './NetworkButton'; | ||
|
||
export type SelectNetworkButtonProps = { | ||
onPress: () => void; | ||
selectedNetwork: NetworkSymbol | undefined; | ||
}; | ||
|
||
export const SelectNetworkButton = ({ onPress, selectedNetwork }: SelectNetworkButtonProps) => { | ||
const { iconColor } = buttonSchemeToColorsMap.primary; | ||
|
||
if (selectedNetwork) { | ||
return <NetworkButton symbol={selectedNetwork} onPress={onPress} caret />; | ||
} | ||
|
||
return ( | ||
<Button | ||
onPress={onPress} | ||
viewRight={<Icon name="caretDown" color={iconColor} size="medium" />} | ||
size="small" | ||
> | ||
<Translation id="moduleTrading.selectCoin.buttonTitle" /> | ||
</Button> | ||
); | ||
}; |
21 changes: 21 additions & 0 deletions
21
suite-native/module-trading/src/components/general/__tests__/NetworkButton.comp.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { render, fireEvent } from '@suite-native/test-utils'; | ||
|
||
import { NetworkButton } from '../NetworkButton'; | ||
|
||
describe('NetworkButton', () => { | ||
it('should render display name of given symbol', () => { | ||
const { getByText } = render(<NetworkButton symbol="btc" onPress={jest.fn()} />); | ||
|
||
expect(getByText('BTC')).toBeDefined(); | ||
}); | ||
|
||
it('should call onPress callback', () => { | ||
const pressSpy = jest.fn(); | ||
const { getByText } = render(<NetworkButton symbol="btc" onPress={pressSpy} />); | ||
|
||
const button = getByText('BTC'); | ||
fireEvent.press(button); | ||
|
||
expect(pressSpy).toHaveBeenCalledWith(); | ||
}); | ||
}); |
48 changes: 48 additions & 0 deletions
48
suite-native/module-trading/src/components/general/__tests__/PopularNetworks.comp.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { render, fireEvent } from '@suite-native/test-utils'; | ||
|
||
import { PopularNetworks } from '../PopularNetworks'; | ||
|
||
describe('PopularNetworks', () => { | ||
it('should render up to 4 networks by default', () => { | ||
const { queryByText } = render( | ||
<PopularNetworks | ||
symbols={['btc', 'eth', 'ada', 'sol', 'doge']} | ||
onNetworkSelect={jest.fn()} | ||
/>, | ||
); | ||
|
||
expect(queryByText('BTC')).toBeDefined(); | ||
expect(queryByText('ETH')).toBeDefined(); | ||
expect(queryByText('ADA')).toBeDefined(); | ||
expect(queryByText('SOL')).toBeDefined(); | ||
expect(queryByText('DOGE')).toBeNull(); | ||
}); | ||
|
||
it('should render up to maxNetworkSymbols networks', () => { | ||
const { queryByText } = render( | ||
<PopularNetworks | ||
symbols={['btc', 'eth', 'ada', 'sol', 'doge']} | ||
onNetworkSelect={jest.fn()} | ||
maxNetworkSymbols={3} | ||
/>, | ||
); | ||
|
||
expect(queryByText('BTC')).toBeDefined(); | ||
expect(queryByText('ETH')).toBeDefined(); | ||
expect(queryByText('ADA')).toBeDefined(); | ||
expect(queryByText('SOL')).toBeNull(); | ||
expect(queryByText('DOGE')).toBeNull(); | ||
}); | ||
|
||
it('should call onNetworkSelect callback', () => { | ||
const selectSpy = jest.fn(); | ||
const { getByText } = render( | ||
<PopularNetworks symbols={['btc']} onNetworkSelect={selectSpy} />, | ||
); | ||
|
||
const button = getByText('BTC'); | ||
fireEvent.press(button); | ||
|
||
expect(selectSpy).toHaveBeenCalledWith('btc'); | ||
}); | ||
}); |
22 changes: 22 additions & 0 deletions
22
...-native/module-trading/src/components/general/__tests__/SelectNetworkButton.comp.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { render } from '@suite-native/test-utils'; | ||
|
||
import { SelectNetworkButton } from '../SelectNetworkButton'; | ||
|
||
describe('SelectNetworkButton', () => { | ||
it('should render "select coin" when no network is selected', () => { | ||
const { getByText } = render( | ||
<SelectNetworkButton onPress={jest.fn()} selectedNetwork={undefined} />, | ||
); | ||
|
||
expect(getByText('Select coin')).toBeDefined(); | ||
}); | ||
|
||
it('should render NetworkButton when network is selected', () => { | ||
const { queryByText } = render( | ||
<SelectNetworkButton onPress={jest.fn()} selectedNetwork="ada" />, | ||
); | ||
|
||
expect(queryByText('Select coin')).toBeNull(); | ||
expect(queryByText('ADA')).toBeDefined(); | ||
}); | ||
}); |
34 changes: 34 additions & 0 deletions
34
suite-native/module-trading/src/hooks/__tests__/useTokensSheetControls.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { renderHook, act } from '@suite-native/test-utils'; | ||
|
||
import { useTokensSheetControls } from '../useTokensSheetControls'; | ||
|
||
describe('useTokensSheetControls', () => { | ||
describe('isTokensSheetVisible', () => { | ||
it('should be false by default', () => { | ||
const { result } = renderHook(() => useTokensSheetControls()); | ||
|
||
expect(result.current.isTokensSheetVisible).toBe(false); | ||
}); | ||
|
||
it('should be true after showTokensSheet call', () => { | ||
const { result } = renderHook(() => useTokensSheetControls()); | ||
|
||
act(() => { | ||
result.current.showTokensSheet(); | ||
}); | ||
|
||
expect(result.current.isTokensSheetVisible).toBe(true); | ||
}); | ||
|
||
it('should be false after hideTokensSheet call', () => { | ||
const { result } = renderHook(() => useTokensSheetControls()); | ||
|
||
act(() => { | ||
result.current.showTokensSheet(); | ||
result.current.hideTokensSheet(); | ||
}); | ||
|
||
expect(result.current.isTokensSheetVisible).toBe(false); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.