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
aa81d368
Commit
aa81d368
authored
Dec 06, 2022
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mobile view
parent
7f1f96e2
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
194 additions
and
115 deletions
+194
-115
AddressDetails.tsx
ui/address/AddressDetails.tsx
+3
-2
TokenSelectDesktop.tsx
ui/address/tokenSelect/TokenSelectDesktop.tsx
+35
-0
TokenSelectMenu.tsx
ui/address/tokenSelect/TokenSelectMenu.tsx
+80
-0
TokenSelectMobile.tsx
ui/address/tokenSelect/TokenSelectMobile.tsx
+31
-0
Tokens.tsx
ui/address/tokenSelect/Tokens.tsx
+0
-113
useTokenSelect.ts
ui/address/tokenSelect/useTokenSelect.ts
+45
-0
No files found.
ui/address/AddressDetails.tsx
View file @
aa81d368
...
...
@@ -21,7 +21,8 @@ import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import
ExternalLink
from
'
ui/shared/ExternalLink
'
;
import
HashStringShorten
from
'
ui/shared/HashStringShorten
'
;
import
Tokens
from
'
./tokenSelect/Tokens
'
;
import
TokenSelectDesktop
from
'
./tokenSelect/TokenSelectDesktop
'
;
import
TokenSelectMobile
from
'
./tokenSelect/TokenSelectMobile
'
;
interface
Props
{
addressQuery
:
UseQueryResult
<
TAddress
>
;
...
...
@@ -98,7 +99,7 @@ const AddressDetails = ({ addressQuery }: Props) => {
>
{
tokenBalancesQuery
.
data
.
length
>
0
?
(
<>
<
Tokens
data=
{
tokenBalancesQuery
.
data
}
/>
{
isMobile
?
<
TokenSelectMobile
data=
{
tokenBalancesQuery
.
data
}
/>
:
<
TokenSelectDesktop
data=
{
tokenBalancesQuery
.
data
}
/>
}
<
Button
variant=
"outline"
size=
"sm"
ml=
{
3
}
>
<
Icon
as=
{
walletIcon
}
boxSize=
{
5
}
/>
</
Button
>
...
...
ui/address/tokenSelect/TokenSelectDesktop.tsx
0 → 100644
View file @
aa81d368
import
{
useColorModeValue
,
Popover
,
PopoverTrigger
,
PopoverContent
,
PopoverBody
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
TokenSelectButton
from
'
./TokenSelectButton
'
;
import
TokenSelectMenu
from
'
./TokenSelectMenu
'
;
import
useTokenSelect
from
'
./useTokenSelect
'
;
interface
Props
{
data
:
Array
<
AddressTokenBalance
>
;
}
const
TokenSelectDesktop
=
({
data
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
bgColor
=
useColorModeValue
(
'
white
'
,
'
gray.900
'
);
const
result
=
useTokenSelect
(
data
);
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
"bottom-start"
isLazy
>
<
PopoverTrigger
>
<
TokenSelectButton
isOpen=
{
isOpen
}
onClick=
{
onToggle
}
data=
{
result
.
modifiedData
}
/>
</
PopoverTrigger
>
<
PopoverContent
w=
"355px"
maxH=
"450px"
overflowY=
"scroll"
>
<
PopoverBody
px=
{
4
}
py=
{
6
}
bgColor=
{
bgColor
}
boxShadow=
"2xl"
>
<
TokenSelectMenu
{
...
result
}
/>
</
PopoverBody
>
</
PopoverContent
>
</
Popover
>
);
};
export
default
React
.
memo
(
TokenSelectDesktop
);
ui/address/tokenSelect/TokenSelectMenu.tsx
0 → 100644
View file @
aa81d368
import
{
Icon
,
Text
,
Box
,
Input
,
InputGroup
,
InputLeftElement
,
useColorModeValue
,
Flex
,
Link
}
from
'
@chakra-ui/react
'
;
import
type
{
Dictionary
}
from
'
lodash
'
;
import
type
{
ChangeEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
TokenType
}
from
'
types/api/tokenInfo
'
;
import
arrowIcon
from
'
icons/arrows/east.svg
'
;
import
searchIcon
from
'
icons/search.svg
'
;
import
TokenSelectItem
from
'
./TokenSelectItem
'
;
import
type
{
Sort
,
EnhancedData
}
from
'
./utils
'
;
import
{
SORTABLE_TOKENS
,
sortTokenGroups
,
sortingFns
}
from
'
./utils
'
;
interface
Props
{
searchTerm
:
string
;
erc20sort
:
Sort
;
erc1155sort
:
Sort
;
modifiedData
:
Array
<
EnhancedData
>
;
groupedData
:
Dictionary
<
Array
<
EnhancedData
>>
;
onInputChange
:
(
event
:
ChangeEvent
<
HTMLInputElement
>
)
=>
void
;
onSortClick
:
(
event
:
React
.
SyntheticEvent
)
=>
void
;
}
const
TokenSelectMenu
=
({
erc20sort
,
erc1155sort
,
modifiedData
,
groupedData
,
onInputChange
,
onSortClick
,
searchTerm
}:
Props
)
=>
{
const
searchIconColor
=
useColorModeValue
(
'
blackAlpha.600
'
,
'
whiteAlpha.600
'
);
const
inputBorderColor
=
useColorModeValue
(
'
blackAlpha.100
'
,
'
whiteAlpha.200
'
);
return
(
<>
<
InputGroup
size=
"xs"
mb=
{
5
}
>
<
InputLeftElement
>
<
Icon
as=
{
searchIcon
}
boxSize=
{
4
}
color=
{
searchIconColor
}
/>
</
InputLeftElement
>
<
Input
paddingInlineStart=
"38px"
placeholder=
"Search by token name"
ml=
"1px"
onChange=
{
onInputChange
}
borderColor=
{
inputBorderColor
}
/>
</
InputGroup
>
<
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
'
)
||
(
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
'
;
}
})();
return
(
<
Box
key=
{
type
}
>
<
Flex
justifyContent=
"space-between"
>
<
Text
mb=
{
3
}
color=
"gray.500"
fontWeight=
{
600
}
fontSize=
"sm"
>
{
type
}
tokens (
{
tokenInfo
.
length
}
)
</
Text
>
{
SORTABLE_TOKENS
.
includes
(
type
)
&&
(
<
Link
data
-
type=
{
type
}
onClick=
{
onSortClick
}
>
<
Icon
as=
{
arrowIcon
}
boxSize=
{
5
}
transform=
{
arrowTransform
}
transitionDuration=
"fast"
/>
</
Link
>
)
}
</
Flex
>
{
tokenInfo
.
sort
(
sortingFns
[
type
](
sortDirection
)).
map
((
data
)
=>
<
TokenSelectItem
key=
{
data
.
token
.
address
+
data
.
token_id
}
data=
{
data
}
/>)
}
</
Box
>
);
})
}
</
Flex
>
{
modifiedData
.
length
===
0
&&
searchTerm
&&
<
Text
fontSize=
"sm"
>
Could not find any matches.
</
Text
>
}
</>
);
};
export
default
React
.
memo
(
TokenSelectMenu
);
ui/address/tokenSelect/TokenSelectMobile.tsx
0 → 100644
View file @
aa81d368
import
{
useDisclosure
,
Modal
,
ModalContent
,
ModalCloseButton
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
TokenSelectButton
from
'
./TokenSelectButton
'
;
import
TokenSelectMenu
from
'
./TokenSelectMenu
'
;
import
useTokenSelect
from
'
./useTokenSelect
'
;
interface
Props
{
data
:
Array
<
AddressTokenBalance
>
;
}
const
TokenSelectMobile
=
({
data
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
result
=
useTokenSelect
(
data
);
return
(
<>
<
TokenSelectButton
isOpen=
{
isOpen
}
onClick=
{
onToggle
}
data=
{
result
.
modifiedData
}
/>
<
Modal
isOpen=
{
isOpen
}
onClose=
{
onClose
}
size=
"full"
>
<
ModalContent
>
<
ModalCloseButton
/>
<
TokenSelectMenu
{
...
result
}
/>
</
ModalContent
>
</
Modal
>
</>
);
};
export
default
React
.
memo
(
TokenSelectMobile
);
ui/address/tokenSelect/Tokens.tsx
deleted
100644 → 0
View file @
7f1f96e2
import
{
Icon
,
Text
,
Input
,
InputGroup
,
InputLeftElement
,
useColorModeValue
,
Popover
,
PopoverTrigger
,
PopoverContent
,
PopoverBody
,
Box
,
useDisclosure
,
Flex
,
Link
,
}
from
'
@chakra-ui/react
'
;
import
_groupBy
from
'
lodash/groupBy
'
;
import
type
{
ChangeEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
type
{
TokenType
}
from
'
types/api/tokenInfo
'
;
import
arrowIcon
from
'
icons/arrows/east.svg
'
;
import
searchIcon
from
'
icons/search.svg
'
;
import
TokenSelectButton
from
'
./TokenSelectButton
'
;
import
TokenSelectItem
from
'
./TokenSelectItem
'
;
import
type
{
Sort
}
from
'
./utils
'
;
import
{
SORTABLE_TOKENS
,
sortTokenGroups
,
sortingFns
,
calculateUsdValue
,
filterTokens
}
from
'
./utils
'
;
interface
Props
{
data
:
Array
<
AddressTokenBalance
>
;
}
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
>
)
=>
{
setSearchTerm
(
event
.
target
.
value
);
},
[]);
const
handleSortClick
=
React
.
useCallback
((
event
:
React
.
SyntheticEvent
)
=>
{
const
tokenType
=
(
event
.
currentTarget
as
HTMLAnchorElement
).
getAttribute
(
'
data-type
'
);
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
modifiedData
=
data
.
filter
(
filterTokens
(
searchTerm
.
toLowerCase
())).
map
(
calculateUsdValue
);
const
groupedData
=
_groupBy
(
modifiedData
,
'
token.type
'
);
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
"bottom-start"
isLazy
>
<
PopoverTrigger
>
<
TokenSelectButton
isOpen=
{
isOpen
}
onClick=
{
onToggle
}
data=
{
modifiedData
}
/>
</
PopoverTrigger
>
<
PopoverContent
w=
"355px"
maxH=
"450px"
overflowY=
"scroll"
>
<
PopoverBody
px=
{
4
}
py=
{
6
}
bgColor=
{
bgColor
}
boxShadow=
"2xl"
>
<
InputGroup
size=
"xs"
mb=
{
5
}
>
<
InputLeftElement
>
<
Icon
as=
{
searchIcon
}
boxSize=
{
4
}
color=
{
searchIconColor
}
/>
</
InputLeftElement
>
<
Input
paddingInlineStart=
"38px"
placeholder=
"Search by token name"
ml=
"1px"
onChange=
{
handleInputChange
}
borderColor=
{
inputBorderColor
}
/>
</
InputGroup
>
<
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
'
)
||
(
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
'
;
}
})();
return
(
<
Box
key=
{
type
}
>
<
Flex
justifyContent=
"space-between"
>
<
Text
mb=
{
3
}
color=
"gray.500"
fontWeight=
{
600
}
fontSize=
"sm"
>
{
type
}
tokens (
{
tokenInfo
.
length
}
)
</
Text
>
{
SORTABLE_TOKENS
.
includes
(
type
)
&&
(
<
Link
data
-
type=
{
type
}
onClick=
{
handleSortClick
}
>
<
Icon
as=
{
arrowIcon
}
boxSize=
{
5
}
transform=
{
arrowTransform
}
transitionDuration=
"fast"
/>
</
Link
>
)
}
</
Flex
>
{
tokenInfo
.
sort
(
sortingFns
[
type
](
sortDirection
)).
map
((
data
)
=>
<
TokenSelectItem
key=
{
data
.
token
.
address
+
data
.
token_id
}
data=
{
data
}
/>)
}
</
Box
>
);
})
}
</
Flex
>
{
modifiedData
.
length
===
0
&&
searchTerm
&&
<
Text
fontSize=
"sm"
>
Could not find any matches.
</
Text
>
}
</
PopoverBody
>
</
PopoverContent
>
</
Popover
>
);
};
export
default
React
.
memo
(
Tokens
);
ui/address/tokenSelect/useTokenSelect.ts
0 → 100644
View file @
aa81d368
import
_groupBy
from
'
lodash/groupBy
'
;
import
type
{
ChangeEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
type
{
Sort
}
from
'
./utils
'
;
import
{
calculateUsdValue
,
filterTokens
}
from
'
./utils
'
;
export
default
function
useData
(
data
:
Array
<
AddressTokenBalance
>
)
{
const
[
searchTerm
,
setSearchTerm
]
=
React
.
useState
(
''
);
const
[
erc1155sort
,
setErc1155Sort
]
=
React
.
useState
<
Sort
>
(
'
desc
'
);
const
[
erc20sort
,
setErc20Sort
]
=
React
.
useState
<
Sort
>
(
'
desc
'
);
const
onInputChange
=
React
.
useCallback
((
event
:
ChangeEvent
<
HTMLInputElement
>
)
=>
{
setSearchTerm
(
event
.
target
.
value
);
},
[]);
const
onSortClick
=
React
.
useCallback
((
event
:
React
.
SyntheticEvent
)
=>
{
const
tokenType
=
(
event
.
currentTarget
as
HTMLAnchorElement
).
getAttribute
(
'
data-type
'
);
if
(
tokenType
===
'
ERC-1155
'
)
{
setErc1155Sort
((
prevValue
)
=>
prevValue
===
'
desc
'
?
'
asc
'
:
'
desc
'
);
}
if
(
tokenType
===
'
ERC-20
'
)
{
setErc20Sort
((
prevValue
)
=>
prevValue
===
'
desc
'
?
'
asc
'
:
'
desc
'
);
}
},
[]);
const
modifiedData
=
React
.
useMemo
(()
=>
{
return
data
.
filter
(
filterTokens
(
searchTerm
.
toLowerCase
())).
map
(
calculateUsdValue
);
},
[
data
,
searchTerm
]);
const
groupedData
=
React
.
useMemo
(()
=>
{
return
_groupBy
(
modifiedData
,
'
token.type
'
);
},
[
modifiedData
]);
return
{
searchTerm
,
erc20sort
,
erc1155sort
,
onInputChange
,
onSortClick
,
modifiedData
,
groupedData
,
};
}
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