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
2d99aba9
Commit
2d99aba9
authored
Feb 07, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
watchlist page refactoring
parent
bb7d3592
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
158 additions
and
209 deletions
+158
-209
eslint.config.mjs
eslint.config.mjs
+1
-1
watchlist.tsx
pages/account/watchlist.tsx
+2
-2
Modal.ts
theme/components/Modal.ts
+1
-1
PinInput.ts
theme/components/PinInput.ts
+1
-1
semanticTokens.ts
theme/foundations/semanticTokens.ts
+1
-1
TokenSelectMenu.tsx
ui/address/tokenSelect/TokenSelectMenu.tsx
+1
-1
AddressVerificationStepAddress.tsx
...ressVerification/steps/AddressVerificationStepAddress.tsx
+1
-1
AddressVerificationStepSignature.tsx
...ssVerification/steps/AddressVerificationStepSignature.tsx
+2
-2
ApiKeyForm.tsx
ui/apiKey/ApiKeyModal/ApiKeyForm.tsx
+2
-2
CustomAbiForm.tsx
ui/customAbi/CustomAbiModal/CustomAbiForm.tsx
+3
-3
Watchlist.tsx
ui/pages/Watchlist.tsx
+38
-41
TableItemActionButtons.tsx
ui/shared/TableItemActionButtons.tsx
+0
-2
FormFieldCheckbox.tsx
ui/shared/forms/fields/FormFieldCheckbox.tsx
+14
-22
AddressForm.tsx
ui/watchlist/AddressModal/AddressForm.tsx
+13
-17
AddressModal.tsx
ui/watchlist/AddressModal/AddressModal.tsx
+5
-5
DeleteAddressModal.tsx
ui/watchlist/DeleteAddressModal.tsx
+5
-5
WatchListAddressItem.tsx
ui/watchlist/WatchlistTable/WatchListAddressItem.tsx
+10
-10
WatchListItem.tsx
ui/watchlist/WatchlistTable/WatchListItem.tsx
+20
-32
WatchListTableItem.tsx
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
+25
-41
WatchlistTable.tsx
ui/watchlist/WatchlistTable/WatchlistTable.tsx
+13
-19
No files found.
eslint.config.mjs
View file @
2d99aba9
...
@@ -32,7 +32,7 @@ const RESTRICTED_MODULES = {
...
@@ -32,7 +32,7 @@ const RESTRICTED_MODULES = {
{
{
name
:
'
@chakra-ui/react
'
,
name
:
'
@chakra-ui/react
'
,
importNames
:
[
importNames
:
[
'
Menu
'
,
'
useToast
'
,
'
useDisclosure
'
,
'
useClipboard
'
,
'
Tooltip
'
,
'
Skeleton
'
,
'
IconButton
'
,
'
Button
'
,
'
Link
'
,
'
Tag
'
,
'
Menu
'
,
'
useToast
'
,
'
useDisclosure
'
,
'
useClipboard
'
,
'
Tooltip
'
,
'
Skeleton
'
,
'
IconButton
'
,
'
Button
'
,
'
Link
'
,
'
Tag
'
,
'
Switch
'
,
'
Image
'
,
'
Popover
'
,
'
PopoverTrigger
'
,
'
PopoverContent
'
,
'
PopoverBody
'
,
'
PopoverFooter
'
,
'
Image
'
,
'
Popover
'
,
'
PopoverTrigger
'
,
'
PopoverContent
'
,
'
PopoverBody
'
,
'
PopoverFooter
'
,
'
DrawerRoot
'
,
'
DrawerBody
'
,
'
DrawerContent
'
,
'
DrawerOverlay
'
,
'
DrawerBackdrop
'
,
'
DrawerTrigger
'
,
'
Drawer
'
,
'
DrawerRoot
'
,
'
DrawerBody
'
,
'
DrawerContent
'
,
'
DrawerOverlay
'
,
'
DrawerBackdrop
'
,
'
DrawerTrigger
'
,
'
Drawer
'
,
'
Alert
'
,
'
AlertIcon
'
,
'
AlertTitle
'
,
'
AlertDescription
'
,
'
Alert
'
,
'
AlertIcon
'
,
'
AlertTitle
'
,
'
AlertDescription
'
,
...
...
pages/account/watchlist.tsx
View file @
2d99aba9
...
@@ -4,12 +4,12 @@ import React from 'react';
...
@@ -4,12 +4,12 @@ import React from 'react';
import
PageNextJs
from
'
nextjs/PageNextJs
'
;
import
PageNextJs
from
'
nextjs/PageNextJs
'
;
//
const WatchList = dynamic(() => import('ui/pages/Watchlist'), { ssr: false });
const
WatchList
=
dynamic
(()
=>
import
(
'
ui/pages/Watchlist
'
),
{
ssr
:
false
});
const
Page
:
NextPage
=
()
=>
{
const
Page
:
NextPage
=
()
=>
{
return
(
return
(
<
PageNextJs
pathname=
"/account/watchlist"
>
<
PageNextJs
pathname=
"/account/watchlist"
>
{
/* <WatchList/> */
}
<
WatchList
/>
</
PageNextJs
>
</
PageNextJs
>
);
);
};
};
...
...
theme/components/Modal.ts
View file @
2d99aba9
...
@@ -14,7 +14,7 @@ const baseStyleDialog = defineStyle(() => {
...
@@ -14,7 +14,7 @@ const baseStyleDialog = defineStyle(() => {
return
{
return
{
padding
:
8
,
padding
:
8
,
borderRadius
:
'
lg
'
,
borderRadius
:
'
lg
'
,
bg
:
'
dialog
_
bg
'
,
bg
:
'
dialog
.
bg
'
,
margin
:
'
auto
'
,
margin
:
'
auto
'
,
};
};
});
});
...
...
theme/components/PinInput.ts
View file @
2d99aba9
...
@@ -4,7 +4,7 @@ import getOutlinedFieldStyles from '../utils/getOutlinedFieldStyles';
...
@@ -4,7 +4,7 @@ import getOutlinedFieldStyles from '../utils/getOutlinedFieldStyles';
const
baseStyle
=
defineStyle
({
const
baseStyle
=
defineStyle
({
textAlign
:
'
center
'
,
textAlign
:
'
center
'
,
bgColor
:
'
dialog
_
bg
'
,
bgColor
:
'
dialog
.
bg
'
,
});
});
const
sizes
=
{
const
sizes
=
{
...
...
theme/foundations/semanticTokens.ts
View file @
2d99aba9
...
@@ -31,7 +31,7 @@ const semanticTokens = {
...
@@ -31,7 +31,7 @@ const semanticTokens = {
'
default
'
:
'
red.500
'
,
'
default
'
:
'
red.500
'
,
_dark
:
'
red.500
'
,
_dark
:
'
red.500
'
,
},
},
dialog
_
bg
:
{
dialog
.
bg
:
{
'
default
'
:
'
white
'
,
'
default
'
:
'
white
'
,
_dark
:
'
gray.900
'
,
_dark
:
'
gray.900
'
,
},
},
...
...
ui/address/tokenSelect/TokenSelectMenu.tsx
View file @
2d99aba9
...
@@ -39,7 +39,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onI
...
@@ -39,7 +39,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onI
placeholder=
"Search by token name"
placeholder=
"Search by token name"
ml=
"1px"
ml=
"1px"
onChange=
{
onInputChange
}
onChange=
{
onInputChange
}
bgColor=
"dialog
_
bg"
bgColor=
"dialog
.
bg"
/>
/>
</
InputGroup
>
</
InputGroup
>
<
Flex
flexDir=
"column"
rowGap=
{
6
}
>
<
Flex
flexDir=
"column"
rowGap=
{
6
}
>
...
...
ui/addressVerification/steps/AddressVerificationStepAddress.tsx
View file @
2d99aba9
...
@@ -106,7 +106,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) =
...
@@ -106,7 +106,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) =
<
FormFieldAddress
<
Fields
>
<
FormFieldAddress
<
Fields
>
name="address"
name="address"
isRequired
isRequired
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
placeholder="Smart contract address (0x...)"
placeholder="Smart contract address (0x...)"
mt=
{
8
}
mt=
{
8
}
/
>
/
>
...
...
ui/addressVerification/steps/AddressVerificationStepSignature.tsx
View file @
2d99aba9
...
@@ -221,7 +221,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
...
@@ -221,7 +221,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
asComponent="Textarea"
asComponent="Textarea"
isReadOnly
isReadOnly
maxH=
{
{
base
:
'
140px
'
,
lg
:
'
80px
'
}
}
maxH=
{
{
base
:
'
140px
'
,
lg
:
'
80px
'
}
}
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
/
>
/
>
</
div
>
</
div
>
{
!
noWeb3Provider
&&
(
{
!
noWeb3Provider
&&
(
...
@@ -236,7 +236,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
...
@@ -236,7 +236,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
placeholder="Signature hash"
placeholder="Signature hash"
isRequired
isRequired
rules=
{
{
pattern
:
SIGNATURE_REGEXP
}
}
rules=
{
{
pattern
:
SIGNATURE_REGEXP
}
}
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
/
>
/
>
)
}
)
}
</
Flex
>
</
Flex
>
...
...
ui/apiKey/ApiKeyModal/ApiKeyForm.tsx
View file @
2d99aba9
...
@@ -100,7 +100,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
...
@@ -100,7 +100,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
name="token"
name="token"
placeholder="Auto-generated API key token"
placeholder="Auto-generated API key token"
isReadOnly
isReadOnly
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
mb=
{
5
}
mb=
{
5
}
/
>
/
>
)
}
)
}
...
@@ -111,7 +111,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
...
@@ -111,7 +111,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
rules=
{
{
rules=
{
{
maxLength
:
NAME_MAX_LENGTH
,
maxLength
:
NAME_MAX_LENGTH
,
}
}
}
}
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
mb=
{
8
}
mb=
{
8
}
/
>
/
>
<
Box
marginTop=
{
8
}
>
<
Box
marginTop=
{
8
}
>
...
...
ui/customAbi/CustomAbiModal/CustomAbiForm.tsx
View file @
2d99aba9
...
@@ -111,7 +111,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisi
...
@@ -111,7 +111,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisi
name="contract_address_hash"
name="contract_address_hash"
placeholder="Smart contract address (0x...)"
placeholder="Smart contract address (0x...)"
isRequired
isRequired
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
isReadOnly=
{
Boolean
(
data
&&
'
contract_address_hash
'
in
data
)
}
isReadOnly=
{
Boolean
(
data
&&
'
contract_address_hash
'
in
data
)
}
mb=
{
5
}
mb=
{
5
}
/
>
/
>
...
@@ -122,7 +122,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisi
...
@@ -122,7 +122,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisi
rules=
{
{
rules=
{
{
maxLength
:
NAME_MAX_LENGTH
,
maxLength
:
NAME_MAX_LENGTH
,
}
}
}
}
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
mb=
{
5
}
mb=
{
5
}
/
>
/
>
<
FormFieldText
<
Inputs
>
<
FormFieldText
<
Inputs
>
...
@@ -130,7 +130,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisi
...
@@ -130,7 +130,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisi
placeholder="Custom ABI [
{
...
}
] (JSON format)"
placeholder="Custom ABI [
{
...
}
] (JSON format)"
isRequired
isRequired
asComponent="Textarea"
asComponent="Textarea"
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
size="lg"
size="lg"
minH="300px"
minH="300px"
mb=
{
8
}
mb=
{
8
}
...
...
ui/pages/Watchlist.tsx
View file @
2d99aba9
import
{
Box
,
Button
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
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
'
;
...
@@ -7,9 +7,11 @@ import type { WatchlistAddress, WatchlistResponse } from 'types/api/account';
...
@@ -7,9 +7,11 @@ import type { WatchlistAddress, WatchlistResponse } from 'types/api/account';
import
{
resourceKey
}
from
'
lib/api/resources
'
;
import
{
resourceKey
}
from
'
lib/api/resources
'
;
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
{
WATCH_LIST_ITEM_WITH_TOKEN_INFO
}
from
'
stubs/account
'
;
import
{
WATCH_LIST_ITEM_WITH_TOKEN_INFO
}
from
'
stubs/account
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
AccountPageDescription
from
'
ui/shared/AccountPageDescription
'
;
import
ActionBar
,
{
ACTION_BAR_HEIGHT_DESKTOP
}
from
'
ui/shared/ActionBar
'
;
import
ActionBar
,
{
ACTION_BAR_HEIGHT_DESKTOP
}
from
'
ui/shared/ActionBar
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
...
@@ -44,9 +46,9 @@ const WatchList: React.FC = () => {
...
@@ -44,9 +46,9 @@ const WatchList: React.FC = () => {
addressModalProps
.
onOpen
();
addressModalProps
.
onOpen
();
},
[
addressModalProps
]);
},
[
addressModalProps
]);
const
onAddressModal
Close
=
useCallback
((
)
=>
{
const
onAddressModal
OpenChange
=
useCallback
(({
open
}:
{
open
:
boolean
}
)
=>
{
setAddressModalData
(
undefined
);
!
open
&&
setAddressModalData
(
undefined
);
addressModalProps
.
on
Close
(
);
addressModalProps
.
on
OpenChange
({
open
}
);
},
[
addressModalProps
]);
},
[
addressModalProps
]);
const
onAddOrEditSuccess
=
useCallback
(
async
()
=>
{
const
onAddOrEditSuccess
=
useCallback
(
async
()
=>
{
...
@@ -60,9 +62,9 @@ const WatchList: React.FC = () => {
...
@@ -60,9 +62,9 @@ const WatchList: React.FC = () => {
deleteModalProps
.
onOpen
();
deleteModalProps
.
onOpen
();
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
onDeleteModal
Close
=
useCallback
((
)
=>
{
const
onDeleteModal
OpenChange
=
useCallback
(({
open
}:
{
open
:
boolean
}
)
=>
{
setDeleteModalData
(
undefined
);
!
open
&&
setDeleteModalData
(
undefined
);
deleteModalProps
.
on
Close
(
);
deleteModalProps
.
on
OpenChange
({
open
}
);
},
[
deleteModalProps
]);
},
[
deleteModalProps
]);
const
onDeleteSuccess
=
useCallback
(
async
()
=>
{
const
onDeleteSuccess
=
useCallback
(
async
()
=>
{
...
@@ -86,44 +88,39 @@ const WatchList: React.FC = () => {
...
@@ -86,44 +88,39 @@ const WatchList: React.FC = () => {
</
ActionBar
>
</
ActionBar
>
)
:
null
;
)
:
null
;
const
list
=
(
<>
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
{
data
?.
items
.
map
((
item
,
index
)
=>
(
<
WatchListItem
key=
{
item
.
address_hash
+
(
isPlaceholderData
?
index
:
''
)
}
item=
{
item
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
hasEmail=
{
Boolean
(
profileQuery
.
data
?.
email
)
}
/>
))
}
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
WatchlistTable
data=
{
data
?.
items
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
top=
{
pagination
.
isVisible
?
ACTION_BAR_HEIGHT_DESKTOP
:
0
}
hasEmail=
{
Boolean
(
profileQuery
.
data
?.
email
)
}
/>
</
Box
>
</>
);
return
(
return
(
<>
<>
{
description
}
{
description
}
<
DataListDisplay
<
DataListDisplay
isError=
{
isError
}
isError=
{
isError
}
items
=
{
data
?.
items
}
items
Num=
{
data
?.
items
.
length
}
emptyText=
""
emptyText=
""
content=
{
list
}
actionBar=
{
actionBar
}
actionBar=
{
actionBar
}
/>
>
<
Skeleton
mt=
{
8
}
isLoaded=
{
!
isPlaceholderData
}
display=
"inline-block"
>
<
Box
display=
{
{
base
:
'
block
'
,
lg
:
'
none
'
}
}
>
{
data
?.
items
.
map
((
item
,
index
)
=>
(
<
WatchListItem
key=
{
item
.
address_hash
+
(
isPlaceholderData
?
index
:
''
)
}
item=
{
item
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
hasEmail=
{
Boolean
(
profileQuery
.
data
?.
email
)
}
/>
))
}
</
Box
>
<
Box
display=
{
{
base
:
'
none
'
,
lg
:
'
block
'
}
}
>
<
WatchlistTable
data=
{
data
?.
items
}
isLoading=
{
isPlaceholderData
}
onDeleteClick=
{
onDeleteClick
}
onEditClick=
{
onEditClick
}
top=
{
pagination
.
isVisible
?
ACTION_BAR_HEIGHT_DESKTOP
:
0
}
hasEmail=
{
Boolean
(
profileQuery
.
data
?.
email
)
}
/>
</
Box
>
</
DataListDisplay
>
<
Skeleton
mt=
{
8
}
loading=
{
isPlaceholderData
}
display=
"inline-block"
>
<
Button
<
Button
size=
"lg"
size=
"lg"
onClick=
{
addressModalProps
.
onOpen
}
onClick=
{
addressModalProps
.
onOpen
}
...
@@ -133,7 +130,7 @@ const WatchList: React.FC = () => {
...
@@ -133,7 +130,7 @@ const WatchList: React.FC = () => {
</
Skeleton
>
</
Skeleton
>
<
AddressModal
<
AddressModal
{
...
addressModalProps
}
{
...
addressModalProps
}
on
Close=
{
onAddressModalClos
e
}
on
OpenChange=
{
onAddressModalOpenChang
e
}
onSuccess=
{
onAddOrEditSuccess
}
onSuccess=
{
onAddOrEditSuccess
}
data=
{
addressModalData
}
data=
{
addressModalData
}
isAdd=
{
!
addressModalData
}
isAdd=
{
!
addressModalData
}
...
@@ -141,7 +138,7 @@ const WatchList: React.FC = () => {
...
@@ -141,7 +138,7 @@ const WatchList: React.FC = () => {
{
deleteModalData
&&
(
{
deleteModalData
&&
(
<
DeleteAddressModal
<
DeleteAddressModal
{
...
deleteModalProps
}
{
...
deleteModalProps
}
on
Close=
{
onDeleteModalClos
e
}
on
OpenChange=
{
onDeleteModalOpenChang
e
}
onSuccess=
{
onDeleteSuccess
}
onSuccess=
{
onDeleteSuccess
}
data=
{
deleteModalData
}
data=
{
deleteModalData
}
/>
/>
...
...
ui/shared/TableItemActionButtons.tsx
View file @
2d99aba9
...
@@ -21,7 +21,6 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props
...
@@ -21,7 +21,6 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props
<
IconButton
<
IconButton
aria
-
label=
"edit"
aria
-
label=
"edit"
variant=
"link"
variant=
"link"
boxSize=
{
5
}
onClick=
{
onEditClick
}
onClick=
{
onEditClick
}
onFocusCapture=
{
onFocusCapture
}
onFocusCapture=
{
onFocusCapture
}
loading=
{
isLoading
}
loading=
{
isLoading
}
...
@@ -36,7 +35,6 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props
...
@@ -36,7 +35,6 @@ const TableItemActionButtons = ({ onEditClick, onDeleteClick, isLoading }: Props
<
IconButton
<
IconButton
aria
-
label=
"delete"
aria
-
label=
"delete"
variant=
"link"
variant=
"link"
boxSize=
{
5
}
onClick=
{
onDeleteClick
}
onClick=
{
onDeleteClick
}
onFocusCapture=
{
onFocusCapture
}
onFocusCapture=
{
onFocusCapture
}
loading=
{
isLoading
}
loading=
{
isLoading
}
...
...
ui/shared/forms/fields/FormFieldCheckbox.tsx
View file @
2d99aba9
import
type
{
ChakraProps
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Checkbox
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
useController
,
useFormContext
,
type
FieldValues
,
type
Path
}
from
'
react-hook-form
'
;
import
{
useController
,
useFormContext
,
type
FieldValues
,
type
Path
}
from
'
react-hook-form
'
;
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
type
{
CheckboxProps
}
from
'
toolkit/chakra/checkbox
'
;
import
{
Checkbox
}
from
'
toolkit/chakra/checkbox
'
;
interface
Props
<
interface
Props
<
FormFields
extends
FieldValues
,
FormFields
extends
FieldValues
,
Name
extends
Path
<
FormFields
>
=
Path
<
FormFields
>
,
Name
extends
Path
<
FormFields
>
=
Path
<
FormFields
>
,
>
extends
Omit
<
FormFieldPropsBase
<
FormFields
,
Name
>
,
'
size
'
|
'
bgColor
'
|
'
placeholder
'
>
{
>
extends
Pick
<
FormFieldPropsBase
<
FormFields
,
Name
>
,
'
rules
'
|
'
name
'
|
'
onChange
'
|
'
readOnly
'
>
,
Omit
<
CheckboxProps
,
'
name
'
|
'
onChange
'
>
{
label
:
string
;
label
:
string
;
}
}
...
@@ -20,8 +21,8 @@ const FormFieldCheckbox = <
...
@@ -20,8 +21,8 @@ const FormFieldCheckbox = <
label
,
label
,
rules
,
rules
,
onChange
,
onChange
,
isR
eadOnly
,
r
eadOnly
,
className
,
...
rest
}
: Props
<
FormFields
,
Name
>
) =
>
{
}
: Props
<
FormFields
,
Name
>
) =
>
{
const
{
control
}
=
useFormContext
<
FormFields
>
();
const
{
control
}
=
useFormContext
<
FormFields
>
();
const
{
field
,
formState
}
=
useController
<
FormFields
,
typeof
name
>
({
const
{
field
,
formState
}
=
useController
<
FormFields
,
typeof
name
>
({
...
@@ -32,32 +33,23 @@ const FormFieldCheckbox = <
...
@@ -32,32 +33,23 @@ const FormFieldCheckbox = <
const
isDisabled
=
formState
.
isSubmitting
;
const
isDisabled
=
formState
.
isSubmitting
;
const
handleChange
:
typeof
field
.
onChange
=
React
.
useCallback
((
...
args
)
=>
{
const
handleChange
:
typeof
field
.
onChange
=
React
.
useCallback
((
{
checked
}:
{
checked
:
boolean
}
)
=>
{
field
.
onChange
(
...
args
);
field
.
onChange
(
checked
);
onChange
?.();
onChange
?.();
},
[
field
,
onChange
]);
},
[
field
,
onChange
]);
return
(
return
(
<
Checkbox
<
Checkbox
ref=
{
field
.
ref
}
ref=
{
field
.
ref
}
isChecked=
{
field
.
value
}
checked=
{
field
.
value
}
className=
{
className
}
onCheckedChange=
{
handleChange
}
onChange=
{
handleChange
}
size=
"md"
colorScheme=
"blue"
disabled=
{
isDisabled
}
size=
"lg"
{
...
rest
}
isDisabled=
{
isDisabled
}
isReadOnly=
{
isReadOnly
}
>
>
{
label
}
{
label
}
</
Checkbox
>
</
Checkbox
>
);
);
}
;
}
;
const WrappedFormFieldCheckbox = chakra(FormFieldCheckbox);
export default React.memo(FormFieldCheckbox) as typeof FormFieldCheckbox;
export type WrappedComponent =
<
FormFields
extends
FieldValues
,
Name
extends
Path
<
FormFields
>
= Path
<
FormFields
>
,
>
(props: Props
<
FormFields
,
Name
>
&
ChakraProps) =
>
React.JSX.Element;
export default React.memo(WrappedFormFieldCheckbox) as WrappedComponent;
ui/watchlist/AddressModal/AddressForm.tsx
View file @
2d99aba9
import
{
import
{
Box
,
Text
}
from
'
@chakra-ui/react
'
;
Alert
,
Box
,
Button
,
Text
,
useDisclosure
,
}
from
'
@chakra-ui/react
'
;
import
{
useMutation
}
from
'
@tanstack/react-query
'
;
import
{
useMutation
}
from
'
@tanstack/react-query
'
;
import
React
,
{
useState
}
from
'
react
'
;
import
React
,
{
useState
}
from
'
react
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
...
@@ -15,6 +9,9 @@ import type { WatchlistAddress, WatchlistErrors } from 'types/api/account';
...
@@ -15,6 +9,9 @@ import type { WatchlistAddress, WatchlistErrors } from 'types/api/account';
import
type
{
ResourceErrorAccount
}
from
'
lib/api/resources
'
;
import
type
{
ResourceErrorAccount
}
from
'
lib/api/resources
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
getErrorMessage
from
'
lib/getErrorMessage
'
;
import
getErrorMessage
from
'
lib/getErrorMessage
'
;
import
{
Alert
}
from
'
toolkit/chakra/alert
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
FormFieldAddress
from
'
ui/shared/forms/fields/FormFieldAddress
'
;
import
FormFieldAddress
from
'
ui/shared/forms/fields/FormFieldAddress
'
;
import
FormFieldCheckbox
from
'
ui/shared/forms/fields/FormFieldCheckbox
'
;
import
FormFieldCheckbox
from
'
ui/shared/forms/fields/FormFieldCheckbox
'
;
import
FormFieldText
from
'
ui/shared/forms/fields/FormFieldText
'
;
import
FormFieldText
from
'
ui/shared/forms/fields/FormFieldText
'
;
...
@@ -138,25 +135,24 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
...
@@ -138,25 +135,24 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
<
form
noValidate
onSubmit=
{
formApi
.
handleSubmit
(
onSubmit
)
}
>
<
form
noValidate
onSubmit=
{
formApi
.
handleSubmit
(
onSubmit
)
}
>
<
FormFieldAddress
<
Inputs
>
<
FormFieldAddress
<
Inputs
>
name="address"
name="address"
isR
equired
r
equired
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
mb=
{
5
}
mb=
{
5
}
/
>
/
>
<
FormFieldText
<
Inputs
>
<
FormFieldText
<
Inputs
>
name="tag"
name="tag"
placeholder="Private tag (max 35 characters)"
placeholder="Private tag (max 35 characters)"
isR
equired
r
equired
rules=
{
{
rules=
{
{
maxLength
:
TAG_MAX_LENGTH
,
maxLength
:
TAG_MAX_LENGTH
,
}
}
}
}
bgColor="dialog
_
bg"
bgColor="dialog
.
bg"
mb=
{
8
}
mb=
{
8
}
/
>
/
>
{
userWithoutEmail
?
(
{
userWithoutEmail
?
(
<>
<>
<
Alert
<
Alert
status=
"info"
status=
"info"
colorScheme=
"gray"
display=
"flex"
display=
"flex"
flexDirection=
{
{
base
:
'
column
'
,
md
:
'
row
'
}
}
flexDirection=
{
{
base
:
'
column
'
,
md
:
'
row
'
}
}
alignItems=
{
{
base
:
'
flex-start
'
,
lg
:
'
center
'
}
}
alignItems=
{
{
base
:
'
flex-start
'
,
lg
:
'
center
'
}
}
...
@@ -167,17 +163,17 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
...
@@ -167,17 +163,17 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
To receive notifications you need to add an email to your profile.
To receive notifications you need to add an email to your profile.
<
Button
variant=
"outline"
size=
"sm"
onClick=
{
authModal
.
onOpen
}
>
Add email
</
Button
>
<
Button
variant=
"outline"
size=
"sm"
onClick=
{
authModal
.
onOpen
}
>
Add email
</
Button
>
</
Alert
>
</
Alert
>
{
authModal
.
isO
pen
&&
<
AuthModal
initialScreen=
{
{
type
:
'
email
'
,
isAuth
:
true
}
}
onClose=
{
authModal
.
onClose
}
/>
}
{
authModal
.
o
pen
&&
<
AuthModal
initialScreen=
{
{
type
:
'
email
'
,
isAuth
:
true
}
}
onClose=
{
authModal
.
onClose
}
/>
}
</>
</>
)
:
(
)
:
(
<>
<>
<
Text
variant=
"
secondary"
fontSize=
"sm"
marginBottom=
{
5
}
>
<
Text
color=
"text.
secondary"
fontSize=
"sm"
marginBottom=
{
5
}
>
Please select what types of notifications you will receive
Please select what types of notifications you will receive
</
Text
>
</
Text
>
<
Box
marginBottom=
{
8
}
>
<
Box
marginBottom=
{
8
}
>
<
AddressFormNotifications
/>
<
AddressFormNotifications
/>
</
Box
>
</
Box
>
<
Text
variant=
"
secondary"
fontSize=
"sm"
marginBottom=
{
{
base
:
'
10px
'
,
lg
:
5
}
}
>
Notification methods
</
Text
>
<
Text
color=
"text.
secondary"
fontSize=
"sm"
marginBottom=
{
{
base
:
'
10px
'
,
lg
:
5
}
}
>
Notification methods
</
Text
>
<
FormFieldCheckbox
<
Inputs
,
'
notification
'
>
<
FormFieldCheckbox
<
Inputs
,
'
notification
'
>
name="notification"
name="notification"
label="Email notifications"
label="Email notifications"
...
@@ -188,8 +184,8 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
...
@@ -188,8 +184,8 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
<
Button
<
Button
size=
"lg"
size=
"lg"
type=
"submit"
type=
"submit"
isL
oading=
{
pending
}
l
oading=
{
pending
}
isD
isabled=
{
!
formApi
.
formState
.
isDirty
}
d
isabled=
{
!
formApi
.
formState
.
isDirty
}
>
>
{
!
isAdd
?
'
Save changes
'
:
'
Add address
'
}
{
!
isAdd
?
'
Save changes
'
:
'
Add address
'
}
</
Button
>
</
Button
>
...
...
ui/watchlist/AddressModal/AddressModal.tsx
View file @
2d99aba9
...
@@ -8,13 +8,13 @@ import AddressForm from './AddressForm';
...
@@ -8,13 +8,13 @@ import AddressForm from './AddressForm';
type
Props
=
{
type
Props
=
{
isAdd
:
boolean
;
isAdd
:
boolean
;
isO
pen
:
boolean
;
o
pen
:
boolean
;
on
Close
:
(
)
=>
void
;
on
OpenChange
:
({
open
}:
{
open
:
boolean
}
)
=>
void
;
onSuccess
:
()
=>
Promise
<
void
>
;
onSuccess
:
()
=>
Promise
<
void
>
;
data
?:
Partial
<
WatchlistAddress
>
;
data
?:
Partial
<
WatchlistAddress
>
;
};
};
const
AddressModal
:
React
.
FC
<
Props
>
=
({
isOpen
,
onClos
e
,
onSuccess
,
data
,
isAdd
})
=>
{
const
AddressModal
:
React
.
FC
<
Props
>
=
({
open
,
onOpenChang
e
,
onSuccess
,
data
,
isAdd
})
=>
{
const
title
=
!
isAdd
?
'
Edit watch list address
'
:
'
New address to watch list
'
;
const
title
=
!
isAdd
?
'
Edit watch list address
'
:
'
New address to watch list
'
;
const
text
=
isAdd
?
'
An email notification can be sent to you when an address on your watch list sends or receives any transactions.
'
:
''
;
const
text
=
isAdd
?
'
An email notification can be sent to you when an address on your watch list sends or receives any transactions.
'
:
''
;
...
@@ -26,8 +26,8 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, onSuccess, data, isAdd
...
@@ -26,8 +26,8 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, onSuccess, data, isAdd
return
(
return
(
<
FormModal
<
WatchlistAddress
>
<
FormModal
<
WatchlistAddress
>
isOpen=
{
isO
pen
}
open=
{
o
pen
}
on
Close=
{
onClos
e
}
on
OpenChange=
{
onOpenChang
e
}
title=
{
title
}
title=
{
title
}
text=
{
text
}
text=
{
text
}
renderForm=
{
renderForm
}
renderForm=
{
renderForm
}
...
...
ui/watchlist/DeleteAddressModal.tsx
View file @
2d99aba9
...
@@ -8,13 +8,13 @@ import useIsMobile from 'lib/hooks/useIsMobile';
...
@@ -8,13 +8,13 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import
DeleteModal
from
'
ui/shared/DeleteModal
'
;
import
DeleteModal
from
'
ui/shared/DeleteModal
'
;
type
Props
=
{
type
Props
=
{
isO
pen
:
boolean
;
o
pen
:
boolean
;
on
Close
:
(
)
=>
void
;
on
OpenChange
:
({
open
}:
{
open
:
boolean
}
)
=>
void
;
onSuccess
:
()
=>
Promise
<
void
>
;
onSuccess
:
()
=>
Promise
<
void
>
;
data
:
Pick
<
WatchlistAddress
,
'
address_hash
'
|
'
id
'
>
;
data
:
Pick
<
WatchlistAddress
,
'
address_hash
'
|
'
id
'
>
;
};
};
const
DeleteAddressModal
:
React
.
FC
<
Props
>
=
({
isOpen
,
onClos
e
,
onSuccess
,
data
})
=>
{
const
DeleteAddressModal
:
React
.
FC
<
Props
>
=
({
open
,
onOpenChang
e
,
onSuccess
,
data
})
=>
{
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
const
apiFetch
=
useApiFetch
();
const
apiFetch
=
useApiFetch
();
...
@@ -36,8 +36,8 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, onSuccess, data
...
@@ -36,8 +36,8 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, onSuccess, data
return
(
return
(
<
DeleteModal
<
DeleteModal
isOpen=
{
isO
pen
}
open=
{
o
pen
}
on
Close=
{
onClos
e
}
on
OpenChange=
{
onOpenChang
e
}
title=
"Remove address from watch list"
title=
"Remove address from watch list"
renderContent=
{
renderModalContent
}
renderContent=
{
renderModalContent
}
mutationFn=
{
mutationFn
}
mutationFn=
{
mutationFn
}
...
...
ui/watchlist/WatchlistTable/WatchListAddressItem.tsx
View file @
2d99aba9
...
@@ -8,7 +8,7 @@ import config from 'configs/app';
...
@@ -8,7 +8,7 @@ import config from 'configs/app';
import
getCurrencyValue
from
'
lib/getCurrencyValue
'
;
import
getCurrencyValue
from
'
lib/getCurrencyValue
'
;
import
{
nbsp
}
from
'
lib/html-entities
'
;
import
{
nbsp
}
from
'
lib/html-entities
'
;
import
{
currencyUnits
}
from
'
lib/units
'
;
import
{
currencyUnits
}
from
'
lib/units
'
;
import
Skeleton
from
'
ui/shared/chakra/S
keleton
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/s
keleton
'
;
import
CurrencyValue
from
'
ui/shared/CurrencyValue
'
;
import
CurrencyValue
from
'
ui/shared/CurrencyValue
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
...
@@ -26,7 +26,7 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL
...
@@ -26,7 +26,7 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL
const
{
usdBn
:
usdNative
}
=
getCurrencyValue
({
value
:
item
.
address_balance
,
accuracy
:
2
,
accuracyUsd
:
2
,
exchangeRate
:
item
.
exchange_rate
});
const
{
usdBn
:
usdNative
}
=
getCurrencyValue
({
value
:
item
.
address_balance
,
accuracy
:
2
,
accuracyUsd
:
2
,
exchangeRate
:
item
.
exchange_rate
});
return
(
return
(
<
VStack
spacing
=
{
3
}
align=
"stretch"
fontWeight=
{
500
}
>
<
VStack
gap
=
{
3
}
align=
"stretch"
fontWeight=
{
500
}
>
<
AddressEntity
<
AddressEntity
address=
{
item
.
address
}
address=
{
item
.
address
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
...
@@ -38,7 +38,7 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL
...
@@ -38,7 +38,7 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL
token=
{
nativeTokenData
}
token=
{
nativeTokenData
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
/>
<
Skeleton
isLoaded=
{
!
isLoading
}
whiteSpace=
"pre"
display=
"inline-flex"
>
<
Skeleton
loading=
{
isLoading
}
whiteSpace=
"pre"
display=
"inline-flex"
>
<
span
>
{
currencyUnits
.
ether
}
balance:
</
span
>
<
span
>
{
currencyUnits
.
ether
}
balance:
</
span
>
<
CurrencyValue
<
CurrencyValue
value=
{
item
.
address_balance
}
value=
{
item
.
address_balance
}
...
@@ -49,19 +49,19 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL
...
@@ -49,19 +49,19 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL
/>
/>
</
Skeleton
>
</
Skeleton
>
</
Flex
>
</
Flex
>
{
item
.
tokens_count
&&
(
{
Boolean
(
item
.
tokens_count
)
&&
(
<
HStack
spacing
=
{
2
}
fontSize=
"sm"
pl=
{
7
}
>
<
HStack
gap
=
{
2
}
fontSize=
"sm"
pl=
{
7
}
>
<
IconSvg
name=
"tokens"
boxSize=
{
5
}
isLoading=
{
isLoading
}
borderRadius=
"sm"
/>
<
IconSvg
name=
"tokens"
boxSize=
{
5
}
isLoading=
{
isLoading
}
borderRadius=
"sm"
/>
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-flex"
>
<
Skeleton
loading=
{
isLoading
}
display=
"inline-flex"
>
<
span
>
{
`Tokens:${ nbsp }`
+
item
.
tokens_count
+
(
item
.
tokens_overflow
?
'
+
'
:
''
)
}
</
span
>
<
span
>
{
`Tokens:${ nbsp }`
+
item
.
tokens_count
+
(
item
.
tokens_overflow
?
'
+
'
:
''
)
}
</
span
>
<
Text
variant=
"secondary"
fontWeight=
{
400
}
>
{
`${ nbsp }($${ BigNumber(item.tokens_fiat_value).toFormat(2) })`
}
</
Text
>
<
Text
color=
"text.secondary"
>
{
`${ nbsp }($${ BigNumber(item.tokens_fiat_value).toFormat(2) })`
}
</
Text
>
</
Skeleton
>
</
Skeleton
>
</
HStack
>
</
HStack
>
)
}
)
}
{
item
.
tokens_fiat_value
&&
(
{
Boolean
(
item
.
tokens_fiat_value
)
&&
(
<
HStack
spacing
=
{
2
}
fontSize=
"sm"
pl=
{
7
}
>
<
HStack
gap
=
{
2
}
fontSize=
"sm"
pl=
{
7
}
>
<
IconSvg
boxSize=
{
5
}
name=
"wallet"
isLoading=
{
isLoading
}
/>
<
IconSvg
boxSize=
{
5
}
name=
"wallet"
isLoading=
{
isLoading
}
/>
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-flex"
>
<
Skeleton
loading=
{
isLoading
}
display=
"inline-flex"
>
<
Text
>
{
`Net worth:${ nbsp }`
}
<
Text
>
{
`Net worth:${ nbsp }`
}
{
{
`${ item.tokens_overflow ? '>' : '' }
`${ item.tokens_overflow ? '>' : '' }
...
...
ui/watchlist/WatchlistTable/WatchListItem.tsx
View file @
2d99aba9
import
{
Box
,
Switch
,
Text
,
HStack
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Text
,
HStack
,
Flex
}
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
'
;
import
type
{
WatchlistAddress
}
from
'
types/api/account
'
;
import
type
{
WatchlistAddress
}
from
'
types/api/account
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Switch
}
from
'
toolkit/chakra/switch
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
{
Tag
}
from
'
toolkit/chakra/tag
'
;
import
{
toaster
}
from
'
toolkit/chakra/toaster
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
...
@@ -32,34 +33,21 @@ const WatchListItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEmail }
...
@@ -32,34 +33,21 @@ const WatchListItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEmail }
return
onDeleteClick
(
item
);
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
},
[
item
,
onDeleteClick
]);
const
errorToast
=
useToast
();
const
apiFetch
=
useApiFetch
();
const
apiFetch
=
useApiFetch
();
const
showErrorToast
=
useCallback
(()
=>
{
const
showErrorToast
=
useCallback
(()
=>
{
errorToast
({
toaster
.
error
({
position
:
'
top-right
'
,
title
:
'
Error
'
,
description
:
'
There has been an error processing your request
'
,
description
:
'
There has been an error processing your request
'
,
colorScheme
:
'
red
'
,
status
:
'
error
'
,
variant
:
'
subtle
'
,
isClosable
:
true
,
icon
:
null
,
});
});
},
[
errorToast
]);
},
[
]);
const
notificationToast
=
useToast
();
const
showNotificationToast
=
useCallback
((
isOn
:
boolean
)
=>
{
const
showNotificationToast
=
useCallback
((
isOn
:
boolean
)
=>
{
notificationToast
({
toaster
.
success
({
position
:
'
top-right
'
,
description
:
!
isOn
?
'
Email notification is ON
'
:
'
Email notification is OFF
'
,
colorScheme
:
'
green
'
,
status
:
'
success
'
,
variant
:
'
subtle
'
,
title
:
'
Success
'
,
title
:
'
Success
'
,
isClosable
:
true
,
description
:
!
isOn
?
'
Email notification is ON
'
:
'
Email notification is OFF
'
,
icon
:
null
,
});
});
},
[
notificationToast
]);
},
[
]);
const
{
mutate
}
=
useMutation
({
const
{
mutate
}
=
useMutation
({
mutationFn
:
()
=>
{
mutationFn
:
()
=>
{
...
@@ -90,22 +78,22 @@ const WatchListItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEmail }
...
@@ -90,22 +78,22 @@ const WatchListItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEmail }
<
ListItemMobile
>
<
ListItemMobile
>
<
Box
maxW=
"100%"
>
<
Box
maxW=
"100%"
>
<
WatchListAddressItem
item=
{
item
}
isLoading=
{
isLoading
}
/>
<
WatchListAddressItem
item=
{
item
}
isLoading=
{
isLoading
}
/>
<
HStack
spacing
=
{
3
}
mt=
{
6
}
>
<
HStack
gap
=
{
3
}
mt=
{
6
}
>
<
Text
fontSiz
e=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Text
textStyl
e=
"sm"
fontWeight=
{
500
}
>
Private tag
</
Text
>
<
Tag
isLoading=
{
isLoading
}
isT
runcated
>
{
item
.
name
}
</
Tag
>
<
Tag
loading=
{
isLoading
}
t
runcated
>
{
item
.
name
}
</
Tag
>
</
HStack
>
</
HStack
>
</
Box
>
</
Box
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
mt=
{
6
}
w=
"100%"
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
mt=
{
6
}
w=
"100%"
>
<
HStack
spacing
=
{
3
}
>
<
HStack
gap
=
{
3
}
>
<
Text
fontSiz
e=
"sm"
fontWeight=
{
500
}
>
Email notification
</
Text
>
<
Text
textStyl
e=
"sm"
fontWeight=
{
500
}
>
Email notification
</
Text
>
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
<
Skeleton
loading=
{
isLoading
}
display=
"inline-block"
>
<
Switch
<
Switch
colorScheme=
"blue"
colorScheme=
"blue"
size=
"md"
size=
"md"
isC
hecked=
{
notificationEnabled
}
c
hecked=
{
notificationEnabled
}
onChange=
{
onSwitch
}
onCh
eckedCh
ange=
{
onSwitch
}
aria
-
label=
"Email notification"
aria
-
label=
"Email notification"
isD
isabled=
{
!
hasEmail
||
switchDisabled
}
d
isabled=
{
!
hasEmail
||
switchDisabled
}
/>
/>
</
Skeleton
>
</
Skeleton
>
</
HStack
>
</
HStack
>
...
...
ui/watchlist/WatchlistTable/WatchListTableItem.tsx
View file @
2d99aba9
import
{
Tr
,
Td
,
Switch
,
}
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
'
;
import
type
{
WatchlistAddress
}
from
'
types/api/account
'
;
import
type
{
WatchlistAddress
}
from
'
types/api/account
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Switch
}
from
'
toolkit/chakra/switch
'
;
import
Tag
from
'
ui/shared/chakra/Tag
'
;
import
{
TableCell
,
TableRow
}
from
'
toolkit/chakra/table
'
;
import
{
Tag
}
from
'
toolkit/chakra/tag
'
;
import
{
toaster
}
from
'
toolkit/chakra/toaster
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
TableItemActionButtons
from
'
ui/shared/TableItemActionButtons
'
;
import
WatchListAddressItem
from
'
./WatchListAddressItem
'
;
import
WatchListAddressItem
from
'
./WatchListAddressItem
'
;
...
@@ -35,34 +32,21 @@ const WatchlistTableItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEm
...
@@ -35,34 +32,21 @@ const WatchlistTableItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEm
return
onDeleteClick
(
item
);
return
onDeleteClick
(
item
);
},
[
item
,
onDeleteClick
]);
},
[
item
,
onDeleteClick
]);
const
errorToast
=
useToast
();
const
apiFetch
=
useApiFetch
();
const
apiFetch
=
useApiFetch
();
const
showErrorToast
=
useCallback
(()
=>
{
const
showErrorToast
=
useCallback
(()
=>
{
errorToast
({
toaster
.
error
({
position
:
'
top-right
'
,
title
:
'
Error
'
,
description
:
'
There has been an error processing your request
'
,
description
:
'
There has been an error processing your request
'
,
colorScheme
:
'
red
'
,
status
:
'
error
'
,
variant
:
'
subtle
'
,
isClosable
:
true
,
icon
:
null
,
});
});
},
[
errorToast
]);
},
[
]);
const
notificationToast
=
useToast
();
const
showNotificationToast
=
useCallback
((
isOn
:
boolean
)
=>
{
const
showNotificationToast
=
useCallback
((
isOn
:
boolean
)
=>
{
notificationToast
({
toaster
.
success
({
position
:
'
top-right
'
,
description
:
!
isOn
?
'
Email notification is ON
'
:
'
Email notification is OFF
'
,
colorScheme
:
'
green
'
,
status
:
'
success
'
,
variant
:
'
subtle
'
,
title
:
'
Success
'
,
title
:
'
Success
'
,
isClosable
:
true
,
description
:
!
isOn
?
'
Email notification is ON
'
:
'
Email notification is OFF
'
,
icon
:
null
,
});
});
},
[
notificationToast
]);
},
[
]);
const
{
mutate
}
=
useMutation
({
const
{
mutate
}
=
useMutation
({
mutationFn
:
()
=>
{
mutationFn
:
()
=>
{
...
@@ -90,27 +74,27 @@ const WatchlistTableItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEm
...
@@ -90,27 +74,27 @@ const WatchlistTableItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEm
},
[
mutate
]);
},
[
mutate
]);
return
(
return
(
<
T
r
alignItems=
"top"
key=
{
item
.
address_hash
}
>
<
T
ableRow
alignItems=
"top"
key=
{
item
.
address_hash
}
>
<
T
d
><
WatchListAddressItem
item=
{
item
}
isLoading=
{
isLoading
}
/></
Td
>
<
T
ableCell
><
WatchListAddressItem
item=
{
item
}
isLoading=
{
isLoading
}
/></
TableCell
>
<
T
d
>
<
T
ableCell
>
<
Tag
isLoading=
{
isLoading
}
isT
runcated
>
{
item
.
name
}
</
Tag
>
<
Tag
loading=
{
isLoading
}
t
runcated
>
{
item
.
name
}
</
Tag
>
</
T
d
>
</
T
ableCell
>
<
T
d
>
<
T
ableCell
>
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
>
<
Skeleton
loading=
{
isLoading
}
display=
"inline-block"
>
<
Switch
<
Switch
colorScheme=
"blue"
colorScheme=
"blue"
size=
"md"
size=
"md"
isC
hecked=
{
notificationEnabled
}
c
hecked=
{
notificationEnabled
}
onChange=
{
onSwitch
}
onCh
eckedCh
ange=
{
onSwitch
}
isD
isabled=
{
!
hasEmail
||
switchDisabled
}
d
isabled=
{
!
hasEmail
||
switchDisabled
}
aria
-
label=
"Email notification"
aria
-
label=
"Email notification"
/>
/>
</
Skeleton
>
</
Skeleton
>
</
T
d
>
</
T
ableCell
>
<
T
d
>
<
T
ableCell
>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
<
TableItemActionButtons
onDeleteClick=
{
onItemDeleteClick
}
onEditClick=
{
onItemEditClick
}
isLoading=
{
isLoading
}
/>
</
T
d
>
</
T
ableCell
>
</
T
r
>
</
T
ableRow
>
);
);
};
};
...
...
ui/watchlist/WatchlistTable/WatchlistTable.tsx
View file @
2d99aba9
import
{
Table
,
Tbody
,
Tr
,
Th
,
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
WatchlistAddress
}
from
'
types/api/account
'
;
import
type
{
WatchlistAddress
}
from
'
types/api/account
'
;
import
TheadSticky
from
'
ui/shared/TheadSticky
'
;
import
{
TableBody
,
TableColumnHeader
,
TableHeaderSticky
,
TableRoot
,
TableRow
}
from
'
toolkit/chakra/table
'
;
import
WatchlistTableItem
from
'
./WatchListTableItem
'
;
import
WatchlistTableItem
from
'
./WatchListTableItem
'
;
...
@@ -23,16 +17,16 @@ interface Props {
...
@@ -23,16 +17,16 @@ interface Props {
const
WatchlistTable
=
({
data
,
isLoading
,
onDeleteClick
,
onEditClick
,
top
,
hasEmail
}:
Props
)
=>
{
const
WatchlistTable
=
({
data
,
isLoading
,
onDeleteClick
,
onEditClick
,
top
,
hasEmail
}:
Props
)
=>
{
return
(
return
(
<
Table
minWidth=
"600px"
>
<
Table
Root
minWidth=
"600px"
>
<
T
head
Sticky
top=
{
top
}
>
<
T
ableHeader
Sticky
top=
{
top
}
>
<
T
r
>
<
T
ableRow
>
<
T
h
width=
"70%"
>
Address
</
Th
>
<
T
ableColumnHeader
width=
"70%"
>
Address
</
TableColumnHeader
>
<
T
h
width=
"30%"
>
Private tag
</
Th
>
<
T
ableColumnHeader
width=
"30%"
>
Private tag
</
TableColumnHeader
>
<
T
h
width=
"160px"
>
Email notification
</
Th
>
<
T
ableColumnHeader
width=
"160px"
>
Email notification
</
TableColumnHeader
>
<
T
h
width=
"108px"
></
Th
>
<
T
ableColumnHeader
width=
"108px"
></
TableColumnHeader
>
</
T
r
>
</
T
ableRow
>
</
T
head
Sticky
>
</
T
ableHeader
Sticky
>
<
T
b
ody
>
<
T
ableB
ody
>
{
data
?.
map
((
item
,
index
)
=>
(
{
data
?.
map
((
item
,
index
)
=>
(
<
WatchlistTableItem
<
WatchlistTableItem
key=
{
item
.
address_hash
+
(
isLoading
?
index
:
''
)
}
key=
{
item
.
address_hash
+
(
isLoading
?
index
:
''
)
}
...
@@ -43,8 +37,8 @@ const WatchlistTable = ({ data, isLoading, onDeleteClick, onEditClick, top, hasE
...
@@ -43,8 +37,8 @@ const WatchlistTable = ({ data, isLoading, onDeleteClick, onEditClick, top, hasE
hasEmail=
{
hasEmail
}
hasEmail=
{
hasEmail
}
/>
/>
))
}
))
}
</
T
b
ody
>
</
T
ableB
ody
>
</
Table
>
</
Table
Root
>
);
);
};
};
...
...
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