Commit a9af4483 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Loader state for SolidityScan button (#1945)

* SolidityScan loader update

Fixes #1893

* remove custom height of the button

* update screenshot
parent e1317844
...@@ -48,10 +48,11 @@ NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-mainnet.safe.global ...@@ -48,10 +48,11 @@ NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-mainnet.safe.global
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_MARKETPLACE_ENABLED=true NEXT_PUBLIC_MARKETPLACE_ENABLED=true
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json
NEXT_PUBLIC_MARKETPLACE_FEATURED_APP=gearbox-protocol
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
#meta #meta
......
import { Box, Text, chakra, Icon, Popover, PopoverTrigger, PopoverContent, PopoverBody, useDisclosure } from '@chakra-ui/react'; import { Box, Text, Icon, Popover, PopoverTrigger, PopoverContent, PopoverBody, useDisclosure } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
// This icon doesn't work properly when it is in the sprite // This icon doesn't work properly when it is in the sprite
...@@ -13,11 +13,10 @@ import SolidityscanReportDetails from 'ui/shared/solidityscanReport/Solidityscan ...@@ -13,11 +13,10 @@ import SolidityscanReportDetails from 'ui/shared/solidityscanReport/Solidityscan
import SolidityscanReportScore from 'ui/shared/solidityscanReport/SolidityscanReportScore'; import SolidityscanReportScore from 'ui/shared/solidityscanReport/SolidityscanReportScore';
interface Props { interface Props {
className?: string;
hash: string; hash: string;
} }
const SolidityscanReport = ({ className, hash }: Props) => { const SolidityscanReport = ({ hash }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure(); const { isOpen, onToggle, onClose } = useDisclosure();
const { data, isPlaceholderData, isError } = useApiQuery('contract_solidityscan_report', { const { data, isPlaceholderData, isError } = useApiQuery('contract_solidityscan_report', {
...@@ -42,7 +41,6 @@ const SolidityscanReport = ({ className, hash }: Props) => { ...@@ -42,7 +41,6 @@ const SolidityscanReport = ({ className, hash }: Props) => {
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy> <Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger> <PopoverTrigger>
<SolidityscanReportButton <SolidityscanReportButton
className={ className }
score={ score } score={ score }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
onClick={ onToggle } onClick={ onToggle }
...@@ -69,4 +67,4 @@ const SolidityscanReport = ({ className, hash }: Props) => { ...@@ -69,4 +67,4 @@ const SolidityscanReport = ({ className, hash }: Props) => {
); );
}; };
export default chakra(SolidityscanReport); export default React.memo(SolidityscanReport);
...@@ -14,14 +14,13 @@ import SolidityscanReportScore from 'ui/shared/solidityscanReport/SolidityscanRe ...@@ -14,14 +14,13 @@ import SolidityscanReportScore from 'ui/shared/solidityscanReport/SolidityscanRe
type Props = { type Props = {
id: string; id: string;
securityReport?: MarketplaceAppSecurityReport; securityReport?: MarketplaceAppSecurityReport;
height?: string | undefined;
showContractList: () => void; showContractList: () => void;
isLoading?: boolean; isLoading?: boolean;
onlyIcon?: boolean; onlyIcon?: boolean;
source: 'Security view' | 'App modal' | 'App page'; source: 'Security view' | 'App modal' | 'App page';
} }
const AppSecurityReport = ({ id, securityReport, height, showContractList, isLoading, onlyIcon, source }: Props) => { const AppSecurityReport = ({ id, securityReport, showContractList, isLoading, onlyIcon, source }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure(); const { isOpen, onToggle, onClose } = useDisclosure();
const handleButtonClick = React.useCallback(() => { const handleButtonClick = React.useCallback(() => {
...@@ -52,7 +51,6 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList, isLoa ...@@ -52,7 +51,6 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList, isLoa
score={ securityScore } score={ securityScore }
isLoading={ isLoading } isLoading={ isLoading }
onClick={ handleButtonClick } onClick={ handleButtonClick }
height={ height }
onlyIcon={ onlyIcon } onlyIcon={ onlyIcon }
label="The security score is based on analysis of a DApp's smart contracts." label="The security score is based on analysis of a DApp's smart contracts."
/> />
......
...@@ -94,7 +94,6 @@ const ListItem = ({ app, onInfoClick, isFavorite, onFavoriteClick, isLoading, on ...@@ -94,7 +94,6 @@ const ListItem = ({ app, onInfoClick, isFavorite, onFavoriteClick, isLoading, on
isLoading={ isLoading } isLoading={ isLoading }
securityReport={ securityReport } securityReport={ securityReport }
showContractList={ showAnalyzedContracts } showContractList={ showAnalyzedContracts }
height="30px"
source="Security view" source="Security view"
/> />
<ContractListButton <ContractListButton
......
...@@ -264,7 +264,8 @@ const AddressPageContent = () => { ...@@ -264,7 +264,8 @@ const AddressPageContent = () => {
<AddressQrCode address={{ hash }} isLoading={ isLoading }/> <AddressQrCode address={{ hash }} isLoading={ isLoading }/>
<AccountActionsMenu isLoading={ isLoading }/> <AccountActionsMenu isLoading={ isLoading }/>
<HStack ml="auto" gap={ 2 }/> <HStack ml="auto" gap={ 2 }/>
{ addressQuery.data?.is_contract && addressQuery.data?.is_verified && config.UI.views.address.solidityscanEnabled && <SolidityscanReport hash={ hash }/> } { !isLoading && addressQuery.data?.is_contract && addressQuery.data?.is_verified && config.UI.views.address.solidityscanEnabled &&
<SolidityscanReport hash={ hash }/> }
{ !isLoading && addressQuery.data && config.features.nameService.isEnabled && { !isLoading && addressQuery.data && config.features.nameService.isEnabled &&
<AddressEnsDomains addressHash={ hash } mainDomainName={ addressQuery.data.ens_domain_name }/> } <AddressEnsDomains addressHash={ hash } mainDomainName={ addressQuery.data.ens_domain_name }/> }
<NetworkExplorers type="address" pathParam={ hash }/> <NetworkExplorers type="address" pathParam={ hash }/>
......
import { Button } from '@chakra-ui/react'; import { Button, Spinner, Tooltip, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import PopoverTriggerTooltip from '../PopoverTriggerTooltip';
import useScoreLevelAndColor from './useScoreLevelAndColor'; import useScoreLevelAndColor from './useScoreLevelAndColor';
interface Props { interface Props {
className?: string;
score: number; score: number;
isLoading?: boolean; isLoading?: boolean;
height?: string;
onlyIcon?: boolean; onlyIcon?: boolean;
onClick?: () => void; onClick?: () => void;
label?: string; label?: string;
} }
const SolidityscanReportButton = ( const SolidityscanReportButton = (
{ className, score, isLoading, height = '32px', onlyIcon, onClick, label = 'Security score' }: Props, { score, isLoading, onlyIcon, onClick, label = 'Security score' }: Props,
ref: React.ForwardedRef<HTMLButtonElement>, ref: React.ForwardedRef<HTMLButtonElement>,
) => { ) => {
const { scoreColor } = useScoreLevelAndColor(score); const { scoreColor } = useScoreLevelAndColor(score);
const colorLoading = useColorModeValue('gray.300', 'gray.600');
const isMobile = useIsMobile();
return ( return (
<PopoverTriggerTooltip label={ label } isLoading={ isLoading } className={ className }> <Tooltip label={ label } isDisabled={ isMobile } openDelay={ 100 }>
<Button <Button
ref={ ref } ref={ ref }
color={ scoreColor } color={ isLoading ? colorLoading : scoreColor }
size="sm" size="sm"
variant="outline" variant="outline"
colorScheme="gray" colorScheme="gray"
...@@ -34,13 +34,21 @@ const SolidityscanReportButton = ( ...@@ -34,13 +34,21 @@ const SolidityscanReportButton = (
aria-label="SolidityScan score" aria-label="SolidityScan score"
fontWeight={ 500 } fontWeight={ 500 }
px="6px" px="6px"
h={ height }
flexShrink={ 0 } flexShrink={ 0 }
columnGap={ 1 }
isDisabled={ isLoading }
_disabled={{
opacity: 1,
_hover: {
color: colorLoading,
},
}}
> >
<IconSvg name={ score < 80 ? 'score/score-not-ok' : 'score/score-ok' } boxSize={ 5 } mr={ onlyIcon ? 0 : 1 }/> <IconSvg name={ score < 80 ? 'score/score-not-ok' : 'score/score-ok' } boxSize={ 5 }/>
{ onlyIcon ? null : score } { isLoading && <Spinner size="sm"/> }
{ !isLoading && (onlyIcon ? null : score) }
</Button> </Button>
</PopoverTriggerTooltip> </Tooltip>
); );
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment