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
3dc54294
Commit
3dc54294
authored
Apr 12, 2023
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add holders on token instance page
parent
4d40c441
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
64 additions
and
24 deletions
+64
-24
resources.ts
lib/api/resources.ts
+8
-1
tokenInstance.ts
mocks/tokens/tokenInstance.ts
+5
-0
Token.tsx
ui/pages/Token.tsx
+1
-1
TokenHolders.tsx
ui/token/TokenHolders/TokenHolders.tsx
+8
-8
TokenInstanceContent.tsx
ui/tokenInstance/TokenInstanceContent.tsx
+37
-9
TokenInstanceDetails.pw.tsx
ui/tokenInstance/TokenInstanceDetails.pw.tsx
+3
-3
TokenInstanceDetails.tsx
ui/tokenInstance/TokenInstanceDetails.tsx
+1
-1
TokenInstanceTransfersCount.tsx
ui/tokenInstance/details/TokenInstanceTransfersCount.tsx
+1
-1
No files found.
lib/api/resources.ts
View file @
3dc54294
...
@@ -344,6 +344,12 @@ export const RESOURCES = {
...
@@ -344,6 +344,12 @@ export const RESOURCES = {
paginationFields
:
[
'
block_number
'
as
const
,
'
items_count
'
as
const
,
'
index
'
as
const
,
'
token_id
'
as
const
],
paginationFields
:
[
'
block_number
'
as
const
,
'
items_count
'
as
const
,
'
index
'
as
const
,
'
token_id
'
as
const
],
filterFields
:
[],
filterFields
:
[],
},
},
token_instance_holders
:
{
path
:
'
/api/v2/tokens/:hash/instances/:id/holders
'
,
pathParams
:
[
'
hash
'
as
const
,
'
id
'
as
const
],
paginationFields
:
[
'
items_count
'
as
const
,
'
token_id
'
as
const
,
'
value
'
as
const
],
filterFields
:
[],
},
// HOMEPAGE
// HOMEPAGE
homepage_stats
:
{
homepage_stats
:
{
...
@@ -491,7 +497,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' |
...
@@ -491,7 +497,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' |
'
search
'
|
'
search
'
|
'
address_logs
'
|
'
address_tokens
'
|
'
address_logs
'
|
'
address_tokens
'
|
'
token_transfers
'
|
'
token_holders
'
|
'
token_inventory
'
|
'
tokens
'
|
'
token_transfers
'
|
'
token_holders
'
|
'
token_inventory
'
|
'
tokens
'
|
'
token_instance_transfers
'
|
'
token_instance_transfers
'
|
'
token_instance_holders
'
|
'
verified_contracts
'
|
'
verified_contracts
'
|
'
l2_output_roots
'
|
'
l2_withdrawals
'
|
'
l2_txn_batches
'
|
'
l2_deposits
'
|
'
l2_output_roots
'
|
'
l2_withdrawals
'
|
'
l2_txn_batches
'
|
'
l2_deposits
'
|
'
withdrawals
'
|
'
address_withdrawals
'
|
'
block_withdrawals
'
;
'
withdrawals
'
|
'
address_withdrawals
'
|
'
block_withdrawals
'
;
...
@@ -548,6 +554,7 @@ Q extends 'token_holders' ? TokenHolders :
...
@@ -548,6 +554,7 @@ Q extends 'token_holders' ? TokenHolders :
Q
extends
'
token_instance
'
?
TokenInstance
:
Q
extends
'
token_instance
'
?
TokenInstance
:
Q
extends
'
token_instance_transfers_count
'
?
TokenInstanceTransfersCount
:
Q
extends
'
token_instance_transfers_count
'
?
TokenInstanceTransfersCount
:
Q
extends
'
token_instance_transfers
'
?
TokenInstanceTransferResponse
:
Q
extends
'
token_instance_transfers
'
?
TokenInstanceTransferResponse
:
Q
extends
'
token_instance_holders
'
?
TokenHolders
:
Q
extends
'
token_inventory
'
?
TokenInventoryResponse
:
Q
extends
'
token_inventory
'
?
TokenInventoryResponse
:
Q
extends
'
tokens
'
?
TokensResponse
:
Q
extends
'
tokens
'
?
TokensResponse
:
Q
extends
'
search
'
?
SearchResult
:
Q
extends
'
search
'
?
SearchResult
:
...
...
mocks/tokens/tokenInstance.ts
View file @
3dc54294
...
@@ -179,3 +179,8 @@ export const withRichMetadata: TokenInstance = {
...
@@ -179,3 +179,8 @@ export const withRichMetadata: TokenInstance = {
status
:
null
,
status
:
null
,
},
},
};
};
export
const
unique
:
TokenInstance
=
{
...
base
,
is_unique
:
true
,
};
ui/pages/Token.tsx
View file @
3dc54294
...
@@ -138,7 +138,7 @@ const TokenPageContent = () => {
...
@@ -138,7 +138,7 @@ const TokenPageContent = () => {
const tabs: Array<RoutedTab> = [
const tabs: Array<RoutedTab> = [
{ id: 'token_transfers', title: 'Token transfers', component: <TokenTransfer transfersQuery={ transfersQuery }/> },
{ id: 'token_transfers', title: 'Token transfers', component: <TokenTransfer transfersQuery={ transfersQuery }/> },
{ id: 'holders', title: 'Holders', component: <TokenHolders token
Query={ tokenQuery
} holdersQuery={ holdersQuery }/> },
{ id: 'holders', title: 'Holders', component: <TokenHolders token
={ tokenQuery.data
} holdersQuery={ holdersQuery }/> },
(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 }/> } :
{ id: 'inventory', title: 'Inventory', component: <TokenInventory inventoryQuery={ inventoryQuery }/> } :
undefined,
undefined,
...
...
ui/token/TokenHolders/TokenHolders.tsx
View file @
3dc54294
...
@@ -14,17 +14,17 @@ import TokenHoldersList from './TokenHoldersList';
...
@@ -14,17 +14,17 @@ import TokenHoldersList from './TokenHoldersList';
import
TokenHoldersTable
from
'
./TokenHoldersTable
'
;
import
TokenHoldersTable
from
'
./TokenHoldersTable
'
;
type
Props
=
{
type
Props
=
{
token
Query
:
UseQueryResult
<
TokenInfo
>
;
token
?:
TokenInfo
;
holdersQuery
:
UseQueryResult
<
TokenHolders
>
&
{
holdersQuery
:
UseQueryResult
<
TokenHolders
>
&
{
pagination
:
PaginationProps
;
pagination
:
PaginationProps
;
isPaginationVisible
:
boolean
;
isPaginationVisible
:
boolean
;
};
};
}
}
const
TokenHoldersContent
=
({
holdersQuery
,
token
Query
}:
Props
)
=>
{
const
TokenHoldersContent
=
({
holdersQuery
,
token
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
if
(
holdersQuery
.
isError
||
tokenQuery
.
isError
)
{
if
(
holdersQuery
.
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
...
@@ -36,17 +36,17 @@ const TokenHoldersContent = ({ holdersQuery, tokenQuery }: Props) => {
...
@@ -36,17 +36,17 @@ const TokenHoldersContent = ({ holdersQuery, tokenQuery }: Props) => {
const
items
=
holdersQuery
.
data
?.
items
;
const
items
=
holdersQuery
.
data
?.
items
;
const
content
=
items
&&
token
Query
.
data
?
(
const
content
=
items
&&
token
?
(
<>
<>
{
!
isMobile
&&
<
TokenHoldersTable
data=
{
items
}
token=
{
token
Query
.
data
}
top=
{
holdersQuery
.
isPaginationVisible
?
80
:
0
}
/>
}
{
!
isMobile
&&
<
TokenHoldersTable
data=
{
items
}
token=
{
token
}
top=
{
holdersQuery
.
isPaginationVisible
?
80
:
0
}
/>
}
{
isMobile
&&
<
TokenHoldersList
data=
{
items
}
token=
{
token
Query
.
data
}
/>
}
{
isMobile
&&
<
TokenHoldersList
data=
{
items
}
token=
{
token
}
/>
}
</>
</>
)
:
null
;
)
:
null
;
return
(
return
(
<
DataListDisplay
<
DataListDisplay
isError=
{
holdersQuery
.
isError
||
tokenQuery
.
isError
}
isError=
{
holdersQuery
.
isError
}
isLoading=
{
holdersQuery
.
isLoading
||
tokenQuery
.
isLoading
}
isLoading=
{
holdersQuery
.
isLoading
}
items=
{
holdersQuery
.
data
?.
items
}
items=
{
holdersQuery
.
data
?.
items
}
skeletonProps=
{
{
skeletonDesktopColumns
:
[
'
100%
'
,
'
300px
'
,
'
175px
'
]
}
}
skeletonProps=
{
{
skeletonDesktopColumns
:
[
'
100%
'
,
'
300px
'
,
'
175px
'
]
}
}
emptyText=
"There are no holders for this token."
emptyText=
"There are no holders for this token."
...
...
ui/tokenInstance/TokenInstanceContent.tsx
View file @
3dc54294
...
@@ -14,7 +14,10 @@ import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo';
...
@@ -14,7 +14,10 @@ import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo';
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
Pagination
from
'
ui/shared/Pagination
'
;
import
Pagination
from
'
ui/shared/Pagination
'
;
import
type
{
Props
as
PaginationProps
}
from
'
ui/shared/Pagination
'
;
import
RoutedTabs
from
'
ui/shared/RoutedTabs/RoutedTabs
'
;
import
RoutedTabs
from
'
ui/shared/RoutedTabs/RoutedTabs
'
;
import
SkeletonTabs
from
'
ui/shared/skeletons/SkeletonTabs
'
;
import
TokenHolders
from
'
ui/token/TokenHolders/TokenHolders
'
;
import
TokenTransfer
from
'
ui/token/TokenTransfer/TokenTransfer
'
;
import
TokenTransfer
from
'
ui/token/TokenTransfer/TokenTransfer
'
;
import
TokenInstanceDetails
from
'
./TokenInstanceDetails
'
;
import
TokenInstanceDetails
from
'
./TokenInstanceDetails
'
;
...
@@ -50,12 +53,24 @@ const TokenInstanceContent = () => {
...
@@ -50,12 +53,24 @@ const TokenInstanceContent = () => {
},
},
});
});
const
shouldFetchHolders
=
tokenInstanceQuery
.
data
&&
!
tokenInstanceQuery
.
data
.
is_unique
;
const
holdersQuery
=
useQueryWithPages
({
resourceName
:
'
token_instance_holders
'
,
pathParams
:
{
hash
,
id
},
scrollRef
,
options
:
{
enabled
:
Boolean
(
hash
&&
(
!
tab
||
tab
===
'
holders
'
)
&&
shouldFetchHolders
),
},
});
const
tabs
:
Array
<
RoutedTab
>
=
[
const
tabs
:
Array
<
RoutedTab
>
=
[
{
id
:
'
token_transfers
'
,
title
:
'
Token transfers
'
,
component
:
<
TokenTransfer
transfersQuery=
{
transfersQuery
}
tokenId=
{
id
}
/>
},
{
id
:
'
token_transfers
'
,
title
:
'
Token transfers
'
,
component
:
<
TokenTransfer
transfersQuery=
{
transfersQuery
}
tokenId=
{
id
}
/>
},
// there is no api for this tab yet
shouldFetchHolders
?
// { id: 'holders', title: 'Holders', component: <span>Holders</span> },
{
id
:
'
holders
'
,
title
:
'
Holders
'
,
component
:
<
TokenHolders
holdersQuery=
{
holdersQuery
}
token=
{
tokenInstanceQuery
.
data
?.
token
}
/>
}
:
undefined
,
{
id
:
'
metadata
'
,
title
:
'
Metadata
'
,
component
:
<
TokenInstanceMetadata
data=
{
tokenInstanceQuery
.
data
?.
metadata
}
/>
},
{
id
:
'
metadata
'
,
title
:
'
Metadata
'
,
component
:
<
TokenInstanceMetadata
data=
{
tokenInstanceQuery
.
data
?.
metadata
}
/>
},
];
]
.
filter
(
Boolean
)
;
if
(
tokenInstanceQuery
.
isError
)
{
if
(
tokenInstanceQuery
.
isError
)
{
throw
Error
(
'
Token instance fetch failed
'
,
{
cause
:
tokenInstanceQuery
.
error
});
throw
Error
(
'
Token instance fetch failed
'
,
{
cause
:
tokenInstanceQuery
.
error
});
...
@@ -100,6 +115,17 @@ const TokenInstanceContent = () => {
...
@@ -100,6 +115,17 @@ const TokenInstanceContent = () => {
}
}
})();
})();
let
pagination
;
let
isPaginationVisible
;
if
(
tab
===
'
token_transfers
'
)
{
pagination
=
transfersQuery
.
pagination
;
isPaginationVisible
=
transfersQuery
.
isPaginationVisible
;
}
else
if
(
tab
===
'
holders
'
)
{
pagination
=
holdersQuery
.
pagination
;
isPaginationVisible
=
holdersQuery
.
isPaginationVisible
;
}
return
(
return
(
<>
<>
<
TextAd
mb=
{
6
}
/>
<
TextAd
mb=
{
6
}
/>
...
@@ -120,12 +146,14 @@ const TokenInstanceContent = () => {
...
@@ -120,12 +146,14 @@ const TokenInstanceContent = () => {
{
/* should stay before tabs to scroll up with pagination */
}
{
/* should stay before tabs to scroll up with pagination */
}
<
Box
ref=
{
scrollRef
}
></
Box
>
<
Box
ref=
{
scrollRef
}
></
Box
>
<
RoutedTabs
{
tokenInstanceQuery
.
isLoading
?
<
SkeletonTabs
/>
:
(
tabs=
{
tabs
}
<
RoutedTabs
tabListProps=
{
isMobile
?
{
mt
:
8
}
:
{
mt
:
3
,
py
:
5
,
marginBottom
:
0
}
}
tabs=
{
tabs
}
rightSlot=
{
!
isMobile
&&
transfersQuery
.
isPaginationVisible
&&
tab
!==
'
metadata
'
?
<
Pagination
{
...
transfersQuery
.
pagination
}
/>
:
null
}
tabListProps=
{
isMobile
?
{
mt
:
8
}
:
{
mt
:
3
,
py
:
5
,
marginBottom
:
0
}
}
stickyEnabled=
{
!
isMobile
}
rightSlot=
{
!
isMobile
&&
isPaginationVisible
?
<
Pagination
{
...
(
pagination
as
PaginationProps
)
}
/>
:
null
}
/>
stickyEnabled=
{
!
isMobile
}
/>
)
}
{
!
tokenInstanceQuery
.
isLoading
&&
!
tokenInstanceQuery
.
isError
&&
<
Box
h=
{
{
base
:
0
,
lg
:
'
40vh
'
}
}
/>
}
{
!
tokenInstanceQuery
.
isLoading
&&
!
tokenInstanceQuery
.
isError
&&
<
Box
h=
{
{
base
:
0
,
lg
:
'
40vh
'
}
}
/>
}
</>
</>
...
...
ui/tokenInstance/TokenInstanceDetails.pw.tsx
View file @
3dc54294
...
@@ -11,8 +11,8 @@ import TokenInstanceDetails from './TokenInstanceDetails';
...
@@ -11,8 +11,8 @@ import TokenInstanceDetails from './TokenInstanceDetails';
const
API_URL_ADDRESS
=
buildApiUrl
(
'
address
'
,
{
hash
:
tokenInstanceMock
.
base
.
token
.
address
});
const
API_URL_ADDRESS
=
buildApiUrl
(
'
address
'
,
{
hash
:
tokenInstanceMock
.
base
.
token
.
address
});
const
API_URL_TOKEN_TRANSFERS_COUNT
=
buildApiUrl
(
'
token_instance_transfers_count
'
,
{
const
API_URL_TOKEN_TRANSFERS_COUNT
=
buildApiUrl
(
'
token_instance_transfers_count
'
,
{
id
:
tokenInstanceMock
.
bas
e
.
id
,
id
:
tokenInstanceMock
.
uniqu
e
.
id
,
hash
:
tokenInstanceMock
.
bas
e
.
token
.
address
,
hash
:
tokenInstanceMock
.
uniqu
e
.
token
.
address
,
});
});
test
(
'
base view +@dark-mode +@mobile
'
,
async
({
mount
,
page
})
=>
{
test
(
'
base view +@dark-mode +@mobile
'
,
async
({
mount
,
page
})
=>
{
...
@@ -27,7 +27,7 @@ test('base view +@dark-mode +@mobile', async({ mount, page }) => {
...
@@ -27,7 +27,7 @@ test('base view +@dark-mode +@mobile', async({ mount, page }) => {
const
component
=
await
mount
(
const
component
=
await
mount
(
<
TestApp
>
<
TestApp
>
<
TokenInstanceDetails
data=
{
tokenInstanceMock
.
bas
e
}
/>
<
TokenInstanceDetails
data=
{
tokenInstanceMock
.
uniqu
e
}
/>
</
TestApp
>,
</
TestApp
>,
);
);
...
...
ui/tokenInstance/TokenInstanceDetails.tsx
View file @
3dc54294
...
@@ -60,7 +60,7 @@ const TokenInstanceDetails = ({ data, scrollRef }: Props) => {
...
@@ -60,7 +60,7 @@ const TokenInstanceDetails = ({ data, scrollRef }: Props) => {
>
>
<
TokenSnippet
hash=
{
data
.
token
.
address
}
name=
{
data
.
token
.
name
}
/>
<
TokenSnippet
hash=
{
data
.
token
.
address
}
name=
{
data
.
token
.
name
}
/>
</
DetailsInfoItem
>
</
DetailsInfoItem
>
{
data
.
owner
&&
(
{
data
.
is_unique
&&
data
.
owner
&&
(
<
DetailsInfoItem
<
DetailsInfoItem
title=
"Owner"
title=
"Owner"
hint=
"Current owner of this token instance"
hint=
"Current owner of this token instance"
...
...
ui/tokenInstance/details/TokenInstanceTransfersCount.tsx
View file @
3dc54294
...
@@ -42,7 +42,7 @@ const TokenInstanceTransfersCount = ({ hash, id, onClick }: Props) => {
...
@@ -42,7 +42,7 @@ const TokenInstanceTransfersCount = ({ hash, id, onClick }: Props) => {
href=
{
url
}
href=
{
url
}
onClick=
{
transfersCountQuery
.
data
.
transfers_count
>
0
?
onClick
:
undefined
}
onClick=
{
transfersCountQuery
.
data
.
transfers_count
>
0
?
onClick
:
undefined
}
>
>
{
transfersCountQuery
.
data
.
transfers_count
}
{
transfersCountQuery
.
data
.
transfers_count
.
toLocaleString
()
}
</
LinkInternal
>
</
LinkInternal
>
</
DetailsInfoItem
>
</
DetailsInfoItem
>
);
);
...
...
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