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
8b68dfdc
Unverified
Commit
8b68dfdc
authored
Sep 05, 2022
by
tom goriunov
Committed by
GitHub
Sep 05, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'main' into switch-fix
parents
3d44ca80
349f2e75
Changes
55
Hide whitespace changes
Inline
Side-by-side
Showing
55 changed files
with
922 additions
and
309 deletions
+922
-309
key.svg
icons/key.svg
+3
-0
transactions.svg
icons/transactions.svg
+3
-1
Alert.ts
theme/components/Alert.ts
+23
-0
Form.ts
theme/components/Form.ts
+3
-0
Modal.ts
theme/components/Modal.ts
+19
-1
Textarea.ts
theme/components/Textarea.ts
+6
-0
ApiKeyListItem.tsx
ui/apiKey/ApiKeyTable/ApiKeyListItem.tsx
+33
-0
ApiKeyTableItem.tsx
ui/apiKey/ApiKeyTable/ApiKeyTableItem.tsx
+4
-14
DeleteApiKeyModal.tsx
ui/apiKey/DeleteApiKeyModal.tsx
+1
-1
Header.tsx
ui/blocks/header/Header.tsx
+1
-1
SearchBarMobile.tsx
ui/blocks/searchBar/SearchBarMobile.tsx
+1
-0
CustomAbiForm.tsx
ui/customAbi/CustomAbiModal/CustomAbiForm.tsx
+1
-0
CustomAbiListItem.tsx
ui/customAbi/CustomAbiTable/CustomAbiListItem.tsx
+33
-0
CustomAbiTableItem.tsx
ui/customAbi/CustomAbiTable/CustomAbiTableItem.tsx
+4
-14
DeleteCustomAbiModal.tsx
ui/customAbi/DeleteCustomAbiModal.tsx
+1
-1
ApiKeys.tsx
ui/pages/ApiKeys.tsx
+40
-16
CustomAbi.tsx
ui/pages/CustomAbi.tsx
+36
-12
PrivateTags.tsx
ui/pages/PrivateTags.tsx
+1
-1
PublicTags.tsx
ui/pages/PublicTags.tsx
+11
-1
Watchlist.tsx
ui/pages/Watchlist.tsx
+36
-11
AddressTagListItem.tsx
ui/privateTags/AddressTagTable/AddressTagListItem.tsx
+41
-0
AddressTagTableItem.tsx
ui/privateTags/AddressTagTable/AddressTagTableItem.tsx
+4
-13
DeletePrivateTagModal.tsx
ui/privateTags/DeletePrivateTagModal.tsx
+1
-1
PrivateAddressTags.tsx
ui/privateTags/PrivateAddressTags.tsx
+37
-13
PrivateTransactionTags.tsx
ui/privateTags/PrivateTransactionTags.tsx
+36
-12
TransactionTagListItem.tsx
...rivateTags/TransactionTagTable/TransactionTagListItem.tsx
+41
-0
TransactionTagTableItem.tsx
...ivateTags/TransactionTagTable/TransactionTagTableItem.tsx
+6
-11
DeletePublicTagModal.tsx
ui/publicTags/DeletePublicTagModal.tsx
+13
-12
PublicTagListItem.tsx
ui/publicTags/PublicTagTable/PublicTagListItem.tsx
+56
-0
PublicTagTableItem.tsx
ui/publicTags/PublicTagTable/PublicTagTableItem.tsx
+4
-22
PublicTagsData.tsx
ui/publicTags/PublicTagsData.tsx
+32
-6
PublicTagFormAddressInput.tsx
ui/publicTags/PublicTagsForm/PublicTagFormAddressInput.tsx
+35
-31
PublicTagFormComment.tsx
ui/publicTags/PublicTagsForm/PublicTagFormComment.tsx
+5
-4
PublicTagsForm.tsx
ui/publicTags/PublicTagsForm/PublicTagsForm.tsx
+16
-6
PublicTagsFormInput.tsx
ui/publicTags/PublicTagsForm/PublicTagsFormInput.tsx
+5
-3
AccountListItemMobile.tsx
ui/shared/AccountListItemMobile.tsx
+25
-0
AccountPageDescription.tsx
ui/shared/AccountPageDescription.tsx
+12
-0
AccountPageHeader.tsx
ui/shared/AccountPageHeader.tsx
+3
-3
AddressIcon.tsx
ui/shared/AddressIcon.tsx
+1
-1
AddressLinkWithTooltip.tsx
ui/shared/AddressLinkWithTooltip.tsx
+14
-3
AddressSnippet.tsx
ui/shared/AddressSnippet.tsx
+24
-0
ApiKeySnippet.tsx
ui/shared/ApiKeySnippet.tsx
+27
-0
DeleteButton.tsx
ui/shared/DeleteButton.tsx
+0
-27
DeleteModal.tsx
ui/shared/DeleteModal.tsx
+1
-1
EditButton.tsx
ui/shared/EditButton.tsx
+0
-27
FormModal.tsx
ui/shared/FormModal.tsx
+2
-2
SkeletonAccountMobile.tsx
ui/shared/SkeletonAccountMobile.tsx
+48
-0
TableItemActionButtons.tsx
ui/shared/TableItemActionButtons.tsx
+44
-0
TransactionSnippet.tsx
ui/shared/TransactionSnippet.tsx
+22
-0
AddressForm.tsx
ui/watchlist/AddressModal/AddressForm.tsx
+2
-2
AddressFormNotifications.tsx
ui/watchlist/AddressModal/AddressFormNotifications.tsx
+10
-2
DeleteAddressModal.tsx
ui/watchlist/DeleteAddressModal.tsx
+5
-2
WatchListAddressItem.tsx
ui/watchlist/WatchlistTable/WatchListAddressItem.tsx
+21
-24
WatchListItem.tsx
ui/watchlist/WatchlistTable/WatchListItem.tsx
+67
-0
WatchListTableItem.tsx
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
+2
-7
No files found.
icons/key.svg
0 → 100644
View file @
8b68dfdc
<svg
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 24 24"
>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M8 9a7 7 0 1 1 7 7h-2v2h-2v2H9v2H2v-5.414l6.148-6.148A7.025 7.025 0 0 1 8 9Zm3 5h4a5 5 0 1 0-4.786-3.547l.174.573L4 17.414V20h3v-2h2v-2h2v-2Zm4-3a2 2 0 1 1 0-4 2 2 0 0 1 0 4Z"
fill=
"currentColor"
/>
</svg>
\ No newline at end of file
icons/transactions.svg
View file @
8b68dfdc
<svg
width=
"30"
height=
"30"
fill=
"currentColor"
xmlns=
"http://www.w3.org/2000/svg"
><path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M23.433 12.64a1.212 1.212 0 0 1-.857.354H6.212a1.212 1.212 0 0 1-1.12-.745 1.212 1.212 0 0 1 .266-1.321L8.994 7.29a1.212 1.212 0 0 1 1.71 1.71L9.14 10.57h13.436a1.212 1.212 0 0 1 .857 2.068ZM7.424 17.236h16.363a1.213 1.213 0 0 1 1.121.745 1.212 1.212 0 0 1-.266 1.321l-3.636 3.637a1.213 1.213 0 1 1-1.71-1.71l1.564-1.569H7.424a1.212 1.212 0 0 1 0-2.424Z"
/></svg>
<svg
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 30 30"
>
\ No newline at end of file
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M23.433 12.64a1.212 1.212 0 0 1-.857.354H6.212a1.212 1.212 0 0 1-1.12-.745 1.212 1.212 0 0 1 .266-1.321L8.994 7.29a1.212 1.212 0 0 1 1.71 1.71L9.14 10.57h13.436a1.212 1.212 0 0 1 .857 2.068ZM7.424 17.236h16.363a1.213 1.213 0 0 1 1.121.745 1.212 1.212 0 0 1-.266 1.321l-3.636 3.637a1.213 1.213 0 1 1-1.71-1.71l1.564-1.569H7.424a1.212 1.212 0 0 1 0-2.424Z"
fill=
"currentColor"
/>
</svg>
\ No newline at end of file
theme/components/Alert.ts
View file @
8b68dfdc
import
{
alertAnatomy
as
parts
}
from
'
@chakra-ui/anatomy
'
;
import
{
alertAnatomy
as
parts
}
from
'
@chakra-ui/anatomy
'
;
import
type
{
StyleFunctionProps
}
from
'
@chakra-ui/styled-system
'
;
import
{
createMultiStyleConfigHelpers
}
from
'
@chakra-ui/styled-system
'
;
import
{
createMultiStyleConfigHelpers
}
from
'
@chakra-ui/styled-system
'
;
import
{
getColor
,
mode
,
transparentize
}
from
'
@chakra-ui/theme-tools
'
;
const
{
definePartsStyle
,
defineMultiStyleConfig
}
=
const
{
definePartsStyle
,
defineMultiStyleConfig
}
=
createMultiStyleConfigHelpers
(
parts
.
keys
);
createMultiStyleConfigHelpers
(
parts
.
keys
);
function
getBg
(
props
:
StyleFunctionProps
):
string
{
const
{
theme
,
colorScheme
:
c
}
=
props
;
const
lightBg
=
getColor
(
theme
,
`
${
c
}
.100`
,
c
);
const
darkBg
=
transparentize
(
`
${
c
}
.200`
,
0.16
)(
theme
);
return
mode
(
lightBg
,
darkBg
)(
props
);
}
const
baseStyle
=
definePartsStyle
({
const
baseStyle
=
definePartsStyle
({
container
:
{
container
:
{
borderRadius
:
'
md
'
,
borderRadius
:
'
md
'
,
...
@@ -12,8 +22,21 @@ const baseStyle = definePartsStyle({
...
@@ -12,8 +22,21 @@ const baseStyle = definePartsStyle({
},
},
});
});
const
variantSubtle
=
definePartsStyle
((
props
)
=>
{
return
{
container
:
{
bgColor
:
getBg
(
props
),
},
};
});
const
variants
=
{
subtle
:
variantSubtle
,
};
const
Alert
=
defineMultiStyleConfig
({
const
Alert
=
defineMultiStyleConfig
({
baseStyle
,
baseStyle
,
variants
,
});
});
export
default
Alert
;
export
default
Alert
;
theme/components/Form.ts
View file @
8b68dfdc
...
@@ -125,6 +125,9 @@ const variantFloating = definePartsStyle((props) => {
...
@@ -125,6 +125,9 @@ const variantFloating = definePartsStyle((props) => {
margin
:
0
,
margin
:
0
,
transformOrigin
:
'
top left
'
,
transformOrigin
:
'
top left
'
,
transitionProperty
:
'
font-size, line-height, padding, top, background-color
'
,
transitionProperty
:
'
font-size, line-height, padding, top, background-color
'
,
overflow
:
'
hidden
'
,
whiteSpace
:
'
nowrap
'
,
textOverflow
:
'
ellipsis
'
,
},
},
'
input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label
'
:
{
'
input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label
'
:
{
...
activeLabelStyles
,
...
activeLabelStyles
,
...
...
theme/components/Modal.ts
View file @
8b68dfdc
...
@@ -35,6 +35,7 @@ const baseStyleHeader = defineStyle((props) => ({
...
@@ -35,6 +35,7 @@ const baseStyleHeader = defineStyle((props) => ({
const
baseStyleBody
=
defineStyle
({
const
baseStyleBody
=
defineStyle
({
padding
:
0
,
padding
:
0
,
marginBottom
:
8
,
marginBottom
:
8
,
flex
:
'
initial
'
,
});
});
const
baseStyleFooter
=
defineStyle
({
const
baseStyleFooter
=
defineStyle
({
...
@@ -70,16 +71,33 @@ const baseStyle = definePartsStyle((props) => ({
...
@@ -70,16 +71,33 @@ const baseStyle = definePartsStyle((props) => ({
const
sizes
=
{
const
sizes
=
{
md
:
definePartsStyle
({
md
:
definePartsStyle
({
dialogContainer
:
{
height
:
'
100%
'
,
},
dialog
:
{
dialog
:
{
maxW
:
'
760px
'
,
maxW
:
'
760px
'
,
},
},
}),
}),
full
:
definePartsStyle
({
full
:
definePartsStyle
({
dialogContainer
:
{
height
:
'
100%
'
,
},
dialog
:
{
dialog
:
{
maxW
:
'
100vw
'
,
maxW
:
'
100vw
'
,
minH
:
'
100vh
'
,
my
:
'
0
'
,
my
:
'
0
'
,
borderRadius
:
'
0
'
,
borderRadius
:
'
0
'
,
padding
:
'
80px 16px 32px 16px
'
,
height
:
'
100%
'
,
overflowY
:
'
scroll
'
,
},
closeButton
:
{
top
:
4
,
right
:
6
,
width
:
6
,
height
:
6
,
},
header
:
{
mb
:
6
,
},
},
}),
}),
};
};
...
...
theme/components/Textarea.ts
View file @
8b68dfdc
...
@@ -4,6 +4,12 @@ import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
...
@@ -4,6 +4,12 @@ import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import
getOutlinedFieldStyles
from
'
../utils/getOutlinedFieldStyles
'
;
import
getOutlinedFieldStyles
from
'
../utils/getOutlinedFieldStyles
'
;
const
sizes
=
{
const
sizes
=
{
md
:
defineStyle
({
fontSize
:
'
md
'
,
lineHeight
:
'
20px
'
,
h
:
'
160px
'
,
borderRadius
:
'
base
'
,
}),
lg
:
defineStyle
({
lg
:
defineStyle
({
fontSize
:
'
md
'
,
fontSize
:
'
md
'
,
lineHeight
:
'
20px
'
,
lineHeight
:
'
20px
'
,
...
...
ui/apiKey/ApiKeyTable/ApiKeyListItem.tsx
0 → 100644
View file @
8b68dfdc
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
ApiKey
}
from
'
types/api/account
'
;
import
AccountListItemMobile
from
'
ui/shared/AccountListItemMobile
'
;
import
ApiKeySnippet
from
'
ui/shared/ApiKeySnippet
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
interface
Props
{
item
:
ApiKey
;
onEditClick
:
(
item
:
ApiKey
)
=>
void
;
onDeleteClick
:
(
item
:
ApiKey
)
=>
void
;
}
const
ApiKeyListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
return
(
<
AccountListItemMobile
>
<
ApiKeySnippet
apiKey=
{
item
.
api_key
}
name=
{
item
.
name
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
</
AccountListItemMobile
>
);
};
export
default
ApiKeyListItem
;
ui/apiKey/ApiKeyTable/ApiKeyTableItem.tsx
View file @
8b68dfdc
import
{
import
{
Tr
,
Tr
,
Td
,
Td
,
HStack
,
Text
,
}
from
'
@chakra-ui/react
'
;
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
ApiKey
}
from
'
types/api/account
'
;
import
type
{
ApiKey
}
from
'
types/api/account
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
ApiKeySnippet
from
'
ui/shared/ApiKeySnippet
'
;
import
DeleteButton
from
'
ui/shared/DeleteButton
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
EditButton
from
'
ui/shared/EditButton
'
;
interface
Props
{
interface
Props
{
item
:
ApiKey
;
item
:
ApiKey
;
...
@@ -31,17 +28,10 @@ const ApiKeyTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -31,17 +28,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
>
<
HStack
>
<
ApiKeySnippet
apiKey=
{
item
.
api_key
}
name=
{
item
.
name
}
/>
<
Text
fontSize=
"md"
fontWeight=
{
600
}
>
{
item
.
api_key
}
</
Text
>
<
CopyToClipboard
text=
{
item
.
api_key
}
/>
</
HStack
>
<
Text
fontSize=
"sm"
marginTop=
{
0.5
}
variant=
"secondary"
>
{
item
.
name
}
</
Text
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
HStack
spacing=
{
6
}
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
EditButton
onClick=
{
onItemEditClick
}
/>
<
DeleteButton
onClick=
{
onItemDeleteClick
}
/>
</
HStack
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/apiKey/DeleteApiKeyModal.tsx
View file @
8b68dfdc
...
@@ -28,7 +28,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
...
@@ -28,7 +28,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
const
renderText
=
useCallback
(()
=>
{
const
renderText
=
useCallback
(()
=>
{
return
(
return
(
<
Text
display=
"flex"
>
API key for
<
Text
fontWeight=
"600"
whiteSpace=
"pre"
>
{
` "${ data.name || 'name' }" `
}
</
Text
>
will be deleted
</
Text
>
<
Text
>
API key for
<
Text
fontWeight=
"600"
as=
"span"
>
{
` "${ data.name || 'name' }" `
}
</
Text
>
will be deleted
</
Text
>
);
);
},
[
data
.
name
]);
},
[
data
.
name
]);
...
...
ui/blocks/header/Header.tsx
View file @
8b68dfdc
...
@@ -28,7 +28,7 @@ const Header = () => {
...
@@ -28,7 +28,7 @@ const Header = () => {
width=
"100%"
width=
"100%"
alignItems=
"center"
alignItems=
"center"
justifyContent=
"space-between"
justifyContent=
"space-between"
zIndex=
{
10
}
zIndex=
"sticky"
>
>
<
Burger
/>
<
Burger
/>
<
NetworkLogo
/>
<
NetworkLogo
/>
...
...
ui/blocks/searchBar/SearchBarMobile.tsx
View file @
8b68dfdc
...
@@ -56,6 +56,7 @@ const SearchBarMobile = ({ onChange, onSubmit }: Props) => {
...
@@ -56,6 +56,7 @@ const SearchBarMobile = ({ onChange, onSubmit }: Props) => {
position=
"fixed"
position=
"fixed"
top=
"56px"
top=
"56px"
left=
"0"
left=
"0"
zIndex=
"docked"
bgColor=
{
bgColor
}
bgColor=
{
bgColor
}
transform=
{
isVisible
?
'
translateY(0)
'
:
'
translateY(-100%)
'
}
transform=
{
isVisible
?
'
translateY(0)
'
:
'
translateY(-100%)
'
}
transitionProperty=
"transform"
transitionProperty=
"transform"
...
...
ui/customAbi/CustomAbiModal/CustomAbiForm.tsx
View file @
8b68dfdc
...
@@ -128,6 +128,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
...
@@ -128,6 +128,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
<
Textarea
<
Textarea
{
...
field
}
{
...
field
}
size=
"lg"
size=
"lg"
minH=
"300px"
isInvalid=
{
Boolean
(
errors
.
abi
)
}
isInvalid=
{
Boolean
(
errors
.
abi
)
}
/>
/>
<
FormLabel
>
{
getPlaceholderWithError
(
`Custom ABI [{...}] (JSON format)`
,
errors
.
abi
?.
message
)
}
</
FormLabel
>
<
FormLabel
>
{
getPlaceholderWithError
(
`Custom ABI [{...}] (JSON format)`
,
errors
.
abi
?.
message
)
}
</
FormLabel
>
...
...
ui/customAbi/CustomAbiTable/CustomAbiListItem.tsx
0 → 100644
View file @
8b68dfdc
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
CustomAbi
}
from
'
types/api/account
'
;
import
AccountListItemMobile
from
'
ui/shared/AccountListItemMobile
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
interface
Props
{
item
:
CustomAbi
;
onEditClick
:
(
item
:
CustomAbi
)
=>
void
;
onDeleteClick
:
(
item
:
CustomAbi
)
=>
void
;
}
const
CustomAbiListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
return
(
<
AccountListItemMobile
>
<
AddressSnippet
address=
{
item
.
contract_address_hash
}
subtitle=
{
item
.
name
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
</
AccountListItemMobile
>
);
};
export
default
React
.
memo
(
CustomAbiListItem
);
ui/customAbi/CustomAbiTable/CustomAbiTableItem.tsx
View file @
8b68dfdc
import
{
import
{
Tr
,
Tr
,
Td
,
Td
,
HStack
,
Text
,
}
from
'
@chakra-ui/react
'
;
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
CustomAbi
}
from
'
types/api/account
'
;
import
type
{
CustomAbi
}
from
'
types/api/account
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
DeleteButton
from
'
ui/shared/DeleteButton
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
EditButton
from
'
ui/shared/EditButton
'
;
interface
Props
{
interface
Props
{
item
:
CustomAbi
;
item
:
CustomAbi
;
...
@@ -31,17 +28,10 @@ const CustomAbiTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -31,17 +28,10 @@ const CustomAbiTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Td
>
<
Td
>
<
HStack
>
<
AddressSnippet
address=
{
item
.
contract_address_hash
}
subtitle=
{
item
.
name
}
/>
<
Text
fontSize=
"md"
fontWeight=
{
600
}
>
{
item
.
contract_address_hash
}
</
Text
>
<
CopyToClipboard
text=
{
item
.
contract_address_hash
}
/>
</
HStack
>
<
Text
fontSize=
"sm"
marginTop=
{
0.5
}
variant=
"secondary"
>
{
item
.
name
}
</
Text
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
HStack
spacing=
{
6
}
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
EditButton
onClick=
{
onItemEditClick
}
/>
<
DeleteButton
onClick=
{
onItemDeleteClick
}
/>
</
HStack
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/customAbi/DeleteCustomAbiModal.tsx
View file @
8b68dfdc
...
@@ -28,7 +28,7 @@ const DeleteCustomAbiModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
...
@@ -28,7 +28,7 @@ const DeleteCustomAbiModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
const
renderText
=
useCallback
(()
=>
{
const
renderText
=
useCallback
(()
=>
{
return
(
return
(
<
Text
display=
"flex"
>
Custom ABI for
<
Text
fontWeight=
"600"
whiteSpace=
"pre
"
>
{
` "${ data.name || 'name' }" `
}
</
Text
>
will be deleted
</
Text
>
<
Text
>
Custom ABI for
<
Text
fontWeight=
"600"
as=
"span
"
>
{
` "${ data.name || 'name' }" `
}
</
Text
>
will be deleted
</
Text
>
);
);
},
[
data
.
name
]);
},
[
data
.
name
]);
...
...
ui/pages/ApiKeys.tsx
View file @
8b68dfdc
import
{
Box
,
Button
,
H
Stack
,
Link
,
Text
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
Stack
,
Link
,
Text
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
ApiKey
,
ApiKeys
}
from
'
types/api/account
'
;
import
type
{
ApiKey
,
ApiKeys
}
from
'
types/api/account
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
space
}
from
'
lib/html-entities
'
;
import
{
space
}
from
'
lib/html-entities
'
;
import
ApiKeyModal
from
'
ui/apiKey/ApiKeyModal/ApiKeyModal
'
;
import
ApiKeyModal
from
'
ui/apiKey/ApiKeyModal/ApiKeyModal
'
;
import
ApiKeyListItem
from
'
ui/apiKey/ApiKeyTable/ApiKeyListItem
'
;
import
ApiKeyTable
from
'
ui/apiKey/ApiKeyTable/ApiKeyTable
'
;
import
ApiKeyTable
from
'
ui/apiKey/ApiKeyTable/ApiKeyTable
'
;
import
DeleteApiKeyModal
from
'
ui/apiKey/DeleteApiKeyModal
'
;
import
DeleteApiKeyModal
from
'
ui/apiKey/DeleteApiKeyModal
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageHeader
from
'
ui/shared/AccountPageHeader
'
;
import
AccountPageHeader
from
'
ui/shared/AccountPageHeader
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
SkeletonAccountMobile
from
'
ui/shared/SkeletonAccountMobile
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
DataFetchAlert
from
'
../shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
../shared/DataFetchAlert
'
;
...
@@ -20,6 +24,7 @@ const DATA_LIMIT = 3;
...
@@ -20,6 +24,7 @@ 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
();
const
[
apiKeyModalData
,
setApiKeyModalData
]
=
useState
<
ApiKey
>
();
const
[
apiKeyModalData
,
setApiKeyModalData
]
=
useState
<
ApiKey
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
ApiKey
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
ApiKey
>
();
...
@@ -47,40 +52,59 @@ const ApiKeysPage: React.FC = () => {
...
@@ -47,40 +52,59 @@ const ApiKeysPage: React.FC = () => {
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
description
=
(
const
description
=
(
<
Text
marginBottom=
{
12
}
>
<
AccountPageDescription
>
Create API keys to use for your RPC and EthRPC API requests. For more information, see
{
space
}
Create API keys to use for your RPC and EthRPC API requests. For more information, see
{
space
}
<
Link
href=
"#"
>
“How to use a Blockscout API key”
</
Link
>
.
<
Link
href=
"#"
>
“How to use a Blockscout API key”
</
Link
>
.
</
Text
>
</
AccountPageDescription
>
);
);
const
content
=
(()
=>
{
const
content
=
(()
=>
{
if
(
isLoading
&&
!
data
)
{
if
(
isLoading
&&
!
data
)
{
return
(
const
loader
=
isMobile
?
<
SkeletonAccountMobile
/>
:
(
<>
<>
{
description
}
<
SkeletonTable
columns=
{
[
'
100%
'
,
'
108px
'
]
}
/>
<
SkeletonTable
columns=
{
[
'
100%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"48px"
width=
"156px"
marginTop=
{
8
}
/>
<
Skeleton
height=
"48px"
width=
"156px"
marginTop=
{
8
}
/>
</>
</>
);
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
}
if
(
isError
)
{
if
(
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
list
=
isMobile
?
(
<
Box
>
{
data
.
map
((
item
)
=>
(
<
ApiKeyListItem
item=
{
item
}
key=
{
item
.
api_key
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
))
}
</
Box
>
)
:
(
<
ApiKeyTable
data=
{
data
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
limit=
{
DATA_LIMIT
}
/>
);
const
canAdd
=
data
.
length
<
DATA_LIMIT
;
const
canAdd
=
data
.
length
<
DATA_LIMIT
;
return
(
return
(
<>
<>
{
description
}
{
description
}
{
Boolean
(
data
.
length
)
&&
(
{
Boolean
(
data
.
length
)
&&
list
}
<
ApiKeyTable
<
Stack
marginTop=
{
8
}
spacing=
{
5
}
direction=
{
{
base
:
'
column
'
,
lg
:
'
row
'
}
}
>
data=
{
data
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
limit=
{
DATA_LIMIT
}
/>
)
}
<
HStack
marginTop=
{
8
}
spacing=
{
5
}
>
<
Button
<
Button
variant=
"primary"
variant=
"primary"
size=
"lg"
size=
"lg"
...
@@ -94,7 +118,7 @@ const ApiKeysPage: React.FC = () => {
...
@@ -94,7 +118,7 @@ const ApiKeysPage: React.FC = () => {
{
`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
>
)
}
)
}
</
H
Stack
>
</
Stack
>
<
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 @
8b68dfdc
import
{
Box
,
Button
,
HStack
,
Text
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
HStack
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
CustomAbi
,
CustomAbis
}
from
'
types/api/account
'
;
import
type
{
CustomAbi
,
CustomAbis
}
from
'
types/api/account
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
CustomAbiModal
from
'
ui/customAbi/CustomAbiModal/CustomAbiModal
'
;
import
CustomAbiModal
from
'
ui/customAbi/CustomAbiModal/CustomAbiModal
'
;
import
CustomAbiListItem
from
'
ui/customAbi/CustomAbiTable/CustomAbiListItem
'
;
import
CustomAbiTable
from
'
ui/customAbi/CustomAbiTable/CustomAbiTable
'
;
import
CustomAbiTable
from
'
ui/customAbi/CustomAbiTable/CustomAbiTable
'
;
import
DeleteCustomAbiModal
from
'
ui/customAbi/DeleteCustomAbiModal
'
;
import
DeleteCustomAbiModal
from
'
ui/customAbi/DeleteCustomAbiModal
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageHeader
from
'
ui/shared/AccountPageHeader
'
;
import
AccountPageHeader
from
'
ui/shared/AccountPageHeader
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
SkeletonAccountMobile
from
'
ui/shared/SkeletonAccountMobile
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
DataFetchAlert
from
'
../shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
../shared/DataFetchAlert
'
;
...
@@ -17,6 +21,7 @@ import DataFetchAlert from '../shared/DataFetchAlert';
...
@@ -17,6 +21,7 @@ import DataFetchAlert from '../shared/DataFetchAlert';
const
CustomAbiPage
:
React
.
FC
=
()
=>
{
const
CustomAbiPage
:
React
.
FC
=
()
=>
{
const
customAbiModalProps
=
useDisclosure
();
const
customAbiModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
const
[
customAbiModalData
,
setCustomAbiModalData
]
=
useState
<
CustomAbi
>
();
const
[
customAbiModalData
,
setCustomAbiModalData
]
=
useState
<
CustomAbi
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
CustomAbi
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
CustomAbi
>
();
...
@@ -44,36 +49,55 @@ const CustomAbiPage: React.FC = () => {
...
@@ -44,36 +49,55 @@ const CustomAbiPage: React.FC = () => {
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
description
=
(
const
description
=
(
<
Text
marginBottom=
{
12
}
>
<
AccountPageDescription
>
Add custom ABIs for any contract and access when logged into your account. Helpful for debugging, functional testing and contract interaction.
Add custom ABIs for any contract and access when logged into your account. Helpful for debugging, functional testing and contract interaction.
</
Text
>
</
AccountPageDescription
>
);
);
const
content
=
(()
=>
{
const
content
=
(()
=>
{
if
(
isLoading
&&
!
data
)
{
if
(
isLoading
&&
!
data
)
{
return
(
const
loader
=
isMobile
?
<
SkeletonAccountMobile
/>
:
(
<>
<>
{
description
}
<
SkeletonTable
columns=
{
[
'
100%
'
,
'
108px
'
]
}
/>
<
SkeletonTable
columns=
{
[
'
100%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
</>
</>
);
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
}
if
(
isError
)
{
if
(
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
return
(
const
list
=
isMobile
?
(
<>
<
Box
>
{
d
escription
}
{
d
ata
.
map
((
item
)
=>
(
{
data
.
length
>
0
&&
(
<
CustomAbiListItem
<
CustomAbiTable
item=
{
item
}
data=
{
data
}
key=
{
item
.
id
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
)
}
))
}
</
Box
>
)
:
(
<
CustomAbiTable
data=
{
data
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
return
(
<>
{
description
}
{
data
.
length
>
0
&&
list
}
<
HStack
marginTop=
{
8
}
spacing=
{
5
}
>
<
HStack
marginTop=
{
8
}
spacing=
{
5
}
>
<
Button
<
Button
variant=
"primary"
variant=
"primary"
...
...
ui/pages/PrivateTags.tsx
View file @
8b68dfdc
...
@@ -38,7 +38,7 @@ const PrivateTags = ({ tab }: Props) => {
...
@@ -38,7 +38,7 @@ const PrivateTags = ({ tab }: Props) => {
<
Box
h=
"100%"
>
<
Box
h=
"100%"
>
<
AccountPageHeader
text=
"Private tags"
/>
<
AccountPageHeader
text=
"Private tags"
/>
<
Tabs
variant=
"soft-rounded"
colorScheme=
"blue"
isLazy
onChange=
{
onChangeTab
}
defaultIndex=
{
TABS
.
indexOf
(
tab
)
}
>
<
Tabs
variant=
"soft-rounded"
colorScheme=
"blue"
isLazy
onChange=
{
onChangeTab
}
defaultIndex=
{
TABS
.
indexOf
(
tab
)
}
>
<
TabList
marginBottom=
{
8
}
>
<
TabList
marginBottom=
{
{
base
:
6
,
lg
:
8
}
}
>
<
Tab
>
Address
</
Tab
>
<
Tab
>
Address
</
Tab
>
<
Tab
>
Transaction
</
Tab
>
<
Tab
>
Transaction
</
Tab
>
</
TabList
>
</
TabList
>
...
...
ui/pages/PublicTags.tsx
View file @
8b68dfdc
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
{
ArrowBackIcon
}
from
'
@chakra-ui/icons
'
;
import
{
Box
,
Link
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
{
animateScroll
}
from
'
react-scroll
'
;
import
{
animateScroll
}
from
'
react-scroll
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
PublicTagsData
from
'
ui/publicTags/PublicTagsData
'
;
import
PublicTagsData
from
'
ui/publicTags/PublicTagsData
'
;
import
PublicTagsForm
from
'
ui/publicTags/PublicTagsForm/PublicTagsForm
'
;
import
PublicTagsForm
from
'
ui/publicTags/PublicTagsForm/PublicTagsForm
'
;
...
@@ -24,6 +26,7 @@ const PublicTagsComponent: React.FC = () => {
...
@@ -24,6 +26,7 @@ const PublicTagsComponent: React.FC = () => {
const
[
formData
,
setFormData
]
=
useState
<
PublicTag
>
();
const
[
formData
,
setFormData
]
=
useState
<
PublicTag
>
();
const
toast
=
useToast
();
const
toast
=
useToast
();
const
isMobile
=
useIsMobile
();
const
showToast
=
useCallback
((
action
:
TToastAction
)
=>
{
const
showToast
=
useCallback
((
action
:
TToastAction
)
=>
{
toast
({
toast
({
...
@@ -59,6 +62,7 @@ const PublicTagsComponent: React.FC = () => {
...
@@ -59,6 +62,7 @@ const PublicTagsComponent: React.FC = () => {
},
[
showToast
]);
},
[
showToast
]);
const
onTagDelete
=
useCallback
(()
=>
showToast
(
'
removed
'
),
[
showToast
]);
const
onTagDelete
=
useCallback
(()
=>
showToast
(
'
removed
'
),
[
showToast
]);
const
onGoBack
=
useCallback
(()
=>
setScreen
(
'
data
'
),
[
]);
let
content
;
let
content
;
let
header
;
let
header
;
...
@@ -74,6 +78,12 @@ const PublicTagsComponent: React.FC = () => {
...
@@ -74,6 +78,12 @@ const PublicTagsComponent: React.FC = () => {
return
(
return
(
<
Page
>
<
Page
>
<
Box
h=
"100%"
>
<
Box
h=
"100%"
>
{
isMobile
&&
screen
===
'
form
'
&&
(
<
Link
display=
"inline-flex"
alignItems=
"center"
mb=
{
6
}
onClick=
{
onGoBack
}
>
<
ArrowBackIcon
w=
{
6
}
h=
{
6
}
/>
<
Text
variant=
"inherit"
fontSize=
"sm"
ml=
{
2
}
>
Public tags
</
Text
>
</
Link
>
)
}
<
AccountPageHeader
text=
{
header
}
/>
<
AccountPageHeader
text=
{
header
}
/>
{
content
}
{
content
}
</
Box
>
</
Box
>
...
...
ui/pages/Watchlist.tsx
View file @
8b68dfdc
import
{
Box
,
Button
,
Text
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
TWatchlist
,
TWatchlistItem
}
from
'
types/client/account
'
;
import
type
{
TWatchlist
,
TWatchlistItem
}
from
'
types/client/account
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageHeader
from
'
ui/shared/AccountPageHeader
'
;
import
AccountPageHeader
from
'
ui/shared/AccountPageHeader
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
Page
from
'
ui/shared/Page/Page
'
;
import
SkeletonAccountMobile
from
'
ui/shared/SkeletonAccountMobile
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
SkeletonTable
from
'
ui/shared/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
WatchlistTable
from
'
ui/watchlist/WatchlistTable/WatchlistTable
'
;
import
WatchlistTable
from
'
ui/watchlist/WatchlistTable/WatchlistTable
'
;
const
WatchList
:
React
.
FC
=
()
=>
{
const
WatchList
:
React
.
FC
=
()
=>
{
...
@@ -19,6 +23,7 @@ const WatchList: React.FC = () => {
...
@@ -19,6 +23,7 @@ const WatchList: React.FC = () => {
const
addressModalProps
=
useDisclosure
();
const
addressModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
deleteModalProps
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
const
[
addressModalData
,
setAddressModalData
]
=
useState
<
TWatchlistItem
>
();
const
[
addressModalData
,
setAddressModalData
]
=
useState
<
TWatchlistItem
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
TWatchlistItem
>
();
const
[
deleteModalData
,
setDeleteModalData
]
=
useState
<
TWatchlistItem
>
();
...
@@ -44,32 +49,52 @@ const WatchList: React.FC = () => {
...
@@ -44,32 +49,52 @@ const WatchList: React.FC = () => {
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
description
=
(
const
description
=
(
<
Text
marginBottom=
{
12
}
>
<
AccountPageDescription
>
An email notification can be sent to you when an address on your watch list sends or receives any transactions.
An email notification can be sent to you when an address on your watch list sends or receives any transactions.
</
Text
>
</
AccountPageDescription
>
);
);
let
content
;
let
content
;
if
(
isLoading
&&
!
data
)
{
if
(
isLoading
&&
!
data
)
{
con
tent
=
(
con
st
loader
=
isMobile
?
<
SkeletonAccountMobile
showFooterSlot
/>
:
(
<>
<>
{
description
}
<
SkeletonTable
columns=
{
[
'
70%
'
,
'
30%
'
,
'
160px
'
,
'
108px
'
]
}
/>
<
SkeletonTable
columns=
{
[
'
70%
'
,
'
30%
'
,
'
160px
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
</>
</>
);
);
content
=
(
<>
{
description
}
{
loader
}
</>
);
}
else
if
(
isError
)
{
}
else
if
(
isError
)
{
content
=
<
DataFetchAlert
/>;
content
=
<
DataFetchAlert
/>;
}
else
{
}
else
{
content
=
(
const
list
=
isMobile
?
(
<>
<
Box
>
{
Boolean
(
data
?.
length
)
&&
(
{
data
.
map
((
item
)
=>
(
<
WatchlistTable
<
WatchListItem
data=
{
data
}
item=
{
item
}
key=
{
item
.
address_hash
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
)
}
))
}
</
Box
>
)
:
(
<
WatchlistTable
data=
{
data
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
content
=
(
<>
{
description
}
{
Boolean
(
data
?.
length
)
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Box
marginTop=
{
8
}
>
<
Button
<
Button
variant=
"primary"
variant=
"primary"
...
...
ui/privateTags/AddressTagTable/AddressTagListItem.tsx
0 → 100644
View file @
8b68dfdc
import
{
Tag
,
Flex
,
HStack
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
AddressTag
}
from
'
types/api/account
'
;
import
AccountListItemMobile
from
'
ui/shared/AccountListItemMobile
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
interface
Props
{
item
:
AddressTag
;
onEditClick
:
(
data
:
AddressTag
)
=>
void
;
onDeleteClick
:
(
data
:
AddressTag
)
=>
void
;
}
const
AddressTagListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
return
(
<
AccountListItemMobile
>
<
Flex
alignItems=
"flex-start"
flexDirection=
"column"
maxW=
"100%"
>
<
AddressSnippet
address=
{
item
.
address_hash
}
/>
<
HStack
spacing=
{
3
}
mt=
{
4
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Tag
variant=
"gray"
lineHeight=
"24px"
>
{
item
.
name
}
</
Tag
>
</
HStack
>
</
Flex
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
</
AccountListItemMobile
>
);
};
export
default
React
.
memo
(
AddressTagListItem
);
ui/privateTags/AddressTagTable/AddressTagTableItem.tsx
View file @
8b68dfdc
...
@@ -2,16 +2,13 @@ import {
...
@@ -2,16 +2,13 @@ import {
Tag
,
Tag
,
Tr
,
Tr
,
Td
,
Td
,
HStack
,
}
from
'
@chakra-ui/react
'
;
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
AddressTag
}
from
'
types/api/account
'
;
import
type
{
AddressTag
}
from
'
types/api/account
'
;
import
AddressIcon
from
'
ui/shared/AddressIcon
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
AddressLinkWithTooltip
from
'
ui/shared/AddressLinkWithTooltip
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
DeleteButton
from
'
ui/shared/DeleteButton
'
;
import
EditButton
from
'
ui/shared/EditButton
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
interface
Props
{
interface
Props
{
...
@@ -32,10 +29,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -32,10 +29,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Td
>
<
Td
>
<
HStack
spacing=
{
4
}
>
<
AddressSnippet
address=
{
item
.
address_hash
}
/>
<
AddressIcon
address=
{
item
.
address_hash
}
/>
<
AddressLinkWithTooltip
address=
{
item
.
address_hash
}
/>
</
HStack
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
TruncatedTextTooltip
label=
{
item
.
name
}
>
<
TruncatedTextTooltip
label=
{
item
.
name
}
>
...
@@ -45,10 +39,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -45,10 +39,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</
TruncatedTextTooltip
>
</
TruncatedTextTooltip
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
HStack
spacing=
{
6
}
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
EditButton
onClick=
{
onItemEditClick
}
/>
<
DeleteButton
onClick=
{
onItemDeleteClick
}
/>
</
HStack
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/privateTags/DeletePrivateTagModal.tsx
View file @
8b68dfdc
...
@@ -37,7 +37,7 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type })
...
@@ -37,7 +37,7 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type })
const
renderText
=
useCallback
(()
=>
{
const
renderText
=
useCallback
(()
=>
{
return
(
return
(
<
Text
display=
"flex"
>
Tag
<
Text
fontWeight=
"600"
whiteSpace=
"pre
"
>
{
` "${ tag || 'tag' }" `
}
</
Text
>
will be deleted
</
Text
>
<
Text
>
Tag
<
Text
fontWeight=
"600"
as=
"span
"
>
{
` "${ tag || 'tag' }" `
}
</
Text
>
will be deleted
</
Text
>
);
);
},
[
tag
]);
},
[
tag
]);
...
...
ui/privateTags/PrivateAddressTags.tsx
View file @
8b68dfdc
import
{
Box
,
Button
,
Text
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
AddressTags
,
AddressTag
}
from
'
types/api/account
'
;
import
type
{
AddressTags
,
AddressTag
}
from
'
types/api/account
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
SkeletonAccountMobile
from
'
ui/shared/SkeletonAccountMobile
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
AddressModal
from
'
./AddressModal/AddressModal
'
;
import
AddressModal
from
'
./AddressModal/AddressModal
'
;
import
AddressTagListItem
from
'
./AddressTagTable/AddressTagListItem
'
;
import
AddressTagTable
from
'
./AddressTagTable/AddressTagTable
'
;
import
AddressTagTable
from
'
./AddressTagTable/AddressTagTable
'
;
import
DeletePrivateTagModal
from
'
./DeletePrivateTagModal
'
;
import
DeletePrivateTagModal
from
'
./DeletePrivateTagModal
'
;
...
@@ -18,6 +22,7 @@ const PrivateAddressTags = () => {
...
@@ -18,6 +22,7 @@ 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
>
();
...
@@ -43,36 +48,55 @@ const PrivateAddressTags = () => {
...
@@ -43,36 +48,55 @@ const PrivateAddressTags = () => {
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
description
=
(
const
description
=
(
<
Text
marginBottom=
{
12
}
>
<
AccountPageDescription
>
Use private
transaction tags to label any transaction
s of interest.
Use private
address tags to track any addresse
s of interest.
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.
</
Text
>
</
AccountPageDescription
>
);
);
if
(
isLoading
&&
!
addressTagsData
)
{
if
(
isLoading
&&
!
addressTagsData
)
{
return
(
const
loader
=
isMobile
?
<
SkeletonAccountMobile
/>
:
(
<>
<>
{
description
}
<
SkeletonTable
columns=
{
[
'
60%
'
,
'
40%
'
,
'
108px
'
]
}
/>
<
SkeletonTable
columns=
{
[
'
60%
'
,
'
40%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
</>
</>
);
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
}
if
(
isError
)
{
if
(
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
return
(
const
list
=
isMobile
?
(
<>
<
Box
>
{
description
}
{
addressTagsData
.
map
((
item
:
AddressTag
)
=>
(
{
Boolean
(
addressTagsData
?.
length
)
&&
(
<
AddressTagListItem
<
AddressTagTable
item=
{
item
}
data=
{
addressTagsData
}
key=
{
item
.
id
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
)
}
))
}
</
Box
>
)
:
(
<
AddressTagTable
data=
{
addressTagsData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
return
(
<>
{
description
}
{
Boolean
(
addressTagsData
?.
length
)
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Box
marginTop=
{
8
}
>
<
Button
<
Button
variant=
"primary"
variant=
"primary"
...
...
ui/privateTags/PrivateTransactionTags.tsx
View file @
8b68dfdc
import
{
Box
,
Button
,
Skeleton
,
Text
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
TransactionTags
,
TransactionTag
}
from
'
types/api/account
'
;
import
type
{
TransactionTags
,
TransactionTag
}
from
'
types/api/account
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
SkeletonAccountMobile
from
'
ui/shared/SkeletonAccountMobile
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
DeletePrivateTagModal
from
'
./DeletePrivateTagModal
'
;
import
DeletePrivateTagModal
from
'
./DeletePrivateTagModal
'
;
import
TransactionModal
from
'
./TransactionModal/TransactionModal
'
;
import
TransactionModal
from
'
./TransactionModal/TransactionModal
'
;
import
TransactionTagListItem
from
'
./TransactionTagTable/TransactionTagListItem
'
;
import
TransactionTagTable
from
'
./TransactionTagTable/TransactionTagTable
'
;
import
TransactionTagTable
from
'
./TransactionTagTable/TransactionTagTable
'
;
const
PrivateTransactionTags
=
()
=>
{
const
PrivateTransactionTags
=
()
=>
{
...
@@ -18,6 +22,7 @@ const PrivateTransactionTags = () => {
...
@@ -18,6 +22,7 @@ const PrivateTransactionTags = () => {
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
>
();
...
@@ -43,36 +48,55 @@ const PrivateTransactionTags = () => {
...
@@ -43,36 +48,55 @@ const PrivateTransactionTags = () => {
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
description
=
(
const
description
=
(
<
Text
marginBottom=
{
12
}
>
<
AccountPageDescription
>
Use private transaction tags to label any transactions of interest.
Use private transaction tags to label any transactions of interest.
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.
</
Text
>
</
AccountPageDescription
>
);
);
if
(
isLoading
&&
!
transactionTagsData
)
{
if
(
isLoading
&&
!
transactionTagsData
)
{
return
(
const
loader
=
isMobile
?
<
SkeletonAccountMobile
/>
:
(
<>
<>
{
description
}
<
SkeletonTable
columns=
{
[
'
75%
'
,
'
25%
'
,
'
108px
'
]
}
/>
<
SkeletonTable
columns=
{
[
'
75%
'
,
'
25%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
<
Skeleton
height=
"44px"
width=
"156px"
marginTop=
{
8
}
/>
</>
</>
);
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
}
if
(
isError
)
{
if
(
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
return
(
const
list
=
isMobile
?
(
<>
<
Box
>
{
description
}
{
transactionTagsData
.
map
((
item
)
=>
(
{
Boolean
(
transactionTagsData
.
length
)
&&
(
<
TransactionTagListItem
<
TransactionTagTable
item=
{
item
}
data=
{
transactionTagsData
}
key=
{
item
.
id
}
onDeleteClick=
{
onDeleteClick
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
onEditClick=
{
onEditClick
}
/>
/>
)
}
))
}
</
Box
>
)
:
(
<
TransactionTagTable
data=
{
transactionTagsData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
/>
);
return
(
<>
{
description
}
{
Boolean
(
transactionTagsData
.
length
)
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Box
marginTop=
{
8
}
>
<
Button
<
Button
variant=
"primary"
variant=
"primary"
...
...
ui/privateTags/TransactionTagTable/TransactionTagListItem.tsx
0 → 100644
View file @
8b68dfdc
import
{
Tag
,
HStack
,
Text
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
TransactionTag
}
from
'
types/api/account
'
;
import
AccountListItemMobile
from
'
ui/shared/AccountListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TransactionSnippet
from
'
ui/shared/TransactionSnippet
'
;
interface
Props
{
item
:
TransactionTag
;
onEditClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
}
const
TransactionTagListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
return
(
<
AccountListItemMobile
>
<
Flex
alignItems=
"flex-start"
flexDirection=
"column"
maxW=
"100%"
>
<
TransactionSnippet
hash=
{
item
.
transaction_hash
}
/>
<
HStack
spacing=
{
3
}
mt=
{
4
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Tag
variant=
"gray"
lineHeight=
"24px"
>
{
item
.
name
}
</
Tag
>
</
HStack
>
</
Flex
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
</
AccountListItemMobile
>
);
};
export
default
React
.
memo
(
TransactionTagListItem
);
ui/privateTags/TransactionTagTable/TransactionTagTableItem.tsx
View file @
8b68dfdc
...
@@ -2,16 +2,14 @@ import {
...
@@ -2,16 +2,14 @@ import {
Tag
,
Tag
,
Tr
,
Tr
,
Td
,
Td
,
HStack
,
Tooltip
,
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
AddressLinkWithTooltip
from
'
ui/shared/AddressLinkWithTooltip
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
DeleteButton
from
'
ui/shared/DeleteButton
'
;
import
TransactionSnippet
from
'
ui/shared/TransactionSnippet
'
;
import
EditButton
from
'
ui/shared/EditButton
'
;
interface
Props
{
interface
Props
{
item
:
TransactionTag
;
item
:
TransactionTag
;
...
@@ -19,7 +17,7 @@ interface Props {
...
@@ -19,7 +17,7 @@ interface Props {
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
onDeleteClick
:
(
data
:
TransactionTag
)
=>
void
;
}
}
const
Address
TagTableItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
Transaction
TagTableItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
},
[
item
,
onEditClick
]);
...
@@ -31,7 +29,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -31,7 +29,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
return
(
return
(
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Tr
alignItems=
"top"
key=
{
item
.
id
}
>
<
Td
>
<
Td
>
<
AddressLinkWithTooltip
address
=
{
item
.
transaction_hash
}
/>
<
TransactionSnippet
hash
=
{
item
.
transaction_hash
}
/>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
Tooltip
label=
{
item
.
name
}
>
<
Tooltip
label=
{
item
.
name
}
>
...
@@ -41,13 +39,10 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -41,13 +39,10 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</
Tooltip
>
</
Tooltip
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
HStack
spacing=
{
6
}
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
EditButton
onClick=
{
onItemEditClick
}
/>
<
DeleteButton
onClick=
{
onItemDeleteClick
}
/>
</
HStack
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
};
};
export
default
Address
TagTableItem
;
export
default
Transaction
TagTableItem
;
ui/publicTags/DeletePublicTagModal.tsx
View file @
8b68dfdc
import
{
Flex
,
Text
,
FormControl
,
FormLabel
,
Textarea
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Text
,
FormControl
,
FormLabel
,
Textarea
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
ChangeEvent
}
from
'
react
'
;
import
type
{
ChangeEvent
}
from
'
react
'
;
...
@@ -22,6 +22,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
...
@@ -22,6 +22,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
const
tags
=
data
.
tags
.
split
(
'
;
'
);
const
tags
=
data
.
tags
.
split
(
'
;
'
);
const
queryClient
=
useQueryClient
();
const
queryClient
=
useQueryClient
();
const
formBackgroundColor
=
useColorModeValue
(
'
white
'
,
'
gray.900
'
);
const
deleteApiKey
=
useCallback
(()
=>
{
const
deleteApiKey
=
useCallback
(()
=>
{
const
body
=
JSON
.
stringify
({
remove_reason
:
reason
});
const
body
=
JSON
.
stringify
({
remove_reason
:
reason
});
...
@@ -44,9 +45,9 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
...
@@ -44,9 +45,9 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
if
(
tags
.
length
===
1
)
{
if
(
tags
.
length
===
1
)
{
text
=
(
text
=
(
<>
<>
<
Text
display=
"
flex
"
>
Public tag
</
Text
>
<
Text
display=
"
inline"
as=
"span
"
>
Public tag
</
Text
>
<
Text
fontWeight=
"600"
whiteSpace=
"pre"
>
{
` "${ tags[0] }" `
}
</
Text
>
<
Text
fontWeight=
"600"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tags[0] }" `
}
</
Text
>
<
Text
>
will be removed.
</
Text
>
<
Text
as=
"span"
>
will be removed.
</
Text
>
</>
</>
);
);
}
}
...
@@ -54,29 +55,29 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
...
@@ -54,29 +55,29 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
const
tagsText
:
Array
<
JSX
.
Element
|
string
>
=
[];
const
tagsText
:
Array
<
JSX
.
Element
|
string
>
=
[];
tags
.
forEach
((
tag
,
index
)
=>
{
tags
.
forEach
((
tag
,
index
)
=>
{
if
(
index
<
tags
.
length
-
2
)
{
if
(
index
<
tags
.
length
-
2
)
{
tagsText
.
push
(<
Text
fontWeight=
"600"
whiteSpace=
"pre"
>
{
` "${ tag }"`
}
</
Text
>);
tagsText
.
push
(<
Text
fontWeight=
"600"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tag }"`
}
</
Text
>);
tagsText
.
push
(
'
,
'
);
tagsText
.
push
(
'
,
'
);
}
}
if
(
index
===
tags
.
length
-
2
)
{
if
(
index
===
tags
.
length
-
2
)
{
tagsText
.
push
(<
Text
fontWeight=
"600"
whiteSpace=
"pre"
>
{
` "${ tag }" `
}
</
Text
>);
tagsText
.
push
(<
Text
fontWeight=
"600"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tag }" `
}
</
Text
>);
tagsText
.
push
(
'
and
'
);
tagsText
.
push
(
'
and
'
);
}
}
if
(
index
===
tags
.
length
-
1
)
{
if
(
index
===
tags
.
length
-
1
)
{
tagsText
.
push
(<
Text
fontWeight=
"600"
whiteSpace=
"pre"
>
{
` "${ tag }" `
}
</
Text
>);
tagsText
.
push
(<
Text
fontWeight=
"600"
whiteSpace=
"pre"
as=
"span"
>
{
` "${ tag }" `
}
</
Text
>);
}
}
});
});
text
=
(
text
=
(
<>
<>
<
Text
>
Public tags
</
Text
>
{
tagsText
}
<
Text
>
will be removed.
</
Text
>
<
Text
as=
"span"
>
Public tags
</
Text
>
{
tagsText
}
<
Text
as=
"span"
>
will be removed.
</
Text
>
</>
</>
);
);
}
}
return
(
return
(
<>
<>
<
Fle
x
marginBottom=
{
12
}
>
<
Bo
x
marginBottom=
{
12
}
>
{
text
}
{
text
}
</
Fle
x
>
</
Bo
x
>
<
FormControl
variant=
"floating"
id=
"tag-delete"
>
<
FormControl
variant=
"floating"
id=
"tag-delete"
backgroundColor=
{
formBackgroundColor
}
>
<
Textarea
<
Textarea
size=
"lg"
size=
"lg"
value=
{
reason
}
value=
{
reason
}
...
@@ -86,7 +87,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
...
@@ -86,7 +87,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
</
FormControl
>
</
FormControl
>
</>
</>
);
);
},
[
tags
,
reason
,
onFieldChange
]);
},
[
tags
,
reason
,
onFieldChange
,
formBackgroundColor
]);
return
(
return
(
<
DeleteModal
<
DeleteModal
...
...
ui/publicTags/PublicTagTable/PublicTagListItem.tsx
0 → 100644
View file @
8b68dfdc
import
{
Tag
,
VStack
,
Text
,
HStack
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
AccountListItemMobile
from
'
ui/shared/AccountListItemMobile
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
interface
Props
{
item
:
PublicTag
;
onEditClick
:
(
data
:
PublicTag
)
=>
void
;
onDeleteClick
:
(
data
:
PublicTag
)
=>
void
;
}
const
PublicTagListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
return
(
<
AccountListItemMobile
>
<
VStack
spacing=
{
3
}
alignItems=
"flex-start"
maxW=
"100%"
>
<
VStack
spacing=
{
4
}
alignItems=
"unset"
maxW=
"100%"
>
{
item
.
addresses
.
map
((
address
)
=>
<
AddressSnippet
key=
{
address
}
address=
{
address
}
/>)
}
</
VStack
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Public tags
</
Text
>
<
HStack
spacing=
{
2
}
alignItems=
"baseline"
>
{
item
.
tags
.
split
(
'
;
'
).
map
((
tag
)
=>
{
return
(
<
TruncatedTextTooltip
label=
{
tag
}
key=
{
tag
}
>
<
Tag
variant=
"gray"
lineHeight=
"24px"
>
{
tag
}
</
Tag
>
</
TruncatedTextTooltip
>
);
})
}
</
HStack
>
</
HStack
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Status
</
Text
>
<
Text
fontSize=
"sm"
variant=
"secondary"
>
Submitted
</
Text
>
</
HStack
>
</
VStack
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
</
AccountListItemMobile
>
);
};
export
default
React
.
memo
(
PublicTagListItem
);
ui/publicTags/PublicTagTable/PublicTagTableItem.tsx
View file @
8b68dfdc
import
{
import
{
Box
,
Tag
,
Tag
,
Tr
,
Tr
,
Td
,
Td
,
HStack
,
VStack
,
VStack
,
Text
,
Text
,
}
from
'
@chakra-ui/react
'
;
}
from
'
@chakra-ui/react
'
;
...
@@ -11,10 +9,8 @@ import React, { useCallback } from 'react';
...
@@ -11,10 +9,8 @@ import React, { useCallback } from 'react';
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
type
{
PublicTag
}
from
'
types/api/account
'
;
import
AddressIcon
from
'
ui/shared/AddressIcon
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
AddressLinkWithTooltip
from
'
ui/shared/AddressLinkWithTooltip
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
DeleteButton
from
'
ui/shared/DeleteButton
'
;
import
EditButton
from
'
ui/shared/EditButton
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
interface
Props
{
interface
Props
{
...
@@ -36,18 +32,7 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -36,18 +32,7 @@ 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
.
map
((
address
)
=>
{
{
item
.
addresses
.
map
((
address
)
=>
<
AddressSnippet
key=
{
address
}
address=
{
address
}
/>)
}
return
(
<
HStack
spacing=
{
4
}
key=
{
address
}
overflow=
"hidden"
alignItems=
"start"
>
<
AddressIcon
address=
{
address
}
/>
<
Box
overflow=
"hidden"
>
<
AddressLinkWithTooltip
address=
{
address
}
/>
{
/* will be added later */
}
{
/* <Text fontSize="sm" variant="secondary" mt={ 0.5 }>Address Name</Text> */
}
</
Box
>
</
HStack
>
);
})
}
</
VStack
>
</
VStack
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
...
@@ -69,10 +54,7 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -69,10 +54,7 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</
VStack
>
</
VStack
>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
HStack
spacing=
{
6
}
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
EditButton
onClick=
{
onItemEditClick
}
/>
<
DeleteButton
onClick=
{
onItemDeleteClick
}
/>
</
HStack
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
ui/publicTags/PublicTagsData.tsx
View file @
8b68dfdc
import
{
Box
,
Text
,
Button
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Button
,
Skeleton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
{
useQuery
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
PublicTags
,
PublicTag
}
from
'
types/api/account
'
;
import
type
{
PublicTags
,
PublicTag
}
from
'
types/api/account
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
PublicTagListItem
from
'
ui/publicTags/PublicTagTable/PublicTagListItem
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
SkeletonAccountMobile
from
'
ui/shared/SkeletonAccountMobile
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
SkeletonTable
from
'
ui/shared/SkeletonTable
'
;
import
DeletePublicTagModal
from
'
./DeletePublicTagModal
'
;
import
DeletePublicTagModal
from
'
./DeletePublicTagModal
'
;
...
@@ -19,6 +23,7 @@ type Props = {
...
@@ -19,6 +23,7 @@ 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
}
=
useQuery
<
unknown
,
unknown
,
PublicTags
>
([
'
public-tags
'
],
async
()
=>
await
fetch
(
'
/api/account/public-tags
'
));
const
{
data
,
isLoading
,
isError
}
=
useQuery
<
unknown
,
unknown
,
PublicTags
>
([
'
public-tags
'
],
async
()
=>
await
fetch
(
'
/api/account/public-tags
'
));
...
@@ -41,32 +46,53 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
...
@@ -41,32 +46,53 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
description
=
(
const
description
=
(
<
Text
marginBottom=
{
12
}
>
<
AccountPageDescription
>
You can request a public category tag which is displayed to all Blockscout users.
You can request a public category tag which is displayed to all Blockscout users.
Public tags may be added to contract or external addresses, and any associated transactions will inherit that tag.
Public tags may be added to contract or external addresses, and any associated transactions will inherit that tag.
Clicking a tag opens a page with related information and helps provide context and data organization.
Clicking a tag opens a page with related information and helps provide context and data organization.
Requests are sent to a moderator for review and approval. This process can take several days.
Requests are sent to a moderator for review and approval. This process can take several days.
</
Text
>
</
AccountPageDescription
>
);
);
if
(
isLoading
)
{
if
(
isLoading
)
{
return
(
const
loader
=
isMobile
?
<
SkeletonAccountMobile
/>
:
(
<>
<>
{
description
}
<
SkeletonTable
columns=
{
[
'
50%
'
,
'
25%
'
,
'
25%
'
,
'
108px
'
]
}
/>
<
SkeletonTable
columns=
{
[
'
50%
'
,
'
25%
'
,
'
25%
'
,
'
108px
'
]
}
/>
<
Skeleton
height=
"48px"
width=
"270px"
marginTop=
{
8
}
/>
<
Skeleton
height=
"48px"
width=
"270px"
marginTop=
{
8
}
/>
</>
</>
);
);
return
(
<>
{
description
}
{
loader
}
</>
);
}
}
if
(
isError
)
{
if
(
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
list
=
isMobile
?
(
<
Box
>
{
data
.
map
((
item
)
=>
(
<
PublicTagListItem
item=
{
item
}
key=
{
item
.
id
}
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
))
}
</
Box
>
)
:
(
<
PublicTagTable
data=
{
data
}
onEditClick=
{
onItemEditClick
}
onDeleteClick=
{
onItemDeleteClick
}
/>
);
return
(
return
(
<>
<>
{
description
}
{
description
}
{
data
.
length
>
0
&&
<
PublicTagTable
data=
{
data
}
onEditClick=
{
onItemEditClick
}
onDeleteClick=
{
onItemDeleteClick
}
/>
}
{
data
.
length
>
0
&&
list
}
<
Box
marginTop=
{
8
}
>
<
Box
marginTop=
{
8
}
>
<
Button
<
Button
variant=
"primary"
variant=
"primary"
...
...
ui/publicTags/PublicTagsForm/PublicTagFormAddressInput.tsx
View file @
8b68dfdc
import
{
IconButton
,
Icon
}
from
'
@chakra-ui/react
'
;
import
{
IconButton
,
Icon
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
ControllerRenderProps
,
Control
,
FieldError
}
from
'
react-hook-form
'
;
import
type
{
ControllerRenderProps
,
Control
,
FieldError
}
from
'
react-hook-form
'
;
import
{
Controller
}
from
'
react-hook-form
'
;
import
{
Controller
}
from
'
react-hook-form
'
;
...
@@ -17,24 +17,25 @@ interface Props {
...
@@ -17,24 +17,25 @@ interface Props {
error
?:
FieldError
;
error
?:
FieldError
;
onAddFieldClick
:
(
e
:
React
.
SyntheticEvent
)
=>
void
;
onAddFieldClick
:
(
e
:
React
.
SyntheticEvent
)
=>
void
;
onRemoveFieldClick
:
(
index
:
number
)
=>
(
e
:
React
.
SyntheticEvent
)
=>
void
;
onRemoveFieldClick
:
(
index
:
number
)
=>
(
e
:
React
.
SyntheticEvent
)
=>
void
;
size
?:
string
;
}
}
const
MAX_INPUTS_NUM
=
10
;
const
MAX_INPUTS_NUM
=
10
;
export
default
function
PublicTagFormAction
({
control
,
index
,
fieldsLength
,
error
,
onAddFieldClick
,
onRemoveFieldClick
}:
Props
)
{
export
default
function
PublicTagFormAction
({
control
,
index
,
fieldsLength
,
error
,
onAddFieldClick
,
onRemoveFieldClick
,
size
}:
Props
)
{
const
renderAddressInput
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
`addresses.
${
number
}
.address`
>
})
=>
{
const
renderAddressInput
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
`addresses.
${
number
}
.address`
>
})
=>
{
return
(
return
(
<
AddressInput
<
Inputs
,
`
addresses
.
$
{
number
}
.
address
`
>
<
AddressInput
<
Inputs
,
`
addresses
.
$
{
number
}
.
address
`
>
field=
{
field
}
field=
{
field
}
error=
{
error
}
error=
{
error
}
size=
"lg"
size=
{
size
}
placeholder="Smart contract / Address (0x...)"
placeholder="Smart contract / Address (0x...)"
/
>
/
>
);
);
}, [ error ]);
}, [ error
, size
]);
return (
return (
<>
<
Flex
flexDir=
"column"
rowGap=
{
5
}
alignItems=
"flex-end"
>
<
Controller
<
Controller
name=
{
`addresses.${ index }.address`
}
name=
{
`addresses.${ index }.address`
}
control=
{
control
}
control=
{
control
}
...
@@ -44,31 +45,34 @@ export default function PublicTagFormAction({ control, index, fieldsLength, erro
...
@@ -44,31 +45,34 @@ export default function PublicTagFormAction({ control, index, fieldsLength, erro
required
:
index
===
0
,
required
:
index
===
0
,
}
}
}
}
/>
/>
{
index
===
fieldsLength
-
1
&&
fieldsLength
<
MAX_INPUTS_NUM
&&
(
<
Flex
<
IconButton
columnGap=
{
5
}
aria
-
label=
"add"
position=
{
{
base
:
'
static
'
,
lg
:
'
absolute
'
}
}
variant=
"iconBorder"
left=
{
{
base
:
'
auto
'
,
lg
:
'
calc(100% + 20px)
'
}
}
w=
"30px"
h=
"100%"
h=
"30px"
alignItems=
"center"
onClick=
{
onAddFieldClick
}
>
icon=
{
<
Icon
as=
{
PlusIcon
}
w=
"20px"
h=
"20px"
/>
}
{
fieldsLength
>
1
&&
(
position=
"absolute"
<
IconButton
right=
{
index
===
0
?
'
-50px
'
:
'
-100px
'
}
aria
-
label=
"delete"
top=
"25px"
variant=
"iconBorder"
/>
w=
"30px"
)
}
h=
"30px"
{
fieldsLength
>
1
&&
(
onClick=
{
onRemoveFieldClick
(
index
)
}
<
IconButton
icon=
{
<
Icon
as=
{
MinusIcon
}
w=
"20px"
h=
"20px"
/>
}
aria
-
label=
"delete"
/>
variant=
"iconBorder"
)
}
w=
"30px"
{
index
===
fieldsLength
-
1
&&
fieldsLength
<
MAX_INPUTS_NUM
&&
(
h=
"30px"
<
IconButton
onClick=
{
onRemoveFieldClick
(
index
)
}
aria
-
label=
"add"
icon=
{
<
Icon
as=
{
MinusIcon
}
w=
"20px"
h=
"20px"
/>
}
variant=
"iconBorder"
position=
"absolute"
w=
"30px"
right=
"-50px"
h=
"30px"
top=
"25px"
onClick=
{
onAddFieldClick
}
/>
icon=
{
<
Icon
as=
{
PlusIcon
}
w=
"20px"
h=
"20px"
/>
}
)
}
</>
/>
)
}
</
Flex
>
</
Flex
>
);
);
}
}
ui/publicTags/PublicTagsForm/PublicTagFormComment.tsx
View file @
8b68dfdc
...
@@ -12,23 +12,24 @@ const TEXT_INPUT_MAX_LENGTH = 255;
...
@@ -12,23 +12,24 @@ const TEXT_INPUT_MAX_LENGTH = 255;
interface
Props
{
interface
Props
{
control
:
Control
<
Inputs
>
;
control
:
Control
<
Inputs
>
;
error
?:
FieldError
;
error
?:
FieldError
;
size
?:
string
;
}
}
export
default
function
PublicTagFormComment
({
control
,
error
}:
Props
)
{
export
default
function
PublicTagFormComment
({
control
,
error
,
size
}:
Props
)
{
const
renderComment
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
'
comment
'
>
})
=>
{
const
renderComment
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
'
comment
'
>
})
=>
{
return
(
return
(
<
FormControl
variant=
"floating"
id=
{
field
.
name
}
size=
"lg"
isRequired
>
<
FormControl
variant=
"floating"
id=
{
field
.
name
}
size=
{
size
}
isRequired
>
<
Textarea
<
Textarea
{
...
field
}
{
...
field
}
isInvalid=
{
Boolean
(
error
)
}
isInvalid=
{
Boolean
(
error
)
}
size=
"lg"
size=
{
size
}
/>
/>
<
FormLabel
>
<
FormLabel
>
{
getPlaceholderWithError
(
'
Specify the reason for adding tags and color preference(s)
'
,
error
?.
message
)
}
{
getPlaceholderWithError
(
'
Specify the reason for adding tags and color preference(s)
'
,
error
?.
message
)
}
</
FormLabel
>
</
FormLabel
>
</
FormControl
>
</
FormControl
>
);
);
},
[
error
]);
},
[
error
,
size
]);
return
(
return
(
<
Controller
<
Controller
...
...
ui/publicTags/PublicTagsForm/PublicTagsForm.tsx
View file @
8b68dfdc
...
@@ -16,6 +16,7 @@ import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types
...
@@ -16,6 +16,7 @@ import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types
import
type
{
ErrorType
}
from
'
lib/client/fetch
'
;
import
type
{
ErrorType
}
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
getErrorMessage
from
'
lib/getErrorMessage
'
;
import
getErrorMessage
from
'
lib/getErrorMessage
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
EMAIL_REGEXP
}
from
'
lib/validations/email
'
;
import
{
EMAIL_REGEXP
}
from
'
lib/validations/email
'
;
import
FormSubmitAlert
from
'
ui/shared/FormSubmitAlert
'
;
import
FormSubmitAlert
from
'
ui/shared/FormSubmitAlert
'
;
...
@@ -52,10 +53,12 @@ const placeholders = {
...
@@ -52,10 +53,12 @@ const placeholders = {
comment
:
'
Specify the reason for adding tags and color preference(s).
'
,
comment
:
'
Specify the reason for adding tags and color preference(s).
'
,
}
as
Record
<
Path
<
Inputs
>
,
string
>
;
}
as
Record
<
Path
<
Inputs
>
,
string
>
;
const
ADDRESS_INPUT_BUTTONS_WIDTH
=
1
7
0
;
const
ADDRESS_INPUT_BUTTONS_WIDTH
=
1
0
0
;
const
PublicTagsForm
=
({
changeToDataScreen
,
data
}:
Props
)
=>
{
const
PublicTagsForm
=
({
changeToDataScreen
,
data
}:
Props
)
=>
{
const
queryClient
=
useQueryClient
();
const
queryClient
=
useQueryClient
();
const
isMobile
=
useIsMobile
();
const
inputSize
=
isMobile
?
'
md
'
:
'
lg
'
;
const
{
control
,
handleSubmit
,
formState
:
{
errors
,
isValid
},
setError
}
=
useForm
<
Inputs
>
({
const
{
control
,
handleSubmit
,
formState
:
{
errors
,
isValid
},
setError
}
=
useForm
<
Inputs
>
({
defaultValues
:
{
defaultValues
:
{
...
@@ -149,10 +152,10 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
...
@@ -149,10 +152,10 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
},
[
changeToDataScreen
]);
},
[
changeToDataScreen
]);
return
(
return
(
<
Box
width=
{
`calc(100% - ${ ADDRESS_INPUT_BUTTONS_WIDTH }px)`
}
maxWidth=
"844px"
>
<
Box
width=
{
{
base
:
'
auto
'
,
lg
:
`calc(100% - ${ ADDRESS_INPUT_BUTTONS_WIDTH }px)`
}
}
maxWidth=
"844px"
>
{
isAlertVisible
&&
<
Box
mb=
{
4
}
><
FormSubmitAlert
/></
Box
>
}
{
isAlertVisible
&&
<
Box
mb=
{
4
}
><
FormSubmitAlert
/></
Box
>
}
<
Text
size=
"sm"
variant=
"secondary"
paddingBottom=
{
5
}
>
Company info
</
Text
>
<
Text
size=
"sm"
variant=
"secondary"
paddingBottom=
{
5
}
>
Company info
</
Text
>
<
Grid
templateColumns=
"1fr 1fr"
rowGap=
{
4
}
columnGap=
{
5
}
>
<
Grid
templateColumns=
{
{
base
:
'
1fr
'
,
lg
:
'
1fr 1fr
'
}
}
rowGap=
{
4
}
columnGap=
{
5
}
>
<
GridItem
>
<
GridItem
>
<
PublicTagsFormInput
<
Inputs
>
<
PublicTagsFormInput
<
Inputs
>
fieldName="fullName"
fieldName="fullName"
...
@@ -160,6 +163,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
...
@@ -160,6 +163,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
label=
{
placeholders
.
fullName
}
label=
{
placeholders
.
fullName
}
error=
{
errors
.
fullName
}
error=
{
errors
.
fullName
}
required
required
size=
{
inputSize
}
/
>
/
>
</
GridItem
>
</
GridItem
>
<
GridItem
>
<
GridItem
>
...
@@ -168,6 +172,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
...
@@ -168,6 +172,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
control=
{
control
}
control=
{
control
}
label=
{
placeholders
.
companyName
}
label=
{
placeholders
.
companyName
}
error=
{
errors
.
companyName
}
error=
{
errors
.
companyName
}
size=
{
inputSize
}
/
>
/
>
</
GridItem
>
</
GridItem
>
<
GridItem
>
<
GridItem
>
...
@@ -178,6 +183,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
...
@@ -178,6 +183,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
pattern=
{
EMAIL_REGEXP
}
pattern=
{
EMAIL_REGEXP
}
error=
{
errors
.
email
}
error=
{
errors
.
email
}
required
required
size=
{
inputSize
}
/
>
/
>
</
GridItem
>
</
GridItem
>
<
GridItem
>
<
GridItem
>
...
@@ -186,10 +192,11 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
...
@@ -186,10 +192,11 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
control=
{
control
}
control=
{
control
}
label=
{
placeholders
.
companyUrl
}
label=
{
placeholders
.
companyUrl
}
error=
{
errors
?.
companyUrl
}
error=
{
errors
?.
companyUrl
}
size=
{
inputSize
}
/
>
/
>
</
GridItem
>
</
GridItem
>
</
Grid
>
</
Grid
>
<
Box
marginTop=
{
4
}
marginBottom=
{
8
}
>
<
Box
marginTop=
{
{
base
:
5
,
lg
:
8
}
}
marginBottom=
{
{
base
:
5
,
lg
:
8
}
}
>
<
PublicTagFormAction
control=
{
control
}
/>
<
PublicTagFormAction
control=
{
control
}
/>
</
Box
>
</
Box
>
<
Text
size=
"sm"
variant=
"secondary"
marginBottom=
{
5
}
>
Public tags (2 tags maximum, please use
"
;
"
as a divider)
</
Text
>
<
Text
size=
"sm"
variant=
"secondary"
marginBottom=
{
5
}
>
Public tags (2 tags maximum, please use
"
;
"
as a divider)
</
Text
>
...
@@ -199,7 +206,9 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
...
@@ -199,7 +206,9 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
control=
{
control
}
control=
{
control
}
label=
{
placeholders
.
tags
}
label=
{
placeholders
.
tags
}
error=
{
errors
.
tags
}
error=
{
errors
.
tags
}
required/
>
required
size=
{
inputSize
}
/
>
</
Box
>
</
Box
>
{
fields
.
map
((
field
,
index
)
=>
{
{
fields
.
map
((
field
,
index
)
=>
{
return
(
return
(
...
@@ -211,12 +220,13 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
...
@@ -211,12 +220,13 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
fieldsLength=
{
fields
.
length
}
fieldsLength=
{
fields
.
length
}
onAddFieldClick=
{
onAddFieldClick
}
onAddFieldClick=
{
onAddFieldClick
}
onRemoveFieldClick=
{
onRemoveFieldClick
}
onRemoveFieldClick=
{
onRemoveFieldClick
}
size=
{
inputSize
}
/>
/>
</
Box
>
</
Box
>
);
);
})
}
})
}
<
Box
marginBottom=
{
8
}
>
<
Box
marginBottom=
{
8
}
>
<
PublicTagFormComment
control=
{
control
}
error=
{
errors
.
comment
}
/>
<
PublicTagFormComment
control=
{
control
}
error=
{
errors
.
comment
}
size=
{
inputSize
}
/>
</
Box
>
</
Box
>
<
HStack
spacing=
{
6
}
>
<
HStack
spacing=
{
6
}
>
<
Button
<
Button
...
...
ui/publicTags/PublicTagsForm/PublicTagsFormInput.tsx
View file @
8b68dfdc
...
@@ -14,6 +14,7 @@ interface Props<TInputs extends FieldValues> {
...
@@ -14,6 +14,7 @@ interface Props<TInputs extends FieldValues> {
control
:
Control
<
TInputs
,
object
>
;
control
:
Control
<
TInputs
,
object
>
;
pattern
?:
RegExp
;
pattern
?:
RegExp
;
error
?:
FieldError
;
error
?:
FieldError
;
size
?:
string
;
}
}
export
default
function
PublicTagsFormInput
<
Inputs
extends
FieldValues
>
({
export
default
function
PublicTagsFormInput
<
Inputs
extends
FieldValues
>
({
...
@@ -23,13 +24,14 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({
...
@@ -23,13 +24,14 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({
fieldName
,
fieldName
,
pattern
,
pattern
,
error
,
error
,
size
,
}:
Props
<
Inputs
>
)
{
}:
Props
<
Inputs
>
)
{
const
renderInput
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
typeof
fieldName
>
})
=>
{
const
renderInput
=
useCallback
(({
field
}:
{
field
:
ControllerRenderProps
<
Inputs
,
typeof
fieldName
>
})
=>
{
return
(
return
(
<
FormControl
variant=
"floating"
id=
{
field
.
name
}
isRequired=
{
required
}
size=
"lg"
>
<
FormControl
variant=
"floating"
id=
{
field
.
name
}
isRequired=
{
required
}
size=
{
size
}
>
<
Input
<
Input
{
...
field
}
{
...
field
}
size=
"lg"
size=
{
size
}
required=
{
required
}
required=
{
required
}
isInvalid=
{
Boolean
(
error
)
}
isInvalid=
{
Boolean
(
error
)
}
maxLength=
{
TEXT_INPUT_MAX_LENGTH
}
maxLength=
{
TEXT_INPUT_MAX_LENGTH
}
...
@@ -37,7 +39,7 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({
...
@@ -37,7 +39,7 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({
<
FormLabel
>
{
getPlaceholderWithError
(
label
,
error
?.
message
)
}
</
FormLabel
>
<
FormLabel
>
{
getPlaceholderWithError
(
label
,
error
?.
message
)
}
</
FormLabel
>
</
FormControl
>
</
FormControl
>
);
);
},
[
label
,
required
,
error
]);
},
[
label
,
required
,
error
,
size
]);
return
(
return
(
<
Controller
<
Controller
name=
{
fieldName
}
name=
{
fieldName
}
...
...
ui/shared/AccountListItemMobile.tsx
0 → 100644
View file @
8b68dfdc
import
{
VStack
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
interface
Props
{
children
:
React
.
ReactNode
;
}
const
AccountListItemMobile
=
({
children
}:
Props
)
=>
{
return
(
<
VStack
gap=
{
4
}
alignItems=
"flex-start"
paddingY=
{
6
}
borderColor=
{
useColorModeValue
(
'
blackAlpha.200
'
,
'
whiteAlpha.200
'
)
}
borderTopWidth=
"1px"
_last=
{
{
borderBottomWidth
:
'
1px
'
,
}
}
>
{
children
}
</
VStack
>
);
};
export
default
AccountListItemMobile
;
ui/shared/AccountPageDescription.tsx
0 → 100644
View file @
8b68dfdc
import
{
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
const
AccountPageDescription
=
({
children
}:
{
children
:
React
.
ReactNode
})
=>
{
return
(
<
Text
marginBottom=
{
{
base
:
6
,
lg
:
12
}
}
>
{
children
}
</
Text
>
);
};
export
default
AccountPageDescription
;
ui/shared/AccountPageHeader.tsx
View file @
8b68dfdc
import
{
Heading
}
from
'
@chakra-ui/react
'
;
import
{
Heading
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
const
PageHeader
=
({
text
}:
{
text
:
string
})
=>
{
const
Account
PageHeader
=
({
text
}:
{
text
:
string
})
=>
{
return
(
return
(
<
Heading
as=
"h1"
size=
"lg"
marginBottom=
{
8
}
>
{
text
}
</
Heading
>
<
Heading
as=
"h1"
size=
"lg"
marginBottom=
{
{
base
:
6
,
lg
:
8
}
}
>
{
text
}
</
Heading
>
);
);
};
};
export
default
PageHeader
;
export
default
Account
PageHeader
;
ui/shared/AddressIcon.tsx
View file @
8b68dfdc
...
@@ -4,7 +4,7 @@ import Jazzicon, { jsNumberForAddress } from 'react-jazzicon';
...
@@ -4,7 +4,7 @@ import Jazzicon, { jsNumberForAddress } from 'react-jazzicon';
const
AddressIcon
=
({
address
}:
{
address
:
string
})
=>
{
const
AddressIcon
=
({
address
}:
{
address
:
string
})
=>
{
return
(
return
(
<
Box
width=
"24px"
>
<
Box
width=
"24px"
display=
"inline-flex"
>
<
Jazzicon
diameter=
{
24
}
seed=
{
jsNumberForAddress
(
address
)
}
/>
<
Jazzicon
diameter=
{
24
}
seed=
{
jsNumberForAddress
(
address
)
}
/>
</
Box
>
</
Box
>
);
);
...
...
ui/shared/AddressLinkWithTooltip.tsx
View file @
8b68dfdc
...
@@ -8,17 +8,28 @@ import CopyToClipboard from './CopyToClipboard';
...
@@ -8,17 +8,28 @@ import CopyToClipboard from './CopyToClipboard';
const
FONT_WEIGHT
=
'
600
'
;
const
FONT_WEIGHT
=
'
600
'
;
const
AddressLinkWithTooltip
=
({
address
}:
{
address
:
string
})
=>
{
type
Props
=
{
address
:
string
;
type
?:
'
address
'
|
'
transaction
'
;
}
const
AddressLinkWithTooltip
=
({
address
,
type
=
'
address
'
}:
Props
)
=>
{
const
basePath
=
useBasePath
();
const
basePath
=
useBasePath
();
const
url
=
basePath
+
'
/address/
'
+
address
+
'
/tokens#address-tabs
'
;
let
url
;
if
(
type
===
'
transaction
'
)
{
url
=
basePath
+
'
/tx/
'
+
address
;
}
else
{
url
=
basePath
+
'
/address/
'
+
address
+
'
/tokens#address-tabs
'
;
}
return
(
return
(
<
HStack
spacing=
{
2
}
alignContent=
"center"
overflow=
"hidden"
>
<
HStack
spacing=
{
2
}
alignContent=
"center"
overflow=
"hidden"
maxW=
"100%"
>
<
Link
<
Link
href=
{
url
}
href=
{
url
}
target=
"_blank"
target=
"_blank"
overflow=
"hidden"
overflow=
"hidden"
fontWeight=
{
FONT_WEIGHT
}
fontWeight=
{
FONT_WEIGHT
}
lineHeight=
"24px"
lineHeight=
"24px"
whiteSpace=
"nowrap"
>
>
<
AddressWithDots
address=
{
address
}
fontWeight=
{
FONT_WEIGHT
}
/>
<
AddressWithDots
address=
{
address
}
fontWeight=
{
FONT_WEIGHT
}
/>
</
Link
>
</
Link
>
...
...
ui/shared/AddressSnippet.tsx
0 → 100644
View file @
8b68dfdc
import
{
Box
,
HStack
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
AddressIcon
from
'
ui/shared/AddressIcon
'
;
import
AddressLinkWithTooltip
from
'
ui/shared/AddressLinkWithTooltip
'
;
interface
Props
{
address
:
string
;
subtitle
?:
string
;
}
const
AddressSnippet
=
({
address
,
subtitle
}:
Props
)
=>
{
return
(
<
HStack
spacing=
{
4
}
key=
{
address
}
overflow=
"hidden"
alignItems=
"start"
maxW=
"100%"
>
<
AddressIcon
address=
{
address
}
/>
<
Box
overflow=
"hidden"
>
<
AddressLinkWithTooltip
address=
{
address
}
/>
{
subtitle
&&
<
Text
fontSize=
"sm"
variant=
"secondary"
mt=
{
0.5
}
>
{
subtitle
}
</
Text
>
}
</
Box
>
</
HStack
>
);
};
export
default
React
.
memo
(
AddressSnippet
);
ui/shared/ApiKeySnippet.tsx
0 → 100644
View file @
8b68dfdc
import
{
Box
,
HStack
,
Icon
,
Flex
,
Text
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
keyIcon
from
'
icons/key.svg
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
interface
Props
{
apiKey
:
string
;
name
:
string
;
}
const
ApiKeySnippet
=
({
apiKey
,
name
}:
Props
)
=>
{
return
(
<
HStack
spacing=
{
2
}
alignItems=
"start"
>
<
Icon
as=
{
keyIcon
}
boxSize=
{
6
}
color=
{
useColorModeValue
(
'
gray.500
'
,
'
gray.400
'
)
}
/>
<
Box
>
<
Flex
alignItems=
{
{
base
:
'
flex-start
'
,
lg
:
'
center
'
}
}
>
<
Text
fontSize=
"md"
lineHeight=
{
6
}
fontWeight=
{
600
}
mr=
{
1
}
>
{
apiKey
}
</
Text
>
<
CopyToClipboard
text=
{
apiKey
}
/>
</
Flex
>
{
name
&&
<
Text
fontSize=
"sm"
variant=
"secondary"
mt=
{
1
}
>
{
name
}
</
Text
>
}
</
Box
>
</
HStack
>
);
};
export
default
React
.
memo
(
ApiKeySnippet
);
ui/shared/DeleteButton.tsx
deleted
100644 → 0
View file @
3d44ca80
import
{
Tooltip
,
IconButton
,
Icon
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
DeleteIcon
from
'
icons/delete.svg
'
;
type
Props
=
{
onClick
:
()
=>
void
;
}
const
DeleteButton
=
({
onClick
}:
Props
)
=>
{
const
onFocusCapture
=
useCallback
((
e
:
React
.
SyntheticEvent
)
=>
e
.
stopPropagation
(),
[]);
return
(
<
Tooltip
label=
"Delete"
>
<
IconButton
aria
-
label=
"delete"
variant=
"icon"
w=
"30px"
h=
"30px"
onClick=
{
onClick
}
icon=
{
<
Icon
as=
{
DeleteIcon
}
w=
"20px"
h=
"20px"
/>
}
onFocusCapture=
{
onFocusCapture
}
/>
</
Tooltip
>
);
};
export
default
DeleteButton
;
ui/shared/DeleteModal.tsx
View file @
8b68dfdc
...
@@ -54,7 +54,7 @@ const DeleteModal: React.FC<Props> = ({
...
@@ -54,7 +54,7 @@ const DeleteModal: React.FC<Props> = ({
},
[
setAlertVisible
,
mutation
]);
},
[
setAlertVisible
,
mutation
]);
return
(
return
(
<
Modal
isOpen=
{
isOpen
}
onClose=
{
onModalClose
}
size=
"md"
>
<
Modal
isOpen=
{
isOpen
}
onClose=
{
onModalClose
}
size=
{
{
base
:
'
full
'
,
lg
:
'
md
'
}
}
>
<
ModalOverlay
/>
<
ModalOverlay
/>
<
ModalContent
>
<
ModalContent
>
<
ModalHeader
fontWeight=
"500"
textStyle=
"h3"
>
{
title
}
</
ModalHeader
>
<
ModalHeader
fontWeight=
"500"
textStyle=
"h3"
>
{
title
}
</
ModalHeader
>
...
...
ui/shared/EditButton.tsx
deleted
100644 → 0
View file @
3d44ca80
import
{
Tooltip
,
IconButton
,
Icon
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
EditIcon
from
'
icons/edit.svg
'
;
type
Props
=
{
onClick
:
()
=>
void
;
}
const
EditButton
=
({
onClick
}:
Props
)
=>
{
const
onFocusCapture
=
useCallback
((
e
:
React
.
SyntheticEvent
)
=>
e
.
stopPropagation
(),
[]);
return
(
<
Tooltip
label=
"Edit"
>
<
IconButton
aria
-
label=
"edit"
variant=
"icon"
w=
"30px"
h=
"30px"
onClick=
{
onClick
}
icon=
{
<
Icon
as=
{
EditIcon
}
w=
"20px"
h=
"20px"
/>
}
onFocusCapture=
{
onFocusCapture
}
/>
</
Tooltip
>
);
};
export
default
EditButton
;
ui/shared/FormModal.tsx
View file @
8b68dfdc
...
@@ -39,14 +39,14 @@ export default function FormModal<TData>({
...
@@ -39,14 +39,14 @@ export default function FormModal<TData>({
},
[
onClose
,
setAlertVisible
]);
},
[
onClose
,
setAlertVisible
]);
return
(
return
(
<
Modal
isOpen=
{
isOpen
}
onClose=
{
onModalClose
}
size=
"md"
>
<
Modal
isOpen=
{
isOpen
}
onClose=
{
onModalClose
}
size=
{
{
base
:
'
full
'
,
lg
:
'
md
'
}
}
>
<
ModalOverlay
/>
<
ModalOverlay
/>
<
ModalContent
>
<
ModalContent
>
<
ModalHeader
fontWeight=
"500"
textStyle=
"h3"
>
{
title
}
</
ModalHeader
>
<
ModalHeader
fontWeight=
"500"
textStyle=
"h3"
>
{
title
}
</
ModalHeader
>
<
ModalCloseButton
/>
<
ModalCloseButton
/>
<
ModalBody
mb=
{
0
}
>
<
ModalBody
mb=
{
0
}
>
{
(
isAlertVisible
||
text
)
&&
(
{
(
isAlertVisible
||
text
)
&&
(
<
Box
marginBottom=
{
12
}
>
<
Box
marginBottom=
{
{
base
:
6
,
lg
:
12
}
}
>
{
text
&&
(
{
text
&&
(
<
Text
lineHeight=
"30px"
mb=
{
3
}
>
<
Text
lineHeight=
"30px"
mb=
{
3
}
>
{
text
}
{
text
}
...
...
ui/shared/SkeletonAccountMobile.tsx
0 → 100644
View file @
8b68dfdc
import
{
Box
,
Flex
,
Skeleton
,
SkeletonCircle
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
interface
Props
{
showFooterSlot
?:
boolean
;
}
const
SkeletonAccountMobile
=
({
showFooterSlot
}:
Props
)
=>
{
const
borderColor
=
useColorModeValue
(
'
blackAlpha.200
'
,
'
whiteAlpha.200
'
);
return
(
<
Box
>
{
Array
.
from
(
Array
(
2
)).
map
((
item
,
index
)
=>
(
<
Flex
key=
{
index
}
rowGap=
{
3
}
flexDirection=
"column"
paddingY=
{
6
}
borderTopWidth=
"1px"
borderColor=
{
borderColor
}
_first=
{
{
borderTopWidth
:
'
0
'
,
pt
:
'
0
'
,
}
}
>
<
Flex
columnGap=
{
2
}
w=
"100%"
alignItems=
"center"
>
<
SkeletonCircle
size=
"6"
flexShrink=
"0"
/>
<
Skeleton
h=
{
4
}
w=
"100%"
/>
</
Flex
>
<
Skeleton
h=
{
4
}
w=
"164px"
/>
<
Skeleton
h=
{
4
}
w=
"164px"
/>
<
Flex
columnGap=
{
3
}
mt=
{
7
}
>
{
showFooterSlot
&&
(
<
Flex
alignItems=
"center"
columnGap=
{
2
}
>
<
Skeleton
h=
{
4
}
w=
"164px"
/>
<
SkeletonCircle
size=
"6"
flexShrink=
"0"
/>
</
Flex
>
)
}
<
SkeletonCircle
size=
"6"
flexShrink=
"0"
ml=
"auto"
/>
<
SkeletonCircle
size=
"6"
flexShrink=
"0"
/>
</
Flex
>
</
Flex
>
))
}
</
Box
>
);
};
export
default
SkeletonAccountMobile
;
ui/shared/TableItemActionButtons.tsx
0 → 100644
View file @
8b68dfdc
import
{
Tooltip
,
IconButton
,
Icon
,
HStack
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
DeleteIcon
from
'
icons/delete.svg
'
;
import
EditIcon
from
'
icons/edit.svg
'
;
type
Props
=
{
onEditClick
:
()
=>
void
;
onDeleteClick
:
()
=>
void
;
}
const
TableItemActionButtons
=
({
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
// prevent set focus on button when closing modal
const
onFocusCapture
=
useCallback
((
e
:
React
.
SyntheticEvent
)
=>
e
.
stopPropagation
(),
[]);
return
(
<
HStack
spacing=
{
6
}
alignSelf=
"flex-end"
>
<
Tooltip
label=
"Edit"
>
<
IconButton
aria
-
label=
"edit"
variant=
"icon"
w=
"30px"
h=
"30px"
onClick=
{
onEditClick
}
icon=
{
<
Icon
as=
{
EditIcon
}
w=
"20px"
h=
"20px"
/>
}
onFocusCapture=
{
onFocusCapture
}
/>
</
Tooltip
>
<
Tooltip
label=
"Delete"
>
<
IconButton
aria
-
label=
"delete"
variant=
"icon"
w=
"30px"
h=
"30px"
onClick=
{
onDeleteClick
}
icon=
{
<
Icon
as=
{
DeleteIcon
}
w=
"20px"
h=
"20px"
/>
}
onFocusCapture=
{
onFocusCapture
}
/>
</
Tooltip
>
</
HStack
>
);
};
export
default
React
.
memo
(
TableItemActionButtons
);
ui/shared/TransactionSnippet.tsx
0 → 100644
View file @
8b68dfdc
import
{
Box
,
HStack
,
Icon
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
transactionIcon
from
'
icons/transactions.svg
'
;
import
AddressLinkWithTooltip
from
'
ui/shared/AddressLinkWithTooltip
'
;
interface
Props
{
hash
:
string
;
}
const
TransactionSnippet
=
({
hash
}:
Props
)
=>
{
return
(
<
HStack
spacing=
{
2
}
overflow=
"hidden"
alignItems=
"start"
maxW=
"100%"
>
<
Icon
as=
{
transactionIcon
}
boxSize=
{
6
}
color=
{
useColorModeValue
(
'
gray.500
'
,
'
gray.400
'
)
}
/>
<
Box
overflow=
"hidden"
>
<
AddressLinkWithTooltip
address=
{
hash
}
type=
"transaction"
/>
</
Box
>
</
HStack
>
);
};
export
default
React
.
memo
(
TransactionSnippet
);
ui/watchlist/AddressModal/AddressForm.tsx
View file @
8b68dfdc
...
@@ -150,7 +150,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
...
@@ -150,7 +150,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
return (
return (
<>
<>
<
Box
marginBottom=
{
5
}
marginTop=
{
5
}
>
<
Box
marginBottom=
{
5
}
>
<
Controller
<
Controller
name=
"address"
name=
"address"
control=
{
control
}
control=
{
control
}
...
@@ -178,7 +178,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
...
@@ -178,7 +178,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
<
Box
marginBottom=
{
8
}
>
<
Box
marginBottom=
{
8
}
>
<
AddressFormNotifications
control=
{
control
}
/>
<
AddressFormNotifications
control=
{
control
}
/>
</
Box
>
</
Box
>
<
Text
variant=
"secondary"
fontSize=
"sm"
marginBottom=
{
5
}
>
Notification methods
</
Text
>
<
Text
variant=
"secondary"
fontSize=
"sm"
marginBottom=
{
{
base
:
'
10px
'
,
lg
:
5
}
}
>
Notification methods
</
Text
>
<
Controller
<
Controller
name=
{
'
notification
'
as
Checkboxes
}
name=
{
'
notification
'
as
Checkboxes
}
control=
{
control
}
control=
{
control
}
...
...
ui/watchlist/AddressModal/AddressFormNotifications.tsx
View file @
8b68dfdc
...
@@ -20,13 +20,21 @@ export default function AddressFormNotifications<Inputs extends FieldValues, Che
...
@@ -20,13 +20,21 @@ export default function AddressFormNotifications<Inputs extends FieldValues, Che
), []);
), []);
return (
return (
<
Grid
templateColumns=
"repeat(3, max-content)"
gap=
"20px 24px"
>
<
Grid
templateColumns=
{
{
base
:
'
repeat(2, max-content)
'
,
lg
:
'
repeat(3, max-content)
'
}
}
gap=
{
{
base
:
'
10px 24px
'
,
lg
:
'
20px 24px
'
}
}
>
{
NOTIFICATIONS
.
map
((
notification
:
string
,
index
:
number
)
=>
{
{
NOTIFICATIONS
.
map
((
notification
:
string
,
index
:
number
)
=>
{
const
incomingFieldName
=
`notification_settings.${ notification }.incoming`
as
Checkboxes
;
const
incomingFieldName
=
`notification_settings.${ notification }.incoming`
as
Checkboxes
;
const
outgoingFieldName
=
`notification_settings.${ notification }.outcoming`
as
Checkboxes
;
const
outgoingFieldName
=
`notification_settings.${ notification }.outcoming`
as
Checkboxes
;
return
(
return
(
<
React
.
Fragment
key=
{
notification
}
>
<
React
.
Fragment
key=
{
notification
}
>
<
GridItem
>
{
NOTIFICATIONS_NAMES
[
index
]
}
</
GridItem
>
<
GridItem
gridColumnStart=
{
{
base
:
1
,
lg
:
1
}
}
gridColumnEnd=
{
{
base
:
3
,
lg
:
1
}
}
_notFirst=
{
{
mt
:
{
base
:
3
,
lg
:
0
},
}
}
>
{
NOTIFICATIONS_NAMES
[
index
]
}
</
GridItem
>
<
GridItem
>
<
GridItem
>
<
Controller
<
Controller
name=
{
incomingFieldName
}
name=
{
incomingFieldName
}
...
...
ui/watchlist/DeleteAddressModal.tsx
View file @
8b68dfdc
...
@@ -5,6 +5,7 @@ import React, { useCallback } from 'react';
...
@@ -5,6 +5,7 @@ import React, { useCallback } from 'react';
import
type
{
TWatchlistItem
,
TWatchlist
}
from
'
types/client/account
'
;
import
type
{
TWatchlistItem
,
TWatchlist
}
from
'
types/client/account
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
DeleteModal
from
'
ui/shared/DeleteModal
'
;
import
DeleteModal
from
'
ui/shared/DeleteModal
'
;
type
Props
=
{
type
Props
=
{
...
@@ -15,6 +16,7 @@ type Props = {
...
@@ -15,6 +16,7 @@ type Props = {
const
DeleteAddressModal
:
React
.
FC
<
Props
>
=
({
isOpen
,
onClose
,
data
})
=>
{
const
DeleteAddressModal
:
React
.
FC
<
Props
>
=
({
isOpen
,
onClose
,
data
})
=>
{
const
queryClient
=
useQueryClient
();
const
queryClient
=
useQueryClient
();
const
isMobile
=
useIsMobile
();
const
mutationFn
=
useCallback
(()
=>
{
const
mutationFn
=
useCallback
(()
=>
{
return
fetch
(
`/api/account1/watchlist/
${
data
?.
id
}
`, { method: 'DELETE' });
return
fetch
(
`/api/account1/watchlist/
${
data
?.
id
}
`, { method: 'DELETE' });
...
@@ -29,10 +31,11 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
...
@@ -29,10 +31,11 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
const address = data?.address_hash;
const address = data?.address_hash;
const renderModalContent = useCallback(() => {
const renderModalContent = useCallback(() => {
const addressString = isMobile ? [ address.slice(0, 4), address.slice(-4) ].join('...') : address;
return (
return (
<Text
display="flex">Address <Text fontWeight="600" whiteSpace="pre"> { address || 'address' } </Text>
will be deleted</Text>
<Text
>Address <Text fontWeight="600" as="span"> { addressString || 'address' }</Text>
will be deleted</Text>
);
);
}, [ address ]);
}, [ address
, isMobile
]);
return (
return (
<DeleteModal
<DeleteModal
...
...
ui/watchlist/WatchlistTable/WatchListAddressItem.tsx
View file @
8b68dfdc
...
@@ -6,8 +6,7 @@ import type { TWatchlistItem } from 'types/client/account';
...
@@ -6,8 +6,7 @@ import type { TWatchlistItem } from 'types/client/account';
import
TokensIcon
from
'
icons/tokens.svg
'
;
import
TokensIcon
from
'
icons/tokens.svg
'
;
// import WalletIcon from 'icons/wallet.svg';
// import WalletIcon from 'icons/wallet.svg';
import
{
nbsp
}
from
'
lib/html-entities
'
;
import
{
nbsp
}
from
'
lib/html-entities
'
;
import
AddressIcon
from
'
ui/shared/AddressIcon
'
;
import
AddressSnippet
from
'
ui/shared/AddressSnippet
'
;
import
AddressLinkWithTooltip
from
'
ui/shared/AddressLinkWithTooltip
'
;
// now this component works only for xDAI
// now this component works only for xDAI
// for other networks later we will use config or smth
// for other networks later we will use config or smth
...
@@ -18,36 +17,34 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
...
@@ -18,36 +17,34 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
const
nativeBalance
=
((
item
.
address_balance
||
0
)
/
10
**
DECIMALS
).
toFixed
(
1
);
const
nativeBalance
=
((
item
.
address_balance
||
0
)
/
10
**
DECIMALS
).
toFixed
(
1
);
const
nativeBalanceUSD
=
item
.
exchange_rate
?
`$
${
Number
(
nativeBalance
)
*
item
.
exchange_rate
}
USD`
:
'
N/A
'
;
const
nativeBalanceUSD
=
item
.
exchange_rate
?
`$
${
Number
(
nativeBalance
)
*
item
.
exchange_rate
}
USD`
:
'
N/A
'
;
const
infoItemsPaddingLeft
=
{
base
:
0
,
lg
:
10
};
return
(
return
(
<
HStack
spacing=
{
3
}
align=
"top"
>
<
VStack
spacing=
{
2
}
align=
"stretch"
overflow=
"hidden"
fontWeight=
{
500
}
color=
"gray.700"
>
<
AddressIcon
address=
{
item
.
address_hash
}
/>
<
AddressSnippet
address=
{
item
.
address_hash
}
/>
<
VStack
spacing=
{
2
}
align=
"stretch"
overflow=
"hidden"
fontWeight=
{
500
}
color=
"gray.700"
>
<
HStack
spacing=
{
0
}
fontSize=
"sm"
h=
{
6
}
pl=
{
infoItemsPaddingLeft
}
>
<
AddressLinkWithTooltip
address=
{
item
.
address_hash
}
/>
<
Image
src=
"/xdai.png"
alt=
"chain-logo"
marginRight=
"10px"
w=
"16px"
h=
"16px"
/>
<
HStack
spacing=
{
0
}
fontSize=
"sm"
h=
{
6
}
>
<
Text
color=
{
mainTextColor
}
>
{
`xDAI balance:${ nbsp }`
+
nativeBalance
}
</
Text
>
<
Image
src=
"/xdai.png"
alt=
"chain-logo"
marginRight=
"10px"
w=
"16px"
h=
"16px"
/>
<
Text
variant=
"secondary"
>
{
`${ nbsp }(${ nativeBalanceUSD })`
}
</
Text
>
<
Text
color=
{
mainTextColor
}
>
{
`xDAI balance:${ nbsp }`
+
nativeBalance
}
</
Text
>
</
HStack
>
<
Text
variant=
"secondary"
>
{
`${ nbsp }(${ nativeBalanceUSD })`
}
</
Text
>
{
item
.
tokens_count
&&
(
<
HStack
spacing=
{
0
}
fontSize=
"sm"
h=
{
6
}
pl=
{
infoItemsPaddingLeft
}
>
<
Icon
as=
{
TokensIcon
}
marginRight=
"10px"
w=
"17px"
h=
"16px"
/>
<
Text
color=
{
mainTextColor
}
>
{
`Tokens:${ nbsp }`
+
item
.
tokens_count
}
</
Text
>
{
/* api does not provide token prices */
}
{
/* <Text variant="secondary">{ `${ nbsp }($${ item.tokensUSD } USD)` }</Text> */
}
<
Text
variant=
"secondary"
>
{
`${ nbsp }(N/A)`
}
</
Text
>
</
HStack
>
</
HStack
>
{
item
.
tokens_count
&&
(
)
}
<
HStack
spacing=
{
0
}
fontSize=
"sm"
h=
{
6
}
>
{
/* api does not provide token prices */
}
<
Icon
as=
{
TokensIcon
}
marginRight=
"10px"
w=
"17px"
h=
"16px"
/>
{
/* { item.address_balance && (
<
Text
color=
{
mainTextColor
}
>
{
`Tokens:${ nbsp }`
+
item
.
tokens_count
}
</
Text
>
<HStack spacing={ 0 } fontSize="sm" h={ 6 } pl={ infoItemsPaddingLeft }>
{
/* api does not provide token prices */
}
{
/* <Text variant="secondary">{ `${ nbsp }($${ item.tokensUSD } USD)` }</Text> */
}
<
Text
variant=
"secondary"
>
{
`${ nbsp }(N/A)`
}
</
Text
>
</
HStack
>
)
}
{
/* api does not provide token prices */
}
{
/* { item.address_balance && (
<HStack spacing={ 0 } fontSize="sm" h={ 6 }>
<Icon as={ WalletIcon } marginRight="10px" w="16px" h="16px"/>
<Icon as={ WalletIcon } marginRight="10px" w="16px" h="16px"/>
<Text color={ mainTextColor }>{ `Net worth:${ nbsp }` }</Text>
<Text color={ mainTextColor }>{ `Net worth:${ nbsp }` }</Text>
<Link href="#">{ `$${ item.totalUSD } USD` }</Link>
<Link href="#">{ `$${ item.totalUSD } USD` }</Link>
</HStack>
</HStack>
) } */
}
) } */
}
</
VStack
>
</
VStack
>
</
HStack
>
);
);
};
};
...
...
ui/watchlist/WatchlistTable/WatchListItem.tsx
0 → 100644
View file @
8b68dfdc
import
{
Tag
,
Box
,
Switch
,
Text
,
HStack
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
useMutation
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
TWatchlistItem
}
from
'
types/client/account
'
;
import
AccountListItemMobile
from
'
ui/shared/AccountListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
WatchListAddressItem
from
'
./WatchListAddressItem
'
;
interface
Props
{
item
:
TWatchlistItem
;
onEditClick
:
(
data
:
TWatchlistItem
)
=>
void
;
onDeleteClick
:
(
data
:
TWatchlistItem
)
=>
void
;
}
const
WatchListItem
=
({
item
,
onEditClick
,
onDeleteClick
}:
Props
)
=>
{
const
[
notificationEnabled
,
setNotificationEnabled
]
=
useState
(
item
.
notification_methods
.
email
);
const
onItemEditClick
=
useCallback
(()
=>
{
return
onEditClick
(
item
);
},
[
item
,
onEditClick
]);
const
onItemDeleteClick
=
useCallback
(()
=>
{
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
const
{
mutate
}
=
useMutation
(()
=>
{
const
data
=
{
...
item
,
notification_methods
:
{
email
:
!
notificationEnabled
}
};
return
fetch
(
`/api/account/watchlist/
${
item
.
id
}
`
,
{
method
:
'
PUT
'
,
body
:
JSON
.
stringify
(
data
)
});
},
{
onError
:
()
=>
{
// eslint-disable-next-line no-console
console
.
log
(
'
error
'
);
},
onSuccess
:
()
=>
{
setNotificationEnabled
(
prevState
=>
!
prevState
);
},
});
const
onSwitch
=
useCallback
(()
=>
{
return
mutate
();
},
[
mutate
]);
return
(
<
AccountListItemMobile
>
<
Box
maxW=
"100%"
>
<
WatchListAddressItem
item=
{
item
}
/>
<
HStack
spacing=
{
3
}
mt=
{
6
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Tag
variant=
"gray"
lineHeight=
"24px"
>
{
item
.
name
}
</
Tag
>
</
HStack
>
</
Box
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
mt=
{
6
}
w=
"100%"
>
<
HStack
spacing=
{
3
}
>
<
Text
fontSize=
"sm"
fontWeight=
{
500
}
>
Email notification
</
Text
>
<
Switch
colorScheme=
"blue"
size=
"md"
isChecked=
{
notificationEnabled
}
onChange=
{
onSwitch
}
/>
</
HStack
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
</
Flex
>
</
AccountListItemMobile
>
);
};
export
default
WatchListItem
;
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
View file @
8b68dfdc
...
@@ -3,7 +3,6 @@ import {
...
@@ -3,7 +3,6 @@ import {
Tr
,
Tr
,
Td
,
Td
,
Switch
,
Switch
,
HStack
,
}
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
'
;
...
@@ -12,8 +11,7 @@ import type { TWatchlistItem } from 'types/client/account';
...
@@ -12,8 +11,7 @@ import type { TWatchlistItem } from 'types/client/account';
import
fetch
from
'
lib/client/fetch
'
;
import
fetch
from
'
lib/client/fetch
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
DeleteButton
from
'
ui/shared/DeleteButton
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
EditButton
from
'
ui/shared/EditButton
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
import
WatchListAddressItem
from
'
./WatchListAddressItem
'
;
import
WatchListAddressItem
from
'
./WatchListAddressItem
'
;
...
@@ -89,10 +87,7 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
...
@@ -89,10 +87,7 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
/>
/>
</
Td
>
</
Td
>
<
Td
>
<
Td
>
<
HStack
spacing=
{
6
}
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
/>
<
EditButton
onClick=
{
onItemEditClick
}
/>
<
DeleteButton
onClick=
{
onItemDeleteClick
}
/>
</
HStack
>
</
Td
>
</
Td
>
</
Tr
>
</
Tr
>
);
);
...
...
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