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
ee3337ae
Unverified
Commit
ee3337ae
authored
May 24, 2023
by
tom goriunov
Committed by
GitHub
May 24, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #820 from blockscout/skeletons/account
skeletons: account pages
parents
360a305a
2d9c9fa3
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
473 additions
and
405 deletions
+473
-405
api_key.tsx
pages/account/api_key.tsx
+2
-1
custom_abi.tsx
pages/account/custom_abi.tsx
+3
-1
public_tags_request.tsx
pages/account/public_tags_request.tsx
+3
-1
tag_address.tsx
pages/account/tag_address.tsx
+5
-3
watchlist.tsx
pages/account/watchlist.tsx
+3
-1
account.ts
stubs/account.ts
+74
-1
account.ts
types/api/account.ts
+2
-2
ApiKeyListItem.tsx
ui/apiKey/ApiKeyTable/ApiKeyListItem.tsx
+4
-3
ApiKeyTable.tsx
ui/apiKey/ApiKeyTable/ApiKeyTable.tsx
+6
-4
ApiKeyTableItem.tsx
ui/apiKey/ApiKeyTable/ApiKeyTableItem.tsx
+4
-3
CustomAbiForm.tsx
ui/customAbi/CustomAbiModal/CustomAbiForm.tsx
+1
-1
CustomAbiListItem.tsx
ui/customAbi/CustomAbiTable/CustomAbiListItem.tsx
+4
-3
CustomAbiTable.tsx
ui/customAbi/CustomAbiTable/CustomAbiTable.tsx
+6
-4
CustomAbiTableItem.tsx
ui/customAbi/CustomAbiTable/CustomAbiTableItem.tsx
+4
-3
ApiKeys.tsx
ui/pages/ApiKeys.tsx
+39
-45
CustomAbi.tsx
ui/pages/CustomAbi.tsx
+29
-39
Watchlist.tsx
ui/pages/Watchlist.tsx
+49
-57
PrivateAddressTags.tsx
ui/privateTags/PrivateAddressTags.tsx
+26
-27
PrivateTransactionTags.tsx
ui/privateTags/PrivateTransactionTags.tsx
+29
-38
TransactionTagListItem.tsx
...rivateTags/TransactionTagTable/TransactionTagListItem.tsx
+7
-7
TransactionTagTable.tsx
ui/privateTags/TransactionTagTable/TransactionTagTable.tsx
+6
-4
TransactionTagTableItem.tsx
...ivateTags/TransactionTagTable/TransactionTagTableItem.tsx
+6
-10
PublicTagListItem.tsx
ui/publicTags/PublicTagTable/PublicTagListItem.tsx
+10
-15
PublicTagTable.tsx
ui/publicTags/PublicTagTable/PublicTagTable.tsx
+6
-4
PublicTagTableItem.tsx
ui/publicTags/PublicTagTable/PublicTagTableItem.tsx
+13
-18
PublicTagsData.tsx
ui/publicTags/PublicTagsData.tsx
+26
-37
AddressSnippet.tsx
ui/shared/AddressSnippet.tsx
+6
-2
ApiKeySnippet.tsx
ui/shared/ApiKeySnippet.tsx
+15
-6
CurrencyValue.tsx
ui/shared/CurrencyValue.tsx
+9
-2
TableItemActionButtons.tsx
ui/shared/TableItemActionButtons.tsx
+2
-2
TransactionSnippet.tsx
ui/shared/TransactionSnippet.tsx
+8
-5
WatchListAddressItem.tsx
ui/watchlist/WatchlistTable/WatchListAddressItem.tsx
+26
-19
WatchListItem.tsx
ui/watchlist/WatchlistTable/WatchListItem.tsx
+17
-15
WatchListTableItem.tsx
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
+17
-18
WatchlistTable.tsx
ui/watchlist/WatchlistTable/WatchlistTable.tsx
+6
-4
No files found.
pages/account/api_key.tsx
View file @
ee3337ae
import
type
{
NextPage
}
from
'
next
'
;
import
type
{
NextPage
}
from
'
next
'
;
import
dynamic
from
'
next/dynamic
'
;
import
Head
from
'
next/head
'
;
import
Head
from
'
next/head
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
ApiKeys
from
'
ui/pages/ApiKeys
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
const
ApiKeys
=
dynamic
(()
=>
import
(
'
ui/pages/ApiKeys
'
),
{
ssr
:
false
});
const
ApiKeysPage
:
NextPage
=
()
=>
{
const
ApiKeysPage
:
NextPage
=
()
=>
{
const
title
=
getNetworkTitle
();
const
title
=
getNetworkTitle
();
...
...
pages/account/custom_abi.tsx
View file @
ee3337ae
import
type
{
NextPage
}
from
'
next
'
;
import
type
{
NextPage
}
from
'
next
'
;
import
dynamic
from
'
next/dynamic
'
;
import
Head
from
'
next/head
'
;
import
Head
from
'
next/head
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
CustomAbi
from
'
ui/pages/CustomAbi
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
const
CustomAbi
=
dynamic
(()
=>
import
(
'
ui/pages/CustomAbi
'
),
{
ssr
:
false
});
const
CustomAbiPage
:
NextPage
=
()
=>
{
const
CustomAbiPage
:
NextPage
=
()
=>
{
const
title
=
getNetworkTitle
();
const
title
=
getNetworkTitle
();
return
(
return
(
...
...
pages/account/public_tags_request.tsx
View file @
ee3337ae
import
type
{
NextPage
}
from
'
next
'
;
import
type
{
NextPage
}
from
'
next
'
;
import
dynamic
from
'
next/dynamic
'
;
import
Head
from
'
next/head
'
;
import
Head
from
'
next/head
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
PublicTags
from
'
ui/pages/PublicTags
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
const
PublicTags
=
dynamic
(()
=>
import
(
'
ui/pages/PublicTags
'
),
{
ssr
:
false
});
const
PublicTagsPage
:
NextPage
=
()
=>
{
const
PublicTagsPage
:
NextPage
=
()
=>
{
const
title
=
getNetworkTitle
();
const
title
=
getNetworkTitle
();
return
(
return
(
...
...
pages/account/tag_address.tsx
View file @
ee3337ae
import
type
{
NextPage
}
from
'
next
'
;
import
type
{
NextPage
}
from
'
next
'
;
import
dynamic
from
'
next/dynamic
'
;
import
Head
from
'
next/head
'
;
import
Head
from
'
next/head
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
PrivateTags
from
'
ui/pages/PrivateTags
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
const
AddressTagsPage
:
NextPage
=
()
=>
{
const
PrivateTags
=
dynamic
(()
=>
import
(
'
ui/pages/PrivateTags
'
),
{
ssr
:
false
});
const
PrivateTagsPage
:
NextPage
=
()
=>
{
const
title
=
getNetworkTitle
();
const
title
=
getNetworkTitle
();
return
(
return
(
<>
<>
...
@@ -18,6 +20,6 @@ const AddressTagsPage: NextPage = () => {
...
@@ -18,6 +20,6 @@ const AddressTagsPage: NextPage = () => {
);
);
};
};
export
default
Address
TagsPage
;
export
default
Private
TagsPage
;
export
{
getServerSideProps
}
from
'
lib/next/account/getServerSideProps
'
;
export
{
getServerSideProps
}
from
'
lib/next/account/getServerSideProps
'
;
pages/account/watchlist.tsx
View file @
ee3337ae
import
type
{
NextPage
}
from
'
next
'
;
import
type
{
NextPage
}
from
'
next
'
;
import
dynamic
from
'
next/dynamic
'
;
import
Head
from
'
next/head
'
;
import
Head
from
'
next/head
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
getNetworkTitle
from
'
lib/networks/getNetworkTitle
'
;
import
WatchList
from
'
ui/pages/Watchlist
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
const
WatchList
=
dynamic
(()
=>
import
(
'
ui/pages/Watchlist
'
),
{
ssr
:
false
});
const
WatchListPage
:
NextPage
=
()
=>
{
const
WatchListPage
:
NextPage
=
()
=>
{
const
title
=
getNetworkTitle
();
const
title
=
getNetworkTitle
();
return
(
return
(
...
...
stubs/account.ts
View file @
ee3337ae
import
type
{
PublicTag
,
AddressTag
,
TransactionTag
,
ApiKey
,
CustomAbi
}
from
'
types/api/account
'
;
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
import
{
ADDRESS_PARAMS
,
ADDRESS_HASH
}
from
'
./addressParams
'
;
import
{
ADDRESS_PARAMS
,
ADDRESS_HASH
}
from
'
./addressParams
'
;
import
{
TX_HASH
}
from
'
./tx
'
;
export
const
PRIVATE_TAG_ADDRESS
=
{
export
const
PRIVATE_TAG_ADDRESS
:
AddressTag
=
{
address
:
ADDRESS_PARAMS
,
address
:
ADDRESS_PARAMS
,
address_hash
:
ADDRESS_HASH
,
address_hash
:
ADDRESS_HASH
,
id
:
'
4
'
,
id
:
'
4
'
,
name
:
'
placeholder
'
,
name
:
'
placeholder
'
,
};
};
export
const
PRIVATE_TAG_TX
:
TransactionTag
=
{
id
:
'
1
'
,
name
:
'
placeholder
'
,
transaction_hash
:
TX_HASH
,
};
export
const
PUBLIC_TAG
:
PublicTag
=
{
additional_comment
:
'
my comment
'
,
addresses
:
[
ADDRESS_HASH
],
addresses_with_info
:
[
ADDRESS_PARAMS
],
company
:
'
Blockscout
'
,
email
:
'
john.doe@example.com
'
,
full_name
:
'
name
'
,
id
:
1
,
is_owner
:
true
,
tags
:
'
placeholder
'
,
website
:
'
example.com
'
,
};
export
const
WATCH_LIST_ITEM_WITH_TOKEN_INFO
:
TWatchlistItem
=
{
address
:
ADDRESS_PARAMS
,
address_balance
:
'
7072643779453701031672
'
,
address_hash
:
ADDRESS_HASH
,
exchange_rate
:
'
0.00099052
'
,
id
:
'
18
'
,
name
:
'
placeholder
'
,
notification_methods
:
{
email
:
false
,
},
notification_settings
:
{
'
ERC-20
'
:
{
incoming
:
true
,
outcoming
:
true
,
},
'
ERC-721
'
:
{
incoming
:
true
,
outcoming
:
true
,
},
'
native
'
:
{
incoming
:
true
,
outcoming
:
true
,
},
},
tokens_count
:
42
,
};
export
const
API_KEY
:
ApiKey
=
{
api_key
:
'
9c3ecf44-a1ca-4ff1-b28e-329e8b65f652
'
,
name
:
'
placeholder
'
,
};
export
const
CUSTOM_ABI
:
CustomAbi
=
{
abi
:
[
{
constant
:
false
,
payable
:
false
,
inputs
:
[
{
name
:
'
target
'
,
type
:
'
address
'
}
],
name
:
'
unknownWriteMethod
'
,
outputs
:
[
{
name
:
'
result
'
,
type
:
'
address
'
}
],
stateMutability
:
'
nonpayable
'
,
type
:
'
function
'
,
},
],
contract_address
:
ADDRESS_PARAMS
,
contract_address_hash
:
ADDRESS_HASH
,
id
:
'
1
'
,
name
:
'
placeholder
'
,
};
types/api/account.ts
View file @
ee3337ae
...
@@ -102,7 +102,7 @@ export type CustomAbis = Array<CustomAbi>
...
@@ -102,7 +102,7 @@ export type CustomAbis = Array<CustomAbi>
export
interface
CustomAbi
{
export
interface
CustomAbi
{
name
:
string
;
name
:
string
;
id
:
number
;
id
:
string
;
contract_address_hash
:
string
;
contract_address_hash
:
string
;
contract_address
:
AddressParam
;
contract_address
:
AddressParam
;
abi
:
Array
<
AbiItem
>
;
abi
:
Array
<
AbiItem
>
;
...
@@ -119,7 +119,7 @@ export interface AbiItem {
...
@@ -119,7 +119,7 @@ export interface AbiItem {
}
}
interface
AbiInputOutput
{
interface
AbiInputOutput
{
type
:
'
uint256
'
;
type
:
'
uint256
'
|
'
address
'
;
name
:
string
;
name
:
string
;
}
}
...
...
ui/apiKey/ApiKeyTable/ApiKeyListItem.tsx
View file @
ee3337ae
...
@@ -8,11 +8,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
...
@@ -8,11 +8,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
interface
Props
{
interface
Props
{
item
:
ApiKey
;
item
:
ApiKey
;
isLoading
?:
boolean
;
onEditClick
:
(
item
:
ApiKey
)
=>
void
;
onEditClick
:
(
item
:
ApiKey
)
=>
void
;
onDeleteClick
:
(
item
:
ApiKey
)
=>
void
;
onDeleteClick
:
(
item
:
ApiKey
)
=>
void
;
}
}
const
ApiKeyListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
ApiKeyListItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
...
@@ -24,8 +25,8 @@ const ApiKeyListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -24,8 +25,8 @@ const ApiKeyListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
ListItemMobile
>
<
ListItemMobile
>
<
ApiKeySnippet
apiKey=
{
item
.
api_key
}
name=
{
item
.
name
}
/>
<
ApiKeySnippet
apiKey=
{
item
.
api_key
}
name=
{
item
.
name
}
isLoading=
{
isLoading
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
ListItemMobile
>
</
ListItemMobile
>
);
);
};
};
...
...
ui/apiKey/ApiKeyTable/ApiKeyTable.tsx
View file @
ee3337ae
...
@@ -12,13 +12,14 @@ import type { ApiKeys, ApiKey } from 'types/api/account';
...
@@ -12,13 +12,14 @@ import type { ApiKeys, ApiKey } from 'types/api/account';
import
ApiKeyTableItem
from
'
./ApiKeyTableItem
'
;
import
ApiKeyTableItem
from
'
./ApiKeyTableItem
'
;
interface
Props
{
interface
Props
{
data
:
ApiKeys
;
data
?:
ApiKeys
;
isLoading
?:
boolean
;
onEditClick
:
(
item
:
ApiKey
)
=>
void
;
onEditClick
:
(
item
:
ApiKey
)
=>
void
;
onDeleteClick
:
(
item
:
ApiKey
)
=>
void
;
onDeleteClick
:
(
item
:
ApiKey
)
=>
void
;
limit
:
number
;
limit
:
number
;
}
}
const
ApiKeyTable
=
({
data
,
onDeleteClick
,
onEditClick
,
limit
}:
Props
)
=>
{
const
ApiKeyTable
=
({
data
,
isLoading
,
onDeleteClick
,
onEditClick
,
limit
}:
Props
)
=>
{
return
(
return
(
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Thead
>
<
Thead
>
...
@@ -28,10 +29,11 @@ const ApiKeyTable = ({ data, onDeleteClick, onEditClick, limit }: Props) => {
...
@@ -28,10 +29,11 @@ const ApiKeyTable = ({ data, onDeleteClick, onEditClick, limit }: Props) => {
</
Tr
>
</
Tr
>
</
Thead
>
</
Thead
>
<
Tbody
>
<
Tbody
>
{
data
.
map
((
item
)
=>
(
{
data
?.
map
((
item
,
index
)
=>
(
<
ApiKeyTableItem
<
ApiKeyTableItem
key=
{
item
.
api_key
+
(
isLoading
?
index
:
''
)
}
item=
{
item
}
item=
{
item
}
key=
{
item
.
api_key
}
isLoading=
{
isLoading
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
...
...
ui/apiKey/ApiKeyTable/ApiKeyTableItem.tsx
View file @
ee3337ae
...
@@ -11,11 +11,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
...
@@ -11,11 +11,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
interface
Props
{
interface
Props
{
item
:
ApiKey
;
item
:
ApiKey
;
isLoading
?:
boolean
;
onEditClick
:
(
item
:
ApiKey
)
=>
void
;
onEditClick
:
(
item
:
ApiKey
)
=>
void
;
onDeleteClick
:
(
item
:
ApiKey
)
=>
void
;
onDeleteClick
:
(
item
:
ApiKey
)
=>
void
;
}
}
const
ApiKeyTableItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
ApiKeyTableItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
...
@@ -28,10 +29,10 @@ const ApiKeyTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -28,10 +29,10 @@ const ApiKeyTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
api_key
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
api_key
}
>
<
Td
>
<
Td
>
<
ApiKeySnippet
apiKey=
{
item
.
api_key
}
name=
{
item
.
name
}
/>
<
ApiKeySnippet
apiKey=
{
item
.
api_key
}
name=
{
item
.
name
}
isLoading=
{
isLoading
}
/>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/customAbi/CustomAbiModal/CustomAbiForm.tsx
View file @
ee3337ae
...
@@ -48,7 +48,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
...
@@ -48,7 +48,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
const
queryClient
=
useQueryClient
();
const
queryClient
=
useQueryClient
();
const
apiFetch
=
useApiFetch
();
const
apiFetch
=
useApiFetch
();
const
customAbiKey
=
(
data
:
Inputs
&
{
id
?:
number
})
=>
{
const
customAbiKey
=
(
data
:
Inputs
&
{
id
?:
string
})
=>
{
const
body
=
{
name
:
data
.
name
,
contract_address_hash
:
data
.
contract_address_hash
,
abi
:
data
.
abi
};
const
body
=
{
name
:
data
.
name
,
contract_address_hash
:
data
.
contract_address_hash
,
abi
:
data
.
abi
};
if
(
!
data
.
id
)
{
if
(
!
data
.
id
)
{
...
...
ui/customAbi/CustomAbiTable/CustomAbiListItem.tsx
View file @
ee3337ae
...
@@ -8,11 +8,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
...
@@ -8,11 +8,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
interface
Props
{
interface
Props
{
item
:
CustomAbi
;
item
:
CustomAbi
;
isLoading
?:
boolean
;
onEditClick
:
(
item
:
CustomAbi
)
=>
void
;
onEditClick
:
(
item
:
CustomAbi
)
=>
void
;
onDeleteClick
:
(
item
:
CustomAbi
)
=>
void
;
onDeleteClick
:
(
item
:
CustomAbi
)
=>
void
;
}
}
const
CustomAbiListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
CustomAbiListItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
...
@@ -24,8 +25,8 @@ const CustomAbiListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -24,8 +25,8 @@ const CustomAbiListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
ListItemMobile
>
<
ListItemMobile
>
<
AddressSnippet
address=
{
item
.
contract_address
}
subtitle=
{
item
.
name
}
/>
<
AddressSnippet
address=
{
item
.
contract_address
}
subtitle=
{
item
.
name
}
isLoading=
{
isLoading
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
ListItemMobile
>
</
ListItemMobile
>
);
);
};
};
...
...
ui/customAbi/CustomAbiTable/CustomAbiTable.tsx
View file @
ee3337ae
...
@@ -12,12 +12,13 @@ import type { CustomAbis, CustomAbi } from 'types/api/account';
...
@@ -12,12 +12,13 @@ import type { CustomAbis, CustomAbi } from 'types/api/account';
import
CustomAbiTableItem
from
'
./CustomAbiTableItem
'
;
import
CustomAbiTableItem
from
'
./CustomAbiTableItem
'
;
interface
Props
{
interface
Props
{
data
:
CustomAbis
;
data
?:
CustomAbis
;
isLoading
?:
boolean
;
onEditClick
:
(
item
:
CustomAbi
)
=>
void
;
onEditClick
:
(
item
:
CustomAbi
)
=>
void
;
onDeleteClick
:
(
item
:
CustomAbi
)
=>
void
;
onDeleteClick
:
(
item
:
CustomAbi
)
=>
void
;
}
}
const
CustomAbiTable
=
({
data
,
onDeleteClick
,
onEditClick
}:
Props
)
=>
{
const
CustomAbiTable
=
({
data
,
isLoading
,
onDeleteClick
,
onEditClick
}:
Props
)
=>
{
return
(
return
(
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Thead
>
<
Thead
>
...
@@ -27,10 +28,11 @@ const CustomAbiTable = ({ data, onDeleteClick, onEditClick }: Props) => {
...
@@ -27,10 +28,11 @@ const CustomAbiTable = ({ data, onDeleteClick, onEditClick }: Props) => {
</
Tr
>
</
Tr
>
</
Thead
>
</
Thead
>
<
Tbody
>
<
Tbody
>
{
data
.
map
((
item
)
=>
(
{
data
?.
map
((
item
,
index
)
=>
(
<
CustomAbiTableItem
<
CustomAbiTableItem
key=
{
item
.
id
+
(
isLoading
?
index
:
''
)
}
item=
{
item
}
item=
{
item
}
key=
{
item
.
id
}
isLoading=
{
isLoading
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
...
...
ui/customAbi/CustomAbiTable/CustomAbiTableItem.tsx
View file @
ee3337ae
...
@@ -11,11 +11,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
...
@@ -11,11 +11,12 @@ import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
interface
Props
{
interface
Props
{
item
:
CustomAbi
;
item
:
CustomAbi
;
isLoading
?:
boolean
;
onEditClick
:
(
item
:
CustomAbi
)
=>
void
;
onEditClick
:
(
item
:
CustomAbi
)
=>
void
;
onDeleteClick
:
(
item
:
CustomAbi
)
=>
void
;
onDeleteClick
:
(
item
:
CustomAbi
)
=>
void
;
}
}
const
CustomAbiTableItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
CustomAbiTableItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
...
@@ -28,10 +29,10 @@ const CustomAbiTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -28,10 +29,10 @@ const CustomAbiTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Td
>
<
Td
>
<
AddressSnippet
address=
{
item
.
contract_address
}
subtitle=
{
item
.
name
}
/>
<
AddressSnippet
address=
{
item
.
contract_address
}
subtitle=
{
item
.
name
}
isLoading=
{
isLoading
}
/>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/pages/ApiKeys.tsx
View file @
ee3337ae
import
{
Box
,
Button
,
Stack
,
Link
,
Text
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
Link
,
Text
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
ApiKey
}
from
'
types/api/account
'
;
import
type
{
ApiKey
}
from
'
types/api/account
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
{
space
}
from
'
lib/html-entities
'
;
import
{
space
}
from
'
lib/html-entities
'
;
import
{
API_KEY
}
from
'
stubs/account
'
;
import
ApiKeyModal
from
'
ui/apiKey/ApiKeyModal/ApiKeyModal
'
;
import
ApiKeyModal
from
'
ui/apiKey/ApiKeyModal/ApiKeyModal
'
;
import
ApiKeyListItem
from
'
ui/apiKey/ApiKeyTable/ApiKeyListItem
'
;
import
ApiKeyListItem
from
'
ui/apiKey/ApiKeyTable/ApiKeyListItem
'
;
import
ApiKeyTable
from
'
ui/apiKey/ApiKeyTable/ApiKeyTable
'
;
import
ApiKeyTable
from
'
ui/apiKey/ApiKeyTable/ApiKeyTable
'
;
...
@@ -14,21 +14,22 @@ import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
...
@@ -14,21 +14,22 @@ import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
SkeletonListAccount
from
'
ui/shared/skeletons/SkeletonListAccount
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
const
DATA_LIMIT
=
3
;
const
DATA_LIMIT
=
3
;
const
ApiKeysPage
:
React
.
FC
=
()
=>
{
const
ApiKeysPage
:
React
.
FC
=
()
=>
{
const
apiKeyModalProps
=
useDisclosure
();
const
apiKeyModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
useRedirectForInvalidAuthToken
();
useRedirectForInvalidAuthToken
();
const
[
apiKeyModalData
,
setApiKeyModalData
]
=
useState
<
ApiKey
>
();
const
[
apiKeyModalData
,
setApiKeyModalData
]
=
useState
<
ApiKey
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
ApiKey
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
ApiKey
>
();
const
{
data
,
isLoading
,
isError
,
error
}
=
useApiQuery
(
'
api_keys
'
);
const
{
data
,
isPlaceholderData
,
isError
,
error
}
=
useApiQuery
(
'
api_keys
'
,
{
queryOptions
:
{
placeholderData
:
Array
(
3
).
fill
(
API_KEY
),
},
});
const
onEditClick
=
useCallback
((
data
:
ApiKey
)
=>
{
const
onEditClick
=
useCallback
((
data
:
ApiKey
)
=>
{
setApiKeyModalData
(
data
);
setApiKeyModalData
(
data
);
...
@@ -58,22 +59,6 @@ const ApiKeysPage: React.FC = () => {
...
@@ -58,22 +59,6 @@ const ApiKeysPage: React.FC = () => {
);
);
const
content
=
(()
=>
{
const
content
=
(()
=>
{
if
(
isLoading
&&
!
data
)
{
const
loader
=
isMobile
?
<
SkeletonListAccount
/>
:
(
<>
<
SkeletonTable
columns=
{
[
'
100%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"48px"
width=
"156px"
marginTop=
{
8
}
/>
</>
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
if
(
isError
)
{
if
(
isError
)
{
if
(
error
.
status
===
403
)
{
if
(
error
.
status
===
403
)
{
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
...
@@ -81,50 +66,59 @@ const ApiKeysPage: React.FC = () => {
...
@@ -81,50 +66,59 @@ const ApiKeysPage: React.FC = () => {
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
list
=
isMobile
?
(
const
list
=
(
<
Box
>
<>
{
data
.
map
((
item
)
=>
(
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
<
ApiKeyListItem
{
data
?.
map
((
item
,
index
)
=>
(
item=
{
item
}
<
ApiKeyListItem
key=
{
item
.
api_key
}
key=
{
item
.
api_key
+
(
isPlaceholderData
?
index
:
''
)
}
item=
{
item
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
))
}
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
ApiKeyTable
data=
{
data
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
limit=
{
DATA_LIMIT
}
/>
/>
))
}
</
Box
>
</
Box
>
</>
)
:
(
<
ApiKeyTable
data=
{
data
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
limit=
{
DATA_LIMIT
}
/>
);
);
const
canAdd
=
data
.
length
<
DATA_LIMIT
;
const
canAdd
=
!
isPlaceholderData
?
(
data
?.
length
||
0
)
<
DATA_LIMIT
:
true
;
return
(
return
(
<>
<>
{
description
}
{
description
}
{
Boolean
(
data
.
length
)
&&
list
}
{
Boolean
(
data
?
.
length
)
&&
list
}
<
S
tack
<
S
keleton
marginTop=
{
8
}
marginTop=
{
8
}
spacing=
{
5
}
flexDir=
{
{
base
:
'
column
'
,
lg
:
'
row
'
}
}
direction=
{
{
base
:
'
column
'
,
lg
:
'
row
'
}
}
alignItems=
{
{
base
:
'
start
'
,
lg
:
'
center
'
}
}
align=
{
{
base
:
'
start
'
,
lg
:
'
center
'
}
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-flex"
columnGap=
{
5
}
rowGap=
{
5
}
>
>
<
Button
<
Button
size=
"lg"
size=
"lg"
onClick=
{
apiKeyModalProps
.
onOpen
}
onClick=
{
apiKeyModalProps
.
onOpen
}
isDisabled=
{
!
canAdd
}
isDisabled=
{
!
canAdd
}
>
>
Add API key
Add API key
</
Button
>
</
Button
>
{
!
canAdd
&&
(
{
!
canAdd
&&
(
<
Text
fontSize=
"sm"
variant=
"secondary"
>
<
Text
fontSize=
"sm"
variant=
"secondary"
>
{
`You have added the maximum number of API keys (${ DATA_LIMIT }). Contact us to request additional keys.`
}
{
`You have added the maximum number of API keys (${ DATA_LIMIT }). Contact us to request additional keys.`
}
</
Text
>
</
Text
>
)
}
)
}
</
S
tack
>
</
S
keleton
>
<
ApiKeyModal
{
...
apiKeyModalProps
}
onClose=
{
onApiKeyModalClose
}
data=
{
apiKeyModalData
}
/>
<
ApiKeyModal
{
...
apiKeyModalProps
}
onClose=
{
onApiKeyModalClose
}
data=
{
apiKeyModalData
}
/>
{
deleteModalData
&&
<
DeleteApiKeyModal
{
...
deleteModalProps
}
onClose=
{
onDeleteModalClose
}
data=
{
deleteModalData
}
/>
}
{
deleteModalData
&&
<
DeleteApiKeyModal
{
...
deleteModalProps
}
onClose=
{
onDeleteModalClose
}
data=
{
deleteModalData
}
/>
}
</>
</>
...
...
ui/pages/CustomAbi.tsx
View file @
ee3337ae
import
{
Box
,
Button
,
HStack
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
CustomAbi
}
from
'
types/api/account
'
;
import
type
{
CustomAbi
}
from
'
types/api/account
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
{
CUSTOM_ABI
}
from
'
stubs/account
'
;
import
CustomAbiModal
from
'
ui/customAbi/CustomAbiModal/CustomAbiModal
'
;
import
CustomAbiModal
from
'
ui/customAbi/CustomAbiModal/CustomAbiModal
'
;
import
CustomAbiListItem
from
'
ui/customAbi/CustomAbiTable/CustomAbiListItem
'
;
import
CustomAbiListItem
from
'
ui/customAbi/CustomAbiTable/CustomAbiListItem
'
;
import
CustomAbiTable
from
'
ui/customAbi/CustomAbiTable/CustomAbiTable
'
;
import
CustomAbiTable
from
'
ui/customAbi/CustomAbiTable/CustomAbiTable
'
;
...
@@ -13,19 +13,20 @@ import DeleteCustomAbiModal from 'ui/customAbi/DeleteCustomAbiModal';
...
@@ -13,19 +13,20 @@ import DeleteCustomAbiModal from 'ui/customAbi/DeleteCustomAbiModal';
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
SkeletonListAccount
from
'
ui/shared/skeletons/SkeletonListAccount
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
const
CustomAbiPage
:
React
.
FC
=
()
=>
{
const
CustomAbiPage
:
React
.
FC
=
()
=>
{
const
customAbiModalProps
=
useDisclosure
();
const
customAbiModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
useRedirectForInvalidAuthToken
();
useRedirectForInvalidAuthToken
();
const
[
customAbiModalData
,
setCustomAbiModalData
]
=
useState
<
CustomAbi
>
();
const
[
customAbiModalData
,
setCustomAbiModalData
]
=
useState
<
CustomAbi
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
CustomAbi
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
CustomAbi
>
();
const
{
data
,
isLoading
,
isError
,
error
}
=
useApiQuery
(
'
custom_abi
'
);
const
{
data
,
isPlaceholderData
,
isError
,
error
}
=
useApiQuery
(
'
custom_abi
'
,
{
queryOptions
:
{
placeholderData
:
Array
(
3
).
fill
(
CUSTOM_ABI
),
},
});
const
onEditClick
=
useCallback
((
data
:
CustomAbi
)
=>
{
const
onEditClick
=
useCallback
((
data
:
CustomAbi
)
=>
{
setCustomAbiModalData
(
data
);
setCustomAbiModalData
(
data
);
...
@@ -54,22 +55,6 @@ const CustomAbiPage: React.FC = () => {
...
@@ -54,22 +55,6 @@ const CustomAbiPage: React.FC = () => {
);
);
const
content
=
(()
=>
{
const
content
=
(()
=>
{
if
(
isLoading
&&
!
data
)
{
const
loader
=
isMobile
?
<
SkeletonListAccount
/>
:
(
<>
<
SkeletonTable
columns=
{
[
'
100%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
</>
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
if
(
isError
)
{
if
(
isError
)
{
if
(
error
.
status
===
403
)
{
if
(
error
.
status
===
403
)
{
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
...
@@ -77,37 +62,42 @@ const CustomAbiPage: React.FC = () => {
...
@@ -77,37 +62,42 @@ const CustomAbiPage: React.FC = () => {
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
list
=
isMobile
?
(
const
list
=
(
<
Box
>
<>
{
data
.
map
((
item
)
=>
(
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
<
CustomAbiListItem
{
data
?.
map
((
item
,
index
)
=>
(
item=
{
item
}
<
CustomAbiListItem
key=
{
item
.
id
}
key=
{
item
.
id
+
(
isPlaceholderData
?
index
:
''
)
}
item=
{
item
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
))
}
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
CustomAbiTable
data=
{
data
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
))
}
</
Box
>
</
Box
>
</>
)
:
(
<
CustomAbiTable
data=
{
data
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
);
return
(
return
(
<>
<>
{
description
}
{
description
}
{
data
.
length
>
0
&&
list
}
{
Boolean
(
data
?.
length
)
&&
list
}
<
HStack
marginTop=
{
8
}
spacing=
{
5
}
>
<
Skeleton
mt=
{
8
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Button
<
Button
size=
"lg"
size=
"lg"
onClick=
{
customAbiModalProps
.
onOpen
}
onClick=
{
customAbiModalProps
.
onOpen
}
>
>
Add custom ABI
Add custom ABI
</
Button
>
</
Button
>
</
HStack
>
</
Skeleton
>
<
CustomAbiModal
{
...
customAbiModalProps
}
onClose=
{
onCustomAbiModalClose
}
data=
{
customAbiModalData
}
/>
<
CustomAbiModal
{
...
customAbiModalProps
}
onClose=
{
onCustomAbiModalClose
}
data=
{
customAbiModalData
}
/>
{
deleteModalData
&&
<
DeleteCustomAbiModal
{
...
deleteModalProps
}
onClose=
{
onDeleteModalClose
}
data=
{
deleteModalData
}
/>
}
{
deleteModalData
&&
<
DeleteCustomAbiModal
{
...
deleteModalProps
}
onClose=
{
onDeleteModalClose
}
data=
{
deleteModalData
}
/>
}
</>
</>
...
...
ui/pages/Watchlist.tsx
View file @
ee3337ae
...
@@ -8,13 +8,11 @@ import type { TWatchlist, TWatchlistItem } from 'types/client/account';
...
@@ -8,13 +8,11 @@ import type { TWatchlist, TWatchlistItem } from 'types/client/account';
import
type
{
ResourceError
}
from
'
lib/api/resources
'
;
import
type
{
ResourceError
}
from
'
lib/api/resources
'
;
import
{
resourceKey
}
from
'
lib/api/resources
'
;
import
{
resourceKey
}
from
'
lib/api/resources
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
useRedirectForInvalidAuthToken
from
'
lib/hooks/useRedirectForInvalidAuthToken
'
;
import
{
WATCH_LIST_ITEM_WITH_TOKEN_INFO
}
from
'
stubs/account
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
SkeletonListAccount
from
'
ui/shared/skeletons/SkeletonListAccount
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
import
AddressModal
from
'
ui/watchlist/AddressModal/AddressModal
'
;
import
AddressModal
from
'
ui/watchlist/AddressModal/AddressModal
'
;
import
DeleteAddressModal
from
'
ui/watchlist/DeleteAddressModal
'
;
import
DeleteAddressModal
from
'
ui/watchlist/DeleteAddressModal
'
;
import
WatchListItem
from
'
ui/watchlist/WatchlistTable/WatchListItem
'
;
import
WatchListItem
from
'
ui/watchlist/WatchlistTable/WatchListItem
'
;
...
@@ -22,33 +20,38 @@ import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable';
...
@@ -22,33 +20,38 @@ import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable';
const
WatchList
:
React
.
FC
=
()
=>
{
const
WatchList
:
React
.
FC
=
()
=>
{
const
apiFetch
=
useApiFetch
();
const
apiFetch
=
useApiFetch
();
const
{
data
,
isLoading
,
isError
,
error
}
=
useQuery
<
unknown
,
ResourceError
,
TWatchlist
>
([
resourceKey
(
'
watchlist
'
)
],
async
()
=>
{
const
{
data
,
isPlaceholderData
,
isError
,
error
}
=
useQuery
<
unknown
,
ResourceError
,
TWatchlist
>
(
const
watchlistAddresses
=
await
apiFetch
<
'
watchlist
'
,
Array
<
WatchlistAddress
>>
(
'
watchlist
'
);
[
resourceKey
(
'
watchlist
'
)
],
async
()
=>
{
const
watchlistAddresses
=
await
apiFetch
<
'
watchlist
'
,
Array
<
WatchlistAddress
>>
(
'
watchlist
'
);
if
(
!
Array
.
isArray
(
watchlistAddresses
))
{
if
(
!
Array
.
isArray
(
watchlistAddresses
))
{
return
;
return
;
}
const
watchlistTokens
=
await
Promise
.
all
(
watchlistAddresses
.
map
(({
address
})
=>
{
if
(
!
address
?.
hash
)
{
return
Promise
.
resolve
(
0
);
}
}
return
apiFetch
<
'
old_api
'
,
WatchlistTokensResponse
>
(
'
old_api
'
,
{
queryParams
:
{
address
:
address
.
hash
,
module
:
'
account
'
,
action
:
'
tokenlist
'
}
})
.
then
((
response
)
=>
{
const
watchlistTokens
=
await
Promise
.
all
(
watchlistAddresses
.
map
(({
address
})
=>
{
if
(
'
result
'
in
response
&&
Array
.
isArray
(
response
.
result
))
{
if
(
!
address
?.
hash
)
{
return
response
.
result
.
length
;
return
Promise
.
resolve
(
0
);
}
}
return
0
;
return
apiFetch
<
'
old_api
'
,
WatchlistTokensResponse
>
(
'
old_api
'
,
{
queryParams
:
{
address
:
address
.
hash
,
module
:
'
account
'
,
action
:
'
tokenlist
'
}
})
});
.
then
((
response
)
=>
{
}));
if
(
'
result
'
in
response
&&
Array
.
isArray
(
response
.
result
))
{
return
response
.
result
.
length
;
return
watchlistAddresses
.
map
((
item
,
index
)
=>
({
...
item
,
tokens_count
:
watchlistTokens
[
index
]
}));
}
});
return
0
;
});
}));
return
watchlistAddresses
.
map
((
item
,
index
)
=>
({
...
item
,
tokens_count
:
watchlistTokens
[
index
]
}));
},
{
placeholderData
:
Array
(
3
).
fill
(
WATCH_LIST_ITEM_WITH_TOKEN_INFO
),
},
);
const
queryClient
=
useQueryClient
();
const
queryClient
=
useQueryClient
();
const
addressModalProps
=
useDisclosure
();
const
addressModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
useRedirectForInvalidAuthToken
();
useRedirectForInvalidAuthToken
();
const
[
addressModalData
,
setAddressModalData
]
=
useState
<
TWatchlistItem
>
();
const
[
addressModalData
,
setAddressModalData
]
=
useState
<
TWatchlistItem
>
();
...
@@ -100,53 +103,42 @@ const WatchList: React.FC = () => {
...
@@ -100,53 +103,42 @@ const WatchList: React.FC = () => {
}
}
const
content
=
(()
=>
{
const
content
=
(()
=>
{
if
(
isLoading
&&
!
data
)
{
const
list
=
(
const
loader
=
isMobile
?
<
SkeletonListAccount
showFooterSlot
/>
:
(
<>
<>
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
<
SkeletonTable
columns=
{
[
'
70%
'
,
'
30%
'
,
'
160px
'
,
'
108px
'
]
}
/>
{
data
?.
map
((
item
,
index
)
=>
(
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
<
WatchListItem
</>
key=
{
item
.
address_hash
+
(
isPlaceholderData
?
index
:
''
)
}
);
item=
{
item
}
isLoading=
{
isPlaceholderData
}
return
(
onDeleteClick=
{
onDeleteClick
}
<>
onEditClick=
{
onEditClick
}
{
description
}
/>
{
loader
}
))
}
</>
</
Box
>
);
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
}
<
WatchlistTable
data=
{
data
}
const
list
=
isMobile
?
(
isLoading=
{
isPlaceholderData
}
<
Box
>
{
data
.
map
((
item
)
=>
(
<
WatchListItem
item=
{
item
}
key=
{
item
.
address_hash
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
))
}
</
Box
>
</
Box
>
</>
)
:
(
<
WatchlistTable
data=
{
data
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
);
return
(
return
(
<>
<>
{
description
}
{
description
}
{
Boolean
(
data
?.
length
)
&&
list
}
{
Boolean
(
data
?.
length
)
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Skeleton
mt=
{
8
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Button
<
Button
size=
"lg"
size=
"lg"
onClick=
{
addressModalProps
.
onOpen
}
onClick=
{
addressModalProps
.
onOpen
}
>
>
Add address
Add address
</
Button
>
</
Button
>
</
Box
>
</
Skeleton
>
<
AddressModal
<
AddressModal
{
...
addressModalProps
}
{
...
addressModalProps
}
onClose=
{
onAddressModalClose
}
onClose=
{
onAddressModalClose
}
...
...
ui/privateTags/PrivateAddressTags.tsx
View file @
ee3337ae
...
@@ -4,7 +4,6 @@ import React, { useCallback, useState } from 'react';
...
@@ -4,7 +4,6 @@ import React, { useCallback, useState } from 'react';
import
type
{
AddressTag
}
from
'
types/api/account
'
;
import
type
{
AddressTag
}
from
'
types/api/account
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
PRIVATE_TAG_ADDRESS
}
from
'
stubs/account
'
;
import
{
PRIVATE_TAG_ADDRESS
}
from
'
stubs/account
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
...
@@ -24,7 +23,6 @@ const PrivateAddressTags = () => {
...
@@ -24,7 +23,6 @@ const PrivateAddressTags = () => {
const
addressModalProps
=
useDisclosure
();
const
addressModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
const
[
addressModalData
,
setAddressModalData
]
=
useState
<
AddressTag
>
();
const
[
addressModalData
,
setAddressModalData
]
=
useState
<
AddressTag
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
AddressTag
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
AddressTag
>
();
...
@@ -60,25 +58,28 @@ const PrivateAddressTags = () => {
...
@@ -60,25 +58,28 @@ const PrivateAddressTags = () => {
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
list
=
isMobile
?
(
const
list
=
(
<
Box
>
<>
{
addressTagsData
?.
map
((
item
:
AddressTag
,
index
:
number
)
=>
(
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
<
AddressTagListItem
{
addressTagsData
?.
map
((
item
:
AddressTag
,
index
:
number
)
=>
(
item=
{
item
}
<
AddressTagListItem
key=
{
item
.
id
+
(
isPlaceholderData
?
index
:
''
)
}
item=
{
item
}
key=
{
item
.
id
+
(
isPlaceholderData
?
index
:
''
)
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
isLoading=
{
isPlaceholderData
}
/>
))
}
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
AddressTagTable
isLoading=
{
isPlaceholderData
}
data=
{
addressTagsData
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
isLoading=
{
isPlaceholderData
}
/>
/>
))
}
</
Box
>
</
Box
>
</>
)
:
(
<
AddressTagTable
isLoading=
{
isPlaceholderData
}
data=
{
addressTagsData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
);
return
(
return
(
...
@@ -88,16 +89,14 @@ const PrivateAddressTags = () => {
...
@@ -88,16 +89,14 @@ const PrivateAddressTags = () => {
Private tags are saved in your account and are only visible when you are logged in.
Private tags are saved in your account and are only visible when you are logged in.
</
AccountPageDescription
>
</
AccountPageDescription
>
{
Boolean
(
addressTagsData
?.
length
)
&&
list
}
{
Boolean
(
addressTagsData
?.
length
)
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Skeleton
mt=
{
8
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Skeleton
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Button
<
Button
size=
"lg"
size=
"lg"
onClick=
{
addressModalProps
.
onOpen
}
onClick=
{
addressModalProps
.
onOpen
}
>
>
Add address tag
Add address tag
</
Button
>
</
Button
>
</
Skeleton
>
</
Skeleton
>
</
Box
>
<
AddressModal
{
...
addressModalProps
}
onClose=
{
onAddressModalClose
}
data=
{
addressModalData
}
onSuccess=
{
onAddOrEditSuccess
}
/>
<
AddressModal
{
...
addressModalProps
}
onClose=
{
onAddressModalClose
}
data=
{
addressModalData
}
onSuccess=
{
onAddOrEditSuccess
}
/>
{
deleteModalData
&&
(
{
deleteModalData
&&
(
<
DeletePrivateTagModal
<
DeletePrivateTagModal
...
...
ui/privateTags/PrivateTransactionTags.tsx
View file @
ee3337ae
...
@@ -4,11 +4,9 @@ import React, { useCallback, useState } from 'react';
...
@@ -4,11 +4,9 @@ import React, { useCallback, useState } from 'react';
import
type
{
TransactionTag
}
from
'
types/api/account
'
;
import
type
{
TransactionTag
}
from
'
types/api/account
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
PRIVATE_TAG_TX
}
from
'
stubs/account
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
SkeletonListAccount
from
'
ui/shared/skeletons/SkeletonListAccount
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
import
DeletePrivateTagModal
from
'
./DeletePrivateTagModal
'
;
import
DeletePrivateTagModal
from
'
./DeletePrivateTagModal
'
;
import
TransactionModal
from
'
./TransactionModal/TransactionModal
'
;
import
TransactionModal
from
'
./TransactionModal/TransactionModal
'
;
...
@@ -16,11 +14,15 @@ import TransactionTagListItem from './TransactionTagTable/TransactionTagListItem
...
@@ -16,11 +14,15 @@ import TransactionTagListItem from './TransactionTagTable/TransactionTagListItem
import
TransactionTagTable
from
'
./TransactionTagTable/TransactionTagTable
'
;
import
TransactionTagTable
from
'
./TransactionTagTable/TransactionTagTable
'
;
const
PrivateTransactionTags
=
()
=>
{
const
PrivateTransactionTags
=
()
=>
{
const
{
data
:
transactionTagsData
,
isLoading
,
isError
,
error
}
=
useApiQuery
(
'
private_tags_tx
'
,
{
queryOptions
:
{
refetchOnMount
:
false
}
});
const
{
data
:
transactionTagsData
,
isPlaceholderData
,
isError
,
error
}
=
useApiQuery
(
'
private_tags_tx
'
,
{
queryOptions
:
{
refetchOnMount
:
false
,
placeholderData
:
Array
(
3
).
fill
(
PRIVATE_TAG_TX
),
},
});
const
transactionModalProps
=
useDisclosure
();
const
transactionModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
const
[
transactionModalData
,
setTransactionModalData
]
=
useState
<
TransactionTag
>
();
const
[
transactionModalData
,
setTransactionModalData
]
=
useState
<
TransactionTag
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
TransactionTag
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
TransactionTag
>
();
...
@@ -52,22 +54,6 @@ const PrivateTransactionTags = () => {
...
@@ -52,22 +54,6 @@ const PrivateTransactionTags = () => {
</
AccountPageDescription
>
</
AccountPageDescription
>
);
);
if
(
isLoading
&&
!
transactionTagsData
)
{
const
loader
=
isMobile
?
<
SkeletonListAccount
/>
:
(
<>
<
SkeletonTable
columns=
{
[
'
75%
'
,
'
25%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
</>
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
if
(
isError
)
{
if
(
isError
)
{
if
(
error
.
status
===
403
)
{
if
(
error
.
status
===
403
)
{
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
...
@@ -75,37 +61,42 @@ const PrivateTransactionTags = () => {
...
@@ -75,37 +61,42 @@ const PrivateTransactionTags = () => {
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
list
=
isMobile
?
(
const
list
=
(
<
Box
>
<>
{
transactionTagsData
.
map
((
item
)
=>
(
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
<
TransactionTagListItem
{
transactionTagsData
?.
map
((
item
,
index
)
=>
(
item=
{
item
}
<
TransactionTagListItem
key=
{
item
.
id
}
key=
{
item
.
id
+
(
isPlaceholderData
?
index
:
''
)
}
item=
{
item
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
))
}
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
TransactionTagTable
data=
{
transactionTagsData
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
))
}
</
Box
>
</
Box
>
</>
)
:
(
<
TransactionTagTable
data=
{
transactionTagsData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
);
return
(
return
(
<>
<>
{
description
}
{
description
}
{
Boolean
(
transactionTagsData
.
length
)
&&
list
}
{
Boolean
(
transactionTagsData
?
.
length
)
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Skeleton
mt=
{
8
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Button
<
Button
size=
"lg"
size=
"lg"
onClick=
{
transactionModalProps
.
onOpen
}
onClick=
{
transactionModalProps
.
onOpen
}
>
>
Add transaction tag
Add transaction tag
</
Button
>
</
Button
>
</
Box
>
</
Skeleton
>
<
TransactionModal
{
...
transactionModalProps
}
onClose=
{
onAddressModalClose
}
data=
{
transactionModalData
}
/>
<
TransactionModal
{
...
transactionModalProps
}
onClose=
{
onAddressModalClose
}
data=
{
transactionModalData
}
/>
{
deleteModalData
&&
(
{
deleteModalData
&&
(
<
DeletePrivateTagModal
<
DeletePrivateTagModal
...
...
ui/privateTags/TransactionTagTable/TransactionTagListItem.tsx
View file @
ee3337ae
import
{
Tag
,
HStack
,
Text
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
HStack
,
Text
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
TransactionTag
}
from
'
types/api/account
'
;
import
type
{
TransactionTag
}
from
'
types/api/account
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TransactionSnippet
from
'
ui/shared/TransactionSnippet
'
;
import
TransactionSnippet
from
'
ui/shared/TransactionSnippet
'
;
interface
Props
{
interface
Props
{
item
:
TransactionTag
;
item
:
TransactionTag
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
TransactionTag
)
=>
void
;
onEditClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
}
}
const
TransactionTagListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
TransactionTagListItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
},
[
item
,
onEditClick
]);
...
@@ -25,15 +27,13 @@ const TransactionTagListItem = ({ item, onEditClick, onDeleteClick }: Props) =>
...
@@ -25,15 +27,13 @@ const TransactionTagListItem = ({ item, onEditClick, onDeleteClick }: Props) =>
return
(
return
(
<
ListItemMobile
>
<
ListItemMobile
>
<
Flex
alignItems=
"flex-start"
flexDirection=
"column"
maxW=
"100%"
>
<
Flex
alignItems=
"flex-start"
flexDirection=
"column"
maxW=
"100%"
>
<
TransactionSnippet
hash=
{
item
.
transaction_hash
}
/>
<
TransactionSnippet
hash=
{
item
.
transaction_hash
}
isLoading=
{
isLoading
}
/>
<
HStack
spacing=
{
3
}
mt=
{
4
}
>
<
HStack
spacing=
{
3
}
mt=
{
4
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Tag
>
<
Tag
isLoading=
{
isLoading
}
isTruncated
>
{
item
.
name
}
</
Tag
>
{
item
.
name
}
</
Tag
>
</
HStack
>
</
HStack
>
</
Flex
>
</
Flex
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
ListItemMobile
>
</
ListItemMobile
>
);
);
};
};
...
...
ui/privateTags/TransactionTagTable/TransactionTagTable.tsx
View file @
ee3337ae
...
@@ -12,12 +12,13 @@ import type { TransactionTags, TransactionTag } from 'types/api/account';
...
@@ -12,12 +12,13 @@ import type { TransactionTags, TransactionTag } from 'types/api/account';
import
TransactionTagTableItem
from
'
./TransactionTagTableItem
'
;
import
TransactionTagTableItem
from
'
./TransactionTagTableItem
'
;
interface
Props
{
interface
Props
{
data
:
TransactionTags
;
data
?:
TransactionTags
;
isLoading
:
boolean
;
onEditClick
:
(
data
:
TransactionTag
)
=>
void
;
onEditClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
}
}
const
AddressTagTable
=
({
data
,
onDeleteClick
,
onEditClick
}:
Props
)
=>
{
const
AddressTagTable
=
({
data
,
isLoading
,
onDeleteClick
,
onEditClick
}:
Props
)
=>
{
return
(
return
(
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Thead
>
<
Thead
>
...
@@ -28,10 +29,11 @@ const AddressTagTable = ({ data, onDeleteClick, onEditClick }: Props) => {
...
@@ -28,10 +29,11 @@ const AddressTagTable = ({ data, onDeleteClick, onEditClick }: Props) => {
</
Tr
>
</
Tr
>
</
Thead
>
</
Thead
>
<
Tbody
>
<
Tbody
>
{
data
.
map
((
item
)
=>
(
{
data
?.
map
((
item
,
index
)
=>
(
<
TransactionTagTableItem
<
TransactionTagTableItem
key=
{
item
.
id
+
(
isLoading
?
index
:
''
)
}
item=
{
item
}
item=
{
item
}
key=
{
item
.
id
}
isLoading=
{
isLoading
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
...
...
ui/privateTags/TransactionTagTable/TransactionTagTableItem.tsx
View file @
ee3337ae
import
{
import
{
Tag
,
Tr
,
Tr
,
Td
,
Td
,
Tooltip
,
}
from
'
@chakra-ui/react
'
;
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
TransactionTag
}
from
'
types/api/account
'
;
import
type
{
TransactionTag
}
from
'
types/api/account
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TransactionSnippet
from
'
ui/shared/TransactionSnippet
'
;
import
TransactionSnippet
from
'
ui/shared/TransactionSnippet
'
;
interface
Props
{
interface
Props
{
item
:
TransactionTag
;
item
:
TransactionTag
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
TransactionTag
)
=>
void
;
onEditClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
}
}
const
TransactionTagTableItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
TransactionTagTableItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
},
[
item
,
onEditClick
]);
...
@@ -29,17 +29,13 @@ const TransactionTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) =>
...
@@ -29,17 +29,13 @@ const TransactionTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) =>
return
(
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Td
>
<
Td
>
<
TransactionSnippet
hash=
{
item
.
transaction_hash
}
/>
<
TransactionSnippet
hash=
{
item
.
transaction_hash
}
isLoading=
{
isLoading
}
/>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
Tooltip
label=
{
item
.
name
}
>
<
Tag
isLoading=
{
isLoading
}
isTruncated
>
{
item
.
name
}
</
Tag
>
<
Tag
>
{
item
.
name
}
</
Tag
>
</
Tooltip
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/publicTags/PublicTagTable/PublicTagListItem.tsx
View file @
ee3337ae
import
{
Tag
,
VStack
,
Text
,
HStack
}
from
'
@chakra-ui/react
'
;
import
{
VStack
,
Text
,
HStack
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
interface
Props
{
interface
Props
{
item
:
PublicTag
;
item
:
PublicTag
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
}
}
const
PublicTagListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
PublicTagListItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
},
[
item
,
onEditClick
]);
...
@@ -27,28 +28,22 @@ const PublicTagListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -27,28 +28,22 @@ const PublicTagListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
<
ListItemMobile
>
<
ListItemMobile
>
<
VStack
spacing=
{
3
}
alignItems=
"flex-start"
maxW=
"100%"
>
<
VStack
spacing=
{
3
}
alignItems=
"flex-start"
maxW=
"100%"
>
<
VStack
spacing=
{
4
}
alignItems=
"unset"
maxW=
"100%"
>
<
VStack
spacing=
{
4
}
alignItems=
"unset"
maxW=
"100%"
>
{
item
.
addresses_with_info
.
map
((
address
)
=>
<
AddressSnippet
key=
{
address
.
hash
}
address=
{
address
}
/>)
}
{
item
.
addresses_with_info
.
map
((
address
)
=>
<
AddressSnippet
key=
{
address
.
hash
}
address=
{
address
}
isLoading=
{
isLoading
}
/>)
}
</
VStack
>
</
VStack
>
<
HStack
spacing=
{
3
}
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Public tags
</
Text
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Public tags
</
Text
>
<
HStack
spacing=
{
2
}
alignItems=
"baseline"
>
<
HStack
spacing=
{
2
}
alignItems=
"baseline"
>
{
item
.
tags
.
split
(
'
;
'
).
map
((
tag
)
=>
{
{
item
.
tags
.
split
(
'
;
'
).
map
((
tag
)
=>
<
Tag
key=
{
tag
}
isLoading=
{
isLoading
}
isTruncated
>
{
tag
}
</
Tag
>)
}
return
(
<
TruncatedTextTooltip
label=
{
tag
}
key=
{
tag
}
>
<
Tag
>
{
tag
}
</
Tag
>
</
TruncatedTextTooltip
>
);
})
}
</
HStack
>
</
HStack
>
</
HStack
>
</
HStack
>
<
HStack
spacing=
{
3
}
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Status
</
Text
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Status
</
Text
>
<
Text
fontSize=
"sm"
variant=
"secondary"
>
Submitted
</
Text
>
<
Skeleton
fontSize=
"sm"
color=
"text_secondary"
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
<
span
>
Submitted
</
span
>
</
Skeleton
>
</
HStack
>
</
HStack
>
</
VStack
>
</
VStack
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
ListItemMobile
>
</
ListItemMobile
>
);
);
};
};
...
...
ui/publicTags/PublicTagTable/PublicTagTable.tsx
View file @
ee3337ae
...
@@ -12,12 +12,13 @@ import type { PublicTags, PublicTag } from 'types/api/account';
...
@@ -12,12 +12,13 @@ import type { PublicTags, PublicTag } from 'types/api/account';
import
PublicTagTableItem
from
'
./PublicTagTableItem
'
;
import
PublicTagTableItem
from
'
./PublicTagTableItem
'
;
interface
Props
{
interface
Props
{
data
:
PublicTags
;
data
?:
PublicTags
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
}
}
const
PublicTagTable
=
({
data
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
PublicTagTable
=
({
data
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
return
(
return
(
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Thead
>
<
Thead
>
...
@@ -29,10 +30,11 @@ const PublicTagTable = ({ data, onEditClick, onDeleteClick }: Props) => {
...
@@ -29,10 +30,11 @@ const PublicTagTable = ({ data, onEditClick, onDeleteClick }: Props) => {
</
Tr
>
</
Tr
>
</
Thead
>
</
Thead
>
<
Tbody
>
<
Tbody
>
{
data
.
map
((
item
)
=>
(
{
data
?.
map
((
item
,
index
)
=>
(
<
PublicTagTableItem
<
PublicTagTableItem
key=
{
item
.
id
+
(
isLoading
?
String
(
index
)
:
''
)
}
item=
{
item
}
item=
{
item
}
key=
{
item
.
id
}
isLoading=
{
isLoading
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
...
...
ui/publicTags/PublicTagTable/PublicTagTableItem.tsx
View file @
ee3337ae
import
{
import
{
Tag
,
Tr
,
Tr
,
Td
,
Td
,
VStack
,
VStack
,
Text
,
Box
,
Skeleton
,
}
from
'
@chakra-ui/react
'
;
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
interface
Props
{
interface
Props
{
item
:
PublicTag
;
item
:
PublicTag
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
}
}
const
PublicTagTableItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
PublicTagTableItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
},
[
item
,
onEditClick
]);
...
@@ -32,29 +33,23 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -32,29 +33,23 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Td
>
<
Td
>
<
VStack
spacing=
{
4
}
alignItems=
"unset"
>
<
VStack
spacing=
{
4
}
alignItems=
"unset"
>
{
item
.
addresses_with_info
.
map
((
address
)
=>
<
AddressSnippet
key=
{
address
.
hash
}
address=
{
address
}
/>)
}
{
item
.
addresses_with_info
.
map
((
address
)
=>
<
AddressSnippet
key=
{
address
.
hash
}
address=
{
address
}
isLoading=
{
isLoading
}
/>)
}
</
VStack
>
</
VStack
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
VStack
spacing=
{
2
}
alignItems=
"baseline"
>
<
VStack
spacing=
{
2
}
alignItems=
"baseline"
>
{
item
.
tags
.
split
(
'
;
'
).
map
((
tag
)
=>
{
{
item
.
tags
.
split
(
'
;
'
).
map
((
tag
)
=>
<
Tag
key=
{
tag
}
isLoading=
{
isLoading
}
isTruncated
>
{
tag
}
</
Tag
>)
}
return
(
<
TruncatedTextTooltip
label=
{
tag
}
key=
{
tag
}
>
<
Tag
>
{
tag
}
</
Tag
>
</
TruncatedTextTooltip
>
);
})
}
</
VStack
>
</
VStack
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
VStack
alignItems=
"flex-start
"
>
<
Skeleton
fontSize=
"sm"
fontWeight=
"500"
py=
"2px"
isLoaded=
{
!
isLoading
}
display=
"inline-block
"
>
<
Text
fontSize=
"sm"
fontWeight=
"500"
>
Submitted
</
Text
>
Submitted
</
VStack
>
</
Skeleton
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
Box
py=
"2px"
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
Box
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/publicTags/PublicTagsData.tsx
View file @
ee3337ae
...
@@ -4,12 +4,10 @@ import React, { useCallback, useState } from 'react';
...
@@ -4,12 +4,10 @@ import React, { useCallback, useState } from 'react';
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
PUBLIC_TAG
}
from
'
stubs/account
'
;
import
PublicTagListItem
from
'
ui/publicTags/PublicTagTable/PublicTagListItem
'
;
import
PublicTagListItem
from
'
ui/publicTags/PublicTagTable/PublicTagListItem
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
SkeletonListAccount
from
'
ui/shared/skeletons/SkeletonListAccount
'
;
import
SkeletonTable
from
'
ui/shared/skeletons/SkeletonTable
'
;
import
DeletePublicTagModal
from
'
./DeletePublicTagModal
'
;
import
DeletePublicTagModal
from
'
./DeletePublicTagModal
'
;
import
PublicTagTable
from
'
./PublicTagTable/PublicTagTable
'
;
import
PublicTagTable
from
'
./PublicTagTable/PublicTagTable
'
;
...
@@ -22,9 +20,12 @@ type Props = {
...
@@ -22,9 +20,12 @@ type Props = {
const
PublicTagsData
=
({
changeToFormScreen
,
onTagDelete
}:
Props
)
=>
{
const
PublicTagsData
=
({
changeToFormScreen
,
onTagDelete
}:
Props
)
=>
{
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
PublicTag
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
PublicTag
>
();
const
isMobile
=
useIsMobile
();
const
{
data
,
isLoading
,
isError
,
error
}
=
useApiQuery
(
'
public_tags
'
);
const
{
data
,
isPlaceholderData
,
isError
,
error
}
=
useApiQuery
(
'
public_tags
'
,
{
queryOptions
:
{
placeholderData
:
Array
(
3
).
fill
(
PUBLIC_TAG
),
},
});
const
onDeleteModalClose
=
useCallback
(()
=>
{
const
onDeleteModalClose
=
useCallback
(()
=>
{
setDeleteModalData
(
undefined
);
setDeleteModalData
(
undefined
);
...
@@ -53,22 +54,6 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
...
@@ -53,22 +54,6 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
</
AccountPageDescription
>
</
AccountPageDescription
>
);
);
if
(
isLoading
)
{
const
loader
=
isMobile
?
<
SkeletonListAccount
/>
:
(
<>
<
SkeletonTable
columns=
{
[
'
50%
'
,
'
25%
'
,
'
25%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"48px"
width=
"270px"
marginTop=
{
8
}
/>
</>
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
if
(
isError
)
{
if
(
isError
)
{
if
(
error
.
status
===
403
)
{
if
(
error
.
status
===
403
)
{
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
throw
new
Error
(
'
Unverified email error
'
,
{
cause
:
error
});
...
@@ -76,33 +61,37 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
...
@@ -76,33 +61,37 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
list
=
isMobile
?
(
const
list
=
(
<
Box
>
<>
{
data
.
map
((
item
)
=>
(
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
<
PublicTagListItem
{
data
?.
map
((
item
,
index
)
=>
(
item=
{
item
}
<
PublicTagListItem
key=
{
item
.
id
}
key=
{
item
.
id
+
(
isPlaceholderData
?
String
(
index
)
:
''
)
}
onDeleteClick=
{
onItemDeleteClick
}
item=
{
item
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isPlaceholderData
}
/>
onDeleteClick=
{
onItemDeleteClick
}
))
}
onEditClick=
{
onItemEditClick
}
</
Box
>
/>
)
:
(
))
}
<
PublicTagTable
data=
{
data
}
onEditClick=
{
onItemEditClick
}
onDeleteClick=
{
onItemDeleteClick
}
/>
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
PublicTagTable
data=
{
data
}
isLoading=
{
isPlaceholderData
}
onEditClick=
{
onItemEditClick
}
onDeleteClick=
{
onItemDeleteClick
}
/>
</
Box
>
</>
);
);
return
(
return
(
<>
<>
{
description
}
{
description
}
{
data
.
length
>
0
&&
list
}
{
Boolean
(
data
?.
length
)
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Skeleton
mt=
{
8
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Button
<
Button
size=
"lg"
size=
"lg"
onClick=
{
changeToForm
}
onClick=
{
changeToForm
}
>
>
Request to add public tag
Request to add public tag
</
Button
>
</
Button
>
</
Box
>
</
Skeleton
>
{
deleteModalData
&&
(
{
deleteModalData
&&
(
<
DeletePublicTagModal
<
DeletePublicTagModal
{
...
deleteModalProps
}
{
...
deleteModalProps
}
...
...
ui/shared/AddressSnippet.tsx
View file @
ee3337ae
import
{
Text
,
Box
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
AddressParam
}
from
'
types/api/addressParams
'
;
import
type
{
AddressParam
}
from
'
types/api/addressParams
'
;
...
@@ -22,7 +22,11 @@ const AddressSnippet = ({ address, subtitle, isLoading }: Props) => {
...
@@ -22,7 +22,11 @@ const AddressSnippet = ({ address, subtitle, isLoading }: Props) => {
<
AddressLink
type=
"address"
hash=
{
address
.
hash
}
fontWeight=
"600"
ml=
{
2
}
isLoading=
{
isLoading
}
/>
<
AddressLink
type=
"address"
hash=
{
address
.
hash
}
fontWeight=
"600"
ml=
{
2
}
isLoading=
{
isLoading
}
/>
<
CopyToClipboard
text=
{
address
.
hash
}
isLoading=
{
isLoading
}
/>
<
CopyToClipboard
text=
{
address
.
hash
}
isLoading=
{
isLoading
}
/>
</
Address
>
</
Address
>
{
subtitle
&&
<
Text
fontSize=
"sm"
variant=
"secondary"
mt=
{
0.5
}
ml=
{
8
}
>
{
subtitle
}
</
Text
>
}
{
subtitle
&&
(
<
Skeleton
fontSize=
"sm"
color=
"text_secondary"
mt=
{
0.5
}
ml=
{
8
}
display=
"inline-block"
isLoaded=
{
!
isLoading
}
>
<
span
>
{
subtitle
}
</
span
>
</
Skeleton
>
)
}
</
Box
>
</
Box
>
);
);
};
};
...
...
ui/shared/ApiKeySnippet.tsx
View file @
ee3337ae
import
{
Box
,
HStack
,
Icon
,
Flex
,
Text
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
HStack
,
Icon
,
Flex
,
Skeleton
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
keyIcon
from
'
icons/key.svg
'
;
import
keyIcon
from
'
icons/key.svg
'
;
...
@@ -7,18 +7,27 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard';
...
@@ -7,18 +7,27 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard';
interface
Props
{
interface
Props
{
apiKey
:
string
;
apiKey
:
string
;
name
:
string
;
name
:
string
;
isLoading
?:
boolean
;
}
}
const
ApiKeySnippet
=
({
apiKey
,
name
}:
Props
)
=>
{
const
ApiKeySnippet
=
({
apiKey
,
name
,
isLoading
}:
Props
)
=>
{
return
(
return
(
<
HStack
spacing=
{
2
}
alignItems=
"start"
>
<
HStack
spacing=
{
2
}
alignItems=
"start"
>
<
Icon
as=
{
keyIcon
}
boxSize=
{
6
}
color=
{
useColorModeValue
(
'
gray.500
'
,
'
gray.400
'
)
}
/>
<
Skeleton
isLoaded=
{
!
isLoading
}
boxSize=
{
6
}
display=
"inline-block"
>
<
Icon
as=
{
keyIcon
}
boxSize=
{
6
}
color=
{
useColorModeValue
(
'
gray.500
'
,
'
gray.400
'
)
}
/>
</
Skeleton
>
<
Box
>
<
Box
>
<
Flex
alignItems=
{
{
base
:
'
flex-start
'
,
lg
:
'
center
'
}
}
>
<
Flex
alignItems=
{
{
base
:
'
flex-start
'
,
lg
:
'
center
'
}
}
>
<
Text
fontSize=
"md"
lineHeight=
{
6
}
fontWeight=
{
600
}
mr=
{
1
}
>
{
apiKey
}
</
Text
>
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
fontWeight=
{
600
}
mr=
{
1
}
>
<
CopyToClipboard
text=
{
apiKey
}
/>
<
span
>
{
apiKey
}
</
span
>
</
Skeleton
>
<
CopyToClipboard
text=
{
apiKey
}
isLoading=
{
isLoading
}
/>
</
Flex
>
</
Flex
>
{
name
&&
<
Text
fontSize=
"sm"
variant=
"secondary"
mt=
{
1
}
>
{
name
}
</
Text
>
}
{
name
&&
(
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
fontSize=
"sm"
color=
"text_secondary"
mt=
{
1
}
>
<
span
>
{
name
}
</
span
>
</
Skeleton
>
)
}
</
Box
>
</
Box
>
</
HStack
>
</
HStack
>
);
);
...
...
ui/shared/CurrencyValue.tsx
View file @
ee3337ae
import
{
Box
,
Text
,
chakra
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Text
,
chakra
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
getCurrencyValue
from
'
lib/getCurrencyValue
'
;
import
getCurrencyValue
from
'
lib/getCurrencyValue
'
;
...
@@ -11,9 +11,16 @@ interface Props {
...
@@ -11,9 +11,16 @@ interface Props {
accuracy
?:
number
;
accuracy
?:
number
;
accuracyUsd
?:
number
;
accuracyUsd
?:
number
;
decimals
?:
string
|
null
;
decimals
?:
string
|
null
;
isLoading
?:
boolean
;
}
}
const
CurrencyValue
=
({
value
,
currency
=
''
,
decimals
,
exchangeRate
,
className
,
accuracy
,
accuracyUsd
}:
Props
)
=>
{
const
CurrencyValue
=
({
value
,
currency
=
''
,
decimals
,
exchangeRate
,
className
,
accuracy
,
accuracyUsd
,
isLoading
}:
Props
)
=>
{
if
(
isLoading
)
{
return
(
<
Skeleton
className=
{
className
}
display=
"inline-block"
>
0.00 ($0.00)
</
Skeleton
>
);
}
if
(
value
===
undefined
||
value
===
null
)
{
if
(
value
===
undefined
||
value
===
null
)
{
return
(
return
(
<
Box
as=
"span"
className=
{
className
}
>
<
Box
as=
"span"
className=
{
className
}
>
...
...
ui/shared/TableItemActionButtons.tsx
View file @
ee3337ae
...
@@ -17,8 +17,8 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props
...
@@ -17,8 +17,8 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props
if
(
isLoading
)
{
if
(
isLoading
)
{
return
(
return
(
<
HStack
spacing=
{
6
}
alignSelf=
"flex-end"
>
<
HStack
spacing=
{
6
}
alignSelf=
"flex-end"
>
<
Skeleton
boxSize=
{
5
}
flexShrink=
{
0
}
borderRadius=
"
base
"
/>
<
Skeleton
boxSize=
{
5
}
flexShrink=
{
0
}
borderRadius=
"
sm
"
/>
<
Skeleton
boxSize=
{
5
}
flexShrink=
{
0
}
borderRadius=
"
base
"
/>
<
Skeleton
boxSize=
{
5
}
flexShrink=
{
0
}
borderRadius=
"
sm
"
/>
</
HStack
>
</
HStack
>
);
);
}
}
...
...
ui/shared/TransactionSnippet.tsx
View file @
ee3337ae
import
{
Icon
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
Icon
,
Skeleton
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
transactionIcon
from
'
icons/transactions.svg
'
;
import
transactionIcon
from
'
icons/transactions.svg
'
;
...
@@ -8,14 +8,17 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard';
...
@@ -8,14 +8,17 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard';
interface
Props
{
interface
Props
{
hash
:
string
;
hash
:
string
;
isLoading
?:
boolean
;
}
}
const
TransactionSnippet
=
({
hash
}:
Props
)
=>
{
const
TransactionSnippet
=
({
hash
,
isLoading
}:
Props
)
=>
{
return
(
return
(
<
Address
maxW=
"100%"
>
<
Address
maxW=
"100%"
>
<
Icon
as=
{
transactionIcon
}
boxSize=
{
6
}
color=
{
useColorModeValue
(
'
gray.500
'
,
'
gray.400
'
)
}
/>
<
Skeleton
isLoaded=
{
!
isLoading
}
boxSize=
{
6
}
borderRadius=
"base"
>
<
AddressLink
hash=
{
hash
}
fontWeight=
"600"
type=
"transaction"
ml=
{
2
}
/>
<
Icon
as=
{
transactionIcon
}
boxSize=
{
6
}
color=
{
useColorModeValue
(
'
gray.500
'
,
'
gray.400
'
)
}
/>
<
CopyToClipboard
text=
{
hash
}
ml=
{
1
}
/>
</
Skeleton
>
<
AddressLink
hash=
{
hash
}
fontWeight=
"600"
type=
"transaction"
ml=
{
2
}
isLoading=
{
isLoading
}
/>
<
CopyToClipboard
text=
{
hash
}
isLoading=
{
isLoading
}
/>
</
Address
>
</
Address
>
);
);
};
};
...
...
ui/watchlist/WatchlistTable/WatchListAddressItem.tsx
View file @
ee3337ae
import
{
HStack
,
VStack
,
Text
,
Icon
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
HStack
,
VStack
,
chakra
,
Icon
,
Flex
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
...
@@ -11,7 +11,7 @@ import AddressSnippet from 'ui/shared/AddressSnippet';
...
@@ -11,7 +11,7 @@ import AddressSnippet from 'ui/shared/AddressSnippet';
import
CurrencyValue
from
'
ui/shared/CurrencyValue
'
;
import
CurrencyValue
from
'
ui/shared/CurrencyValue
'
;
import
TokenLogo
from
'
ui/shared/TokenLogo
'
;
import
TokenLogo
from
'
ui/shared/TokenLogo
'
;
const
WatchListAddressItem
=
({
item
}:
{
item
:
TWatchlistItem
})
=>
{
const
WatchListAddressItem
=
({
item
,
isLoading
}:
{
item
:
TWatchlistItem
;
isLoading
?:
boolean
})
=>
{
const
infoItemsPaddingLeft
=
{
base
:
1
,
lg
:
8
};
const
infoItemsPaddingLeft
=
{
base
:
1
,
lg
:
8
};
const
nativeTokenData
=
React
.
useMemo
(()
=>
({
const
nativeTokenData
=
React
.
useMemo
(()
=>
({
...
@@ -22,32 +22,39 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
...
@@ -22,32 +22,39 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
return
(
return
(
<
VStack
spacing=
{
2
}
align=
"stretch"
fontWeight=
{
500
}
>
<
VStack
spacing=
{
2
}
align=
"stretch"
fontWeight=
{
500
}
>
<
AddressSnippet
address=
{
item
.
address
}
/>
<
AddressSnippet
address=
{
item
.
address
}
isLoading=
{
isLoading
}
/>
<
Flex
fontSize=
"sm"
h=
{
6
}
pl=
{
infoItemsPaddingLeft
}
flexWrap=
"wrap"
alignItems=
"center"
rowGap=
{
1
}
>
<
Flex
fontSize=
"sm"
pl=
{
infoItemsPaddingLeft
}
flexWrap=
"wrap"
alignItems=
"center"
rowGap=
{
1
}
>
{
appConfig
.
network
.
currency
.
address
&&
(
{
appConfig
.
network
.
currency
.
address
&&
(
<
TokenLogo
<
TokenLogo
data=
{
nativeTokenData
}
data=
{
nativeTokenData
}
boxSize=
{
4
}
boxSize=
{
5
}
borderRadius=
"sm"
borderRadius=
"sm"
mr=
{
2
}
mr=
{
2
}
isLoading=
{
isLoading
}
/>
/>
)
}
)
}
<
Text
as=
"span"
whiteSpace=
"pre"
>
{
appConfig
.
network
.
currency
.
symbol
}
balance:
</
Text
>
<
Skeleton
isLoaded=
{
!
isLoading
}
whiteSpace=
"pre"
display=
"inline-flex"
>
<
CurrencyValue
<
span
>
{
appConfig
.
network
.
currency
.
symbol
}
balance:
</
span
>
value=
{
item
.
address_balance
}
<
CurrencyValue
exchangeRate=
{
item
.
exchange_rate
}
value=
{
item
.
address_balance
}
decimals=
{
String
(
appConfig
.
network
.
currency
.
decimals
)
}
exchangeRate=
{
item
.
exchange_rate
}
accuracy=
{
2
}
decimals=
{
String
(
appConfig
.
network
.
currency
.
decimals
)
}
accuracyUsd=
{
2
}
accuracy=
{
2
}
/>
accuracyUsd=
{
2
}
/>
</
Skeleton
>
</
Flex
>
</
Flex
>
{
item
.
tokens_count
&&
(
{
item
.
tokens_count
&&
(
<
HStack
spacing=
{
0
}
fontSize=
"sm"
h=
{
6
}
pl=
{
infoItemsPaddingLeft
}
>
<
HStack
spacing=
{
0
}
fontSize=
"sm"
pl=
{
infoItemsPaddingLeft
}
>
<
Icon
as=
{
TokensIcon
}
mr=
{
2
}
w=
"17px"
h=
"16px"
/>
<
Skeleton
isLoaded=
{
!
isLoading
}
boxSize=
{
5
}
mr=
{
2
}
borderRadius=
"sm"
>
<
Text
>
{
`Tokens:${ nbsp }`
+
item
.
tokens_count
}
</
Text
>
<
Icon
as=
{
TokensIcon
}
boxSize=
{
5
}
/>
{
/* api does not provide token prices */
}
</
Skeleton
>
{
/* <Text variant="secondary">{ `${ nbsp }($${ item.tokensUSD } USD)` }</Text> */
}
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-flex"
>
<
Text
variant=
"secondary"
>
{
`${ nbsp }(N/A)`
}
</
Text
>
<
span
>
{
`Tokens:${ nbsp }`
+
item
.
tokens_count
}
</
span
>
{
/* api does not provide token prices */
}
{
/* <Text variant="secondary">{ `${ nbsp }($${ item.tokensUSD } USD)` }</Text> */
}
<
chakra
.
span
color=
"text_secondary"
>
{
`${ nbsp }(N/A)`
}
</
chakra
.
span
>
</
Skeleton
>
</
HStack
>
</
HStack
>
)
}
)
}
{
/* api does not provide token prices */
}
{
/* api does not provide token prices */
}
...
...
ui/watchlist/WatchlistTable/WatchListItem.tsx
View file @
ee3337ae
import
{
Tag
,
Box
,
Switch
,
Text
,
HStack
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Switch
,
Text
,
HStack
,
Flex
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
{
useMutation
}
from
'
@tanstack/react-query
'
;
import
{
useMutation
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
...
@@ -6,6 +6,7 @@ import type { TWatchlistItem } from 'types/client/account';
...
@@ -6,6 +6,7 @@ import type { TWatchlistItem } from 'types/client/account';
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
...
@@ -13,11 +14,12 @@ import WatchListAddressItem from './WatchListAddressItem';
...
@@ -13,11 +14,12 @@ import WatchListAddressItem from './WatchListAddressItem';
interface
Props
{
interface
Props
{
item
:
TWatchlistItem
;
item
:
TWatchlistItem
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onEditClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onDeleteClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onDeleteClick
:
(
data
:
TWatchlistItem
)
=>
void
;
}
}
const
WatchListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
WatchListItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
[
notificationEnabled
,
setNotificationEnabled
]
=
useState
(
item
.
notification_methods
.
email
);
const
[
notificationEnabled
,
setNotificationEnabled
]
=
useState
(
item
.
notification_methods
.
email
);
const
[
switchDisabled
,
setSwitchDisabled
]
=
useState
(
false
);
const
[
switchDisabled
,
setSwitchDisabled
]
=
useState
(
false
);
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
...
@@ -84,27 +86,27 @@ const WatchListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -84,27 +86,27 @@ const WatchListItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
ListItemMobile
>
<
ListItemMobile
>
<
Box
maxW=
"100%"
>
<
Box
maxW=
"100%"
>
<
WatchListAddressItem
item=
{
item
}
/>
<
WatchListAddressItem
item=
{
item
}
isLoading=
{
isLoading
}
/>
<
HStack
spacing=
{
3
}
mt=
{
6
}
>
<
HStack
spacing=
{
3
}
mt=
{
6
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Tag
>
<
Tag
isLoading=
{
isLoading
}
isTruncated
>
{
item
.
name
}
</
Tag
>
{
item
.
name
}
</
Tag
>
</
HStack
>
</
HStack
>
</
Box
>
</
Box
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
mt=
{
6
}
w=
"100%"
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
mt=
{
6
}
w=
"100%"
>
<
HStack
spacing=
{
3
}
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Email notification
</
Text
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Email notification
</
Text
>
<
Switch
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
colorScheme=
"blue"
<
Switch
size=
"md"
colorScheme=
"blue"
isChecked=
{
notificationEnabled
}
size=
"md"
onChange=
{
onSwitch
}
isChecked=
{
notificationEnabled
}
aria
-
label=
"Email notification"
onChange=
{
onSwitch
}
isDisabled=
{
switchDisabled
}
aria
-
label=
"Email notification"
/>
isDisabled=
{
switchDisabled
}
/>
</
Skeleton
>
</
HStack
>
</
HStack
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
Flex
>
</
Flex
>
</
ListItemMobile
>
</
ListItemMobile
>
);
);
...
...
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
View file @
ee3337ae
import
{
import
{
Tag
,
Tr
,
Tr
,
Td
,
Td
,
Switch
,
Switch
,
Skeleton
,
}
from
'
@chakra-ui/react
'
;
}
from
'
@chakra-ui/react
'
;
import
{
useMutation
}
from
'
@tanstack/react-query
'
;
import
{
useMutation
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
...
@@ -11,18 +11,19 @@ import type { TWatchlistItem } from 'types/client/account';
...
@@ -11,18 +11,19 @@ import type { TWatchlistItem } from 'types/client/account';
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
import
WatchListAddressItem
from
'
./WatchListAddressItem
'
;
import
WatchListAddressItem
from
'
./WatchListAddressItem
'
;
interface
Props
{
interface
Props
{
item
:
TWatchlistItem
;
item
:
TWatchlistItem
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onEditClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onDeleteClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onDeleteClick
:
(
data
:
TWatchlistItem
)
=>
void
;
}
}
const
WatchlistTableItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
WatchlistTableItem
=
({
item
,
isLoading
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
[
notificationEnabled
,
setNotificationEnabled
]
=
useState
(
item
.
notification_methods
.
email
);
const
[
notificationEnabled
,
setNotificationEnabled
]
=
useState
(
item
.
notification_methods
.
email
);
const
[
switchDisabled
,
setSwitchDisabled
]
=
useState
(
false
);
const
[
switchDisabled
,
setSwitchDisabled
]
=
useState
(
false
);
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
...
@@ -88,26 +89,24 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -88,26 +89,24 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
address_hash
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
address_hash
}
>
<
Td
><
WatchListAddressItem
item=
{
item
}
/></
Td
>
<
Td
><
WatchListAddressItem
item=
{
item
}
isLoading=
{
isLoading
}
/></
Td
>
<
Td
>
<
Td
>
<
TruncatedTextTooltip
label=
{
item
.
name
}
>
<
Tag
isLoading=
{
isLoading
}
isTruncated
>
{
item
.
name
}
</
Tag
>
<
Tag
>
{
item
.
name
}
</
Tag
>
</
TruncatedTextTooltip
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
Switch
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
colorScheme=
"blue"
<
Switch
size=
"md"
colorScheme=
"blue"
isChecked=
{
notificationEnabled
}
size=
"md"
onChange=
{
onSwitch
}
isChecked=
{
notificationEnabled
}
isDisabled=
{
switchDisabled
}
onChange=
{
onSwitch
}
aria
-
label=
"Email notification"
isDisabled=
{
switchDisabled
}
/>
aria
-
label=
"Email notification"
/>
</
Skeleton
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/watchlist/WatchlistTable/WatchlistTable.tsx
View file @
ee3337ae
...
@@ -12,12 +12,13 @@ import type { TWatchlist, TWatchlistItem } from 'types/client/account';
...
@@ -12,12 +12,13 @@ import type { TWatchlist, TWatchlistItem } from 'types/client/account';
import
WatchlistTableItem
from
'
./WatchListTableItem
'
;
import
WatchlistTableItem
from
'
./WatchListTableItem
'
;
interface
Props
{
interface
Props
{
data
:
TWatchlist
;
data
?:
TWatchlist
;
isLoading
?:
boolean
;
onEditClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onEditClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onDeleteClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onDeleteClick
:
(
data
:
TWatchlistItem
)
=>
void
;
}
}
const
WatchlistTable
=
({
data
,
onDeleteClick
,
onEditClick
}:
Props
)
=>
{
const
WatchlistTable
=
({
data
,
isLoading
,
onDeleteClick
,
onEditClick
}:
Props
)
=>
{
return
(
return
(
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Table
variant=
"simple"
minWidth=
"600px"
>
<
Thead
>
<
Thead
>
...
@@ -29,10 +30,11 @@ const WatchlistTable = ({ data, onDeleteClick, onEditClick }: Props) => {
...
@@ -29,10 +30,11 @@ const WatchlistTable = ({ data, onDeleteClick, onEditClick }: Props) => {
</
Tr
>
</
Tr
>
</
Thead
>
</
Thead
>
<
Tbody
>
<
Tbody
>
{
data
.
map
((
item
)
=>
(
{
data
?.
map
((
item
,
index
)
=>
(
<
WatchlistTableItem
<
WatchlistTableItem
key=
{
item
.
address_hash
+
(
isLoading
?
index
:
''
)
}
item=
{
item
}
item=
{
item
}
key=
{
item
.
address_hash
}
isLoading=
{
isLoading
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
...
...
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