Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
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
vicotor
frontend
Commits
52bcc45d
Commit
52bcc45d
authored
Dec 06, 2022
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sort ERC-20 tokens
parent
25ddae54
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
105 additions
and
64 deletions
+105
-64
TokenItem.tsx
ui/address/details/TokenItem.tsx
+6
-7
Tokens.tsx
ui/address/details/Tokens.tsx
+18
-46
TokensButton.tsx
ui/address/details/TokensButton.tsx
+5
-11
utils.ts
ui/address/details/utils.ts
+76
-0
No files found.
ui/address/details/TokenItem.tsx
View file @
52bcc45d
...
...
@@ -2,17 +2,16 @@ import { Flex, Text, useColorModeValue } from '@chakra-ui/react';
import
BigNumber
from
'
bignumber.js
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
HashStringShorten
from
'
ui/shared/HashStringShorten
'
;
import
TokenLogo
from
'
ui/shared/TokenLogo
'
;
import
type
{
EnhancedData
}
from
'
./utils
'
;
interface
Props
{
data
:
AddressTokenBalance
;
usd
?:
string
;
data
:
EnhancedData
;
}
const
TokenItem
=
({
data
,
usd
}:
Props
)
=>
{
const
TokenItem
=
({
data
}:
Props
)
=>
{
const
secondRow
=
(()
=>
{
switch
(
data
.
token
.
type
)
{
...
...
@@ -20,7 +19,7 @@ const TokenItem = ({ data, usd }: Props) => {
const
tokenDecimals
=
Number
(
data
.
token
.
decimals
)
||
18
;
return
(
<>
<
Text
>
{
BigNumber
(
data
.
value
).
dividedBy
(
10
**
tokenDecimals
).
dp
(
2
).
toFormat
(
)
}
{
data
.
token
.
symbol
}
</
Text
>
<
Text
>
{
BigNumber
(
data
.
value
).
dividedBy
(
10
**
tokenDecimals
).
toFormat
(
2
)
}
{
data
.
token
.
symbol
}
</
Text
>
{
data
.
token
.
exchange_rate
&&
<
Text
>
@
{
data
.
token
.
exchange_rate
}
</
Text
>
}
</>
);
...
...
@@ -57,7 +56,7 @@ const TokenItem = ({ data, usd }: Props) => {
<
Flex
alignItems=
"center"
w=
"100%"
>
<
TokenLogo
hash=
{
data
.
token
.
address
}
name=
{
data
.
token
.
name
}
boxSize=
{
6
}
/>
<
Text
fontWeight=
{
700
}
ml=
{
2
}
>
{
data
.
token
.
name
||
<
HashStringShorten
hash=
{
data
.
token
.
address
}
/>
}
</
Text
>
{
usd
&&
<
Text
fontWeight=
{
700
}
ml=
"auto"
>
$
{
usd
}
</
Text
>
}
{
data
.
usd
&&
<
Text
fontWeight=
{
700
}
ml=
"auto"
>
$
{
data
.
usd
.
toFormat
(
2
)
}
</
Text
>
}
</
Flex
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
w=
"100%"
>
{
secondRow
}
...
...
ui/address/details/Tokens.tsx
View file @
52bcc45d
...
...
@@ -18,51 +18,17 @@ import searchIcon from 'icons/search.svg';
import
TokenItem
from
'
./TokenItem
'
;
import
TokensButton
from
'
./TokensButton
'
;
type
Sort
=
'
desc
'
|
'
asc
'
;
const
SORTABLE_TOKENS
:
Array
<
TokenType
>
=
[
'
ERC-20
'
,
'
ERC-1155
'
];
const
TOKEN_GROUPS_ORDER
:
Array
<
TokenType
>
=
[
'
ERC-20
'
,
'
ERC-721
'
,
'
ERC-1155
'
];
type
TokenGroup
=
[
string
,
Array
<
AddressTokenBalance
>
];
const
sortTokenGroups
=
(
groupA
:
TokenGroup
,
groupB
:
TokenGroup
)
=>
{
return
TOKEN_GROUPS_ORDER
.
indexOf
(
groupA
[
0
]
as
TokenType
)
>
TOKEN_GROUPS_ORDER
.
indexOf
(
groupB
[
0
]
as
TokenType
)
?
1
:
-
1
;
};
const
sortErc1155Tokens
=
(
sort
:
'
desc
'
|
'
asc
'
)
=>
(
dataA
:
AddressTokenBalance
,
dataB
:
AddressTokenBalance
)
=>
{
if
(
dataA
.
value
===
dataB
.
value
)
{
return
0
;
}
if
(
sort
===
'
desc
'
)
{
return
Number
(
dataA
.
value
)
>
Number
(
dataB
.
value
)
?
-
1
:
1
;
}
return
Number
(
dataA
.
value
)
>
Number
(
dataB
.
value
)
?
1
:
-
1
;
};
const
sortErc20Tokens
=
()
=>
()
=>
0
;
const
sortErc721Tokens
=
()
=>
()
=>
0
;
const
sortingFns
=
{
'
ERC-20
'
:
sortErc20Tokens
,
'
ERC-721
'
:
sortErc721Tokens
,
'
ERC-1155
'
:
sortErc1155Tokens
,
};
const
filterTokens
=
(
searchTerm
:
string
)
=>
({
token
}:
AddressTokenBalance
)
=>
{
if
(
!
token
.
name
)
{
return
!
searchTerm
?
true
:
token
.
address
.
toLowerCase
().
includes
(
searchTerm
);
}
return
token
.
name
?.
toLowerCase
().
includes
(
searchTerm
);
};
import
type
{
Sort
}
from
'
./utils
'
;
import
{
SORTABLE_TOKENS
,
sortTokenGroups
,
sortingFns
,
calculateUsdValue
,
filterTokens
}
from
'
./utils
'
;
interface
Props
{
data
:
Array
<
AddressTokenBalance
>
;
}
const
AddressTokenSelect
=
({
data
}:
Props
)
=>
{
const
Tokens
=
({
data
}:
Props
)
=>
{
const
[
searchTerm
,
setSearchTerm
]
=
React
.
useState
(
''
);
const
[
erc1155sort
,
setErc1155Sort
]
=
React
.
useState
<
Sort
>
(
'
desc
'
);
const
[
erc20sort
,
setErc20Sort
]
=
React
.
useState
<
Sort
>
(
'
desc
'
);
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
handleInputChange
=
React
.
useCallback
((
event
:
ChangeEvent
<
HTMLInputElement
>
)
=>
{
...
...
@@ -74,19 +40,22 @@ const AddressTokenSelect = ({ data }: Props) => {
if
(
tokenType
===
'
ERC-1155
'
)
{
setErc1155Sort
((
prevValue
)
=>
prevValue
===
'
desc
'
?
'
asc
'
:
'
desc
'
);
}
if
(
tokenType
===
'
ERC-20
'
)
{
setErc20Sort
((
prevValue
)
=>
prevValue
===
'
desc
'
?
'
asc
'
:
'
desc
'
);
}
},
[]);
const
searchIconColor
=
useColorModeValue
(
'
blackAlpha.600
'
,
'
whiteAlpha.600
'
);
const
inputBorderColor
=
useColorModeValue
(
'
blackAlpha.100
'
,
'
whiteAlpha.200
'
);
const
bgColor
=
useColorModeValue
(
'
white
'
,
'
gray.900
'
);
const
filteredData
=
data
.
filter
(
filterTokens
(
searchTerm
.
toLowerCase
())
);
const
groupedData
=
_groupBy
(
filter
edData
,
'
token.type
'
);
const
modifiedData
=
data
.
filter
(
filterTokens
(
searchTerm
.
toLowerCase
())).
map
(
calculateUsdValue
);
const
groupedData
=
_groupBy
(
modifi
edData
,
'
token.type
'
);
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
"bottom-start"
isLazy
>
<
PopoverTrigger
>
<
TokensButton
isOpen=
{
isOpen
}
onClick=
{
onToggle
}
data=
{
d
ata
}
/>
<
TokensButton
isOpen=
{
isOpen
}
onClick=
{
onToggle
}
data=
{
modifiedD
ata
}
/>
</
PopoverTrigger
>
<
PopoverContent
w=
"355px"
maxH=
"450px"
overflowY=
"scroll"
>
<
PopoverBody
px=
{
4
}
py=
{
6
}
bgColor=
{
bgColor
}
boxShadow=
"2xl"
>
...
...
@@ -105,12 +74,15 @@ const AddressTokenSelect = ({ data }: Props) => {
<
Flex
flexDir=
"column"
rowGap=
{
6
}
>
{
Object
.
entries
(
groupedData
).
sort
(
sortTokenGroups
).
map
(([
tokenType
,
tokenInfo
])
=>
{
const
type
=
tokenType
as
TokenType
;
const
arrowTransform
=
type
===
'
ERC-1155
'
&&
erc1155sort
===
'
desc
'
?
'
rotate(90deg)
'
:
'
rotate(-90deg)
'
;
const
arrowTransform
=
(
type
===
'
ERC-1155
'
&&
erc1155sort
===
'
desc
'
)
||
(
type
===
'
ERC-20
'
&&
erc20sort
===
'
desc
'
)
?
'
rotate(90deg)
'
:
'
rotate(-90deg)
'
;
const
sortDirection
:
Sort
=
(()
=>
{
switch
(
type
)
{
case
'
ERC-1155
'
:
return
erc1155sort
;
case
'
ERC-20
'
:
return
erc20sort
;
default
:
return
'
desc
'
;
}
...
...
@@ -126,16 +98,16 @@ const AddressTokenSelect = ({ data }: Props) => {
</
Link
>
)
}
</
Flex
>
{
tokenInfo
.
sort
(
sortingFns
[
type
](
sortDirection
)).
map
((
data
)
=>
<
TokenItem
key=
{
data
.
token
.
address
}
data=
{
data
}
/>)
}
{
tokenInfo
.
sort
(
sortingFns
[
type
](
sortDirection
)).
map
((
data
)
=>
<
TokenItem
key=
{
data
.
token
.
address
+
data
.
token_id
}
data=
{
data
}
/>)
}
</
Box
>
);
})
}
</
Flex
>
{
filter
edData
.
length
===
0
&&
searchTerm
&&
<
Text
fontSize=
"sm"
>
Could not find any matches.
</
Text
>
}
{
modifi
edData
.
length
===
0
&&
searchTerm
&&
<
Text
fontSize=
"sm"
>
Could not find any matches.
</
Text
>
}
</
PopoverBody
>
</
PopoverContent
>
</
Popover
>
);
};
export
default
React
.
memo
(
AddressTokenSelect
);
export
default
React
.
memo
(
Tokens
);
ui/address/details/TokensButton.tsx
View file @
52bcc45d
...
...
@@ -2,26 +2,20 @@ import { Button, Icon, Text } from '@chakra-ui/react';
import
BigNumber
from
'
bignumber.js
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
arrowIcon
from
'
icons/arrows/east-mini.svg
'
;
import
tokensIcon
from
'
icons/tokens.svg
'
;
import
{
ZERO
}
from
'
lib/consts
'
;
import
type
{
EnhancedData
}
from
'
./utils
'
;
interface
Props
{
isOpen
:
boolean
;
onClick
:
()
=>
void
;
data
:
Array
<
AddressTokenBalance
>
;
data
:
Array
<
EnhancedData
>
;
}
const
TokensButton
=
({
isOpen
,
onClick
,
data
}:
Props
,
ref
:
React
.
ForwardedRef
<
HTMLButtonElement
>
)
=>
{
const
usdBn
=
data
.
reduce
((
result
,
item
)
=>
{
if
(
!
item
.
token
.
exchange_rate
)
{
return
result
;
}
const
decimals
=
Number
(
item
.
token
.
decimals
||
'
18
'
);
return
BigNumber
(
item
.
value
).
div
(
BigNumber
(
10
**
decimals
)).
multipliedBy
(
BigNumber
(
item
.
token
.
exchange_rate
));
},
ZERO
);
const
totalBn
=
data
.
reduce
((
result
,
item
)
=>
!
item
.
usd
?
result
:
result
.
plus
(
BigNumber
(
item
.
usd
)),
ZERO
);
return
(
<
Button
...
...
@@ -33,7 +27,7 @@ const TokensButton = ({ isOpen, onClick, data }: Props, ref: React.ForwardedRef<
>
<
Icon
as=
{
tokensIcon
}
boxSize=
{
4
}
mr=
{
2
}
/>
<
Text
fontWeight=
{
600
}
>
{
data
.
length
}
</
Text
>
<
Text
whiteSpace=
"pre"
variant=
"secondary"
fontWeight=
{
400
}
>
($
{
usdBn
.
toFixed
(
2
)
}
)
</
Text
>
<
Text
whiteSpace=
"pre"
variant=
"secondary"
fontWeight=
{
400
}
>
($
{
totalBn
.
toFormat
(
2
)
}
)
</
Text
>
<
Icon
as=
{
arrowIcon
}
transform=
{
isOpen
?
'
rotate(90deg)
'
:
'
rotate(-90deg)
'
}
transitionDuration=
"normal"
boxSize=
{
5
}
ml=
{
3
}
/>
</
Button
>
);
...
...
ui/address/details/utils.ts
0 → 100644
View file @
52bcc45d
import
BigNumber
from
'
bignumber.js
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
type
{
TokenType
}
from
'
types/api/tokenInfo
'
;
export
type
EnhancedData
=
AddressTokenBalance
&
{
usd
?:
BigNumber
;
}
export
type
Sort
=
'
desc
'
|
'
asc
'
;
export
const
SORTABLE_TOKENS
:
Array
<
TokenType
>
=
[
'
ERC-20
'
,
'
ERC-1155
'
];
const
TOKEN_GROUPS_ORDER
:
Array
<
TokenType
>
=
[
'
ERC-20
'
,
'
ERC-721
'
,
'
ERC-1155
'
];
type
TokenGroup
=
[
string
,
Array
<
AddressTokenBalance
>
];
export
const
sortTokenGroups
=
(
groupA
:
TokenGroup
,
groupB
:
TokenGroup
)
=>
{
return
TOKEN_GROUPS_ORDER
.
indexOf
(
groupA
[
0
]
as
TokenType
)
>
TOKEN_GROUPS_ORDER
.
indexOf
(
groupB
[
0
]
as
TokenType
)
?
1
:
-
1
;
};
const
sortErc1155Tokens
=
(
sort
:
Sort
)
=>
(
dataA
:
AddressTokenBalance
,
dataB
:
AddressTokenBalance
)
=>
{
if
(
dataA
.
value
===
dataB
.
value
)
{
return
0
;
}
if
(
sort
===
'
desc
'
)
{
return
Number
(
dataA
.
value
)
>
Number
(
dataB
.
value
)
?
-
1
:
1
;
}
return
Number
(
dataA
.
value
)
>
Number
(
dataB
.
value
)
?
1
:
-
1
;
};
const
sortErc20Tokens
=
(
sort
:
Sort
)
=>
(
dataA
:
EnhancedData
,
dataB
:
EnhancedData
)
=>
{
// keep tokens without usd value in the end of the group
if
(
!
dataB
.
usd
)
{
return
-
1
;
}
if
(
!
dataA
.
usd
)
{
return
0
;
}
if
(
sort
===
'
desc
'
)
{
return
dataA
.
usd
.
gt
(
dataB
.
usd
)
?
-
1
:
1
;
}
return
dataA
.
usd
.
gt
(
dataB
.
usd
)
?
1
:
-
1
;
};
const
sortErc721Tokens
=
()
=>
()
=>
0
;
export
const
sortingFns
=
{
'
ERC-20
'
:
sortErc20Tokens
,
'
ERC-721
'
:
sortErc721Tokens
,
'
ERC-1155
'
:
sortErc1155Tokens
,
};
export
const
filterTokens
=
(
searchTerm
:
string
)
=>
({
token
}:
AddressTokenBalance
)
=>
{
if
(
!
token
.
name
)
{
return
!
searchTerm
?
true
:
token
.
address
.
toLowerCase
().
includes
(
searchTerm
);
}
return
token
.
name
?.
toLowerCase
().
includes
(
searchTerm
);
};
export
const
calculateUsdValue
=
(
data
:
AddressTokenBalance
):
EnhancedData
=>
{
if
(
data
.
token
.
type
!==
'
ERC-20
'
)
{
return
data
;
}
const
exchangeRate
=
data
.
token
.
exchange_rate
;
if
(
!
exchangeRate
)
{
return
data
;
}
const
decimals
=
Number
(
data
.
token
.
decimals
||
'
18
'
);
return
{
...
data
,
usd
:
BigNumber
(
data
.
value
).
div
(
BigNumber
(
10
**
decimals
)).
multipliedBy
(
BigNumber
(
exchangeRate
)),
};
};
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