-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: built generic TokenListItem component
- Loading branch information
Showing
5 changed files
with
393 additions
and
0 deletions.
There are no files selected for viewing
22 changes: 22 additions & 0 deletions
22
app/components/UI/Stake/components/TokenListItem/TokenListItem.styles.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 { StyleSheet } from 'react-native'; | ||
|
||
const styleSheet = () => | ||
StyleSheet.create({ | ||
container: { | ||
padding: 16, | ||
flexDirection: 'row', | ||
justifyContent: 'space-between', | ||
alignItems: 'center', | ||
}, | ||
left: { | ||
flexDirection: 'row', | ||
alignItems: 'center', | ||
gap: 16, | ||
}, | ||
right: { | ||
alignItems: 'flex-end', | ||
justifyContent: 'center', | ||
}, | ||
}); | ||
|
||
export default styleSheet; |
79 changes: 79 additions & 0 deletions
79
app/components/UI/Stake/components/TokenListItem/TokenListItem.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,79 @@ | ||
import React from 'react'; | ||
import { TokenListItemProps } from './TokenListItem.types'; | ||
import TokenListItem from '.'; | ||
import { strings } from '../../../../../../locales/i18n'; | ||
import renderWithProvider from '../../../../../util/test/renderWithProvider'; | ||
import { useSelector } from 'react-redux'; | ||
import { selectIsIpfsGatewayEnabled } from '../../../../../selectors/preferencesController'; | ||
import { | ||
TextColor, | ||
TextVariant, | ||
} from '../../../../../component-library/components/Texts/Text'; | ||
|
||
jest.mock('react-redux', () => ({ | ||
...jest.requireActual('react-redux'), | ||
useSelector: jest.fn(), | ||
})); | ||
|
||
describe('TokenListItem', () => { | ||
beforeEach(() => { | ||
(useSelector as jest.Mock).mockImplementation((selector) => { | ||
if (selector === selectIsIpfsGatewayEnabled) return true; | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
(useSelector as jest.Mock).mockClear(); | ||
}); | ||
|
||
const baseProps: TokenListItemProps = { | ||
token: { | ||
chainId: '0x1', | ||
image: | ||
'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png', | ||
name: 'Dai Stablecoin', | ||
symbol: 'DAI', | ||
}, | ||
primaryText: { | ||
value: `3.0% ${strings('stake.apr')}`, | ||
variant: TextVariant.BodyMDBold, | ||
color: TextColor.Success, | ||
}, | ||
onPress: jest.fn(), | ||
}; | ||
|
||
const secondaryText = { | ||
value: '10,100.00 USDC', | ||
variant: TextVariant.BodySMBold, | ||
color: TextColor.Alternative, | ||
}; | ||
|
||
it('render matches snapshot', () => { | ||
const props: TokenListItemProps = { | ||
...baseProps, | ||
secondaryText, | ||
}; | ||
|
||
const { toJSON } = renderWithProvider(<TokenListItem {...props} />); | ||
|
||
expect(toJSON()).toMatchSnapshot(); | ||
}); | ||
|
||
it('renders primary text and secondary text', () => { | ||
const props: TokenListItemProps = { | ||
...baseProps, | ||
secondaryText, | ||
}; | ||
|
||
const { getByText } = renderWithProvider(<TokenListItem {...props} />); | ||
|
||
expect(getByText('Dai Stablecoin')).toBeDefined(); | ||
expect(getByText('10,100.00 USDC')).toBeDefined(); | ||
}); | ||
|
||
it('renders only primary text', () => { | ||
const { getByText } = renderWithProvider(<TokenListItem {...baseProps} />); | ||
|
||
expect(getByText('Dai Stablecoin')).toBeDefined(); | ||
}); | ||
}); |
19 changes: 19 additions & 0 deletions
19
app/components/UI/Stake/components/TokenListItem/TokenListItem.types.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,19 @@ | ||
import { TextProps } from '../../../../../component-library/components/Texts/Text/Text.types'; | ||
|
||
interface Text extends Omit<TextProps, 'children'> { | ||
value: string; | ||
} | ||
|
||
export interface TokenListAsset { | ||
name: string; | ||
symbol: string; | ||
chainId: string; | ||
image: string; | ||
} | ||
|
||
export interface TokenListItemProps { | ||
token: TokenListAsset; | ||
primaryText: Text; | ||
secondaryText?: Text; | ||
onPress: (token: TokenListAsset) => void; | ||
} |
200 changes: 200 additions & 0 deletions
200
app/components/UI/Stake/components/TokenListItem/__snapshots__/TokenListItem.test.tsx.snap
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,200 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`TokenListItem render matches snapshot 1`] = ` | ||
<TouchableOpacity | ||
onPress={[Function]} | ||
style={ | ||
{ | ||
"alignItems": "center", | ||
"flexDirection": "row", | ||
"justifyContent": "space-between", | ||
"padding": 16, | ||
} | ||
} | ||
> | ||
<View | ||
style={ | ||
{ | ||
"alignItems": "center", | ||
"flexDirection": "row", | ||
"gap": 16, | ||
} | ||
} | ||
> | ||
<View | ||
onLayout={[Function]} | ||
style={ | ||
{ | ||
"alignSelf": "flex-start", | ||
"position": "relative", | ||
} | ||
} | ||
testID="badge-wrapper-badge" | ||
> | ||
<View> | ||
<View | ||
style={ | ||
{ | ||
"backgroundColor": "#ffffff", | ||
"borderRadius": 16, | ||
"height": 32, | ||
"overflow": "hidden", | ||
"width": 32, | ||
} | ||
} | ||
> | ||
<Image | ||
onError={[Function]} | ||
resizeMode="contain" | ||
source={ | ||
{ | ||
"uri": "https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png", | ||
} | ||
} | ||
style={ | ||
{ | ||
"flex": 1, | ||
"height": undefined, | ||
"width": undefined, | ||
} | ||
} | ||
testID="token-avatar-image" | ||
/> | ||
</View> | ||
</View> | ||
<View | ||
style={ | ||
{ | ||
"alignItems": "center", | ||
"aspectRatio": 1, | ||
"height": 0, | ||
"justifyContent": "center", | ||
"position": "absolute", | ||
"right": 0, | ||
"top": 0, | ||
"transform": [ | ||
{ | ||
"translateX": 0, | ||
}, | ||
{ | ||
"translateY": -0, | ||
}, | ||
], | ||
} | ||
} | ||
> | ||
<View | ||
onLayout={[Function]} | ||
style={ | ||
{ | ||
"alignItems": "center", | ||
"aspectRatio": 1, | ||
"height": "50%", | ||
"justifyContent": "center", | ||
"maxHeight": 24, | ||
"minHeight": 8, | ||
"opacity": 0, | ||
} | ||
} | ||
testID="badgenetwork" | ||
> | ||
<View | ||
style={ | ||
{ | ||
"alignItems": "center", | ||
"backgroundColor": "#ffffff", | ||
"borderColor": "#ffffff", | ||
"borderRadius": 16, | ||
"borderWidth": 2, | ||
"height": 32, | ||
"justifyContent": "center", | ||
"overflow": "hidden", | ||
"shadowColor": "#0000001a", | ||
"shadowOffset": { | ||
"height": 2, | ||
"width": 0, | ||
}, | ||
"shadowOpacity": 1, | ||
"shadowRadius": 4, | ||
"transform": [ | ||
{ | ||
"scale": 1, | ||
}, | ||
], | ||
"width": 32, | ||
} | ||
} | ||
> | ||
<Image | ||
onError={[Function]} | ||
resizeMode="contain" | ||
source={1} | ||
style={ | ||
{ | ||
"height": 32, | ||
"width": 32, | ||
} | ||
} | ||
testID="network-avatar-image" | ||
/> | ||
</View> | ||
</View> | ||
</View> | ||
</View> | ||
<Text | ||
accessibilityRole="text" | ||
style={ | ||
{ | ||
"color": "#141618", | ||
"fontFamily": "EuclidCircularB-Medium", | ||
"fontSize": 14, | ||
"fontWeight": "500", | ||
"letterSpacing": 0, | ||
"lineHeight": 22, | ||
} | ||
} | ||
> | ||
Dai Stablecoin | ||
</Text> | ||
</View> | ||
<View | ||
style={ | ||
{ | ||
"alignItems": "flex-end", | ||
"justifyContent": "center", | ||
} | ||
} | ||
> | ||
<Text | ||
accessibilityRole="text" | ||
style={ | ||
{ | ||
"color": "#1c8234", | ||
"fontFamily": "EuclidCircularB-Bold", | ||
"fontSize": 14, | ||
"fontWeight": "700", | ||
"letterSpacing": 0, | ||
"lineHeight": 22, | ||
} | ||
} | ||
> | ||
3.0% APR | ||
</Text> | ||
<Text | ||
accessibilityRole="text" | ||
style={ | ||
{ | ||
"color": "#6a737d", | ||
"fontFamily": "EuclidCircularB-Bold", | ||
"fontSize": 12, | ||
"fontWeight": "700", | ||
"letterSpacing": 0, | ||
"lineHeight": 20, | ||
} | ||
} | ||
> | ||
10,100.00 USDC | ||
</Text> | ||
</View> | ||
</TouchableOpacity> | ||
`; |
73 changes: 73 additions & 0 deletions
73
app/components/UI/Stake/components/TokenListItem/index.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,73 @@ | ||
import React from 'react'; | ||
import { TouchableOpacity, View } from 'react-native'; | ||
import { useSelector } from 'react-redux'; | ||
import { AvatarSize } from '../../../../../component-library/components/Avatars/Avatar'; | ||
import AvatarToken from '../../../../../component-library/components/Avatars/Avatar/variants/AvatarToken'; | ||
import Badge, { | ||
BadgeVariant, | ||
} from '../../../../../component-library/components/Badges/Badge'; | ||
import BadgeWrapper from '../../../../../component-library/components/Badges/BadgeWrapper'; | ||
import Text, { | ||
TextColor, | ||
TextVariant, | ||
} from '../../../../../component-library/components/Texts/Text'; | ||
import { selectNetworkName } from '../../../../../selectors/networkInfos'; | ||
import { useStyles } from '../../../../hooks/useStyles'; | ||
import { TokenListItemProps } from './TokenListItem.types'; | ||
import { getNetworkImageSource } from '../../../../../util/networks'; | ||
import styleSheet from './TokenListItem.styles'; | ||
|
||
const TokenListItem = ({ | ||
token, | ||
primaryText, | ||
secondaryText, | ||
onPress, | ||
}: TokenListItemProps) => { | ||
const { styles } = useStyles(styleSheet, {}); | ||
|
||
const networkName = useSelector(selectNetworkName); | ||
|
||
return ( | ||
<TouchableOpacity style={styles.container} onPress={() => onPress(token)}> | ||
<View style={styles.left}> | ||
<BadgeWrapper | ||
badgeElement={ | ||
<Badge | ||
variant={BadgeVariant.Network} | ||
name={networkName} | ||
// @ts-expect-error The utils/network file is still JS and this function expects a networkType, and should be optional | ||
imageSource={getNetworkImageSource({ chainId: token.chainId })} | ||
/> | ||
} | ||
> | ||
<AvatarToken | ||
name={token.symbol} | ||
imageSource={{ uri: token.image }} | ||
size={AvatarSize.Md} | ||
/> | ||
</BadgeWrapper> | ||
<Text variant={TextVariant.BodyMDMedium}>{token.name}</Text> | ||
</View> | ||
<View style={styles.right}> | ||
{primaryText.value && ( | ||
<Text | ||
variant={primaryText?.variant ?? TextVariant.BodyMDMedium} | ||
color={primaryText?.color} | ||
> | ||
{primaryText.value} | ||
</Text> | ||
)} | ||
{secondaryText?.value && ( | ||
<Text | ||
variant={secondaryText?.variant ?? TextVariant.BodySMMedium} | ||
color={secondaryText?.color ?? TextColor.Alternative} | ||
> | ||
{secondaryText.value} | ||
</Text> | ||
)} | ||
</View> | ||
</TouchableOpacity> | ||
); | ||
}; | ||
|
||
export default TokenListItem; |