-
-
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
17 changed files
with
461 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 { SelectAssetButton } from '../general/SelectAssetButton'; | ||
import { AssetsSheet } from '../general/AssetsSheet'; | ||
import { useAssetsSheetControls } from '../../hooks/useAssetsSheetControls'; | ||
|
||
export const AmountCard = () => { | ||
const { | ||
showTokensSheet, | ||
isTokensSheetVisible, | ||
hideTokensSheet, | ||
setSelectedAsset, | ||
selectedAsset, | ||
} = useAssetsSheetControls(); | ||
|
||
return ( | ||
<Card> | ||
<HStack> | ||
<SelectAssetButton onPress={showTokensSheet} selectedAsset={selectedAsset} /> | ||
</HStack> | ||
<AssetsSheet | ||
isVisible={isTokensSheetVisible} | ||
onClose={hideTokensSheet} | ||
onAssetSelect={setSelectedAsset} | ||
/> | ||
</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 AssetsSheet after button click', () => { | ||
const { getByText } = render(<AmountCard />); | ||
|
||
fireEvent.press(getByText('Select coin')); | ||
|
||
expect(getByText('Tokens')).toBeDefined(); | ||
}); | ||
|
||
it('should display selected network from AssetsSheet', () => { | ||
const { getByText, queryByText } = render(<AmountCard />); | ||
|
||
fireEvent.press(getByText('Select coin')); | ||
fireEvent.press(getByText('BTC')); | ||
|
||
expect(queryByText('Tokens')).toBeNull(); | ||
expect(getByText('BTC')).toBeDefined(); | ||
}); | ||
}); |
60 changes: 60 additions & 0 deletions
60
suite-native/module-trading/src/components/general/AssetButton.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,60 @@ | ||
import { ReactNode } from 'react'; | ||
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 { Text } from '@suite-native/atoms'; | ||
import { Icon } from '@suite-native/icons'; | ||
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; | ||
import { nativeSpacings } from '@trezor/theme'; | ||
|
||
export type AssetButtonProps = { | ||
icon: ReactNode; | ||
children: ReactNode; | ||
bgBaseColor: string; | ||
caret?: boolean; | ||
onPress: () => void; | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
button: { | ||
height: 36, | ||
padding: nativeSpacings.sp4, // TODO 5? | ||
paddingRight: nativeSpacings.sp12, | ||
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 AssetButton = ({ bgBaseColor, caret, icon, children, onPress }: AssetButtonProps) => { | ||
const { applyStyle } = useNativeStyles(); | ||
|
||
return ( | ||
<LinearGradient | ||
colors={[hexToRgba(bgBaseColor, 0.3), hexToRgba(bgBaseColor, 0.01)]} | ||
style={applyStyle(gradientBackgroundStyle)} | ||
start={{ x: 0, y: 0.5 }} | ||
end={{ x: 1, y: 0.5 }} | ||
> | ||
<AnimatedPressable onPress={onPress} style={styles.button}> | ||
{icon} | ||
<Text color="textSubdued" variant="callout"> | ||
{children} | ||
</Text> | ||
{caret && <Icon name="caretDown" color="textSubdued" size="medium" />} | ||
</AnimatedPressable> | ||
</LinearGradient> | ||
); | ||
}; |
33 changes: 33 additions & 0 deletions
33
suite-native/module-trading/src/components/general/AssetsSheet.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,33 @@ | ||
import { NetworkSymbol } from '@suite-common/wallet-config'; | ||
import { BottomSheet, VStack } from '@suite-native/atoms'; | ||
import { Translation } from '@suite-native/intl'; | ||
|
||
import { PickerCloseButton } from './PickerCloseButton'; | ||
import { PickerHeader } from './PickerHeader'; | ||
import { PopularNetworks } from './PopularNetworks'; | ||
|
||
export type AssetsSheetProps = { | ||
isVisible: boolean; | ||
onClose: () => void; | ||
onAssetSelect: (symbol: NetworkSymbol) => void; | ||
}; | ||
|
||
export const AssetsSheet = ({ isVisible, onClose, onAssetSelect }: AssetsSheetProps) => { | ||
const onAssetSelectCallback = (symbol: NetworkSymbol) => { | ||
onAssetSelect(symbol); | ||
onClose(); | ||
}; | ||
|
||
return ( | ||
<BottomSheet isVisible={isVisible} onClose={onClose} isCloseDisplayed={false}> | ||
<VStack spacing="sp16"> | ||
<PickerHeader title={<Translation id="moduleTrading.networksSheet.title" />} /> | ||
<PopularNetworks | ||
symbols={['btc', 'eth', 'sol', 'base']} | ||
onNetworkSelect={onAssetSelectCallback} | ||
/> | ||
<PickerCloseButton onPress={onClose} /> | ||
</VStack> | ||
</BottomSheet> | ||
); | ||
}; |
29 changes: 29 additions & 0 deletions
29
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,29 @@ | ||
import { useFormatters } from '@suite-common/formatters'; | ||
import { NetworkSymbol } from '@suite-common/wallet-config'; | ||
import { CryptoIcon } from '@suite-native/icons'; | ||
import { useNativeStyles } from '@trezor/styles'; | ||
|
||
import { AssetButton } from './AssetButton'; | ||
|
||
export type AssetButtonProps = { | ||
symbol: NetworkSymbol; | ||
onPress: () => void; | ||
caret?: boolean; | ||
}; | ||
|
||
export const NetworkButton = ({ symbol, onPress, caret }: AssetButtonProps) => { | ||
const { DisplaySymbolFormatter } = useFormatters(); | ||
const { utils } = useNativeStyles(); | ||
const baseSymbolColor = utils.coinsColors[symbol]; | ||
|
||
return ( | ||
<AssetButton | ||
bgBaseColor={baseSymbolColor} | ||
caret={caret} | ||
onPress={onPress} | ||
icon={<CryptoIcon symbol={symbol} size="small" />} | ||
> | ||
<DisplaySymbolFormatter value={symbol} areAmountUnitsEnabled={false} /> | ||
</AssetButton> | ||
); | ||
}; |
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/SelectAssetButton.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 SelectAssetButtonProps = { | ||
onPress: () => void; | ||
selectedAsset: NetworkSymbol | undefined; | ||
}; | ||
|
||
export const SelectAssetButton = ({ onPress, selectedAsset }: SelectAssetButtonProps) => { | ||
const { iconColor } = buttonSchemeToColorsMap.primary; | ||
|
||
if (selectedAsset) { | ||
return <NetworkButton symbol={selectedAsset} 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 { SelectAssetButton } from '../SelectAssetButton'; | ||
|
||
describe('SelectNetworkButton', () => { | ||
it('should render "select coin" when no network is selected', () => { | ||
const { getByText } = render( | ||
<SelectAssetButton onPress={jest.fn()} selectedAsset={undefined} />, | ||
); | ||
|
||
expect(getByText('Select coin')).toBeDefined(); | ||
}); | ||
|
||
it('should render NetworkButton when network is selected', () => { | ||
const { queryByText } = render( | ||
<SelectAssetButton onPress={jest.fn()} selectedAsset="ada" />, | ||
); | ||
|
||
expect(queryByText('Select coin')).toBeNull(); | ||
expect(queryByText('ADA')).toBeDefined(); | ||
}); | ||
}); |
Oops, something went wrong.