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
f167d80b
Commit
f167d80b
authored
Feb 09, 2023
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
inventory start
parent
68193e1b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
191 additions
and
32 deletions
+191
-32
resources.ts
lib/api/resources.ts
+9
-3
token.ts
types/api/token.ts
+25
-0
tokens.ts
types/api/tokens.ts
+1
-18
TokensWithIds.tsx
ui/address/tokens/TokensWithIds.tsx
+4
-4
Token.tsx
ui/pages/Token.tsx
+29
-7
TokenInventory.tsx
ui/token/TokenInventory.tsx
+60
-0
TokenInventoryItem.tsx
ui/token/TokenInventoryItem.tsx
+63
-0
No files found.
lib/api/resources.ts
View file @
f167d80b
...
...
@@ -24,8 +24,8 @@ import type { LogsResponseTx, LogsResponseAddress } from 'types/api/log';
import
type
{
RawTracesResponse
}
from
'
types/api/rawTrace
'
;
import
type
{
SearchResult
,
SearchResultFilters
}
from
'
types/api/search
'
;
import
type
{
Counters
,
StatsCharts
,
StatsChart
,
HomeStats
}
from
'
types/api/stats
'
;
import
type
{
TokenCounters
,
TokenInfo
,
TokenHolders
}
from
'
types/api/tokenInfo
'
;
import
type
{
TokensResponse
,
TokensFilters
,
TokenInstance
,
TokenInstanceTransfersCount
}
from
'
types/api/tokens
'
;
import
type
{
TokenCounters
,
TokenInfo
,
TokenHolders
,
TokenInventory
,
TokenInstance
,
TokenInstanceTransfersCount
}
from
'
types/api/token
'
;
import
type
{
TokensResponse
,
TokensFilters
}
from
'
types/api/tokens
'
;
import
type
{
TokenTransferResponse
,
TokenTransferFilters
}
from
'
types/api/tokenTransfer
'
;
import
type
{
TransactionsResponseValidated
,
TransactionsResponsePending
,
Transaction
}
from
'
types/api/transaction
'
;
import
type
{
TTxsFilters
}
from
'
types/api/txsFilters
'
;
...
...
@@ -230,6 +230,11 @@ export const RESOURCES = {
paginationFields
:
[
'
block_number
'
as
const
,
'
items_count
'
as
const
,
'
index
'
as
const
],
filterFields
:
[],
},
token_inventory
:
{
path
:
'
/api/v2/tokens/:hash/instances
'
,
paginationFields
:
[
'
unique_token
'
as
const
],
filterFields
:
[],
},
tokens
:
{
path
:
'
/api/v2/tokens
'
,
paginationFields
:
[
'
holder_count
'
as
const
,
'
items_count
'
as
const
,
'
name
'
as
const
],
...
...
@@ -317,7 +322,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' |
'
address_txs
'
|
'
address_internal_txs
'
|
'
address_token_transfers
'
|
'
address_blocks_validated
'
|
'
address_coin_balance
'
|
'
search
'
|
'
address_logs
'
|
'
address_tokens
'
|
'
token_transfers
'
|
'
token_holders
'
|
'
tokens
'
;
'
token_transfers
'
|
'
token_holders
'
|
'
token
_inventory
'
|
'
token
s
'
;
export
type
PaginatedResponse
<
Q
extends
PaginatedResources
>
=
ResourcePayload
<
Q
>
;
...
...
@@ -367,6 +372,7 @@ Q extends 'token_transfers' ? TokenTransferResponse :
Q
extends
'
token_holders
'
?
TokenHolders
:
Q
extends
'
token_instance
'
?
TokenInstance
:
Q
extends
'
token_instance_transfers_count
'
?
TokenInstanceTransfersCount
:
Q
extends
'
token_inventory
'
?
TokenInventory
:
Q
extends
'
tokens
'
?
TokensResponse
:
Q
extends
'
search
'
?
SearchResult
:
Q
extends
'
contract
'
?
SmartContract
:
...
...
types/api/token
Info
.ts
→
types/api/token.ts
View file @
f167d80b
...
...
@@ -34,3 +34,28 @@ export type TokenHoldersPagination = {
items_count
:
number
;
value
:
string
;
}
export
interface
TokenInstance
{
is_unique
:
boolean
;
id
:
string
;
holder_address_hash
:
string
|
null
;
image_url
:
string
|
null
;
animation_url
:
string
|
null
;
external_app_url
:
string
|
null
;
metadata
:
unknown
;
owner
:
AddressParam
;
token
:
TokenInfo
;
}
export
interface
TokenInstanceTransfersCount
{
transfers_count
:
number
;
}
export
interface
TokenInventory
{
items
:
Array
<
TokenInstance
>
;
next_page_params
:
TokenInventoryPagination
;
}
export
type
TokenInventoryPagination
=
{
unique_token
:
number
;
}
types/api/tokens.ts
View file @
f167d80b
import
type
{
AddressParam
}
from
'
./addressParams
'
;
import
type
{
TokenInfo
,
TokenType
}
from
'
./tokenInfo
'
;
import
type
{
TokenInfo
,
TokenType
}
from
'
./token
'
;
export
type
TokensResponse
=
{
items
:
Array
<
TokenInfo
>
;
...
...
@@ -11,19 +10,3 @@ export type TokensResponse = {
}
export
type
TokensFilters
=
{
filter
:
string
;
type
:
Array
<
TokenType
>
|
undefined
};
export
interface
TokenInstance
{
is_unique
:
boolean
;
id
:
string
;
holder_address_hash
:
string
|
null
;
image_url
:
string
|
null
;
animation_url
:
string
|
null
;
external_app_url
:
string
|
null
;
metadata
:
unknown
;
owner
:
AddressParam
;
token
:
TokenInfo
;
}
export
interface
TokenInstanceTransfersCount
{
transfers_count
:
number
;
}
ui/address/tokens/TokensWithIds.tsx
View file @
f167d80b
...
...
@@ -39,9 +39,9 @@ const TokensWithIds = ({ tokensQuery }: Props) => {
<>
{
bar
}
<
Flex
columnGap=
{
6
}
rowGap=
{
6
}
flexWrap=
"wrap"
>
<
Skeleton
w=
"210px"
h=
"272px"
/>
<
Skeleton
w=
"210px"
h=
"272px"
/>
<
Skeleton
w=
"210px"
h=
"272px"
/>
<
Skeleton
w=
{
{
base
:
'
calc((100% - 12px)/2)
'
,
lg
:
'
210px
'
}
}
h=
"272px"
/>
<
Skeleton
w=
{
{
base
:
'
calc((100% - 12px)/2)
'
,
lg
:
'
210px
'
}
}
h=
"272px"
/>
<
Skeleton
w=
{
{
base
:
'
calc((100% - 12px)/2)
'
,
lg
:
'
210px
'
}
}
h=
"272px"
/>
</
Flex
>
</>
);
...
...
@@ -54,7 +54,7 @@ const TokensWithIds = ({ tokensQuery }: Props) => {
return
(
<>
{
bar
}
<
Flex
columnGap=
{
{
base
:
3
,
lg
:
6
}
}
rowGap=
{
{
base
:
3
,
lg
:
6
}
}
flexWrap=
"wrap"
>
<
Flex
columnGap=
{
{
base
:
3
,
lg
:
6
}
}
rowGap=
{
{
base
:
3
,
lg
:
6
}
}
flexWrap=
"wrap"
justifyContent=
"space-between"
>
{
data
.
items
.
map
(
item
=>
<
NFTItem
key=
{
item
.
token
.
address
}
{
...
item
}
/>)
}
</
Flex
>
</>
...
...
ui/pages/Token.tsx
View file @
f167d80b
...
...
@@ -16,13 +16,15 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import
type
{
Props
as
PaginationProps
}
from
'
ui/shared/Pagination
'
;
import
Pagination
from
'
ui/shared/Pagination
'
;
import
RoutedTabs
from
'
ui/shared/RoutedTabs/RoutedTabs
'
;
import
SkeletonTabs
from
'
ui/shared/skeletons/SkeletonTabs
'
;
import
TokenLogo
from
'
ui/shared/TokenLogo
'
;
import
TokenContractInfo
from
'
ui/token/TokenContractInfo
'
;
import
TokenDetails
from
'
ui/token/TokenDetails
'
;
import
TokenHolders
from
'
ui/token/TokenHolders/TokenHolders
'
;
import
TokenInventory
from
'
ui/token/TokenInventory
'
;
import
TokenTransfer
from
'
ui/token/TokenTransfer/TokenTransfer
'
;
export
type
TokenTabs
=
'
token_transfers
'
|
'
holders
'
export
type
TokenTabs
=
'
token_transfers
'
|
'
holders
'
|
'
inventory
'
;
const
TokenPageContent
=
()
=>
{
const
router
=
useRouter
();
...
...
@@ -72,11 +74,24 @@ const TokenPageContent = () => {
},
});
const
inventoryQuery
=
useQueryWithPages
({
resourceName
:
'
token_inventory
'
,
pathParams
:
{
hash
:
router
.
query
.
hash
?.
toString
()
},
scrollRef
,
options
:
{
enabled
:
Boolean
(
router
.
query
.
hash
&&
router
.
query
.
tab
===
'
inventory
'
&&
tokenQuery
.
data
),
},
});
const
tabs
:
Array
<
RoutedTab
>
=
[
{
id
:
'
token_transfers
'
,
title
:
'
Token transfers
'
,
component
:
<
TokenTransfer
transfersQuery=
{
transfersQuery
}
token=
{
tokenQuery
.
data
}
/>
},
{
id
:
'
holders
'
,
title
:
'
Holders
'
,
component
:
<
TokenHolders
tokenQuery=
{
tokenQuery
}
holdersQuery=
{
holdersQuery
}
/>
},
];
if
(
tokenQuery
.
data
?.
type
===
'
ERC-1155
'
||
tokenQuery
.
data
?.
type
===
'
ERC-721
'
)
{
tabs
.
push
({
id
:
'
inventory
'
,
title
:
'
Inventory
'
,
component
:
<
TokenInventory
tokenQuery=
{
tokenQuery
}
inventoryQuery=
{
inventoryQuery
}
/>
});
}
let
hasPagination
;
let
pagination
;
...
...
@@ -90,6 +105,11 @@ const TokenPageContent = () => {
pagination
=
holdersQuery
.
pagination
;
}
if
(
router
.
query
.
tab
===
'
inventory
'
)
{
hasPagination
=
inventoryQuery
.
isPaginationVisible
;
pagination
=
inventoryQuery
.
pagination
;
}
const
tokenSymbolText
=
tokenQuery
.
data
?.
symbol
?
` (
${
trimTokenSymbol
(
tokenQuery
.
data
.
symbol
)
}
)`
:
''
;
return
(
...
...
@@ -118,12 +138,14 @@ const TokenPageContent = () => {
{
/* should stay before tabs to scroll up whith pagination */
}
<
Box
ref=
{
scrollRef
}
></
Box
>
<
RoutedTabs
tabs=
{
tabs
}
tabListProps=
{
isMobile
?
{
mt
:
8
}
:
{
mt
:
3
,
py
:
5
,
marginBottom
:
0
}
}
rightSlot=
{
!
isMobile
&&
hasPagination
?
<
Pagination
{
...
(
pagination
as
PaginationProps
)
}
/>
:
null
}
stickyEnabled=
{
!
isMobile
}
/>
{
tokenQuery
.
isLoading
?
<
SkeletonTabs
/>
:
(
<
RoutedTabs
tabs=
{
tabs
}
tabListProps=
{
isMobile
?
{
mt
:
8
}
:
{
mt
:
3
,
py
:
5
,
marginBottom
:
0
}
}
rightSlot=
{
!
isMobile
&&
hasPagination
?
<
Pagination
{
...
(
pagination
as
PaginationProps
)
}
/>
:
null
}
stickyEnabled=
{
!
isMobile
}
/>
)
}
</
Page
>
);
};
...
...
ui/token/TokenInventory.tsx
0 → 100644
View file @
f167d80b
import
{
Flex
,
Text
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
type
{
UseQueryResult
}
from
'
@tanstack/react-query
'
;
import
React
from
'
react
'
;
import
{
TokenInventory
}
from
'
types/api/token
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
type
{
Props
as
PaginationProps
}
from
'
ui/shared/Pagination
'
;
import
Pagination
from
'
ui/shared/Pagination
'
;
import
TokenInventoryItem
from
'
./TokenInventoryItem
'
;
type
Props
=
{
inventoryQuery
:
UseQueryResult
<
TokenInventory
>
&
{
pagination
:
PaginationProps
;
isPaginationVisible
:
boolean
;
};
}
const
TokenInventory
=
({
inventoryQuery
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
if
(
inventoryQuery
.
isError
)
{
return
<
DataFetchAlert
/>;
}
const
bar
=
isMobile
&&
inventoryQuery
.
isPaginationVisible
&&
(
<
ActionBar
mt=
{
-
6
}
>
<
Pagination
ml=
"auto"
{
...
inventoryQuery
.
pagination
}
/>
</
ActionBar
>
);
if
(
inventoryQuery
.
isLoading
)
{
return
(
<>
{
bar
}
<
Flex
columnGap=
{
{
base
:
3
,
lg
:
6
}
}
rowGap=
{
{
base
:
3
,
lg
:
6
}
}
flexWrap=
"wrap"
>
<
Skeleton
w=
{
{
base
:
'
calc((100% - 12px)/2)
'
,
lg
:
'
210px
'
}
}
h=
"272px"
/>
<
Skeleton
w=
{
{
base
:
'
calc((100% - 12px)/2)
'
,
lg
:
'
210px
'
}
}
h=
"272px"
/>
<
Skeleton
w=
{
{
base
:
'
calc((100% - 12px)/2)
'
,
lg
:
'
210px
'
}
}
h=
"272px"
/>
</
Flex
>
</>
);
}
const
items
=
inventoryQuery
.
data
.
items
;
if
(
!
items
?.
length
)
{
return
<
Text
as=
"span"
>
There are no tokens.
</
Text
>;
}
return
(
<
Flex
columnGap=
{
{
base
:
3
,
lg
:
6
}
}
rowGap=
{
{
base
:
3
,
lg
:
6
}
}
flexWrap=
"wrap"
justifyContent=
"space-between"
>
{
items
.
map
((
item
)
=>
<
TokenInventoryItem
key=
{
item
.
token
.
address
}
item=
{
item
}
/>)
}
</
Flex
>
);
};
export
default
TokenInventory
;
ui/token/TokenInventoryItem.tsx
0 → 100644
View file @
f167d80b
import
{
Flex
,
Link
,
Text
,
LinkBox
,
LinkOverlay
,
useColorModeValue
,
Hide
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
TokenInstance
}
from
'
types/api/token
'
;
import
link
from
'
lib/link/link
'
;
import
Address
from
'
ui/shared/address/Address
'
;
import
AddressIcon
from
'
ui/shared/address/AddressIcon
'
;
import
AddressLink
from
'
ui/shared/address/AddressLink
'
;
import
NftMedia
from
'
ui/shared/nft/NftMedia
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
type
Props
=
{
item
:
TokenInstance
};
const
NFTItem
=
({
item
}:
Props
)
=>
{
const
tokenLink
=
link
(
'
token_instance_item
'
,
{
hash
:
item
.
token
.
address
,
id
:
item
.
id
});
return
(
<
LinkBox
w=
{
{
base
:
'
calc((100% - 12px)/2)
'
,
lg
:
'
210px
'
}
}
border=
"1px solid"
borderColor=
{
useColorModeValue
(
'
blackAlpha.100
'
,
'
whiteAlpha.200
'
)
}
borderRadius=
"12px"
p=
"10px"
_hover=
{
{
boxShadow
:
'
md
'
}
}
fontSize=
"sm"
fontWeight=
{
500
}
lineHeight=
"20px"
>
<
LinkOverlay
href=
{
tokenLink
}
/>
<
NftMedia
mb=
"18px"
imageUrl=
{
item
.
image_url
}
animationUrl=
{
item
.
animation_url
}
/>
{
item
.
id
&&
(
<
Flex
mb=
{
2
}
ml=
{
1
}
>
<
Text
whiteSpace=
"pre"
variant=
"secondary"
>
ID#
</
Text
>
<
TruncatedTextTooltip
label=
{
item
.
id
}
>
<
Link
overflow=
"hidden"
whiteSpace=
"nowrap"
textOverflow=
"ellipsis"
>
{
item
.
id
}
</
Link
>
</
TruncatedTextTooltip
>
</
Flex
>
)
}
{
item
.
owner
&&
(
<
Flex
mb=
{
2
}
ml=
{
1
}
>
<
Text
whiteSpace=
"pre"
variant=
"secondary"
mr=
{
2
}
>
Owner
</
Text
>
<
Address
>
<
Hide
below=
"lg"
ssr=
{
false
}
><
AddressIcon
address=
{
item
.
owner
}
mr=
{
1
}
/></
Hide
>
<
AddressLink
hash=
{
item
.
owner
.
hash
}
alias=
{
item
.
owner
.
name
}
type=
"address"
truncation=
"constant"
/>
</
Address
>
</
Flex
>
)
}
</
LinkBox
>
);
};
export
default
NFTItem
;
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