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
0a79c372
Commit
0a79c372
authored
Feb 12, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
address subheading refactoring
parent
041f2130
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
195 additions
and
247 deletions
+195
-247
image.tsx
toolkit/chakra/image.tsx
+0
-1
tooltip.tsx
toolkit/chakra/tooltip.tsx
+4
-0
SolidityscanReport.tsx
ui/address/SolidityscanReport.tsx
+17
-15
AddressFavoriteButton.tsx
ui/address/details/AddressFavoriteButton.tsx
+8
-17
AddressQrCode.tsx
ui/address/details/AddressQrCode.tsx
+39
-56
AddressEnsDomains.tsx
ui/address/ensDomains/AddressEnsDomains.tsx
+36
-53
Address.tsx
ui/pages/Address.tsx
+46
-46
NativeTokenIcon.tsx
ui/shared/NativeTokenIcon.tsx
+1
-1
AddressAddToWallet.tsx
ui/shared/address/AddressAddToWallet.tsx
+14
-20
EnsEntity.tsx
ui/shared/entities/ens/EnsEntity.tsx
+2
-3
SolidityscanReportButton.tsx
ui/shared/solidityscanReport/SolidityscanReportButton.tsx
+15
-19
SolidityscanReportDetails.tsx
ui/shared/solidityscanReport/SolidityscanReportDetails.tsx
+3
-5
SolidityscanReportScore.tsx
ui/shared/solidityscanReport/SolidityscanReportScore.tsx
+7
-6
useScoreLevelAndColor.ts
ui/shared/solidityscanReport/useScoreLevelAndColor.ts
+3
-5
No files found.
toolkit/chakra/image.tsx
View file @
0a79c372
/* eslint-disable no-restricted-imports */
import
type
{
BoxProps
,
ImageProps
as
ChakraImageProps
}
from
'
@chakra-ui/react
'
;
import
{
Image
as
ChakraImage
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
...
...
toolkit/chakra/tooltip.tsx
View file @
0a79c372
...
...
@@ -11,10 +11,12 @@ export interface TooltipProps extends ChakraTooltip.RootProps {
portalRef
?:
React
.
RefObject
<
HTMLElement
>
;
content
:
React
.
ReactNode
;
contentProps
?:
ChakraTooltip
.
ContentProps
;
triggerProps
?:
ChakraTooltip
.
TriggerProps
;
disabled
?:
boolean
;
disableOnMobile
?:
boolean
;
}
// TODO @tom2drum fix flashing svg icons when use tooltip (disabled) + popover
export
const
Tooltip
=
React
.
forwardRef
<
HTMLDivElement
,
TooltipProps
>
(
function
Tooltip
(
props
,
ref
)
{
const
{
...
...
@@ -32,6 +34,7 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
defaultOpen
=
false
,
lazyMount
=
true
,
unmountOnExit
=
true
,
triggerProps
,
...
rest
}
=
props
;
...
...
@@ -79,6 +82,7 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
ref=
{
triggerRef
}
asChild
onClick=
{
isMobile
?
handleTriggerClick
:
undefined
}
{
...
triggerProps
}
>
{
children
}
</
ChakraTooltip
.
Trigger
>
...
...
ui/address/SolidityscanReport.tsx
View file @
0a79c372
import
{
Box
,
Text
,
Icon
,
PopoverTrigger
,
PopoverContent
,
PopoverBody
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Text
,
Icon
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
// This icon doesn't work properly when it is in the sprite
...
...
@@ -6,8 +6,9 @@ import React from 'react';
// eslint-disable-next-line no-restricted-imports
import
solidityScanIcon
from
'
icons/brands/solidity_scan.svg
'
;
import
useFetchReport
from
'
lib/solidityScan/useFetchReport
'
;
import
Popover
from
'
ui/shared/chakra/Popover
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
,
PopoverTrigger
}
from
'
toolkit/chakra/popover
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
SolidityscanReportButton
from
'
ui/shared/solidityscanReport/SolidityscanReportButton
'
;
import
SolidityscanReportDetails
from
'
ui/shared/solidityscanReport/SolidityscanReportDetails
'
;
import
SolidityscanReportScore
from
'
ui/shared/solidityscanReport/SolidityscanReportScore
'
;
...
...
@@ -17,7 +18,7 @@ interface Props {
}
const
SolidityscanReport
=
({
hash
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClos
e
}
=
useDisclosure
();
const
{
open
,
onOpenChang
e
}
=
useDisclosure
();
const
{
data
,
isPlaceholderData
,
isError
}
=
useFetchReport
({
hash
});
...
...
@@ -36,17 +37,18 @@ const SolidityscanReport = ({ hash }: Props) => {
const
vulnerabilitiesCount
=
vulnerabilitiesCounts
.
reduce
((
acc
,
val
)
=>
acc
+
val
,
0
);
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
"bottom-start"
isLazy
>
<
Popover
Root
onOpenChange=
{
onOpenChange
}
open=
{
open
}
>
<
PopoverTrigger
>
<
Box
>
<
SolidityscanReportButton
score=
{
score
}
isLoading=
{
isPlaceholderData
}
onClick=
{
onToggle
}
isActive=
{
isOpen
}
isActive=
{
open
}
/>
</
Box
>
</
PopoverTrigger
>
<
PopoverContent
w=
{
{
base
:
'
100vw
'
,
lg
:
'
328px
'
}
}
>
<
PopoverBody
px=
"26px"
py=
"20px"
fontSiz
e=
"sm"
>
<
PopoverBody
textStyl
e=
"sm"
>
<
Box
mb=
{
5
}
lineHeight=
"25px"
>
Contract analyzed for 240+ vulnerability patterns by
<
Icon
as=
{
solidityScanIcon
}
mr=
{
1
}
ml=
"6px"
w=
"23px"
h=
"20px"
display=
"inline-block"
verticalAlign=
"middle"
/>
...
...
@@ -55,14 +57,14 @@ const SolidityscanReport = ({ hash }: Props) => {
<
SolidityscanReportScore
score=
{
score
}
mb=
{
5
}
/>
{
vulnerabilities
&&
vulnerabilitiesCount
>
0
&&
(
<
Box
mb=
{
5
}
>
<
Text
py=
"7px"
variant=
"secondary"
fontSiz
e=
"xs"
fontWeight=
{
500
}
>
Vulnerabilities distribution
</
Text
>
<
Text
py=
"7px"
color=
"text.secondary"
textStyl
e=
"xs"
fontWeight=
{
500
}
>
Vulnerabilities distribution
</
Text
>
<
SolidityscanReportDetails
vulnerabilities=
{
vulnerabilities
}
vulnerabilitiesCount=
{
vulnerabilitiesCount
}
/>
</
Box
>
)
}
<
Link
External
href=
{
data
.
scan_report
.
scanner_reference_url
}
>
View full report
</
LinkExternal
>
<
Link
href=
{
data
.
scan_report
.
scanner_reference_url
}
external
>
View full report
</
Link
>
</
PopoverBody
>
</
PopoverContent
>
</
Popover
>
</
Popover
Root
>
);
};
...
...
ui/address/details/AddressFavoriteButton.tsx
View file @
0a79c372
import
{
chakra
,
Tooltip
,
IconButton
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
chakra
}
from
'
@chakra-ui/react
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
...
...
@@ -7,6 +7,9 @@ import config from 'configs/app';
import
{
getResourceKey
}
from
'
lib/api/useApiQuery
'
;
import
usePreventFocusAfterModalClosing
from
'
lib/hooks/usePreventFocusAfterModalClosing
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
AuthGuard
from
'
ui/snippets/auth/AuthGuard
'
;
import
WatchlistAddModal
from
'
ui/watchlist/AddressModal/AddressModal
'
;
...
...
@@ -36,14 +39,6 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
addModalProps
.
onClose
();
},
[
addModalProps
,
queryClient
,
router
.
query
.
hash
]);
const
handleAddModalClose
=
React
.
useCallback
(()
=>
{
addModalProps
.
onClose
();
},
[
addModalProps
]);
const
handleDeleteModalClose
=
React
.
useCallback
(()
=>
{
deleteModalProps
.
onClose
();
},
[
deleteModalProps
]);
const
formData
=
React
.
useMemo
(()
=>
{
if
(
typeof
watchListId
!==
'
number
'
)
{
return
{
address_hash
:
hash
};
...
...
@@ -63,34 +58,30 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
<>
<
AuthGuard
onAuthSuccess=
{
handleAddToFavorite
}
>
{
({
onClick
})
=>
(
<
Tooltip
label
=
{
`${ watchListId ? 'Remove address from Watch list' : 'Add address to Watch list' }`
}
>
<
Tooltip
content
=
{
`${ watchListId ? 'Remove address from Watch list' : 'Add address to Watch list' }`
}
>
<
IconButton
isActive=
{
Boolean
(
watchListId
)
}
className=
{
className
}
aria
-
label=
"edit"
variant=
"outline"
size=
"sm"
pl=
"6px"
pr=
"6px"
flexShrink=
{
0
}
onClick=
{
onClick
}
icon=
{
<
IconSvg
name=
{
watchListId
?
'
star_filled
'
:
'
star_outline
'
}
boxSize=
{
5
}
/>
}
onFocusCapture=
{
onFocusCapture
}
/>
>
<
IconSvg
name=
{
watchListId
?
'
star_filled
'
:
'
star_outline
'
}
boxSize=
{
5
}
/>
</
IconButton
>
</
Tooltip
>
)
}
</
AuthGuard
>
<
WatchlistAddModal
{
...
addModalProps
}
isAdd
onClose=
{
handleAddModalClose
}
onSuccess=
{
handleAddOrDeleteSuccess
}
data=
{
formData
}
/>
{
formData
.
id
&&
(
<
DeleteAddressModal
{
...
deleteModalProps
}
onClose=
{
handleDeleteModalClose
}
data=
{
formData
}
onSuccess=
{
handleAddOrDeleteSuccess
}
/>
...
...
ui/address/details/AddressQrCode.tsx
View file @
0a79c372
import
{
chakra
,
Alert
,
Modal
,
ModalBody
,
ModalContent
,
ModalCloseButton
,
ModalHeader
,
ModalOverlay
,
LightMode
,
Box
,
useDisclosure
,
Tooltip
,
IconButton
,
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Box
}
from
'
@chakra-ui/react
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
QRCode
from
'
qrcode
'
;
import
React
from
'
react
'
;
import
type
{
Address
as
AddressType
}
from
'
types/api/address
'
;
import
getPageType
from
'
lib/mixpanel/getPageType
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
{
useRollbar
}
from
'
lib/rollbar
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Alert
}
from
'
toolkit/chakra/alert
'
;
import
{
DialogBody
,
DialogContent
,
DialogHeader
,
DialogRoot
}
from
'
toolkit/chakra/dialog
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
...
...
@@ -32,12 +21,12 @@ const SVG_OPTIONS = {
interface
Props
{
className
?:
string
;
address
:
AddressType
;
hash
:
string
;
isLoading
?:
boolean
;
}
const
AddressQrCode
=
({
address
,
className
,
isLoading
}:
Props
)
=>
{
const
{
isOpen
,
onOpen
,
onClos
e
}
=
useDisclosure
();
const
AddressQrCode
=
({
hash
,
className
,
isLoading
}:
Props
)
=>
{
const
{
open
,
onOpen
,
onOpenChang
e
}
=
useDisclosure
();
const
router
=
useRouter
();
const
rollbar
=
useRollbar
();
...
...
@@ -48,8 +37,8 @@ const AddressQrCode = ({ address, className, isLoading }: Props) => {
const
pageType
=
getPageType
(
router
.
pathname
);
React
.
useEffect
(()
=>
{
if
(
isO
pen
)
{
QRCode
.
toString
(
address
.
hash
,
SVG_OPTIONS
,
(
error
:
Error
|
null
|
undefined
,
svg
:
string
)
=>
{
if
(
o
pen
)
{
QRCode
.
toString
(
hash
,
SVG_OPTIONS
,
(
error
:
Error
|
null
|
undefined
,
svg
:
string
)
=>
{
if
(
error
)
{
setError
(
'
We were unable to generate QR code.
'
);
rollbar
?.
warn
(
'
QR code generation failed
'
);
...
...
@@ -61,58 +50,52 @@ const AddressQrCode = ({ address, className, isLoading }: Props) => {
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
QR_CODE
,
{
'
Page type
'
:
pageType
});
});
}
},
[
address
.
hash
,
isOpen
,
onClose
,
pageType
,
rollbar
]);
},
[
hash
,
open
,
pageType
,
rollbar
]);
if
(
isLoading
)
{
return
<
Skeleton
className=
{
className
}
w=
"36px"
h=
"32px"
borderRadius=
"base"
/>;
return
<
Skeleton
loading
className=
{
className
}
w=
"36px"
h=
"32px"
borderRadius=
"base"
/>;
}
return
(
<>
<
Tooltip
label
=
"Click to view QR code"
>
<
Tooltip
content
=
"Click to view QR code"
>
<
IconButton
className=
{
className
}
aria
-
label=
"Show QR code"
variant=
"outline"
size=
"sm"
pl=
"6px"
pr=
"6px"
onClick=
{
onOpen
}
icon=
{
<
IconSvg
name=
"qr_code"
boxSize=
{
5
}
/>
}
flexShrink=
{
0
}
/>
>
<
IconSvg
name=
"qr_code"
boxSize=
{
5
}
/>
</
IconButton
>
</
Tooltip
>
{
error
&&
(
<
Modal
isOpen=
{
isOpen
}
onClose=
{
onClose
}
size=
{
{
base
:
'
full
'
,
lg
:
'
sm
'
}
}
>
<
ModalOverlay
/>
<
ModalContent
>
<
ModalBody
mb=
{
0
}
>
<
DialogRoot
open=
{
open
}
onOpenChange=
{
onOpenChange
}
size=
{
{
lgDown
:
'
full
'
,
lg
:
'
sm
'
}
}
>
<
DialogContent
>
<
DialogBody
>
<
Alert
status=
"warning"
>
{
error
}
</
Alert
>
</
Modal
Body
>
</
Modal
Content
>
</
Modal
>
</
Dialog
Body
>
</
Dialog
Content
>
</
DialogRoot
>
)
}
{
!
error
&&
(
<
LightMode
>
<
Modal
isOpen=
{
isOpen
}
onClose=
{
onClose
}
size=
{
{
base
:
'
full
'
,
lg
:
'
sm
'
}
}
>
<
ModalOverlay
/>
<
ModalContent
>
<
ModalHeader
fontWeight=
"500"
textStyle=
"h3"
mb=
{
4
}
>
Address QR code
</
ModalHeader
>
<
ModalCloseButton
/>
<
ModalBody
mb=
{
0
}
>
<
DialogRoot
open=
{
open
}
onOpenChange=
{
onOpenChange
}
size=
{
{
lgDown
:
'
full
'
,
lg
:
'
sm
'
}
}
>
<
DialogContent
className=
"light"
>
<
DialogHeader
>
Address QR code
</
DialogHeader
>
<
DialogBody
>
<
AddressEntity
mb=
{
3
}
fontWeight=
{
500
}
color=
"text"
address=
{
address
}
address=
{
{
hash
}
}
noLink
/>
<
Box
p=
{
4
}
dangerouslySetInnerHTML=
{
{
__html
:
qr
}
}
/>
</
ModalBody
>
</
ModalContent
>
</
Modal
>
</
LightMode
>
</
DialogBody
>
</
DialogContent
>
</
DialogRoot
>
)
}
</>
);
...
...
ui/address/ensDomains/AddressEnsDomains.tsx
View file @
0a79c372
import
{
Box
,
Button
,
Flex
,
Grid
,
Hide
,
PopoverBody
,
PopoverContent
,
PopoverTrigger
,
Show
,
useDisclosure
,
chakra
,
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Flex
,
Grid
,
chakra
}
from
'
@chakra-ui/react
'
;
import
type
{
UseQueryResult
}
from
'
@tanstack/react-query
'
;
import
{
clamp
}
from
'
es-toolkit
'
;
import
React
from
'
react
'
;
...
...
@@ -21,12 +9,13 @@ import { route } from 'nextjs-routes';
import
type
{
ResourceError
}
from
'
lib/api/resources
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
Popover
from
'
ui/shared/chakra/Popover
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
,
PopoverTrigger
}
from
'
toolkit/chakra/popover
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
EnsEntity
from
'
ui/shared/entities/ens/EnsEntity
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
LinkInternal
from
'
ui/shared/links/LinkInternal
'
;
import
PopoverTriggerTooltip
from
'
ui/shared/PopoverTriggerTooltip
'
;
interface
Props
{
query
:
UseQueryResult
<
bens
.
LookupAddressResponse
,
ResourceError
<
unknown
>>
;
...
...
@@ -48,7 +37,7 @@ const DomainsGrid = ({ data }: { data: Array<bens.Domain> }) => {
};
const
AddressEnsDomains
=
({
query
,
addressHash
,
mainDomainName
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
//
const { isOpen, onToggle, onClose } = useDisclosure();
const
{
data
,
isPending
,
isError
}
=
query
;
...
...
@@ -57,7 +46,7 @@ const AddressEnsDomains = ({ query, addressHash, mainDomainName }: Props) => {
}
if
(
isPending
)
{
return
<
Skeleton
h=
{
8
}
w=
{
{
base
:
'
50px
'
,
xl
:
'
120px
'
}
}
borderRadius=
"base"
/>;
return
<
Skeleton
loading
h=
{
8
}
w=
{
{
base
:
'
50px
'
,
xl
:
'
120px
'
}
}
borderRadius=
"base"
/>;
}
if
(
data
.
items
.
length
===
0
)
{
...
...
@@ -95,62 +84,56 @@ const AddressEnsDomains = ({ query, addressHash, mainDomainName }: Props) => {
const
totalRecords
=
data
.
items
.
length
>
40
?
'
40+
'
:
data
.
items
.
length
;
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
"bottom-start"
isLazy
>
<
Popover
Root
>
<
PopoverTrigger
>
<
PopoverTriggerTooltip
label=
"List of names resolved or owned by this address"
>
<
Box
>
<
Tooltip
content=
"List of names resolved or owned by this address"
>
<
Button
size=
"sm"
variant=
"outline"
colorScheme=
"gray"
onClick=
{
onToggle
}
isActive=
{
isOpen
}
variant=
"dropdown"
aria
-
label=
"Address domains"
fontWeight=
{
500
}
px=
{
2
}
h=
"32px"
flexShrink=
{
0
}
columnGap=
{
1
}
>
<
IconSvg
name=
"ENS_slim"
boxSize=
{
5
}
/>
<
Show
above=
"xl"
>
<
chakra
.
span
ml=
{
1
}
>
{
totalRecords
}
Domain
{
data
.
items
.
length
>
1
?
'
s
'
:
''
}
</
chakra
.
span
>
</
Show
>
<
Hide
above=
"xl"
>
<
chakra
.
span
ml=
{
1
}
>
{
totalRecords
}
</
chakra
.
span
>
</
Hide
>
<
chakra
.
span
hideBelow=
"xl"
>
{
totalRecords
}
Domain
{
data
.
items
.
length
>
1
?
'
s
'
:
''
}
</
chakra
.
span
>
<
chakra
.
span
hideFrom=
"xl"
>
{
totalRecords
}
</
chakra
.
span
>
</
Button
>
</
PopoverTriggerTooltip
>
</
Tooltip
>
</
Box
>
</
PopoverTrigger
>
<
PopoverContent
w=
{
{
base
:
'
100vw
'
,
lg
:
'
500px
'
}
}
>
<
PopoverBody
px=
{
6
}
py=
{
5
}
fontSiz
e=
"sm"
display=
"flex"
flexDir=
"column"
rowGap=
{
5
}
alignItems=
"flex-start"
>
<
PopoverContent
w=
{
{
lg
:
'
500px
'
}
}
>
<
PopoverBody
textStyl
e=
"sm"
display=
"flex"
flexDir=
"column"
rowGap=
{
5
}
alignItems=
"flex-start"
>
{
mainDomain
&&
(
<
Box
w=
"100%"
>
<
chakra
.
span
color=
"text
_secondary"
fontSiz
e=
"xs"
>
Primary*
</
chakra
.
span
>
<
Flex
alignItems=
"center"
fontSiz
e=
"md"
mt=
{
2
}
>
<
chakra
.
span
color=
"text
.secondary"
textStyl
e=
"xs"
>
Primary*
</
chakra
.
span
>
<
Flex
alignItems=
"center"
textStyl
e=
"md"
mt=
{
2
}
>
<
EnsEntity
domain=
{
mainDomain
.
name
}
protocol=
{
mainDomain
.
protocol
}
fontWeight=
{
600
}
noCopy
/>
{
mainDomain
.
expiry_date
&&
<
chakra
.
span
color=
"text
_
secondary"
whiteSpace=
"pre"
>
(expires
{
dayjs
(
mainDomain
.
expiry_date
).
fromNow
()
}
)
</
chakra
.
span
>
}
<
chakra
.
span
color=
"text
.
secondary"
whiteSpace=
"pre"
>
(expires
{
dayjs
(
mainDomain
.
expiry_date
).
fromNow
()
}
)
</
chakra
.
span
>
}
</
Flex
>
</
Box
>
)
}
{
ownedDomains
.
length
>
0
&&
(
<
div
>
<
chakra
.
span
color=
"text
_secondary"
fontSiz
e=
"xs"
>
Owned by this address
</
chakra
.
span
>
<
chakra
.
span
color=
"text
.secondary"
textStyl
e=
"xs"
>
Owned by this address
</
chakra
.
span
>
<
DomainsGrid
data=
{
ownedDomains
}
/>
</
div
>
)
}
{
resolvedDomains
.
length
>
0
&&
(
<
div
>
<
chakra
.
span
color=
"text
_secondary"
fontSiz
e=
"xs"
>
Resolved to this address
</
chakra
.
span
>
<
chakra
.
span
color=
"text
.secondary"
textStyl
e=
"xs"
>
Resolved to this address
</
chakra
.
span
>
<
DomainsGrid
data=
{
resolvedDomains
}
/>
</
div
>
)
}
{
(
ownedDomains
.
length
>
9
||
resolvedDomains
.
length
>
9
)
&&
(
<
Link
Internal
<
Link
href=
{
route
({
pathname
:
'
/name-domains
'
,
query
:
{
owned_by
:
'
true
'
,
resolved_to
:
'
true
'
,
address
:
addressHash
}
})
}
>
<
span
>
More results
</
span
>
<
chakra
.
span
color=
"text
_
secondary"
>
(
{
totalRecords
}
)
</
chakra
.
span
>
</
Link
Internal
>
<
chakra
.
span
color=
"text
.
secondary"
>
(
{
totalRecords
}
)
</
chakra
.
span
>
</
Link
>
)
}
{
mainDomain
&&
(
<
chakra
.
span
fontSize=
"xs"
mt=
{
-
1
}
>
...
...
@@ -159,7 +142,7 @@ const AddressEnsDomains = ({ query, addressHash, mainDomainName }: Props) => {
)
}
</
PopoverBody
>
</
PopoverContent
>
</
Popover
>
</
Popover
Root
>
);
};
...
...
ui/pages/Address.tsx
View file @
0a79c372
...
...
@@ -366,51 +366,51 @@ const AddressPageContent = () => {
// In this case it returns 404 with empty payload, so we calculate check-summed hash on the client
const checkSummedHash = React.useMemo(() => addressQuery.data?.hash ?? getCheckedSummedAddress(hash), [ hash, addressQuery.data?.hash ]);
//
const titleSecondRow = (
//
<Flex alignItems="center" w="100%" columnGap={ 2 } rowGap={ 2 } flexWrap={{ base: 'wrap', lg: 'nowrap' }}>
//
{ addressQuery.data?.ens_domain_name && (
//
<EnsEntity
//
domain={ addressQuery.data?.ens_domain_name }
//
protocol={ !addressEnsDomainsQuery.isPending ? addressMainDomain?.protocol : null }
//
fontFamily="heading"
//
fontSize="lg"
//
fontWeight={ 500 }
//
mr={ 1 }
//
maxW="300px"
//
/>
//
) }
//
<AddressEntity
//
address={{
//
...addressQuery.data,
//
hash: checkSummedHash,
//
name: '',
//
ens_domain_name: '',
//
implementations: null,
//
}}
//
isLoading={ isLoading }
//
fontFamily="heading"
//
fontSize="lg"
//
fontWeight={ 500 }
//
noLink
//
isSafeAddress={ isSafeAddress }
//
icon={{ color: isSafeAddress ? { _light: 'black', _dark: 'white' } : undefined }}
//
mr={ 4 }
//
/>
//
{ !isLoading && addressQuery.data?.is_contract && addressQuery.data.token &&
//
<AddressAddToWallet token={ addressQuery.data.token } variant="button"/> }
//
{ !isLoading && !addressQuery.data?.is_contract && config.features.account.isEnabled && (
//
<AddressFavoriteButton hash={ hash } watchListId={ addressQuery.data?.watchlist_address_id }/>
//
) }
// <AddressQrCode address={{ hash: addressQuery.data?.filecoin?.robust ?? checkSummedHash }
} isLoading={ isLoading }/>
//
<AccountActionsMenu isLoading={ isLoading }/>
//
<HStack ml="auto" gap={ 2 }/>
//
{ !isLoading && addressQuery.data?.is_contract && addressQuery.data?.is_verified && config.UI.views.address.solidityscanEnabled &&
//
<SolidityscanReport hash={ hash }/> }
//
{ !isLoading && addressEnsDomainsQuery.data && config.features.nameService.isEnabled &&
//
<AddressEnsDomains query={ addressEnsDomainsQuery } addressHash={ hash } mainDomainName={ addressQuery.data?.ens_domain_name }/> }
//
<NetworkExplorers type="address" pathParam={ hash.toLowerCase() }/>
//
</Flex>
//
);
const titleSecondRow = (
<Flex alignItems="center" w="100%" columnGap={ 2 } rowGap={ 2 } flexWrap={{ base: 'wrap', lg: 'nowrap' }}>
{ addressQuery.data?.ens_domain_name && (
<EnsEntity
domain={ addressQuery.data?.ens_domain_name }
protocol={ !addressEnsDomainsQuery.isPending ? addressMainDomain?.protocol : null }
fontFamily="heading"
fontSize="lg"
fontWeight={ 500 }
mr={ 1 }
maxW="300px"
/>
) }
<AddressEntity
address={{
...addressQuery.data,
hash: checkSummedHash,
name: '',
ens_domain_name: '',
implementations: null,
}}
isLoading={ isLoading }
fontFamily="heading"
fontSize="lg"
fontWeight={ 500 }
noLink
isSafeAddress={ isSafeAddress }
icon={{ color: isSafeAddress ? { _light: 'black', _dark: 'white' } : undefined }}
mr={ 4 }
/>
{ !isLoading && addressQuery.data?.is_contract && addressQuery.data.token &&
<AddressAddToWallet token={ addressQuery.data.token } variant="button"/> }
{ !isLoading && !addressQuery.data?.is_contract && config.features.account.isEnabled && (
<AddressFavoriteButton hash={ hash } watchListId={ addressQuery.data?.watchlist_address_id }/>
) }
<AddressQrCode hash={ addressQuery.data?.filecoin?.robust ?? checkSummedHash
} isLoading={ isLoading }/>
<AccountActionsMenu isLoading={ isLoading }/>
<HStack ml="auto" gap={ 2 }/>
{ !isLoading && addressQuery.data?.is_contract && addressQuery.data?.is_verified && config.UI.views.address.solidityscanEnabled &&
<SolidityscanReport hash={ hash }/> }
{ !isLoading && addressEnsDomainsQuery.data && config.features.nameService.isEnabled &&
<AddressEnsDomains query={ addressEnsDomainsQuery } addressHash={ hash } mainDomainName={ addressQuery.data?.ens_domain_name }/> }
<NetworkExplorers type="address" pathParam={ hash.toLowerCase() }/>
</Flex>
);
return (
<>
...
...
@@ -419,7 +419,7 @@ const AddressPageContent = () => {
title={ `
$
{
addressQuery
.
data
?.
is_contract
?
'
Contract
'
:
'
Address
'
}
details
` }
backLink={ backLink }
contentAfter={ titleContentAfter }
//
secondRow={ titleSecondRow }
secondRow={ titleSecondRow }
isLoading={ isLoading }
/>
{ !addressMetadataQuery.isPending &&
...
...
ui/shared/NativeTokenIcon.tsx
View file @
0a79c372
...
...
@@ -32,7 +32,7 @@ const NativeTokenIcon = ({ isLoading, className, type }: Props) => {
return
(
<
Image
borderRadius=
"base"
c
lassName=
{
className
}
c
ontainerProps=
{
{
className
}
}
src=
{
src
||
undefined
}
alt=
{
`${ config.chain.currency.symbol } logo`
}
fallback=
{
<
TokenLogoPlaceholder
borderRadius=
"base"
className=
{
className
}
/>
}
...
...
ui/shared/address/AddressAddToWallet.tsx
View file @
0a79c372
import
{
Box
,
chakra
,
IconButton
,
Tooltip
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
chakra
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
TokenInfo
}
from
'
types/api/token
'
;
import
config
from
'
configs/app
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
useAddOrSwitchChain
from
'
lib/web3/useAddOrSwitchChain
'
;
import
useProvider
from
'
lib/web3/useProvider
'
;
import
{
WALLETS_INFO
}
from
'
lib/web3/wallets
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
toaster
}
from
'
toolkit/chakra/toaster
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
const
feature
=
config
.
features
.
web3Wallet
;
...
...
@@ -23,7 +25,6 @@ interface Props {
}
const
AddressAddToWallet
=
({
className
,
token
,
isLoading
,
variant
=
'
icon
'
,
iconSize
=
6
}:
Props
)
=>
{
const
toast
=
useToast
();
const
{
provider
,
wallet
}
=
useProvider
();
const
addOrSwitchChain
=
useAddOrSwitchChain
();
...
...
@@ -50,13 +51,9 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico
});
if
(
wasAdded
)
{
toast
({
position
:
'
top-right
'
,
toaster
.
success
({
title
:
'
Success
'
,
description
:
'
Successfully added token to your wallet
'
,
status
:
'
success
'
,
variant
:
'
subtle
'
,
isClosable
:
true
,
});
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
ADD_TO_WALLET
,
{
...
...
@@ -66,23 +63,19 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico
});
}
}
catch
(
error
)
{
toast
({
position
:
'
top-right
'
,
toaster
.
error
({
title
:
'
Error
'
,
description
:
(
error
as
Error
)?.
message
||
'
Something went wrong
'
,
status
:
'
error
'
,
variant
:
'
subtle
'
,
isClosable
:
true
,
});
}
},
[
to
ast
,
to
ken
,
provider
,
wallet
,
addOrSwitchChain
]);
},
[
token
,
provider
,
wallet
,
addOrSwitchChain
]);
if
(
!
provider
||
!
wallet
)
{
return
null
;
}
if
(
isLoading
)
{
return
<
Skeleton
className=
{
className
}
boxSize=
{
iconSize
}
borderRadius=
"base"
/>;
return
<
Skeleton
loading
className=
{
className
}
boxSize=
{
iconSize
}
borderRadius=
"base"
/>;
}
if
(
!
feature
.
isEnabled
)
{
...
...
@@ -91,7 +84,7 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico
if
(
variant
===
'
button
'
)
{
return
(
<
Tooltip
label
=
{
`Add token to ${ WALLETS_INFO[wallet].name }`
}
>
<
Tooltip
content
=
{
`Add token to ${ WALLETS_INFO[wallet].name }`
}
>
<
IconButton
className=
{
className
}
aria
-
label=
"Add token to wallet"
...
...
@@ -99,15 +92,16 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico
size=
"sm"
px=
{
1
}
onClick=
{
handleClick
}
icon=
{
<
IconSvg
name=
{
WALLETS_INFO
[
wallet
].
icon
}
boxSize=
{
6
}
/>
}
flexShrink=
{
0
}
/>
>
<
IconSvg
name=
{
WALLETS_INFO
[
wallet
].
icon
}
boxSize=
{
6
}
/>
</
IconButton
>
</
Tooltip
>
);
}
return
(
<
Tooltip
label
=
{
`Add token to ${ WALLETS_INFO[wallet].name }`
}
>
<
Tooltip
content
=
{
`Add token to ${ WALLETS_INFO[wallet].name }`
}
>
<
Box
className=
{
className
}
display=
"inline-flex"
cursor=
"pointer"
onClick=
{
handleClick
}
flexShrink=
{
0
}
aria
-
label=
"Add token to wallet"
>
<
IconSvg
name=
{
WALLETS_INFO
[
wallet
].
icon
}
boxSize=
{
iconSize
}
/>
</
Box
>
...
...
ui/shared/entities/ens/EnsEntity.tsx
View file @
0a79c372
...
...
@@ -141,13 +141,12 @@ export interface EntityProps extends EntityBase.EntityBaseProps {
const
EnsEntity
=
(
props
:
EntityProps
)
=>
{
const
partsProps
=
distributeEntityProps
(
props
);
const
content
=
<
Content
{
...
partsProps
.
content
}
/>;
return
(
<
Container
{
...
partsProps
.
container
}
>
<
Icon
{
...
partsProps
.
icon
}
/>
<
Link
{
...
partsProps
.
link
}
>
<
Content
{
...
partsProps
.
content
}
/>
</
Link
>
{
props
.
noLink
?
content
:
<
Link
{
...
partsProps
.
link
}
>
{
content
}
</
Link
>
}
<
Copy
{
...
partsProps
.
copy
}
/>
</
Container
>
);
...
...
ui/shared/solidityscanReport/SolidityscanReportButton.tsx
View file @
0a79c372
import
{
Button
,
Spinner
,
Tooltip
,
useColorModeValue
,
chakra
}
from
'
@chakra-ui/react
'
;
import
{
Spinner
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
usePreventFocusAfterModalClosing
from
'
lib/hooks/usePreventFocusAfterModalClosing
'
;
import
type
{
ButtonProps
}
from
'
toolkit/chakra/button
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
useScoreLevelAndColor
from
'
./useScoreLevelAndColor
'
;
interface
Props
{
interface
Props
extends
ButtonProps
{
score
:
number
;
isLoading
?:
boolean
;
onlyIcon
?:
boolean
;
onClick
?:
()
=>
void
;
isActive
?:
boolean
;
label
?:
string
|
React
.
ReactElement
;
isActive
:
boolean
;
className
?:
string
;
}
const
SolidityscanReportButton
=
(
{
score
,
isLoading
,
onlyIcon
,
onClick
,
label
=
'
Security score
'
,
isActive
,
className
}:
Props
,
ref
:
React
.
ForwardedRef
<
HTMLButtonElement
>
,
{
score
,
isLoading
,
onlyIcon
,
isActive
,
label
=
'
Security score
'
,
...
rest
}:
Props
,
)
=>
{
const
{
scoreColor
}
=
useScoreLevelAndColor
(
score
);
const
colorLoading
=
useColorModeValue
(
'
gray.300
'
,
'
gray.600
'
);
const
isMobile
=
useIsMobile
();
const
colorLoading
=
{
_light
:
'
gray.300
'
,
_dark
:
'
gray.600
'
};
const
onFocusCapture
=
usePreventFocusAfterModalClosing
();
return
(
<
Tooltip
label=
{
label
}
isDisabled=
{
isMobile
}
openDelay=
{
100
}
textAlign=
"center"
>
<
Tooltip
content=
{
label
}
disableOnMobile
disabled=
{
isActive
}
>
<
Button
className=
{
className
}
ref=
{
ref
}
color=
{
isLoading
?
colorLoading
:
scoreColor
}
size=
"sm"
variant=
"outline"
colorScheme=
"gray"
onClick=
{
onClick
}
isActive=
{
isActive
}
variant=
"dropdown"
expanded=
{
isActive
}
aria
-
label=
"SolidityScan score"
fontWeight=
{
500
}
px=
"6px"
flexShrink=
{
0
}
columnGap=
{
1
}
isDisabled=
{
isLoading
}
disabled=
{
isLoading
}
_expanded=
{
{
color
:
'
link.primary.hover
'
}
}
_disabled=
{
{
opacity
:
1
,
_hover
:
{
...
...
@@ -50,6 +45,7 @@ const SolidityscanReportButton = (
},
}
}
onFocusCapture=
{
onFocusCapture
}
{
...
rest
}
>
<
IconSvg
name=
{
score
<
80
?
'
score/score-not-ok
'
:
'
score/score-ok
'
}
boxSize=
{
5
}
/>
{
isLoading
&&
<
Spinner
size=
"sm"
/>
}
...
...
@@ -59,4 +55,4 @@ const SolidityscanReportButton = (
);
};
export
default
chakra
(
React
.
forwardRef
(
SolidityscanReportButton
))
;
export
default
SolidityscanReportButton
;
ui/shared/solidityscanReport/SolidityscanReportDetails.tsx
View file @
0a79c372
import
{
Box
,
Flex
,
Text
,
Grid
,
useColorModeValue
,
chakra
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Flex
,
Text
,
Grid
,
chakra
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
SolidityScanReportSeverityDistribution
}
from
'
lib/solidityScan/schema
'
;
...
...
@@ -30,8 +30,6 @@ type ItemProps = {
};
const
SolidityScanReportItem
=
({
item
,
vulnerabilities
,
vulnerabilitiesCount
}:
ItemProps
)
=>
{
const
bgBar
=
useColorModeValue
(
'
blackAlpha.50
'
,
'
whiteAlpha.50
'
);
const
yetAnotherGrayColor
=
useColorModeValue
(
'
gray.400
'
,
'
gray.500
'
);
const
vulnerability
=
vulnerabilities
[
item
.
id
];
if
(
vulnerability
===
undefined
)
{
...
...
@@ -43,9 +41,9 @@ const SolidityScanReportItem = ({ item, vulnerabilities, vulnerabilitiesCount }:
<
Box
w=
{
3
}
h=
{
3
}
bg=
{
item
.
color
}
borderRadius=
"6px"
mr=
{
2
}
></
Box
>
<
Flex
justifyContent=
"space-between"
mr=
{
3
}
>
<
Text
>
{
item
.
name
}
</
Text
>
<
Text
color=
{
vulnerability
>
0
?
'
text
'
:
yetAnotherGrayColor
}
>
{
vulnerabilities
[
item
.
id
]
}
</
Text
>
<
Text
color=
{
vulnerability
>
0
?
'
text
'
:
{
_light
:
'
gray.400
'
,
_dark
:
'
gray.500
'
}
}
>
{
vulnerabilities
[
item
.
id
]
}
</
Text
>
</
Flex
>
<
Box
bg=
{
bgBar
}
h=
"10px"
borderRadius=
"8px"
>
<
Box
bg=
{
{
_light
:
'
blackAlpha.50
'
,
_dark
:
'
whiteAlpha.50
'
}
}
h=
"10px"
borderRadius=
"8px"
>
<
Box
bg=
{
item
.
color
}
w=
{
vulnerability
/
vulnerabilitiesCount
}
h=
"10px"
borderRadius=
"8px"
/>
</
Box
>
</>
...
...
ui/shared/solidityscanReport/SolidityscanReportScore.tsx
View file @
0a79c372
import
{
Box
,
Flex
,
Text
,
chakra
,
Center
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Flex
,
Text
,
chakra
,
Center
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
...
...
@@ -13,21 +13,22 @@ interface Props {
const
SolidityscanReportScore
=
({
className
,
score
}:
Props
)
=>
{
const
{
scoreLevel
,
scoreColor
}
=
useScoreLevelAndColor
(
score
);
const
chartGrayColor
=
useColorModeValue
(
'
gray.100
'
,
'
gray.700
'
);
const
yetAnotherGrayColor
=
useColorModeValue
(
'
gray.400
'
,
'
gray.500
'
);
const
popoverBgColor
=
useColorModeValue
(
'
white
'
,
'
gray.900
'
);
const
yetAnotherGrayColor
=
{
_light
:
'
gray.400
'
,
_dark
:
'
gray.500
'
};
return
(
<
Flex
className=
{
className
}
alignItems=
"center"
>
<
Box
w=
{
12
}
h=
{
12
}
bgGradient=
{
`conic-gradient(${ scoreColor } 0, ${ scoreColor } ${ score }%, ${ chartGrayColor } 0, ${ chartGrayColor } 100%)`
}
bgGradient=
{
{
_light
:
`conic-gradient({colors.${ scoreColor._light }} 0, {colors.${ scoreColor._light }} ${ score }%, {colors.gray.100} 0, {colors.gray.100} 100%)`
,
_dark
:
`conic-gradient({colors.${ scoreColor._dark }} 0, {colors.${ scoreColor._dark }} ${ score }%, {colors.gray.700} 0, {colors.gray.700} 100%)`
,
}
}
borderRadius=
"24px"
position=
"relative"
mr=
{
3
}
>
<
Center
position=
"absolute"
w=
"38px"
h=
"38px"
top=
"5px"
right=
"5px"
bg=
{
popoverBgColor
}
borderRadius=
"20px"
>
<
Center
position=
"absolute"
w=
"38px"
h=
"38px"
top=
"5px"
right=
"5px"
bg=
"popover.bg"
borderRadius=
"20px"
>
<
IconSvg
name=
{
score
<
80
?
'
score/score-not-ok
'
:
'
score/score-ok
'
}
boxSize=
{
5
}
color=
{
scoreColor
}
/>
</
Center
>
</
Box
>
...
...
ui/shared/solidityscanReport/useScoreLevelAndColor.ts
View file @
0a79c372
import
{
useColorModeValue
}
from
'
@chakra-ui/react
'
;
export
default
function
useScoreLevelAndColor
(
score
:
number
)
{
const
greatScoreColor
=
useColorModeValue
(
'
green.600
'
,
'
green.400
'
)
;
const
averageScoreColor
=
useColorModeValue
(
'
purple.600
'
,
'
purple.400
'
)
;
const
lowScoreColor
=
useColorModeValue
(
'
red.600
'
,
'
red.400
'
)
;
const
greatScoreColor
=
{
_light
:
'
green.600
'
,
_dark
:
'
green.400
'
}
;
const
averageScoreColor
=
{
_light
:
'
purple.600
'
,
_dark
:
'
purple.400
'
}
;
const
lowScoreColor
=
{
_light
:
'
red.600
'
,
_dark
:
'
red.400
'
}
;
let
scoreColor
;
let
scoreLevel
;
...
...
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