Skip to content

Commit 8b9a4db

Browse files
CP-12311 - X/P-Chain token details page (#3364)
1 parent a6b14fb commit 8b9a4db

File tree

4 files changed

+136
-147
lines changed

4 files changed

+136
-147
lines changed

packages/core-mobile/app/new/common/components/TokenHeader.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export const TokenHeader = ({
5656
sx={{ lineHeight: 38, flexShrink: 1 }}
5757
numberOfLines={1}>
5858
{token?.balanceDisplayValue ? (
59-
<View sx={{ flexDirection: 'row' }}>
59+
<View sx={{ flexDirection: 'row', alignItems: 'flex-end' }}>
6060
<SubTextNumber
6161
number={token.balanceDisplayValue}
6262
textColor={colors.$textPrimary}
@@ -66,9 +66,12 @@ export const TokenHeader = ({
6666
variant="heading2"
6767
sx={{
6868
fontFamily: 'Aeonik-Medium',
69-
color: colors.$textPrimary
69+
color: colors.$textPrimary,
70+
fontSize: 18,
71+
lineHeight: 18,
72+
marginBottom: 4
7073
}}>
71-
{' ' + token.symbol}
74+
{token.symbol}
7275
</Text>
7376
</View>
7477
) : (

packages/core-mobile/app/new/features/portfolio/assets/components/TokenDetail.tsx

Lines changed: 117 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,10 @@ import {
44
} from '@avalabs/avalanche-module'
55
import { TokenUnit } from '@avalabs/core-utils-sdk'
66
import { PChainBalance, XChainBalances } from '@avalabs/glacier-sdk'
7-
import {
8-
Icons,
9-
SPRING_LINEAR_TRANSITION,
10-
Text,
11-
useTheme,
12-
View
13-
} from '@avalabs/k2-alpine'
7+
import { SPRING_LINEAR_TRANSITION, Text, View } from '@avalabs/k2-alpine'
8+
import { BalanceText } from 'common/components/BalanceText'
149
import { CollapsibleTabs } from 'common/components/CollapsibleTabs'
1510
import { getListItemEnteringAnimation } from 'common/utils/animations'
16-
import { UNKNOWN_AMOUNT } from 'consts/amount'
1711
import React, { FC, useCallback, useMemo } from 'react'
1812
import Animated from 'react-native-reanimated'
1913
import {
@@ -22,9 +16,6 @@ import {
2216
LocalTokenWithBalance
2317
} from 'store/balance'
2418
import { xpChainToken } from 'utils/units/knownTokens'
25-
import { BalanceText } from 'common/components/BalanceText'
26-
import { useFormatCurrency } from 'common/hooks/useFormatCurrency'
27-
import { LogoWithNetwork } from './LogoWithNetwork'
2819

2920
type PChainBalanceType = keyof PChainBalance
3021
type XChainBalanceType = keyof XChainBalances
@@ -34,35 +25,6 @@ interface Props {
3425
}
3526

3627
const TokenDetail: FC<Props> = ({ token }): React.JSX.Element => {
37-
const {
38-
theme: { colors }
39-
} = useTheme()
40-
const { formatCurrency } = useFormatCurrency()
41-
42-
const assetTypes = useMemo(() => {
43-
if (token && isTokenWithBalancePVM(token)) {
44-
return Object.keys(token.balancePerType)
45-
.sort((a, b) => {
46-
return Number(
47-
(token.balancePerType[b as PChainBalanceType] ?? 0n) -
48-
(token.balancePerType[a as PChainBalanceType] ?? 0n)
49-
)
50-
})
51-
.filter(k => (token.balancePerType[k as PChainBalanceType] ?? 0) > 0)
52-
}
53-
if (token && isTokenWithBalanceAVM(token)) {
54-
return Object.keys(token.balancePerType)
55-
.sort((a, b) => {
56-
return Number(
57-
(token.balancePerType[b as XChainBalanceType] ?? 0n) -
58-
(token.balancePerType[a as XChainBalanceType] ?? 0n)
59-
)
60-
})
61-
.filter(k => (token.balancePerType[k as XChainBalanceType] ?? 0) > 0)
62-
}
63-
return []
64-
}, [token])
65-
6628
const getBalanceAndAssetName = useCallback(
6729
(item: string) => {
6830
const balance =
@@ -82,129 +44,153 @@ const TokenDetail: FC<Props> = ({ token }): React.JSX.Element => {
8244
[token]
8345
)
8446

47+
const data = useMemo(() => {
48+
const isPChainToken = token && isTokenWithBalancePVM(token)
49+
const isXChainToken = token && isTokenWithBalanceAVM(token)
50+
51+
if (isPChainToken) {
52+
return [
53+
...Object.keys(token.balancePerType).sort((a, b) => {
54+
return Number(
55+
(token.balancePerType[b as PChainBalanceType] ?? 0n) -
56+
(token.balancePerType[a as PChainBalanceType] ?? 0n)
57+
)
58+
}),
59+
'Total'
60+
]
61+
}
62+
63+
if (isXChainToken) {
64+
return [
65+
...Object.keys(token.balancePerType).sort((a, b) => {
66+
return Number(
67+
(token.balancePerType[b as XChainBalanceType] ?? 0n) -
68+
(token.balancePerType[a as XChainBalanceType] ?? 0n)
69+
)
70+
}),
71+
'Total'
72+
]
73+
}
74+
return []
75+
}, [token])
76+
77+
const totalBalance = useMemo(() => {
78+
return data
79+
.filter(item => item !== 'Total')
80+
.reduce((acc, item) => {
81+
const { balance } = getBalanceAndAssetName(item)
82+
if (balance) {
83+
const balanceUnit = new TokenUnit(
84+
balance,
85+
xpChainToken.maxDecimals,
86+
xpChainToken.symbol
87+
)
88+
return acc.add(balanceUnit)
89+
}
90+
return acc
91+
}, new TokenUnit(0n, xpChainToken.maxDecimals, xpChainToken.symbol))
92+
}, [data, getBalanceAndAssetName])
93+
8594
const renderItem = useCallback(
86-
({ item }: { item: string }): React.JSX.Element => {
95+
({ item, index }: { item: string; index: number }): React.JSX.Element => {
8796
const { balance, assetName } = getBalanceAndAssetName(item)
8897

8998
const balanceInAvax = balance
9099
? new TokenUnit(balance, xpChainToken.maxDecimals, xpChainToken.symbol)
91100
: undefined
101+
102+
const formattedBalanceInAvax =
103+
balanceInAvax?.toDisplay({
104+
fixedDp: 2,
105+
asNumber: true
106+
}) ?? 0
107+
92108
const formattedBalance =
93-
balanceInAvax && token?.priceInCurrency
94-
? formatCurrency({
95-
amount: balanceInAvax
96-
.mul(token.priceInCurrency)
97-
.toDisplay({ fixedDp: 2, asNumber: true })
98-
})
99-
: UNKNOWN_AMOUNT
109+
totalBalance?.toDisplay({
110+
fixedDp: 2,
111+
asNumber: true
112+
}) ?? 0
113+
114+
const title = item === 'Total' ? 'Total balance' : assetName
115+
const value = item === 'Total' ? formattedBalance : formattedBalanceInAvax
116+
const isFirst = index === 0
117+
const isLast = index === data.length - 1
100118

101-
const isAvailableBalanceType =
102-
item === 'unlockedUnstaked' || item === 'unlocked'
119+
const containerSx = {
120+
paddingHorizontal: 16,
121+
backgroundColor: '$surfaceSecondary',
122+
...(isFirst && { borderTopLeftRadius: 16, borderTopRightRadius: 16 }),
123+
...(isLast && {
124+
borderBottomLeftRadius: 16,
125+
borderBottomRightRadius: 16
126+
})
127+
}
103128

104129
return (
105-
<View
106-
sx={{
107-
borderRadius: 18,
108-
paddingLeft: 16,
109-
paddingRight: 12,
110-
paddingVertical: 12,
111-
flexDirection: 'row',
112-
alignItems: 'center',
113-
backgroundColor: '$surfaceSecondary',
114-
marginBottom: 12
115-
}}>
116-
{token && isAvailableBalanceType ? (
117-
<LogoWithNetwork
118-
token={token}
119-
outerBorderColor={colors.$surfaceSecondary}
120-
/>
121-
) : (
122-
<View
123-
sx={{
124-
width: 36,
125-
height: 36,
126-
borderRadius: 18,
127-
justifyContent: 'center',
128-
alignItems: 'center',
129-
overflow: 'hidden',
130-
backgroundColor: '$borderPrimary',
131-
borderColor: '$borderPrimary'
132-
}}>
133-
<Icons.Custom.Psychiatry
134-
width={24}
135-
height={24}
136-
color={colors.$textPrimary}
137-
/>
138-
</View>
139-
)}
130+
<View sx={containerSx}>
140131
<View
141132
sx={{
142-
flexGrow: 1,
143-
marginHorizontal: 12,
133+
borderBottomWidth: isLast ? 0 : 1,
134+
borderBottomColor: '$borderPrimary',
144135
flexDirection: 'row',
145-
justifyContent: 'space-between'
136+
justifyContent: 'space-between',
137+
alignItems: 'center',
138+
height: 48
146139
}}>
147-
<View
140+
<Text variant="subtitle2" numberOfLines={1} sx={{ fontSize: 16 }}>
141+
{title}
142+
</Text>
143+
<BalanceText
144+
variant="subtitle2"
145+
numberOfLines={1}
148146
sx={{
149-
flexShrink: 1
147+
color: '$textSecondary',
148+
fontSize: 16
150149
}}>
151-
<Text variant="buttonMedium" numberOfLines={1} sx={{ flex: 1 }}>
152-
{assetName}
153-
</Text>
154-
<BalanceText
155-
variant="body2"
156-
sx={{ lineHeight: 16, flex: 1 }}
157-
ellipsizeMode="tail"
158-
isCurrency={false}
159-
maskType="covered"
160-
numberOfLines={1}>
161-
{balanceInAvax?.toDisplay()} {xpChainToken.symbol}
162-
</BalanceText>
163-
</View>
164-
<View sx={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
165-
<BalanceText
166-
variant="buttonMedium"
167-
numberOfLines={1}
168-
sx={{ lineHeight: 18, marginBottom: 1 }}>
169-
{formattedBalance}
170-
</BalanceText>
171-
</View>
150+
{value} {xpChainToken.symbol}
151+
</BalanceText>
172152
</View>
173153
</View>
174154
)
175155
},
176-
[
177-
colors.$textPrimary,
178-
colors.$surfaceSecondary,
179-
getBalanceAndAssetName,
180-
token,
181-
formatCurrency
182-
]
156+
[getBalanceAndAssetName, totalBalance, data.length]
183157
)
184158

185-
const renderHeader = (): JSX.Element => {
186-
return (
187-
<Text variant="heading3" sx={{ marginBottom: 12 }}>
188-
Token breakdown
189-
</Text>
190-
)
191-
}
159+
const renderHeader = useCallback((): JSX.Element => {
160+
return <></>
161+
162+
// TODO: Add after ledger is implemented
163+
// return (
164+
// <View sx={{ marginTop: 8 }}>
165+
// <GroupList
166+
// data={[
167+
// {
168+
// title:
169+
// 'UTXOs across multiple addresses. View all of your balances and UTXOs',
170+
// leftIcon: <Icons.Action.Info color={colors.$textPrimary} />,
171+
// onPress: () => {
172+
// // console.log('info')
173+
// }
174+
// }
175+
// ]}
176+
// />
177+
// </View>
178+
// )
179+
}, [])
192180

193181
return (
194182
<Animated.View
195183
entering={getListItemEnteringAnimation(5)}
196184
layout={SPRING_LINEAR_TRANSITION}>
197185
<CollapsibleTabs.FlatList
198-
style={{
199-
paddingTop: 4
200-
}}
201186
contentContainerStyle={{
202187
paddingHorizontal: 16,
203-
paddingBottom: 16
188+
paddingBottom: 16,
189+
paddingTop: 12
204190
}}
205-
data={assetTypes}
191+
data={data}
192+
ListHeaderComponent={renderHeader}
206193
renderItem={renderItem}
207-
ListHeaderComponent={renderHeader()}
208194
showsVerticalScrollIndicator={false}
209195
keyExtractor={item => item}
210196
/>

packages/core-mobile/app/new/features/portfolio/assets/screens/TokenDetailScreen.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ export const TokenDetailScreen = (): React.JSX.Element => {
437437
return isXpToken
438438
? [
439439
{
440-
tabName: TokenDetailTab.Tokens,
440+
tabName: TokenDetailTab.Assets,
441441
component: <TokenDetail token={token} />
442442
},
443443
activityTab
@@ -471,11 +471,11 @@ export const TokenDetailScreen = (): React.JSX.Element => {
471471
}
472472

473473
export enum TokenDetailTab {
474-
Tokens = 'Tokens',
474+
Assets = 'Assets',
475475
Activity = 'Activity'
476476
}
477477

478478
const SEGMENT_ITEMS = [
479-
{ title: TokenDetailTab.Tokens },
479+
{ title: TokenDetailTab.Assets },
480480
{ title: TokenDetailTab.Activity }
481481
]

packages/core-mobile/app/store/balance/types.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ export type LocalTokenWithBalance = TokenWithBalance & {
99
}
1010

1111
export const assetPDisplayNames: Record<string, string> = {
12-
lockedStaked: 'Locked Staked',
13-
lockedStakeable: 'Locked Stakeable',
14-
lockedPlatform: 'Locked Platform',
15-
atomicMemoryLocked: 'Atomic Memory Locked',
16-
atomicMemoryUnlocked: 'Atomic Memory Unlocked',
17-
unlockedUnstaked: 'Unlocked Unstaked',
18-
unlockedStaked: 'Unlocked Staked',
19-
pendingStaked: 'Pending Staked'
12+
lockedStaked: 'Locked staked',
13+
lockedStakeable: 'Locked stakeable',
14+
lockedPlatform: 'Locked platform',
15+
atomicMemoryLocked: 'Atomic memory locked',
16+
atomicMemoryUnlocked: 'Atomic memory unlocked',
17+
unlockedUnstaked: 'Unlocked unstaked',
18+
unlockedStaked: 'Unlocked staked',
19+
pendingStaked: 'Pending staked'
2020
}
2121

2222
export const assetXDisplayNames: Record<string, string> = {
2323
locked: 'Locked',
2424
unlocked: 'Unlocked',
25-
atomicMemoryLocked: 'Atomic Memory Locked',
26-
atomicMemoryUnlocked: 'Atomic Memory Unlocked'
25+
atomicMemoryLocked: 'Atomic memory locked',
26+
atomicMemoryUnlocked: 'Atomic memory unlocked'
2727
}
2828

2929
// Assets

0 commit comments

Comments
 (0)