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
de9afb2b
Commit
de9afb2b
authored
Oct 28, 2023
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nft address start
parent
208183b5
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
375 additions
and
289 deletions
+375
-289
resources.ts
lib/api/resources.ts
+18
-2
address.ts
stubs/address.ts
+23
-11
address.ts
types/api/address.ts
+33
-1
token.ts
types/api/token.ts
+4
-0
AddressTokenTransfers.tsx
ui/address/AddressTokenTransfers.tsx
+3
-18
AddressTokens.tsx
ui/address/AddressTokens.tsx
+48
-22
AddressCollections.tsx
ui/address/tokens/AddressCollections.tsx
+112
-0
AddressNFTs.tsx
ui/address/tokens/AddressNFTs.tsx
+5
-4
ERC721Tokens.tsx
ui/address/tokens/ERC721Tokens.tsx
+0
-52
ERC721TokensListItem.tsx
ui/address/tokens/ERC721TokensListItem.tsx
+0
-48
ERC721TokensTable.tsx
ui/address/tokens/ERC721TokensTable.tsx
+0
-35
ERC721TokensTableItem.tsx
ui/address/tokens/ERC721TokensTableItem.tsx
+0
-53
NFTItem.tsx
ui/address/tokens/NFTItem.tsx
+29
-25
NFTItemContainer.tsx
ui/address/tokens/NFTItemContainer.tsx
+27
-0
Address.tsx
ui/pages/Address.tsx
+1
-8
Token.tsx
ui/pages/Token.tsx
+8
-4
ResetIconButton.tsx
ui/shared/ResetIconButton.tsx
+31
-0
TokenInventory.tsx
ui/token/TokenInventory.tsx
+33
-6
No files found.
lib/api/resources.ts
View file @
de9afb2b
...
@@ -26,6 +26,8 @@ import type {
...
@@ -26,6 +26,8 @@ import type {
AddressTokensFilter
,
AddressTokensFilter
,
AddressTokensResponse
,
AddressTokensResponse
,
AddressWithdrawalsResponse
,
AddressWithdrawalsResponse
,
AddressNFTsResponse
,
AddressCollectionsResponse
,
}
from
'
types/api/address
'
;
}
from
'
types/api/address
'
;
import
type
{
AddressesResponse
}
from
'
types/api/addresses
'
;
import
type
{
AddressesResponse
}
from
'
types/api/addresses
'
;
import
type
{
BlocksResponse
,
BlockTransactionsResponse
,
Block
,
BlockFilters
,
BlockWithdrawalsResponse
}
from
'
types/api/block
'
;
import
type
{
BlocksResponse
,
BlockTransactionsResponse
,
Block
,
BlockFilters
,
BlockWithdrawalsResponse
}
from
'
types/api/block
'
;
...
@@ -51,6 +53,7 @@ import type {
...
@@ -51,6 +53,7 @@ import type {
TokenInstance
,
TokenInstance
,
TokenInstanceTransfersCount
,
TokenInstanceTransfersCount
,
TokenVerifiedInfo
,
TokenVerifiedInfo
,
TokenInventoryFilters
,
}
from
'
types/api/token
'
;
}
from
'
types/api/token
'
;
import
type
{
TokensResponse
,
TokensFilters
,
TokensSorting
,
TokenInstanceTransferResponse
,
TokensBridgedFilters
}
from
'
types/api/tokens
'
;
import
type
{
TokensResponse
,
TokensFilters
,
TokensSorting
,
TokenInstanceTransferResponse
,
TokensBridgedFilters
}
from
'
types/api/tokens
'
;
import
type
{
TokenTransferResponse
,
TokenTransferFilters
}
from
'
types/api/tokenTransfer
'
;
import
type
{
TokenTransferResponse
,
TokenTransferFilters
}
from
'
types/api/tokenTransfer
'
;
...
@@ -305,6 +308,16 @@ export const RESOURCES = {
...
@@ -305,6 +308,16 @@ export const RESOURCES = {
pathParams
:
[
'
hash
'
as
const
],
pathParams
:
[
'
hash
'
as
const
],
filterFields
:
[
'
type
'
as
const
],
filterFields
:
[
'
type
'
as
const
],
},
},
address_nfts
:
{
path
:
'
/api/v2/addresses/:hash/nft
'
,
pathParams
:
[
'
hash
'
as
const
],
filterFields
:
[
],
},
address_collections
:
{
path
:
'
/api/v2/addresses/:hash/nft/collections
'
,
pathParams
:
[
'
hash
'
as
const
],
filterFields
:
[
],
},
address_withdrawals
:
{
address_withdrawals
:
{
path
:
'
/api/v2/addresses/:hash/withdrawals
'
,
path
:
'
/api/v2/addresses/:hash/withdrawals
'
,
pathParams
:
[
'
hash
'
as
const
],
pathParams
:
[
'
hash
'
as
const
],
...
@@ -384,7 +397,7 @@ export const RESOURCES = {
...
@@ -384,7 +397,7 @@ export const RESOURCES = {
token_inventory
:
{
token_inventory
:
{
path
:
'
/api/v2/tokens/:hash/instances
'
,
path
:
'
/api/v2/tokens/:hash/instances
'
,
pathParams
:
[
'
hash
'
as
const
],
pathParams
:
[
'
hash
'
as
const
],
filterFields
:
[],
filterFields
:
[
'
holder_address_hash
'
as
const
],
},
},
tokens
:
{
tokens
:
{
path
:
'
/api/v2/tokens
'
,
path
:
'
/api/v2/tokens
'
,
...
@@ -580,7 +593,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' |
...
@@ -580,7 +593,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' |
'
addresses
'
|
'
addresses
'
|
'
address_txs
'
|
'
address_internal_txs
'
|
'
address_token_transfers
'
|
'
address_blocks_validated
'
|
'
address_coin_balance
'
|
'
address_txs
'
|
'
address_internal_txs
'
|
'
address_token_transfers
'
|
'
address_blocks_validated
'
|
'
address_coin_balance
'
|
'
search
'
|
'
search
'
|
'
address_logs
'
|
'
address_tokens
'
|
'
address_logs
'
|
'
address_tokens
'
|
'
address_nfts
'
|
'
address_collections
'
|
'
token_transfers
'
|
'
token_holders
'
|
'
token_inventory
'
|
'
tokens
'
|
'
tokens_bridged
'
|
'
token_transfers
'
|
'
token_holders
'
|
'
token_inventory
'
|
'
tokens
'
|
'
tokens_bridged
'
|
'
token_instance_transfers
'
|
'
token_instance_holders
'
|
'
token_instance_transfers
'
|
'
token_instance_holders
'
|
'
verified_contracts
'
|
'
verified_contracts
'
|
...
@@ -642,6 +655,8 @@ Q extends 'address_coin_balance' ? AddressCoinBalanceHistoryResponse :
...
@@ -642,6 +655,8 @@ Q extends 'address_coin_balance' ? AddressCoinBalanceHistoryResponse :
Q
extends
'
address_coin_balance_chart
'
?
AddressCoinBalanceHistoryChart
:
Q
extends
'
address_coin_balance_chart
'
?
AddressCoinBalanceHistoryChart
:
Q
extends
'
address_logs
'
?
LogsResponseAddress
:
Q
extends
'
address_logs
'
?
LogsResponseAddress
:
Q
extends
'
address_tokens
'
?
AddressTokensResponse
:
Q
extends
'
address_tokens
'
?
AddressTokensResponse
:
Q
extends
'
address_nfts
'
?
AddressNFTsResponse
:
Q
extends
'
address_collections
'
?
AddressCollectionsResponse
:
Q
extends
'
address_withdrawals
'
?
AddressWithdrawalsResponse
:
Q
extends
'
address_withdrawals
'
?
AddressWithdrawalsResponse
:
Q
extends
'
token
'
?
TokenInfo
:
Q
extends
'
token
'
?
TokenInfo
:
Q
extends
'
token_verified_info
'
?
TokenVerifiedInfo
:
Q
extends
'
token_verified_info
'
?
TokenVerifiedInfo
:
...
@@ -696,6 +711,7 @@ Q extends 'address_txs' | 'address_internal_txs' ? AddressTxsFilters :
...
@@ -696,6 +711,7 @@ Q extends 'address_txs' | 'address_internal_txs' ? AddressTxsFilters :
Q
extends
'
address_token_transfers
'
?
AddressTokenTransferFilters
:
Q
extends
'
address_token_transfers
'
?
AddressTokenTransferFilters
:
Q
extends
'
address_tokens
'
?
AddressTokensFilter
:
Q
extends
'
address_tokens
'
?
AddressTokensFilter
:
Q
extends
'
search
'
?
SearchResultFilters
:
Q
extends
'
search
'
?
SearchResultFilters
:
Q
extends
'
token_inventory
'
?
TokenInventoryFilters
:
Q
extends
'
tokens
'
?
TokensFilters
:
Q
extends
'
tokens
'
?
TokensFilters
:
Q
extends
'
tokens_bridged
'
?
TokensBridgedFilters
:
Q
extends
'
tokens_bridged
'
?
TokensBridgedFilters
:
Q
extends
'
verified_contracts
'
?
VerifiedContractsFilters
:
Q
extends
'
verified_contracts
'
?
VerifiedContractsFilters
:
...
...
stubs/address.ts
View file @
de9afb2b
import
type
{
Address
,
AddressCoinBalanceHistoryItem
,
AddressCounters
,
AddressTabsCounters
,
AddressTokenBalance
}
from
'
types/api/address
'
;
import
type
{
Address
,
AddressCoinBalanceHistoryItem
,
AddressCollection
,
AddressCounters
,
AddressNFT
,
AddressTabsCounters
,
AddressTokenBalance
,
}
from
'
types/api/address
'
;
import
type
{
AddressesItem
}
from
'
types/api/addresses
'
;
import
type
{
AddressesItem
}
from
'
types/api/addresses
'
;
import
{
ADDRESS_HASH
}
from
'
./addressParams
'
;
import
{
ADDRESS_HASH
}
from
'
./addressParams
'
;
import
{
TOKEN_INFO_ERC_1155
,
TOKEN_INFO_ERC_20
,
TOKEN_IN
FO_ERC_721
,
TOKEN_IN
STANCE
}
from
'
./token
'
;
import
{
TOKEN_INFO_ERC_1155
,
TOKEN_INFO_ERC_20
,
TOKEN_INSTANCE
}
from
'
./token
'
;
import
{
TX_HASH
}
from
'
./tx
'
;
import
{
TX_HASH
}
from
'
./tx
'
;
export
const
ADDRESS_INFO
:
Address
=
{
export
const
ADDRESS_INFO
:
Address
=
{
...
@@ -80,16 +88,20 @@ export const ADDRESS_TOKEN_BALANCE_ERC_20: AddressTokenBalance = {
...
@@ -80,16 +88,20 @@ export const ADDRESS_TOKEN_BALANCE_ERC_20: AddressTokenBalance = {
value
:
'
1000000000000000000000000
'
,
value
:
'
1000000000000000000000000
'
,
};
};
export
const
ADDRESS_TOKEN_BALANCE_ERC_721
:
AddressTokenBalance
=
{
export
const
ADDRESS_NFT_721
:
AddressNFT
=
{
token
:
TOKEN_INFO_ERC_721
,
token_type
:
'
ERC-721
'
,
token_id
:
null
,
value
:
'
1
'
,
token_instance
:
null
,
...
TOKEN_INSTANCE
,
value
:
'
176
'
,
};
export
const
ADDRESS_NFT_1155
:
AddressNFT
=
{
token_type
:
'
ERC-1155
'
,
value
:
'
10
'
,
...
TOKEN_INSTANCE
,
};
};
export
const
ADDRESS_
TOKEN_BALANCE_ERC_1155
:
AddressTokenBalance
=
{
export
const
ADDRESS_
COLLECTION
:
AddressCollection
=
{
token
:
TOKEN_INFO_ERC_1155
,
token
:
TOKEN_INFO_ERC_1155
,
token_id
:
'
188882
'
,
amount
:
'
4
'
,
token_instance
:
TOKEN_INSTANCE
,
token_instances
:
Array
(
4
).
fill
(
TOKEN_INSTANCE
),
value
:
'
176
'
,
};
};
types/api/address.ts
View file @
de9afb2b
...
@@ -49,11 +49,43 @@ export interface AddressTokenBalance {
...
@@ -49,11 +49,43 @@ export interface AddressTokenBalance {
token_instance
:
TokenInstance
|
null
;
token_instance
:
TokenInstance
|
null
;
}
}
export
type
AddressNFT
=
TokenInstance
&
{
token_type
:
Omit
<
TokenType
,
'
ERC-20
'
>
;
value
:
string
;
}
export
type
AddressCollection
=
{
token
:
TokenInfo
;
amount
:
string
;
token_instances
:
Array
<
Omit
<
AddressNFT
,
'
token
'
>>
;
}
export
interface
AddressTokensResponse
{
export
interface
AddressTokensResponse
{
items
:
Array
<
AddressTokenBalance
>
;
items
:
Array
<
AddressTokenBalance
>
;
next_page_params
:
{
next_page_params
:
{
items_count
:
number
;
items_count
:
number
;
token_name
:
'
string
'
|
null
;
token_name
:
string
|
null
;
token_type
:
TokenType
;
value
:
number
;
fiat_value
:
string
|
null
;
}
|
null
;
}
export
interface
AddressNFTsResponse
{
items
:
Array
<
AddressNFT
>
;
next_page_params
:
{
items_count
:
number
;
token_id
:
string
;
token_type
:
TokenType
;
token_contract_address_hash
:
string
;
}
|
null
;
}
export
interface
AddressCollectionsResponse
{
items
:
Array
<
AddressCollection
>
;
next_page_params
:
{
items_count
:
number
;
token_name
:
string
|
null
;
token_type
:
TokenType
;
token_type
:
TokenType
;
value
:
number
;
value
:
number
;
fiat_value
:
string
|
null
;
fiat_value
:
string
|
null
;
...
...
types/api/token.ts
View file @
de9afb2b
...
@@ -77,3 +77,7 @@ export type TokenInventoryPagination = {
...
@@ -77,3 +77,7 @@ export type TokenInventoryPagination = {
}
}
export
type
TokenVerifiedInfo
=
Omit
<
TokenInfoApplication
,
'
id
'
|
'
status
'
>
;
export
type
TokenVerifiedInfo
=
Omit
<
TokenInfoApplication
,
'
id
'
|
'
status
'
>
;
export
type
TokenInventoryFilters
=
{
holder_address_hash
?:
string
;
}
ui/address/AddressTokenTransfers.tsx
View file @
de9afb2b
import
{
Flex
,
Hide
,
Icon
,
Show
,
Text
,
Tooltip
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
Flex
,
Hide
,
Show
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
...
@@ -9,7 +9,6 @@ import type { AddressFromToFilter, AddressTokenTransferResponse } from 'types/ap
...
@@ -9,7 +9,6 @@ import type { AddressFromToFilter, AddressTokenTransferResponse } from 'types/ap
import
type
{
TokenType
}
from
'
types/api/token
'
;
import
type
{
TokenType
}
from
'
types/api/token
'
;
import
type
{
TokenTransfer
}
from
'
types/api/tokenTransfer
'
;
import
type
{
TokenTransfer
}
from
'
types/api/tokenTransfer
'
;
import
crossIcon
from
'
icons/cross.svg
'
;
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
getFilterValueFromQuery
from
'
lib/getFilterValueFromQuery
'
;
import
getFilterValueFromQuery
from
'
lib/getFilterValueFromQuery
'
;
import
getFilterValuesFromQuery
from
'
lib/getFilterValuesFromQuery
'
;
import
getFilterValuesFromQuery
from
'
lib/getFilterValuesFromQuery
'
;
...
@@ -26,6 +25,7 @@ import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
...
@@ -26,6 +25,7 @@ import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import
HashStringShorten
from
'
ui/shared/HashStringShorten
'
;
import
HashStringShorten
from
'
ui/shared/HashStringShorten
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
ResetIconButton
from
'
ui/shared/ResetIconButton
'
;
import
*
as
SocketNewItemsNotice
from
'
ui/shared/SocketNewItemsNotice
'
;
import
*
as
SocketNewItemsNotice
from
'
ui/shared/SocketNewItemsNotice
'
;
import
TokenTransferFilter
from
'
ui/shared/TokenTransfer/TokenTransferFilter
'
;
import
TokenTransferFilter
from
'
ui/shared/TokenTransfer/TokenTransferFilter
'
;
import
TokenTransferList
from
'
ui/shared/TokenTransfer/TokenTransferList
'
;
import
TokenTransferList
from
'
ui/shared/TokenTransfer/TokenTransferList
'
;
...
@@ -115,9 +115,6 @@ const AddressTokenTransfers = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Pr
...
@@ -115,9 +115,6 @@ const AddressTokenTransfers = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Pr
onFilterChange
({});
onFilterChange
({});
},
[
onFilterChange
]);
},
[
onFilterChange
]);
const
resetTokenIconColor
=
useColorModeValue
(
'
blue.600
'
,
'
blue.300
'
);
const
resetTokenIconHoverColor
=
useColorModeValue
(
'
blue.400
'
,
'
blue.200
'
);
const
handleNewSocketMessage
:
SocketMessage
.
AddressTokenTransfer
[
'
handler
'
]
=
(
payload
)
=>
{
const
handleNewSocketMessage
:
SocketMessage
.
AddressTokenTransfer
[
'
handler
'
]
=
(
payload
)
=>
{
setSocketAlert
(
''
);
setSocketAlert
(
''
);
...
@@ -235,19 +232,7 @@ const AddressTokenTransfers = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Pr
...
@@ -235,19 +232,7 @@ const AddressTokenTransfers = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Pr
<
Flex
alignItems=
"center"
py=
{
1
}
>
<
Flex
alignItems=
"center"
py=
{
1
}
>
<
TokenEntity
.
Icon
token=
{
tokenData
}
isLoading=
{
isPlaceholderData
}
/>
<
TokenEntity
.
Icon
token=
{
tokenData
}
isLoading=
{
isPlaceholderData
}
/>
{
isMobile
?
<
HashStringShorten
hash=
{
tokenFilter
}
/>
:
tokenFilter
}
{
isMobile
?
<
HashStringShorten
hash=
{
tokenFilter
}
/>
:
tokenFilter
}
<
Tooltip
label=
"Reset filter"
>
<
ResetIconButton
onClick=
{
resetTokenFilter
}
/>
<
Flex
>
<
Icon
as=
{
crossIcon
}
boxSize=
{
5
}
ml=
{
1
}
color=
{
resetTokenIconColor
}
cursor=
"pointer"
_hover=
{
{
color
:
resetTokenIconHoverColor
}
}
onClick=
{
resetTokenFilter
}
/>
</
Flex
>
</
Tooltip
>
</
Flex
>
</
Flex
>
</
Flex
>
</
Flex
>
);
);
...
...
ui/address/AddressTokens.tsx
View file @
de9afb2b
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Radio
,
RadioGroup
}
from
'
@chakra-ui/react
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
...
@@ -13,18 +13,19 @@ import useIsMobile from 'lib/hooks/useIsMobile';
...
@@ -13,18 +13,19 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import
getQueryParamString
from
'
lib/router/getQueryParamString
'
;
import
getQueryParamString
from
'
lib/router/getQueryParamString
'
;
import
useSocketChannel
from
'
lib/socket/useSocketChannel
'
;
import
useSocketChannel
from
'
lib/socket/useSocketChannel
'
;
import
useSocketMessage
from
'
lib/socket/useSocketMessage
'
;
import
useSocketMessage
from
'
lib/socket/useSocketMessage
'
;
import
{
ADDRESS_TOKEN_BALANCE_ERC_
1155
,
ADDRESS_TOKEN_BALANCE_ERC_20
,
ADDRESS_TOKEN_BALANCE_ERC_721
}
from
'
stubs/address
'
;
import
{
ADDRESS_TOKEN_BALANCE_ERC_
20
,
ADDRESS_NFT_1155
,
ADDRESS_COLLECTION
}
from
'
stubs/address
'
;
import
{
generateListStub
}
from
'
stubs/utils
'
;
import
{
generateListStub
}
from
'
stubs/utils
'
;
import
{
tokenTabsByType
}
from
'
ui/pages/Address
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
RoutedTabs
from
'
ui/shared/Tabs/RoutedTabs
'
;
import
RoutedTabs
from
'
ui/shared/Tabs/RoutedTabs
'
;
import
ERC1155Tokens
from
'
./tokens/ERC1155Tokens
'
;
import
AddressCollections
from
'
./tokens/AddressCollections
'
;
import
AddressNFTs
from
'
./tokens/AddressNFTs
'
;
import
ERC20Tokens
from
'
./tokens/ERC20Tokens
'
;
import
ERC20Tokens
from
'
./tokens/ERC20Tokens
'
;
import
ERC721Tokens
from
'
./tokens/ERC721Tokens
'
;
import
TokenBalances
from
'
./tokens/TokenBalances
'
;
import
TokenBalances
from
'
./tokens/TokenBalances
'
;
type
TNftDisplayType
=
'
collection
'
|
'
list
'
;
const
TAB_LIST_PROPS
=
{
const
TAB_LIST_PROPS
=
{
marginBottom
:
0
,
marginBottom
:
0
,
py
:
5
,
py
:
5
,
...
@@ -49,6 +50,8 @@ const AddressTokens = () => {
...
@@ -49,6 +50,8 @@ const AddressTokens = () => {
const
scrollRef
=
React
.
useRef
<
HTMLDivElement
>
(
null
);
const
scrollRef
=
React
.
useRef
<
HTMLDivElement
>
(
null
);
const
[
nftDisplayType
,
setNftDisplayType
]
=
React
.
useState
<
TNftDisplayType
>
(
'
collection
'
);
const
tab
=
getQueryParamString
(
router
.
query
.
tab
);
const
tab
=
getQueryParamString
(
router
.
query
.
tab
);
const
hash
=
getQueryParamString
(
router
.
query
.
hash
);
const
hash
=
getQueryParamString
(
router
.
query
.
hash
);
...
@@ -58,30 +61,31 @@ const AddressTokens = () => {
...
@@ -58,30 +61,31 @@ const AddressTokens = () => {
filters
:
{
type
:
'
ERC-20
'
},
filters
:
{
type
:
'
ERC-20
'
},
scrollRef
,
scrollRef
,
options
:
{
options
:
{
enabled
:
!
tab
||
tab
===
'
tokens_erc20
'
,
refetchOnMount
:
false
,
refetchOnMount
:
false
,
placeholderData
:
generateListStub
<
'
address_tokens
'
>
(
ADDRESS_TOKEN_BALANCE_ERC_20
,
10
,
{
next_page_params
:
null
}),
placeholderData
:
generateListStub
<
'
address_tokens
'
>
(
ADDRESS_TOKEN_BALANCE_ERC_20
,
10
,
{
next_page_params
:
null
}),
},
},
});
});
const
erc721
Query
=
useQueryWithPages
({
const
collections
Query
=
useQueryWithPages
({
resourceName
:
'
address_
toke
ns
'
,
resourceName
:
'
address_
collectio
ns
'
,
pathParams
:
{
hash
},
pathParams
:
{
hash
},
filters
:
{
type
:
'
ERC-721
'
},
scrollRef
,
scrollRef
,
options
:
{
options
:
{
enabled
:
tab
===
'
tokens_nfts
'
&&
nftDisplayType
===
'
collection
'
,
refetchOnMount
:
false
,
refetchOnMount
:
false
,
placeholderData
:
generateListStub
<
'
address_
tokens
'
>
(
ADDRESS_TOKEN_BALANCE_ERC_721
,
10
,
{
next_page_params
:
null
}),
placeholderData
:
generateListStub
<
'
address_
collections
'
>
(
ADDRESS_COLLECTION
,
10
,
{
next_page_params
:
null
}),
},
},
});
});
const
erc1155
Query
=
useQueryWithPages
({
const
nfts
Query
=
useQueryWithPages
({
resourceName
:
'
address_
token
s
'
,
resourceName
:
'
address_
nft
s
'
,
pathParams
:
{
hash
},
pathParams
:
{
hash
},
filters
:
{
type
:
'
ERC-1155
'
},
scrollRef
,
scrollRef
,
options
:
{
options
:
{
enabled
:
tab
===
'
tokens_nfts
'
&&
nftDisplayType
===
'
list
'
,
refetchOnMount
:
false
,
refetchOnMount
:
false
,
placeholderData
:
generateListStub
<
'
address_
tokens
'
>
(
ADDRESS_TOKEN_BALANCE_ERC
_1155
,
10
,
{
next_page_params
:
null
}),
placeholderData
:
generateListStub
<
'
address_
nfts
'
>
(
ADDRESS_NFT
_1155
,
10
,
{
next_page_params
:
null
}),
},
},
});
});
...
@@ -128,7 +132,8 @@ const AddressTokens = () => {
...
@@ -128,7 +132,8 @@ const AddressTokens = () => {
const
channel
=
useSocketChannel
({
const
channel
=
useSocketChannel
({
topic
:
`addresses:
${
hash
.
toLowerCase
()
}
`
,
topic
:
`addresses:
${
hash
.
toLowerCase
()
}
`
,
isDisabled
:
erc20Query
.
isPlaceholderData
||
erc721Query
.
isPlaceholderData
||
erc1155Query
.
isPlaceholderData
,
// !!!
isDisabled
:
erc20Query
.
isPlaceholderData
||
nftsQuery
.
isPlaceholderData
||
collectionsQuery
.
isPlaceholderData
,
});
});
useSocketMessage
({
useSocketMessage
({
...
@@ -147,22 +152,43 @@ const AddressTokens = () => {
...
@@ -147,22 +152,43 @@ const AddressTokens = () => {
handler
:
handleTokenBalancesErc1155Message
,
handler
:
handleTokenBalancesErc1155Message
,
});
});
const
handleNFTsDisplayTypeChange
=
React
.
useCallback
((
val
:
TNftDisplayType
)
=>
{
setNftDisplayType
(
val
);
},
[]);
const
tabs
=
[
const
tabs
=
[
{
id
:
tokenTabsByType
[
'
ERC-20
'
],
title
:
'
ERC-20
'
,
component
:
<
ERC20Tokens
tokensQuery=
{
erc20Query
}
/>
},
{
id
:
'
tokens_erc20
'
,
title
:
'
ERC-20
'
,
component
:
<
ERC20Tokens
tokensQuery=
{
erc20Query
}
/>
},
{
id
:
tokenTabsByType
[
'
ERC-721
'
],
title
:
'
ERC-721
'
,
component
:
<
ERC721Tokens
tokensQuery=
{
erc721Query
}
/>
},
{
{
id
:
tokenTabsByType
[
'
ERC-1155
'
],
title
:
'
ERC-1155
'
,
component
:
<
ERC1155Tokens
tokensQuery=
{
erc1155Query
}
/>
},
id
:
'
tokens_nfts
'
,
title
:
'
NFTs
'
,
component
:
nftDisplayType
===
'
list
'
?
<
AddressNFTs
tokensQuery=
{
nftsQuery
}
/>
:
<
AddressCollections
collectionsQuery=
{
collectionsQuery
}
address=
{
hash
}
/>,
},
];
];
const
nftDisplayTypeRadio
=
(
<
RadioGroup
onChange=
{
handleNFTsDisplayTypeChange
}
value=
{
nftDisplayType
}
>
<
Radio
value=
"collection"
>
Collection
</
Radio
>
<
Radio
value=
"list"
>
List
</
Radio
>
</
RadioGroup
>
);
let
pagination
:
PaginationParams
|
undefined
;
let
pagination
:
PaginationParams
|
undefined
;
if
(
tab
===
tokenTabsByType
[
'
ERC-1155
'
])
{
if
(
tab
===
'
tokens_nfts
'
)
{
pagination
=
erc1155Query
.
pagination
;
pagination
=
nftDisplayType
===
'
list
'
?
nftsQuery
.
pagination
:
collectionsQuery
.
pagination
;
}
else
if
(
tab
===
tokenTabsByType
[
'
ERC-721
'
])
{
pagination
=
erc721Query
.
pagination
;
}
else
{
}
else
{
pagination
=
erc20Query
.
pagination
;
pagination
=
erc20Query
.
pagination
;
}
}
const
rightSlot
=
(
<>
{
tab
!==
'
tokens_erc20
'
&&
nftDisplayTypeRadio
}
{
pagination
.
isVisible
&&
!
isMobile
&&
<
Pagination
{
...
pagination
}
/>
}
</>
);
return
(
return
(
<>
<>
<
TokenBalances
/>
<
TokenBalances
/>
...
@@ -174,7 +200,7 @@ const AddressTokens = () => {
...
@@ -174,7 +200,7 @@ const AddressTokens = () => {
colorScheme=
"gray"
colorScheme=
"gray"
size=
"sm"
size=
"sm"
tabListProps=
{
isMobile
?
TAB_LIST_PROPS_MOBILE
:
TAB_LIST_PROPS
}
tabListProps=
{
isMobile
?
TAB_LIST_PROPS_MOBILE
:
TAB_LIST_PROPS
}
rightSlot=
{
pagination
.
isVisible
&&
!
isMobile
?
<
Pagination
{
...
pagination
}
/>
:
null
}
rightSlot=
{
rightSlot
}
stickyEnabled=
{
!
isMobile
}
stickyEnabled=
{
!
isMobile
}
/>
/>
</>
</>
...
...
ui/address/tokens/AddressCollections.tsx
0 → 100644
View file @
de9afb2b
import
{
Box
,
Flex
,
Text
,
Grid
,
HStack
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
{
route
}
from
'
nextjs-routes
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
LinkInternal
from
'
ui/shared/LinkInternal
'
;
import
NftFallback
from
'
ui/shared/nft/NftFallback
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
type
{
QueryWithPagesResult
}
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
NFTItem
from
'
./NFTItem
'
;
import
NFTItemContainer
from
'
./NFTItemContainer
'
;
type
Props
=
{
collectionsQuery
:
QueryWithPagesResult
<
'
address_collections
'
>
;
address
:
string
;
}
const
AddressCollections
=
({
collectionsQuery
,
address
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
{
isError
,
isPlaceholderData
,
data
,
pagination
}
=
collectionsQuery
;
const
actionBar
=
isMobile
&&
pagination
.
isVisible
&&
(
<
ActionBar
mt=
{
-
6
}
>
<
Pagination
ml=
"auto"
{
...
pagination
}
/>
</
ActionBar
>
);
const
content
=
data
?.
items
?
data
?.
items
.
map
((
item
,
index
)
=>
{
const
collectionUrl
=
route
({
pathname
:
'
/token/[hash]
'
,
query
:
{
hash
:
item
.
token
.
address
,
tab
:
'
inventory
'
,
holder_address_hash
:
address
,
scroll_to_tabs
:
'
true
'
,
},
});
const
hasOverload
=
Number
(
item
.
amount
)
>
item
.
token_instances
.
length
;
return
(
<
Box
key=
{
item
.
token
.
address
+
index
}
mb=
{
6
}
>
<
Flex
mb=
{
3
}
>
<
TokenEntity
width=
"auto"
noSymbol
token=
{
item
.
token
}
isLoading=
{
isPlaceholderData
}
noCopy
fontWeight=
"600"
/>
<
Skeleton
isLoaded=
{
!
isPlaceholderData
}
>
<
Text
variant=
"secondary"
whiteSpace=
"pre"
>
{
` - ${ Number(item.amount).toLocaleString() } item${ Number(item.amount) > 1 ? 's' : '' }`
}
</
Text
>
</
Skeleton
>
{
hasOverload
&&
(
<
LinkInternal
href=
{
collectionUrl
}
ml=
{
3
}
isLoading=
{
isPlaceholderData
}
>
<
Skeleton
isLoaded=
{
!
isPlaceholderData
}
>
View in collection
</
Skeleton
>
</
LinkInternal
>
)
}
</
Flex
>
<
Grid
w=
"100%"
mb=
{
7
}
columnGap=
{
{
base
:
3
,
lg
:
6
}
}
rowGap=
{
{
base
:
3
,
lg
:
6
}
}
gridTemplateColumns=
{
{
base
:
'
repeat(2, calc((100% - 12px)/2))
'
,
lg
:
'
repeat(auto-fill, minmax(210px, 1fr))
'
}
}
>
{
item
.
token_instances
.
map
((
instance
,
index
)
=>
{
const
key
=
item
.
token
.
address
+
'
_
'
+
(
instance
.
id
&&
!
isPlaceholderData
?
`id_${ instance.id }`
:
`index_${ index }`
);
return
(
<
NFTItem
key=
{
key
}
{
...
instance
}
token=
{
item
.
token
}
isLoading=
{
isPlaceholderData
}
/>
);
})
}
{
hasOverload
&&
(
<
LinkInternal
display=
"flex"
href=
{
collectionUrl
}
>
<
NFTItemContainer
display=
"flex"
alignItems=
"center"
justifyContent=
"center"
flexDirection=
"column"
minH=
"248px"
>
<
HStack
gap=
{
2
}
mb=
{
3
}
>
<
NftFallback
bgColor=
"unset"
w=
"30px"
h=
"30px"
boxSize=
"30px"
p=
{
0
}
/>
<
NftFallback
bgColor=
"unset"
w=
"30px"
h=
"30px"
boxSize=
"30px"
p=
{
0
}
/>
<
NftFallback
bgColor=
"unset"
w=
"30px"
h=
"30px"
boxSize=
"30px"
p=
{
0
}
/>
</
HStack
>
View all NFTs
</
NFTItemContainer
>
</
LinkInternal
>
)
}
</
Grid
>
</
Box
>
);
})
:
null
;
return
(
<
DataListDisplay
isError=
{
isError
}
items=
{
data
?.
items
}
emptyText=
"There are no tokens of selected type."
content=
{
content
}
actionBar=
{
actionBar
}
/>
);
};
export
default
AddressCollections
;
ui/address/tokens/
ERC1155Token
s.tsx
→
ui/address/tokens/
AddressNFT
s.tsx
View file @
de9afb2b
...
@@ -10,10 +10,10 @@ import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPage
...
@@ -10,10 +10,10 @@ import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPage
import
NFTItem
from
'
./NFTItem
'
;
import
NFTItem
from
'
./NFTItem
'
;
type
Props
=
{
type
Props
=
{
tokensQuery
:
QueryWithPagesResult
<
'
address_
token
s
'
>
;
tokensQuery
:
QueryWithPagesResult
<
'
address_
nft
s
'
>
;
}
}
const
ERC1155Token
s
=
({
tokensQuery
}:
Props
)
=>
{
const
AddressNFT
s
=
({
tokensQuery
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
const
{
isError
,
isPlaceholderData
,
data
,
pagination
}
=
tokensQuery
;
const
{
isError
,
isPlaceholderData
,
data
,
pagination
}
=
tokensQuery
;
...
@@ -32,13 +32,14 @@ const ERC1155Tokens = ({ tokensQuery }: Props) => {
...
@@ -32,13 +32,14 @@ const ERC1155Tokens = ({ tokensQuery }: Props) => {
gridTemplateColumns=
{
{
base
:
'
repeat(2, calc((100% - 12px)/2))
'
,
lg
:
'
repeat(auto-fill, minmax(210px, 1fr))
'
}
}
gridTemplateColumns=
{
{
base
:
'
repeat(2, calc((100% - 12px)/2))
'
,
lg
:
'
repeat(auto-fill, minmax(210px, 1fr))
'
}
}
>
>
{
data
.
items
.
map
((
item
,
index
)
=>
{
{
data
.
items
.
map
((
item
,
index
)
=>
{
const
key
=
item
.
token
.
address
+
'
_
'
+
(
item
.
token_instance
?.
id
&&
!
isPlaceholderData
?
`id_${ item.token_instance?
.id }`
:
`index_${ index }`
);
const
key
=
item
.
token
.
address
+
'
_
'
+
(
item
.
id
&&
!
isPlaceholderData
?
`id_${ item
.id }`
:
`index_${ index }`
);
return
(
return
(
<
NFTItem
<
NFTItem
key=
{
key
}
key=
{
key
}
{
...
item
}
{
...
item
}
isLoading=
{
isPlaceholderData
}
isLoading=
{
isPlaceholderData
}
withTokenLink
/>
/>
);
);
})
}
})
}
...
@@ -56,4 +57,4 @@ const ERC1155Tokens = ({ tokensQuery }: Props) => {
...
@@ -56,4 +57,4 @@ const ERC1155Tokens = ({ tokensQuery }: Props) => {
);
);
};
};
export
default
ERC1155Token
s
;
export
default
AddressNFT
s
;
ui/address/tokens/ERC721Tokens.tsx
deleted
100644 → 0
View file @
208183b5
import
{
Show
,
Hide
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
type
{
QueryWithPagesResult
}
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
ERC721TokensListItem
from
'
./ERC721TokensListItem
'
;
import
ERC721TokensTable
from
'
./ERC721TokensTable
'
;
type
Props
=
{
tokensQuery
:
QueryWithPagesResult
<
'
address_tokens
'
>
;
}
const
ERC721Tokens
=
({
tokensQuery
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
{
isError
,
isPlaceholderData
,
data
,
pagination
}
=
tokensQuery
;
const
actionBar
=
isMobile
&&
pagination
.
isVisible
&&
(
<
ActionBar
mt=
{
-
6
}
>
<
Pagination
ml=
"auto"
{
...
pagination
}
/>
</
ActionBar
>
);
const
content
=
data
?.
items
?
(
<>
<
Hide
below=
"lg"
ssr=
{
false
}
><
ERC721TokensTable
data=
{
data
.
items
}
isLoading=
{
isPlaceholderData
}
top=
{
pagination
.
isVisible
?
72
:
0
}
/></
Hide
>
<
Show
below=
"lg"
ssr=
{
false
}
>
{
data
.
items
.
map
((
item
,
index
)
=>
(
<
ERC721TokensListItem
key=
{
item
.
token
.
address
+
(
isPlaceholderData
?
index
:
''
)
}
{
...
item
}
isLoading=
{
isPlaceholderData
}
/>
))
}
</
Show
></>
)
:
null
;
return
(
<
DataListDisplay
isError=
{
isError
}
items=
{
data
?.
items
}
emptyText=
"There are no tokens of selected type."
content=
{
content
}
actionBar=
{
actionBar
}
/>
);
};
export
default
ERC721Tokens
;
ui/address/tokens/ERC721TokensListItem.tsx
deleted
100644 → 0
View file @
208183b5
import
{
Flex
,
HStack
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
AddressAddToWallet
from
'
ui/shared/address/AddressAddToWallet
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
TokenEntityWithAddressFilter
from
'
ui/shared/entities/token/TokenEntityWithAddressFilter
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
type
Props
=
AddressTokenBalance
&
{
isLoading
:
boolean
};
const
ERC721TokensListItem
=
({
token
,
value
,
isLoading
}:
Props
)
=>
{
const
router
=
useRouter
();
const
hash
=
router
.
query
.
hash
?.
toString
()
||
''
;
return
(
<
ListItemMobile
rowGap=
{
2
}
>
<
TokenEntityWithAddressFilter
token=
{
token
}
isLoading=
{
isLoading
}
addressHash=
{
hash
}
noCopy
jointSymbol
fontWeight=
{
700
}
/>
<
Flex
alignItems=
"center"
pl=
{
8
}
>
<
AddressEntity
address=
{
{
hash
:
token
.
address
}
}
isLoading=
{
isLoading
}
truncation=
"constant"
noIcon
/>
<
AddressAddToWallet
token=
{
token
}
ml=
{
2
}
isLoading=
{
isLoading
}
/>
</
Flex
>
<
HStack
spacing=
{
3
}
>
<
Skeleton
isLoaded=
{
!
isLoading
}
fontSize=
"sm"
fontWeight=
{
500
}
>
Quantity
</
Skeleton
>
<
Skeleton
isLoaded=
{
!
isLoading
}
fontSize=
"sm"
color=
"text_secondary"
>
<
span
>
{
value
}
</
span
>
</
Skeleton
>
</
HStack
>
</
ListItemMobile
>
);
};
export
default
ERC721TokensListItem
;
ui/address/tokens/ERC721TokensTable.tsx
deleted
100644 → 0
View file @
208183b5
import
{
Table
,
Tbody
,
Tr
,
Th
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
{
default
as
Thead
}
from
'
ui/shared/TheadSticky
'
;
import
ERC721TokensTableItem
from
'
./ERC721TokensTableItem
'
;
interface
Props
{
data
:
Array
<
AddressTokenBalance
>
;
top
:
number
;
isLoading
:
boolean
;
}
const
ERC721TokensTable
=
({
data
,
top
,
isLoading
}:
Props
)
=>
{
return
(
<
Table
variant=
"simple"
size=
"sm"
>
<
Thead
top=
{
top
}
>
<
Tr
>
<
Th
width=
"40%"
>
Asset
</
Th
>
<
Th
width=
"40%"
>
Contract address
</
Th
>
<
Th
width=
"20%"
isNumeric
>
Quantity
</
Th
>
</
Tr
>
</
Thead
>
<
Tbody
>
{
data
.
map
((
item
,
index
)
=>
(
<
ERC721TokensTableItem
key=
{
item
.
token
.
address
+
(
isLoading
?
index
:
''
)
}
{
...
item
}
isLoading=
{
isLoading
}
/>
))
}
</
Tbody
>
</
Table
>
);
};
export
default
ERC721TokensTable
;
ui/address/tokens/ERC721TokensTableItem.tsx
deleted
100644 → 0
View file @
208183b5
import
{
Tr
,
Td
,
Flex
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
type
{
AddressTokenBalance
}
from
'
types/api/address
'
;
import
AddressAddToWallet
from
'
ui/shared/address/AddressAddToWallet
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
TokenEntityWithAddressFilter
from
'
ui/shared/entities/token/TokenEntityWithAddressFilter
'
;
type
Props
=
AddressTokenBalance
&
{
isLoading
:
boolean
};
const
ERC721TokensTableItem
=
({
token
,
value
,
isLoading
,
}:
Props
)
=>
{
const
router
=
useRouter
();
const
hash
=
router
.
query
.
hash
?.
toString
()
||
''
;
return
(
<
Tr
>
<
Td
verticalAlign=
"middle"
>
<
TokenEntityWithAddressFilter
token=
{
token
}
addressHash=
{
hash
}
isLoading=
{
isLoading
}
noCopy
jointSymbol
fontWeight=
"700"
/>
</
Td
>
<
Td
verticalAlign=
"middle"
>
<
Flex
alignItems=
"center"
width=
"150px"
justifyContent=
"space-between"
>
<
AddressEntity
address=
{
{
hash
:
token
.
address
}
}
isLoading=
{
isLoading
}
noIcon
/>
<
AddressAddToWallet
token=
{
token
}
ml=
{
4
}
isLoading=
{
isLoading
}
/>
</
Flex
>
</
Td
>
<
Td
isNumeric
verticalAlign=
"middle"
>
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
{
value
}
</
Skeleton
>
</
Td
>
</
Tr
>
);
};
export
default
React
.
memo
(
ERC721TokensTableItem
);
ui/address/tokens/NFTItem.tsx
View file @
de9afb2b
import
{
Box
,
Flex
,
Text
,
Link
,
useColorModeValu
e
}
from
'
@chakra-ui/react
'
;
import
{
Tag
,
Flex
,
Text
,
Link
,
Skeleton
,
LightMod
e
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
Address
TokenBalance
}
from
'
types/api/address
'
;
import
type
{
Address
NFT
}
from
'
types/api/address
'
;
import
{
route
}
from
'
nextjs-routes
'
;
import
{
route
}
from
'
nextjs-routes
'
;
...
@@ -9,22 +9,20 @@ import NftEntity from 'ui/shared/entities/nft/NftEntity';
...
@@ -9,22 +9,20 @@ import NftEntity from 'ui/shared/entities/nft/NftEntity';
import
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
NftMedia
from
'
ui/shared/nft/NftMedia
'
;
import
NftMedia
from
'
ui/shared/nft/NftMedia
'
;
type
Props
=
AddressTokenBalance
&
{
isLoading
:
boolean
}
;
import
NFTItemContainer
from
'
./NFTItemContainer
'
;
const
NFTItem
=
({
token
,
token_id
:
tokenId
,
token_instance
:
tokenInstance
,
isLoading
}:
Props
)
=>
{
type
Props
=
AddressNFT
&
{
isLoading
:
boolean
;
withTokenLink
?:
boolean
};
const
tokenInstanceLink
=
tokenId
?
route
({
pathname
:
'
/token/[hash]/instance/[id]
'
,
query
:
{
hash
:
token
.
address
,
id
:
tokenId
}
})
:
undefined
;
const
NFTItem
=
({
token
,
value
,
isLoading
,
withTokenLink
,
...
tokenInstance
}:
Props
)
=>
{
const
tokenInstanceLink
=
tokenInstance
.
id
?
route
({
pathname
:
'
/token/[hash]/instance/[id]
'
,
query
:
{
hash
:
token
.
address
,
id
:
tokenInstance
.
id
}
})
:
undefined
;
return
(
return
(
<
Box
<
NFTItemContainer
position=
"relative"
>
w=
{
{
base
:
'
100%
'
,
lg
:
'
210px
'
}
}
<
Skeleton
isLoaded=
{
!
isLoading
}
>
border=
"1px solid"
<
LightMode
><
Tag
background=
"gray.50"
zIndex=
{
1
}
position=
"absolute"
top=
"18px"
right=
"18px"
>
{
token
.
type
}
</
Tag
></
LightMode
>
borderColor=
{
useColorModeValue
(
'
blackAlpha.100
'
,
'
whiteAlpha.200
'
)
}
</
Skeleton
>
borderRadius=
"12px"
p=
"10px"
fontSize=
"sm"
fontWeight=
{
500
}
lineHeight=
"20px"
>
<
Link
href=
{
isLoading
?
undefined
:
tokenInstanceLink
}
>
<
Link
href=
{
isLoading
?
undefined
:
tokenInstanceLink
}
>
<
NftMedia
<
NftMedia
mb=
"18px"
mb=
"18px"
...
@@ -32,19 +30,25 @@ const NFTItem = ({ token, token_id: tokenId, token_instance: tokenInstance, isLo
...
@@ -32,19 +30,25 @@ const NFTItem = ({ token, token_id: tokenId, token_instance: tokenInstance, isLo
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
/>
</
Link
>
</
Link
>
{
tokenId
&&
(
<
Flex
justifyContent=
"space-between"
w=
"100%"
>
<
Flex
m
b=
{
2
}
m
l=
{
1
}
>
<
Flex
ml=
{
1
}
>
<
Text
whiteSpace=
"pre"
variant=
"secondary"
>
ID#
</
Text
>
<
Text
whiteSpace=
"pre"
variant=
"secondary"
>
ID#
</
Text
>
<
NftEntity
hash=
{
token
.
address
}
id=
{
tokenId
}
isLoading=
{
isLoading
}
noIcon
/>
<
NftEntity
hash=
{
token
.
address
}
id=
{
tokenI
nstance
.
i
d
}
isLoading=
{
isLoading
}
noIcon
/>
</
Flex
>
</
Flex
>
<
Skeleton
isLoaded=
{
!
isLoading
}
>
{
Number
(
value
)
>
1
&&
<
Flex
><
Text
variant=
"secondary"
whiteSpace=
"pre"
>
Qty
</
Text
>
{
value
}
</
Flex
>
}
</
Skeleton
>
</
Flex
>
{
withTokenLink
&&
(
<
TokenEntity
mt=
{
2
}
token=
{
token
}
isLoading=
{
isLoading
}
noCopy
noSymbol
/>
)
}
)
}
<
TokenEntity
</
NFTItemContainer
>
token=
{
token
}
isLoading=
{
isLoading
}
noCopy
noSymbol
/>
</
Box
>
);
);
};
};
...
...
ui/address/tokens/NFTItemContainer.tsx
0 → 100644
View file @
de9afb2b
import
{
Box
,
useColorModeValue
,
chakra
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
type
Props
=
{
children
:
React
.
ReactNode
;
className
?:
string
;
};
const
NFTItem
=
({
children
,
className
}:
Props
)
=>
{
return
(
<
Box
w=
{
{
base
:
'
100%
'
,
lg
:
'
210px
'
}
}
border=
"1px solid"
borderColor=
{
useColorModeValue
(
'
blackAlpha.100
'
,
'
whiteAlpha.200
'
)
}
borderRadius=
"12px"
p=
"10px"
fontSize=
"sm"
fontWeight=
{
500
}
lineHeight=
"20px"
className=
{
className
}
>
{
children
}
</
Box
>
);
};
export
default
chakra
(
NFTItem
);
ui/pages/Address.tsx
View file @
de9afb2b
...
@@ -2,7 +2,6 @@ import { Box, Flex, HStack, Icon } from '@chakra-ui/react';
...
@@ -2,7 +2,6 @@ import { Box, Flex, HStack, Icon } from '@chakra-ui/react';
import
{
useRouter
}
from
'
next/router
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
TokenType
}
from
'
types/api/token
'
;
import
type
{
RoutedTab
}
from
'
ui/shared/Tabs/types
'
;
import
type
{
RoutedTab
}
from
'
ui/shared/Tabs/types
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
...
@@ -36,13 +35,7 @@ import PageTitle from 'ui/shared/Page/PageTitle';
...
@@ -36,13 +35,7 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import
RoutedTabs
from
'
ui/shared/Tabs/RoutedTabs
'
;
import
RoutedTabs
from
'
ui/shared/Tabs/RoutedTabs
'
;
import
TabsSkeleton
from
'
ui/shared/Tabs/TabsSkeleton
'
;
import
TabsSkeleton
from
'
ui/shared/Tabs/TabsSkeleton
'
;
export
const
tokenTabsByType
:
Record
<
TokenType
,
string
>
=
{
const
TOKEN_TABS
=
[
'
tokens_erc20
'
,
'
tokens_nfts
'
,
'
tokens_nfts_collection
'
,
'
tokens_nfts_list
'
];
'
ERC-20
'
:
'
tokens_erc20
'
,
'
ERC-721
'
:
'
tokens_erc721
'
,
'
ERC-1155
'
:
'
tokens_erc1155
'
,
}
as
const
;
const
TOKEN_TABS
=
Object
.
values
(
tokenTabsByType
);
const
AddressPageContent
=
()
=>
{
const
AddressPageContent
=
()
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
...
...
ui/pages/Token.tsx
View file @
de9afb2b
...
@@ -56,6 +56,7 @@ const TokenPageContent = () => {
...
@@ -56,6 +56,7 @@ const TokenPageContent = () => {
const
hashString
=
getQueryParamString
(
router
.
query
.
hash
);
const
hashString
=
getQueryParamString
(
router
.
query
.
hash
);
const
tab
=
getQueryParamString
(
router
.
query
.
tab
);
const
tab
=
getQueryParamString
(
router
.
query
.
tab
);
const
ownerFilter
=
getQueryParamString
(
router
.
query
.
holder_address_hash
)
||
undefined
;
const
queryClient
=
useQueryClient
();
const
queryClient
=
useQueryClient
();
...
@@ -140,6 +141,7 @@ const TokenPageContent = () => {
...
@@ -140,6 +141,7 @@ const TokenPageContent = () => {
const inventoryQuery = useQueryWithPages({
const inventoryQuery = useQueryWithPages({
resourceName: 'token_inventory',
resourceName: 'token_inventory',
pathParams: { hash: hashString },
pathParams: { hash: hashString },
filters: ownerFilter ? { holder_address_hash: ownerFilter } : {},
scrollRef,
scrollRef,
options: {
options: {
enabled: Boolean(
enabled: Boolean(
...
@@ -150,7 +152,7 @@ const TokenPageContent = () => {
...
@@ -150,7 +152,7 @@ const TokenPageContent = () => {
tab === 'inventory'
tab === 'inventory'
),
),
),
),
placeholderData: generateListStub<'token_inventory'>(tokenStubs.TOKEN_INSTANCE, 50, { next_page_params:
null
}),
placeholderData: generateListStub<'token_inventory'>(tokenStubs.TOKEN_INSTANCE, 50, { next_page_params:
{ unique_token: 1 }
}),
},
},
});
});
...
@@ -173,9 +175,11 @@ const TokenPageContent = () => {
...
@@ -173,9 +175,11 @@ const TokenPageContent = () => {
const contractTabs = useContractTabs(contractQuery.data);
const contractTabs = useContractTabs(contractQuery.data);
const tabs: Array<RoutedTab> = [
const tabs: Array<RoutedTab> = [
(tokenQuery.data?.type === 'ERC-1155' || tokenQuery.data?.type === 'ERC-721') ?
(tokenQuery.data?.type === 'ERC-1155' || tokenQuery.data?.type === 'ERC-721') ? {
{ id: 'inventory', title: 'Inventory', component: <TokenInventory inventoryQuery={ inventoryQuery } tokenQuery={ tokenQuery }/> } :
id: 'inventory',
undefined,
title: 'Inventory',
component: <TokenInventory inventoryQuery={ inventoryQuery } tokenQuery={ tokenQuery } ownerFilter={ ownerFilter }/>
} : undefined,
{ id: 'token_transfers', title: 'Token transfers', component: <TokenTransfer transfersQuery={ transfersQuery } token={ tokenQuery.data }/> },
{ id: 'token_transfers', title: 'Token transfers', component: <TokenTransfer transfersQuery={ transfersQuery } token={ tokenQuery.data }/> },
{ id: 'holders', title: 'Holders', component: <TokenHolders token={ tokenQuery.data } holdersQuery={ holdersQuery }/> },
{ id: 'holders', title: 'Holders', component: <TokenHolders token={ tokenQuery.data } holdersQuery={ holdersQuery }/> },
contractQuery.data?.is_contract ? {
contractQuery.data?.is_contract ? {
...
...
ui/shared/ResetIconButton.tsx
0 → 100644
View file @
de9afb2b
import
{
Tooltip
,
Flex
,
Icon
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
crossIcon
from
'
icons/cross.svg
'
;
type
Props
=
{
onClick
:
()
=>
void
;
}
const
ResetIconButton
=
({
onClick
}:
Props
)
=>
{
const
resetTokenIconColor
=
useColorModeValue
(
'
blue.600
'
,
'
blue.300
'
);
const
resetTokenIconHoverColor
=
useColorModeValue
(
'
blue.400
'
,
'
blue.200
'
);
return
(
<
Tooltip
label=
"Reset filter"
>
<
Flex
>
<
Icon
as=
{
crossIcon
}
boxSize=
{
5
}
ml=
{
1
}
color=
{
resetTokenIconColor
}
cursor=
"pointer"
_hover=
{
{
color
:
resetTokenIconHoverColor
}
}
onClick=
{
onClick
}
/>
</
Flex
>
</
Tooltip
>
);
};
export
default
ResetIconButton
;
ui/token/TokenInventory.tsx
View file @
de9afb2b
import
{
Grid
}
from
'
@chakra-ui/react
'
;
import
{
Flex
,
Grid
,
Text
}
from
'
@chakra-ui/react
'
;
import
type
{
UseQueryResult
}
from
'
@tanstack/react-query
'
;
import
type
{
UseQueryResult
}
from
'
@tanstack/react-query
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
...
@@ -8,23 +8,50 @@ import type { ResourceError } from 'lib/api/resources';
...
@@ -8,23 +8,50 @@ import type { ResourceError } from 'lib/api/resources';
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
type
{
QueryWithPagesResult
}
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
type
{
QueryWithPagesResult
}
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
ResetIconButton
from
'
ui/shared/ResetIconButton
'
;
import
TokenInventoryItem
from
'
./TokenInventoryItem
'
;
import
TokenInventoryItem
from
'
./TokenInventoryItem
'
;
type
Props
=
{
type
Props
=
{
inventoryQuery
:
QueryWithPagesResult
<
'
token_inventory
'
>
;
inventoryQuery
:
QueryWithPagesResult
<
'
token_inventory
'
>
;
tokenQuery
:
UseQueryResult
<
TokenInfo
,
ResourceError
<
unknown
>>
;
tokenQuery
:
UseQueryResult
<
TokenInfo
,
ResourceError
<
unknown
>>
;
ownerFilter
?:
string
;
}
}
const
TokenInventory
=
({
inventoryQuery
,
tokenQuery
}:
Props
)
=>
{
const
TokenInventory
=
({
inventoryQuery
,
tokenQuery
,
ownerFilter
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
const
actionBar
=
isMobile
&&
inventoryQuery
.
pagination
.
isVisible
&&
(
const
resetOwnerFilter
=
React
.
useCallback
(()
=>
{
<
ActionBar
mt=
{
-
6
}
>
inventoryQuery
.
onFilterChange
({});
<
Pagination
ml=
"auto"
{
...
inventoryQuery
.
pagination
}
/>
},
[
inventoryQuery
]);
</
ActionBar
>
const
isActionBarHidden
=
!
ownerFilter
&&
!
inventoryQuery
.
data
?.
items
.
length
;
const
ownerFilterComponent
=
ownerFilter
&&
(
<
Flex
alignItems=
"center"
flexWrap=
"wrap"
mb=
{
{
base
:
isActionBarHidden
?
3
:
6
,
lg
:
3
}
}
mr=
{
4
}
>
<
Text
whiteSpace=
"nowrap"
mr=
{
2
}
py=
{
1
}
>
Filtered by owner
</
Text
>
<
Flex
alignItems=
"center"
py=
{
1
}
>
<
AddressEntity
address=
{
{
hash
:
ownerFilter
}
}
truncation=
{
isMobile
?
'
constant
'
:
'
none
'
}
/>
<
ResetIconButton
onClick=
{
resetOwnerFilter
}
/>
</
Flex
>
</
Flex
>
);
const
actionBar
=
!
isActionBarHidden
&&
(
<>
{
ownerFilterComponent
}
<
ActionBar
mt=
{
-
6
}
>
{
isMobile
&&
<
Pagination
ml=
"auto"
{
...
inventoryQuery
.
pagination
}
/>
}
</
ActionBar
>
</>
);
);
const
items
=
inventoryQuery
.
data
?.
items
;
const
items
=
inventoryQuery
.
data
?.
items
;
...
...
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