Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
interface
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LuckySwap
interface
Commits
485764fe
Unverified
Commit
485764fe
authored
Aug 14, 2023
by
Nate Wienert
Committed by
GitHub
Aug 14, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: improve logic around hidden section of mini-portfolio balances spam tokens (#6988)
parent
51dc10b4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
170 additions
and
32 deletions
+170
-32
token-explore-filter.test.ts
cypress/e2e/token-explore-filter.test.ts
+3
-1
tokens.json
cypress/fixtures/mini-portfolio/tokens.json
+1
-1
index.tsx
src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx
+9
-30
portfolios.ts
src/graphql/data/portfolios.ts
+1
-0
splitHiddenTokens.test.tsx
src/utils/splitHiddenTokens.test.tsx
+117
-0
splitHiddenTokens.tsx
src/utils/splitHiddenTokens.tsx
+39
-0
No files found.
cypress/e2e/token-explore-filter.test.ts
View file @
485764fe
...
@@ -18,7 +18,9 @@ describe('Token explore filter', () => {
...
@@ -18,7 +18,9 @@ describe('Token explore filter', () => {
searchFor
(
'
dao
'
)
searchFor
(
'
dao
'
)
cy
.
get
(
'
@filteredTokens
'
).
then
((
filteredTokens
)
=>
{
cy
.
get
(
'
@filteredTokens
'
).
then
((
filteredTokens
)
=>
{
cy
.
get
(
'
[data-cy="token-name"]
'
).
should
(
'
deep.equal
'
,
filteredTokens
)
cy
.
get
(
'
[data-cy="token-name"]
'
).
then
((
tokens
)
=>
{
cy
.
wrap
(
Array
.
from
(
tokens
)).
should
(
'
deep.equal
'
,
Array
.
from
(
filteredTokens
))
})
})
})
})
})
})
})
cypress/fixtures/mini-portfolio/tokens.json
View file @
485764fe
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx
View file @
485764fe
...
@@ -3,7 +3,7 @@ import { TraceEvent } from 'analytics'
...
@@ -3,7 +3,7 @@ import { TraceEvent } from 'analytics'
import
{
useCachedPortfolioBalancesQuery
}
from
'
components/AccountDrawer/PrefetchBalancesWrapper
'
import
{
useCachedPortfolioBalancesQuery
}
from
'
components/AccountDrawer/PrefetchBalancesWrapper
'
import
Row
from
'
components/Row
'
import
Row
from
'
components/Row
'
import
{
formatDelta
}
from
'
components/Tokens/TokenDetails/PriceChart
'
import
{
formatDelta
}
from
'
components/Tokens/TokenDetails/PriceChart
'
import
{
PortfolioBalancesQuery
}
from
'
graphql/data/__generated__/types-and-hooks
'
import
{
TokenBalance
}
from
'
graphql/data/__generated__/types-and-hooks
'
import
{
getTokenDetailsURL
,
gqlToCurrency
,
logSentryErrorForUnsupportedChain
}
from
'
graphql/data/util
'
import
{
getTokenDetailsURL
,
gqlToCurrency
,
logSentryErrorForUnsupportedChain
}
from
'
graphql/data/util
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
EmptyWalletModule
}
from
'
nft/components/profile/view/EmptyWalletContent
'
import
{
EmptyWalletModule
}
from
'
nft/components/profile/view/EmptyWalletContent
'
...
@@ -12,6 +12,7 @@ import { useNavigate } from 'react-router-dom'
...
@@ -12,6 +12,7 @@ import { useNavigate } from 'react-router-dom'
import
styled
from
'
styled-components
'
import
styled
from
'
styled-components
'
import
{
EllipsisStyle
,
ThemedText
}
from
'
theme
'
import
{
EllipsisStyle
,
ThemedText
}
from
'
theme
'
import
{
formatNumber
,
NumberType
}
from
'
utils/formatNumbers
'
import
{
formatNumber
,
NumberType
}
from
'
utils/formatNumbers
'
import
{
splitHiddenTokens
}
from
'
utils/splitHiddenTokens
'
import
{
useToggleAccountDrawer
}
from
'
../..
'
import
{
useToggleAccountDrawer
}
from
'
../..
'
import
{
PortfolioArrow
}
from
'
../../AuthenticatedHeader
'
import
{
PortfolioArrow
}
from
'
../../AuthenticatedHeader
'
...
@@ -20,12 +21,6 @@ import { ExpandoRow } from '../ExpandoRow'
...
@@ -20,12 +21,6 @@ import { ExpandoRow } from '../ExpandoRow'
import
{
PortfolioLogo
}
from
'
../PortfolioLogo
'
import
{
PortfolioLogo
}
from
'
../PortfolioLogo
'
import
PortfolioRow
,
{
PortfolioSkeleton
,
PortfolioTabWrapper
}
from
'
../PortfolioRow
'
import
PortfolioRow
,
{
PortfolioSkeleton
,
PortfolioTabWrapper
}
from
'
../PortfolioRow
'
const
HIDE_SMALL_USD_BALANCES_THRESHOLD
=
1
function
meetsThreshold
(
tokenBalance
:
TokenBalance
,
hideSmallBalances
:
boolean
)
{
return
!
hideSmallBalances
||
(
tokenBalance
.
denominatedValue
?.
value
??
0
)
>
HIDE_SMALL_USD_BALANCES_THRESHOLD
}
export
default
function
Tokens
({
account
}:
{
account
:
string
})
{
export
default
function
Tokens
({
account
}:
{
account
:
string
})
{
const
toggleWalletDrawer
=
useToggleAccountDrawer
()
const
toggleWalletDrawer
=
useToggleAccountDrawer
()
const
hideSmallBalances
=
useAtomValue
(
hideSmallBalancesAtom
)
const
hideSmallBalances
=
useAtomValue
(
hideSmallBalancesAtom
)
...
@@ -33,27 +28,18 @@ export default function Tokens({ account }: { account: string }) {
...
@@ -33,27 +28,18 @@ export default function Tokens({ account }: { account: string }) {
const
{
data
}
=
useCachedPortfolioBalancesQuery
({
account
})
const
{
data
}
=
useCachedPortfolioBalancesQuery
({
account
})
const
visibleTokens
=
useMemo
(()
=>
{
const
tokenBalances
=
data
?.
portfolios
?.[
0
].
tokenBalances
as
TokenBalance
[]
|
undefined
return
!
hideSmallBalances
?
data
?.
portfolios
?.[
0
].
tokenBalances
??
[]
:
data
?.
portfolios
?.[
0
].
tokenBalances
?.
filter
((
tokenBalance
)
=>
meetsThreshold
(
tokenBalance
,
hideSmallBalances
)
)
??
[]
},
[
data
?.
portfolios
,
hideSmallBalances
])
const
hiddenTokens
=
useMemo
(()
=>
{
const
{
visibleTokens
,
hiddenTokens
}
=
useMemo
(
return
!
hideSmallBalances
()
=>
splitHiddenTokens
(
tokenBalances
??
[],
{
hideSmallBalances
}),
?
[]
[
hideSmallBalances
,
tokenBalances
]
:
data
?.
portfolios
?.[
0
].
tokenBalances
?.
filter
(
)
(
tokenBalance
)
=>
!
meetsThreshold
(
tokenBalance
,
hideSmallBalances
)
)
??
[]
},
[
data
?.
portfolios
,
hideSmallBalances
])
if
(
!
data
)
{
if
(
!
data
)
{
return
<
PortfolioSkeleton
/>
return
<
PortfolioSkeleton
/>
}
}
if
(
data
?.
portfolios
?.[
0
].
tokenBalances
?.
length
===
0
)
{
if
(
tokenBalances
?.
length
===
0
)
{
// TODO: consider launching moonpay here instead of just closing the drawer
// TODO: consider launching moonpay here instead of just closing the drawer
return
<
EmptyWalletModule
type=
"token"
onNavigateClick=
{
toggleWalletDrawer
}
/>
return
<
EmptyWalletModule
type=
"token"
onNavigateClick=
{
toggleWalletDrawer
}
/>
}
}
...
@@ -64,10 +50,7 @@ export default function Tokens({ account }: { account: string }) {
...
@@ -64,10 +50,7 @@ export default function Tokens({ account }: { account: string }) {
<
PortfolioTabWrapper
>
<
PortfolioTabWrapper
>
{
visibleTokens
.
map
(
{
visibleTokens
.
map
(
(
tokenBalance
)
=>
(
tokenBalance
)
=>
tokenBalance
.
token
&&
tokenBalance
.
token
&&
<
TokenRow
key=
{
tokenBalance
.
id
}
{
...
tokenBalance
}
token=
{
tokenBalance
.
token
}
/>
meetsThreshold
(
tokenBalance
,
hideSmallBalances
)
&&
(
<
TokenRow
key=
{
tokenBalance
.
id
}
{
...
tokenBalance
}
token=
{
tokenBalance
.
token
}
/>
)
)
}
)
}
<
ExpandoRow
isExpanded=
{
showHiddenTokens
}
toggle=
{
toggleHiddenTokens
}
numItems=
{
hiddenTokens
.
length
}
>
<
ExpandoRow
isExpanded=
{
showHiddenTokens
}
toggle=
{
toggleHiddenTokens
}
numItems=
{
hiddenTokens
.
length
}
>
{
hiddenTokens
.
map
(
{
hiddenTokens
.
map
(
...
@@ -86,10 +69,6 @@ const TokenNameText = styled(ThemedText.SubHeader)`
...
@@ -86,10 +69,6 @@ const TokenNameText = styled(ThemedText.SubHeader)`
${
EllipsisStyle
}
${
EllipsisStyle
}
`
`
type
TokenBalance
=
NonNullable
<
NonNullable
<
NonNullable
<
PortfolioBalancesQuery
[
'
portfolios
'
]
>
[
number
]
>
[
'
tokenBalances
'
]
>
[
number
]
type
PortfolioToken
=
NonNullable
<
TokenBalance
[
'
token
'
]
>
type
PortfolioToken
=
NonNullable
<
TokenBalance
[
'
token
'
]
>
function
TokenRow
({
token
,
quantity
,
denominatedValue
,
tokenProjectMarket
}:
TokenBalance
&
{
token
:
PortfolioToken
})
{
function
TokenRow
({
token
,
quantity
,
denominatedValue
,
tokenProjectMarket
}:
TokenBalance
&
{
token
:
PortfolioToken
})
{
...
...
src/graphql/data/portfolios.ts
View file @
485764fe
...
@@ -35,6 +35,7 @@ gql`
...
@@ -35,6 +35,7 @@ gql`
tokenProject {
tokenProject {
id
id
logoUrl
logoUrl
isSpam
}
}
}
}
token {
token {
...
...
src/utils/splitHiddenTokens.test.tsx
0 → 100644
View file @
485764fe
import
{
Currency
,
TokenBalance
}
from
'
graphql/data/__generated__/types-and-hooks
'
import
{
splitHiddenTokens
}
from
'
./splitHiddenTokens
'
const
tokens
:
TokenBalance
[]
=
[
// low balance
{
id
:
'
low-balance
'
,
ownerAddress
:
''
,
__typename
:
'
TokenBalance
'
,
denominatedValue
:
{
id
:
''
,
value
:
0.5
,
},
tokenProjectMarket
:
{
id
:
''
,
currency
:
Currency
.
Eth
,
tokenProject
:
{
id
:
''
,
tokens
:
[],
isSpam
:
false
,
},
},
},
// spam
{
id
:
'
spam
'
,
ownerAddress
:
''
,
__typename
:
'
TokenBalance
'
,
denominatedValue
:
{
id
:
''
,
value
:
100
,
},
tokenProjectMarket
:
{
id
:
''
,
currency
:
Currency
.
Eth
,
tokenProject
:
{
id
:
''
,
tokens
:
[],
isSpam
:
true
,
},
},
},
// valid
{
id
:
'
valid
'
,
ownerAddress
:
''
,
__typename
:
'
TokenBalance
'
,
denominatedValue
:
{
id
:
''
,
value
:
100
,
},
tokenProjectMarket
:
{
id
:
''
,
currency
:
Currency
.
Eth
,
tokenProject
:
{
id
:
''
,
tokens
:
[],
isSpam
:
false
,
},
},
},
// empty value
{
id
:
'
undefined-value
'
,
ownerAddress
:
''
,
__typename
:
'
TokenBalance
'
,
denominatedValue
:
{
id
:
''
,
// @ts-ignore this is evidently possible but not represented in our types
value
:
undefined
,
},
tokenProjectMarket
:
{
id
:
''
,
currency
:
Currency
.
Eth
,
tokenProject
:
{
id
:
''
,
tokens
:
[],
isSpam
:
false
,
},
},
},
]
describe
(
'
splitHiddenTokens
'
,
()
=>
{
it
(
'
splits spam tokens into hidden but keeps small balances if hideSmallBalances = false
'
,
()
=>
{
const
{
visibleTokens
,
hiddenTokens
}
=
splitHiddenTokens
(
tokens
,
{
hideSmallBalances
:
false
,
})
expect
(
hiddenTokens
.
length
).
toBe
(
1
)
expect
(
hiddenTokens
[
0
].
id
).
toBe
(
'
spam
'
)
expect
(
visibleTokens
.
length
).
toBe
(
3
)
expect
(
visibleTokens
[
0
].
id
).
toBe
(
'
low-balance
'
)
expect
(
visibleTokens
[
1
].
id
).
toBe
(
'
valid
'
)
})
it
(
'
splits low balance into hidden by default
'
,
()
=>
{
const
{
visibleTokens
,
hiddenTokens
}
=
splitHiddenTokens
(
tokens
)
expect
(
hiddenTokens
.
length
).
toBe
(
2
)
expect
(
hiddenTokens
[
0
].
id
).
toBe
(
'
low-balance
'
)
expect
(
hiddenTokens
[
1
].
id
).
toBe
(
'
spam
'
)
expect
(
visibleTokens
.
length
).
toBe
(
2
)
expect
(
visibleTokens
[
0
].
id
).
toBe
(
'
valid
'
)
})
it
(
'
splits undefined value tokens into visible
'
,
()
=>
{
const
{
visibleTokens
}
=
splitHiddenTokens
(
tokens
)
expect
(
visibleTokens
.
length
).
toBe
(
2
)
expect
(
visibleTokens
[
0
].
id
).
toBe
(
'
valid
'
)
expect
(
visibleTokens
[
1
].
id
).
toBe
(
'
undefined-value
'
)
})
})
src/utils/splitHiddenTokens.tsx
0 → 100644
View file @
485764fe
import
{
TokenBalance
}
from
'
graphql/data/__generated__/types-and-hooks
'
const
HIDE_SMALL_USD_BALANCES_THRESHOLD
=
1
export
function
splitHiddenTokens
(
tokenBalances
:
TokenBalance
[],
options
?:
{
hideSmallBalances
?:
boolean
}
)
{
const
visibleTokens
:
TokenBalance
[]
=
[]
const
hiddenTokens
:
TokenBalance
[]
=
[]
for
(
const
tokenBalance
of
tokenBalances
)
{
const
isValidValue
=
// if undefined we keep visible (see https://linear.app/uniswap/issue/WEB-1940/[mp]-update-how-we-handle-what-goes-in-hidden-token-section-of-mini)
typeof
tokenBalance
.
denominatedValue
?.
value
===
'
undefined
'
||
// if below $1
options
?.
hideSmallBalances
===
false
||
meetsThreshold
(
tokenBalance
)
if
(
isValidValue
&&
// a spam token
!
tokenBalance
.
tokenProjectMarket
?.
tokenProject
?.
isSpam
)
{
visibleTokens
.
push
(
tokenBalance
)
}
else
{
hiddenTokens
.
push
(
tokenBalance
)
}
}
return
{
visibleTokens
,
hiddenTokens
}
}
function
meetsThreshold
(
tokenBalance
:
TokenBalance
)
{
const
value
=
tokenBalance
.
denominatedValue
?.
value
??
0
return
value
>
HIDE_SMALL_USD_BALANCES_THRESHOLD
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment