1
- import { Button , Card , Paragraph , Spinner , Theme , XStack , YStack } from '@my/ui'
1
+ import {
2
+ Card ,
3
+ type CardProps ,
4
+ H1 ,
5
+ Paragraph ,
6
+ Spinner ,
7
+ Theme ,
8
+ useMedia ,
9
+ XStack ,
10
+ type XStackProps ,
11
+ } from '@my/ui'
2
12
import formatAmount from 'app/utils/formatAmount'
3
13
4
14
import { ChevronLeft , ChevronRight } from '@tamagui/lucide-icons'
5
15
6
16
import { useIsPriceHidden } from './utils/useIsPriceHidden'
7
17
8
18
import { useSendAccountBalances } from 'app/utils/useSendAccountBalances'
9
- import { investmentCoins } from 'app/data/coins'
19
+ import { type CoinWithBalance , investmentCoins } from 'app/data/coins'
10
20
11
21
import { useRootScreenParams } from 'app/routers/params'
12
22
import { useMultipleTokensMarketData } from 'app/utils/coin-gecko'
13
23
import { useMemo } from 'react'
14
- import { IconError } from 'app/components/icons'
24
+ import { IconCoin , IconError } from 'app/components/icons'
15
25
import { useCoins } from 'app/provider/coins'
26
+ import { investmentCoins as investmentCoinsList } from 'app/data/coins'
16
27
17
- export const InvestmentsBalanceCard = ( ) => {
28
+ export const InvestmentsBalanceCard = ( props : CardProps ) => {
29
+ const media = useMedia ( )
18
30
const [ queryParams , setParams ] = useRootScreenParams ( )
19
31
const isInvestmentCoin = investmentCoins . some (
20
- ( coin ) => coin . token . toLowerCase ( ) === queryParams . token
32
+ ( coin ) => coin . token . toLowerCase ( ) === queryParams . token ?. toLowerCase ( )
21
33
)
22
34
const isInvestmentsScreen = queryParams . token === 'investments'
23
35
@@ -39,62 +51,107 @@ export const InvestmentsBalanceCard = () => {
39
51
const formattedBalance = formatAmount ( dollarTotal , 9 , 0 )
40
52
41
53
return (
42
- < Card py = "$5" px = "$4" w = { '100%' } jc = "space-between" onPress = { toggleSubScreen } >
43
- < YStack jc = { 'center' } gap = { '$5' } w = { '100%' } >
44
- < YStack w = { '100%' } gap = { '$2.5' } jc = "space-between" >
45
- < XStack ai = { 'center' } jc = { 'space-between' } gap = "$2.5" width = { '100%' } >
46
- < Paragraph fontSize = { '$7' } fontWeight = "400" >
47
- Invest
48
- </ Paragraph >
49
- < Button
50
- chromeless
51
- backgroundColor = "transparent"
52
- hoverStyle = { { backgroundColor : 'transparent' } }
53
- pressStyle = { {
54
- backgroundColor : 'transparent' ,
55
- borderColor : 'transparent' ,
56
- } }
57
- focusStyle = { { backgroundColor : 'transparent' } }
58
- p = { 0 }
59
- height = { 'auto' }
60
- >
61
- < Button . Icon >
62
- { isInvestmentCoin || isInvestmentsScreen ? (
63
- < ChevronLeft
64
- size = { '$1.5' }
65
- color = { '$lightGrayTextField' }
66
- $theme-light = { { color : '$darkGrayTextField' } }
67
- $lg = { { display : 'none' } }
68
- />
69
- ) : (
70
- < ChevronRight
71
- size = { '$1.5' }
72
- color = { '$primary' }
73
- $theme-light = { { color : '$color12' } }
74
- />
75
- ) }
76
- </ Button . Icon >
77
- </ Button >
78
- </ XStack >
79
- </ YStack >
80
- < Paragraph fontSize = { '$10' } fontWeight = { '600' } color = { '$color12' } >
81
- { ( ( ) => {
82
- switch ( true ) {
83
- case isPriceHidden :
84
- return '///////'
85
- case isLoading || ! dollarBalances :
86
- return < Spinner size = { 'large' } />
87
- default :
88
- return `$${ formattedBalance } `
89
- }
90
- } ) ( ) }
91
- </ Paragraph >
92
- < InvestmentsAggregate />
93
- </ YStack >
54
+ < Card
55
+ elevate
56
+ hoverStyle = { { scale : 0.925 } }
57
+ pressStyle = { { scale : 0.875 } }
58
+ animation = "bouncy"
59
+ onPress = { toggleSubScreen }
60
+ size = { '$5' }
61
+ br = "$7"
62
+ w = "100%"
63
+ { ...props }
64
+ >
65
+ < Card . Header padded >
66
+ < XStack ai = { 'center' } jc = { 'space-between' } gap = "$2.5" width = { '100%' } >
67
+ < Paragraph fontSize = { '$7' } fontWeight = "400" >
68
+ Invest
69
+ </ Paragraph >
70
+ { isInvestmentCoin || isInvestmentsScreen ? (
71
+ < ChevronLeft
72
+ size = { '$1.5' }
73
+ color = { '$primary' }
74
+ $theme-light = { { color : '$color12' } }
75
+ $lg = { { display : 'none' } }
76
+ />
77
+ ) : (
78
+ < ChevronRight
79
+ size = { '$1.5' }
80
+ color = { '$lightGrayTextField' }
81
+ $theme-light = { { color : '$darkGrayTextField' } }
82
+ />
83
+ ) }
84
+ </ XStack >
85
+ </ Card . Header >
86
+ < Card . Footer padded fd = "column" gap = "$2" >
87
+ { isInvestmentsScreen && ! media . gtLg ? (
88
+ < >
89
+ < H1 color = { '$color12' } >
90
+ { ( ( ) => {
91
+ switch ( true ) {
92
+ case isPriceHidden :
93
+ return '///////'
94
+ case isLoading || ! dollarBalances :
95
+ return < Spinner size = { 'large' } color = { '$color12' } />
96
+ default :
97
+ return `$${ formattedBalance } `
98
+ }
99
+ } ) ( ) }
100
+ </ H1 >
101
+ < InvestmentsAggregate />
102
+ </ >
103
+ ) : (
104
+ < InvestmentsPreview />
105
+ ) }
106
+ </ Card . Footer >
94
107
</ Card >
95
108
)
96
109
}
97
110
111
+ function InvestmentsPreview ( ) {
112
+ const { investmentCoins, isLoading } = useCoins ( )
113
+
114
+ if ( isLoading ) return < Spinner size = "small" />
115
+
116
+ const existingSymbols = new Set ( investmentCoins . map ( ( coin ) => coin . symbol ) )
117
+ const coins = [
118
+ ...investmentCoins ,
119
+ ...investmentCoinsList
120
+ . filter ( ( coin ) => ! existingSymbols . has ( coin . symbol ) )
121
+ . map ( ( coin ) => ( { ...coin , balance : 0n } ) ) ,
122
+ ]
123
+
124
+ const sortedByBalance = coins . toSorted ( ( a , b ) =>
125
+ ( b ?. balance ?? 0n ) > ( a ?. balance ?? 0n ) ? 1 : - 1
126
+ )
127
+ return (
128
+ < XStack ai = "center" jc = "space-between" >
129
+ < OverlappingCoinIcons coins = { sortedByBalance } />
130
+ < Card circular ai = "center" jc = "center" bc = "$color0" w = { '$3.5' } h = "$3.5" mih = { 0 } miw = { 0 } >
131
+ < Paragraph fontSize = { '$4' } fontWeight = "500" >
132
+ { `+${ investmentCoinsList . length - 3 } ` }
133
+ </ Paragraph >
134
+ </ Card >
135
+ </ XStack >
136
+ )
137
+ }
138
+
139
+ function OverlappingCoinIcons ( {
140
+ coins,
141
+ length = 3 ,
142
+ ...props
143
+ } : { coins : CoinWithBalance [ ] ; length ?: number } & XStackProps ) {
144
+ return (
145
+ < XStack ai = "center" { ...props } >
146
+ { coins . slice ( 0 , length ) . map ( ( { symbol } ) => (
147
+ < Card key = { symbol } circular mr = { '$-5' } bc = "transparent" ai = "center" jc = "center" >
148
+ < IconCoin size = { '$3' } symbol = { symbol } />
149
+ </ Card >
150
+ ) ) }
151
+ </ XStack >
152
+ )
153
+ }
154
+
98
155
function InvestmentsAggregate ( ) {
99
156
const tokenIds = useCoins ( )
100
157
. investmentCoins . filter ( ( c ) => c ?. balance && c . balance > 0n )
0 commit comments