Commit 4c8f5ae9 authored by tom's avatar tom

api keys, custom abi, vizualize and csv export pages

parent add0e9bb
...@@ -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 ApiKeys = dynamic(() => import('ui/pages/ApiKeys'), { ssr: false }); const ApiKeys = dynamic(() => import('ui/pages/ApiKeys'), { ssr: false });
const Page: NextPage = () => { const Page: NextPage = () => {
return ( return (
<PageNextJs pathname="/account/api-key"> <PageNextJs pathname="/account/api-key">
{ /* <ApiKeys/> */ } <ApiKeys/>
</PageNextJs> </PageNextJs>
); );
}; };
......
...@@ -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 CustomAbi = dynamic(() => import('ui/pages/CustomAbi'), { ssr: false }); const CustomAbi = dynamic(() => import('ui/pages/CustomAbi'), { ssr: false });
const Page: NextPage = () => { const Page: NextPage = () => {
return ( return (
<PageNextJs pathname="/account/custom-abi"> <PageNextJs pathname="/account/custom-abi">
{ /* <CustomAbi/> */ } <CustomAbi/>
</PageNextJs> </PageNextJs>
); );
}; };
......
...@@ -3,12 +3,12 @@ import React from 'react'; ...@@ -3,12 +3,12 @@ import React from 'react';
import PageNextJs from 'nextjs/PageNextJs'; import PageNextJs from 'nextjs/PageNextJs';
// import CsvExport from 'ui/pages/CsvExport'; import CsvExport from 'ui/pages/CsvExport';
const Page: NextPage = () => { const Page: NextPage = () => {
return ( return (
<PageNextJs pathname="/csv-export"> <PageNextJs pathname="/csv-export">
{ /* <CsvExport/> */ } <CsvExport/>
</PageNextJs> </PageNextJs>
); );
}; };
......
...@@ -3,12 +3,12 @@ import React from 'react'; ...@@ -3,12 +3,12 @@ import React from 'react';
import PageNextJs from 'nextjs/PageNextJs'; import PageNextJs from 'nextjs/PageNextJs';
// import Sol2Uml from 'ui/pages/Sol2Uml'; import Sol2Uml from 'ui/pages/Sol2Uml';
const Page: NextPage = () => { const Page: NextPage = () => {
return ( return (
<PageNextJs pathname="/visualize/sol2uml"> <PageNextJs pathname="/visualize/sol2uml">
{ /* <Sol2Uml/> */ } <Sol2Uml/>
</PageNextJs> </PageNextJs>
); );
}; };
......
import { createSystem, defaultConfig, defineConfig } from '@chakra-ui/react'; import { createSystem, defaultConfig, defineConfig } from '@chakra-ui/react';
// TODO @tom2drum migrate this to the new recipe system
// import components from './components/index';
// import config from './config';
import { keyframes } from './foundations/animations'; import { keyframes } from './foundations/animations';
import * as borders from './foundations/borders'; import * as borders from './foundations/borders';
import breakpoints from './foundations/breakpoints'; import breakpoints from './foundations/breakpoints';
...@@ -39,8 +36,6 @@ const customConfig = defineConfig({ ...@@ -39,8 +36,6 @@ const customConfig = defineConfig({
}, },
}, },
}, },
// components,
// config,
}); });
export default createSystem(defaultConfig, customConfig); export default createSystem(defaultConfig, customConfig);
import { import { Box, Flex, Separator, VStack } from '@chakra-ui/react';
Alert,
Box,
Button,
Flex,
Heading,
Modal,
ModalCloseButton,
ModalContent,
PopoverBody,
PopoverContent,
PopoverTrigger,
StackDivider,
useDisclosure,
VStack,
} from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { SmartContractExternalLibrary } from 'types/api/contract'; import type { SmartContractExternalLibrary } from 'types/api/contract';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import Popover from 'ui/shared/chakra/Popover'; import { Alert } from 'toolkit/chakra/alert';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Button } from 'toolkit/chakra/button';
import { DialogBody, DialogContent, DialogHeader, DialogRoot } from 'toolkit/chakra/dialog';
import { Heading } from 'toolkit/chakra/heading';
import { PopoverRoot, PopoverBody, PopoverContent, PopoverTrigger } from 'toolkit/chakra/popover';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -47,11 +37,11 @@ const Item = (data: SmartContractExternalLibrary) => { ...@@ -47,11 +37,11 @@ const Item = (data: SmartContractExternalLibrary) => {
}; };
const ContractExternalLibraries = ({ className, data, isLoading }: Props) => { const ContractExternalLibraries = ({ className, data, isLoading }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure(); const { open, onToggle, onOpenChange } = useDisclosure();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
if (isLoading) { if (isLoading) {
return <Skeleton h={ 8 } w="150px" borderRadius="base"/>; return <Skeleton loading h={ 8 } w="150px" borderRadius="base"/>;
} }
if (data.length === 0) { if (data.length === 0) {
...@@ -62,17 +52,17 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => { ...@@ -62,17 +52,17 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => {
<Button <Button
className={ className } className={ className }
size="sm" size="sm"
variant="outline" variant="dropdown"
colorScheme="gray"
onClick={ onToggle } onClick={ onToggle }
isActive={ isOpen } expanded={ open }
fontWeight={ 600 } fontWeight={ 600 }
px={ 2 } px={ 2 }
gap={ 0 }
aria-label="View external libraries" aria-label="View external libraries"
> >
<span>{ data.length } { data.length > 1 ? 'Libraries' : 'Library' } </span> <span>{ data.length } { data.length > 1 ? 'Libraries' : 'Library' } </span>
<IconSvg name="status/warning" boxSize={ 5 } color="orange.400" ml="2px"/> <IconSvg name="status/warning" boxSize={ 5 } color="orange.400" ml="2px"/>
<IconSvg name="arrows/east-mini" transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 } ml={ 2 }/> <IconSvg name="arrows/east-mini" transform={ open ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 } ml={ 2 }/>
</Button> </Button>
); );
...@@ -84,8 +74,8 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => { ...@@ -84,8 +74,8 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => {
Check the source code at the library address (if any) if you want to be sure in case if there is any library linked Check the source code at the library address (if any) if you want to be sure in case if there is any library linked
</Alert> </Alert>
<VStack <VStack
divider={ <StackDivider borderColor="border.divider"/> } separator={ <Separator/> }
spacing={ 2 } gap={ 2 }
mt={ 4 } mt={ 4 }
maxH={{ lg: '50vh' }} maxH={{ lg: '50vh' }}
overflowY="scroll" overflowY="scroll"
...@@ -99,18 +89,20 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => { ...@@ -99,18 +89,20 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => {
return ( return (
<> <>
{ button } { button }
<Modal isOpen={ isOpen } onClose={ onClose } size="full"> <DialogRoot open={ open } onOpenChange={ onOpenChange } size="full">
<ModalContent paddingTop={ 4 }> <DialogContent paddingTop={ 4 }>
<ModalCloseButton/> <DialogHeader/>
<DialogBody>
{ content } { content }
</ModalContent> </DialogBody>
</Modal> </DialogContent>
</DialogRoot>
</> </>
); );
} }
return ( return (
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy> <PopoverRoot open={ open } onOpenChange={ onOpenChange }>
<PopoverTrigger> <PopoverTrigger>
{ button } { button }
</PopoverTrigger> </PopoverTrigger>
...@@ -119,7 +111,7 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => { ...@@ -119,7 +111,7 @@ const ContractExternalLibraries = ({ className, data, isLoading }: Props) => {
{ content } { content }
</PopoverBody> </PopoverBody>
</PopoverContent> </PopoverContent>
</Popover> </PopoverRoot>
); );
}; };
......
...@@ -6,15 +6,17 @@ import React from 'react'; ...@@ -6,15 +6,17 @@ import React from 'react';
import type { Address } from 'types/api/address'; import type { Address } from 'types/api/address';
import { route } from 'nextjs-routes';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import { IconButton } from 'toolkit/chakra/icon-button'; import { IconButton } from 'toolkit/chakra/icon-button';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip'; import { Tooltip } from 'toolkit/chakra/tooltip';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import NextLink from 'ui/shared/NextLink';
import useFetchTokens from '../utils/useFetchTokens'; import useFetchTokens from '../utils/useFetchTokens';
import TokenSelectDesktop from './TokenSelectDesktop'; import TokenSelectDesktop from './TokenSelectDesktop';
...@@ -64,27 +66,20 @@ const TokenSelect = ({ onClick }: Props) => { ...@@ -64,27 +66,20 @@ const TokenSelect = ({ onClick }: Props) => {
<TokenSelectDesktop data={ data } isLoading={ tokensIsFetching === 1 }/> <TokenSelectDesktop data={ data } isLoading={ tokensIsFetching === 1 }/>
} }
<Tooltip content="Show all tokens"> <Tooltip content="Show all tokens">
<Box> <Link
{ /* TODO @tom2drum: replace with Link */ } href={ route({ pathname: '/address/[hash]', query: { hash: addressHash, tab: 'tokens' } }) }
<NextLink asChild
href={{ pathname: '/address/[hash]', query: { hash: addressHash, tab: 'tokens' } }}
passHref
legacyBehavior
scroll={ false } scroll={ false }
> >
<IconButton <IconButton
aria-label="Show all tokens" aria-label="Show all tokens"
variant="outline" variant="outline"
size="sm" size="sm"
pl="6px"
pr="6px"
as="a"
onClick={ handleIconButtonClick } onClick={ handleIconButtonClick }
> >
<IconSvg name="wallet" boxSize={ 5 }/> <IconSvg name="wallet" boxSize={ 5 }/>
</IconButton> </IconButton>
</NextLink> </Link>
</Box>
</Tooltip> </Tooltip>
</Flex> </Flex>
); );
......
import { import { Box } from '@chakra-ui/react';
Box,
Button,
} from '@chakra-ui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { SubmitHandler } from 'react-hook-form'; import type { SubmitHandler } from 'react-hook-form';
...@@ -13,11 +10,12 @@ import type { ResourceErrorAccount } from 'lib/api/resources'; ...@@ -13,11 +10,12 @@ import type { ResourceErrorAccount } from 'lib/api/resources';
import { resourceKey } from 'lib/api/resources'; import { resourceKey } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import { Button } from 'toolkit/chakra/button';
import FormFieldText from 'ui/shared/forms/fields/FormFieldText'; import FormFieldText from 'ui/shared/forms/fields/FormFieldText';
type Props = { type Props = {
data?: ApiKey; data?: ApiKey;
onClose: () => void; onOpenChange: ({ open }: { open: boolean }) => void;
setAlertVisible: (isAlertVisible: boolean) => void; setAlertVisible: (isAlertVisible: boolean) => void;
}; };
...@@ -28,7 +26,7 @@ type Inputs = { ...@@ -28,7 +26,7 @@ type Inputs = {
const NAME_MAX_LENGTH = 255; const NAME_MAX_LENGTH = 255;
const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { const ApiKeyForm: React.FC<Props> = ({ data, onOpenChange, setAlertVisible }) => {
const formApi = useForm<Inputs>({ const formApi = useForm<Inputs>({
mode: 'onTouched', mode: 'onTouched',
defaultValues: { defaultValues: {
...@@ -73,7 +71,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -73,7 +71,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
return [ response, ...(prevData || []) ]; return [ response, ...(prevData || []) ];
}); });
onClose(); onOpenChange({ open: false });
}, },
onError: (error: ResourceErrorAccount<ApiKeyErrors>) => { onError: (error: ResourceErrorAccount<ApiKeyErrors>) => {
const errorMap = error.payload?.errors; const errorMap = error.payload?.errors;
...@@ -99,15 +97,14 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -99,15 +97,14 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
<FormFieldText<Inputs> <FormFieldText<Inputs>
name="token" name="token"
placeholder="Auto-generated API key token" placeholder="Auto-generated API key token"
isReadOnly readOnly
bgColor="dialog.bg"
mb={ 5 } mb={ 5 }
/> />
) } ) }
<FormFieldText<Inputs> <FormFieldText<Inputs>
name="name" name="name"
placeholder="Application name for API key (e.g Web3 project)" placeholder="Application name for API key (e.g Web3 project)"
isRequired required
rules={{ rules={{
maxLength: NAME_MAX_LENGTH, maxLength: NAME_MAX_LENGTH,
}} }}
...@@ -118,8 +115,8 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -118,8 +115,8 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
<Button <Button
size="lg" size="lg"
type="submit" type="submit"
isDisabled={ !formApi.formState.isDirty } disabled={ !formApi.formState.isDirty }
isLoading={ isPending } loading={ isPending }
> >
{ data ? 'Save' : 'Generate API key' } { data ? 'Save' : 'Generate API key' }
</Button> </Button>
......
...@@ -7,24 +7,24 @@ import FormModal from 'ui/shared/FormModal'; ...@@ -7,24 +7,24 @@ import FormModal from 'ui/shared/FormModal';
import ApiKeyForm from './ApiKeyForm'; import ApiKeyForm from './ApiKeyForm';
type Props = { type Props = {
isOpen: boolean; open: boolean;
onClose: () => void; onOpenChange: ({ open }: { open: boolean }) => void;
data?: ApiKey; data?: ApiKey;
}; };
const ApiKeyModal: React.FC<Props> = ({ isOpen, onClose, data }) => { const ApiKeyModal: React.FC<Props> = ({ open, onOpenChange, data }) => {
const title = data ? 'Edit API key' : 'New API key'; const title = data ? 'Edit API key' : 'New API key';
const text = !data ? 'Add an application name to identify your API key. Click the button below to auto-generate the associated key.' : ''; const text = !data ? 'Add an application name to identify your API key. Click the button below to auto-generate the associated key.' : '';
const [ isAlertVisible, setAlertVisible ] = useState(false); const [ isAlertVisible, setAlertVisible ] = useState(false);
const renderForm = useCallback(() => { const renderForm = useCallback(() => {
return <ApiKeyForm data={ data } onClose={ onClose } setAlertVisible={ setAlertVisible }/>; return <ApiKeyForm data={ data } onOpenChange={ onOpenChange } setAlertVisible={ setAlertVisible }/>;
}, [ data, onClose ]); }, [ data, onOpenChange ]);
return ( return (
<FormModal<ApiKey> <FormModal<ApiKey>
isOpen={ isOpen } open={ open }
onClose={ onClose } onOpenChange={ onOpenChange }
title={ title } title={ title }
text={ text } text={ text }
renderForm={ renderForm } renderForm={ renderForm }
......
import {
Table,
Thead,
Tbody,
Tr,
Th,
} from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { ApiKeys, ApiKey } from 'types/api/account'; import type { ApiKeys, ApiKey } from 'types/api/account';
import { TableBody, TableColumnHeader, TableHeader, TableRoot, TableRow } from 'toolkit/chakra/table';
import ApiKeyTableItem from './ApiKeyTableItem'; import ApiKeyTableItem from './ApiKeyTableItem';
interface Props { interface Props {
...@@ -21,14 +16,14 @@ interface Props { ...@@ -21,14 +16,14 @@ interface Props {
const ApiKeyTable = ({ data, isLoading, onDeleteClick, onEditClick, limit }: Props) => { const ApiKeyTable = ({ data, isLoading, onDeleteClick, onEditClick, limit }: Props) => {
return ( return (
<Table minWidth="600px"> <TableRoot minWidth="600px">
<Thead> <TableHeader>
<Tr> <TableRow>
<Th>{ `API key token (limit ${ limit } keys)` }</Th> <TableColumnHeader>{ `API key token (limit ${ limit } keys)` }</TableColumnHeader>
<Th width="108px"></Th> <TableColumnHeader width="108px"></TableColumnHeader>
</Tr> </TableRow>
</Thead> </TableHeader>
<Tbody> <TableBody>
{ data?.map((item, index) => ( { data?.map((item, index) => (
<ApiKeyTableItem <ApiKeyTableItem
key={ item.api_key + (isLoading ? index : '') } key={ item.api_key + (isLoading ? index : '') }
...@@ -38,8 +33,8 @@ const ApiKeyTable = ({ data, isLoading, onDeleteClick, onEditClick, limit }: Pro ...@@ -38,8 +33,8 @@ const ApiKeyTable = ({ data, isLoading, onDeleteClick, onEditClick, limit }: Pro
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
)) } )) }
</Tbody> </TableBody>
</Table> </TableRoot>
); );
}; };
......
import {
Tr,
Td,
} 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 { TableCell, TableRow } from 'toolkit/chakra/table';
import ApiKeySnippet from 'ui/shared/ApiKeySnippet'; import ApiKeySnippet from 'ui/shared/ApiKeySnippet';
import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
...@@ -27,14 +24,14 @@ const ApiKeyTableItem = ({ item, isLoading, onEditClick, onDeleteClick }: Props) ...@@ -27,14 +24,14 @@ const ApiKeyTableItem = ({ item, isLoading, onEditClick, onDeleteClick }: Props)
}, [ item, onDeleteClick ]); }, [ item, onDeleteClick ]);
return ( return (
<Tr alignItems="top" key={ item.api_key }> <TableRow alignItems="top" key={ item.api_key }>
<Td> <TableCell>
<ApiKeySnippet apiKey={ item.api_key } name={ item.name } isLoading={ isLoading }/> <ApiKeySnippet apiKey={ item.api_key } name={ item.name } isLoading={ isLoading }/>
</Td> </TableCell>
<Td> <TableCell>
<TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/> <TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/>
</Td> </TableCell>
</Tr> </TableRow>
); );
}; };
......
...@@ -9,12 +9,12 @@ import useApiFetch from 'lib/api/useApiFetch'; ...@@ -9,12 +9,12 @@ import useApiFetch from 'lib/api/useApiFetch';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
type Props = { type Props = {
isOpen: boolean; open: boolean;
onClose: () => void; onOpenChange: ({ open }: { open: boolean }) => void;
data: ApiKey; data: ApiKey;
}; };
const DeleteApiKeyModal: React.FC<Props> = ({ isOpen, onClose, data }) => { const DeleteApiKeyModal: React.FC<Props> = ({ open, onOpenChange, data }) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
...@@ -39,8 +39,8 @@ const DeleteApiKeyModal: React.FC<Props> = ({ isOpen, onClose, data }) => { ...@@ -39,8 +39,8 @@ const DeleteApiKeyModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
return ( return (
<DeleteModal <DeleteModal
isOpen={ isOpen } open={ open }
onClose={ onClose } onOpenChange={ onOpenChange }
title="Remove API key" title="Remove API key"
renderContent={ renderText } renderContent={ renderText }
mutationFn={ mutationFn } mutationFn={ mutationFn }
......
import { Alert, Button, chakra, Flex } from '@chakra-ui/react'; import { chakra, Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { SubmitHandler } from 'react-hook-form'; import type { SubmitHandler } from 'react-hook-form';
import { useForm, FormProvider } from 'react-hook-form'; import { useForm, FormProvider } from 'react-hook-form';
...@@ -11,7 +11,9 @@ import buildUrl from 'lib/api/buildUrl'; ...@@ -11,7 +11,9 @@ import buildUrl from 'lib/api/buildUrl';
import type { ResourceName } from 'lib/api/resources'; import type { ResourceName } from 'lib/api/resources';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import downloadBlob from 'lib/downloadBlob'; import downloadBlob from 'lib/downloadBlob';
import useToast from 'lib/hooks/useToast'; import { Alert } from 'toolkit/chakra/alert';
import { Button } from 'toolkit/chakra/button';
import { toaster } from 'toolkit/chakra/toaster';
import ReCaptcha from 'ui/shared/reCaptcha/ReCaptcha'; import ReCaptcha from 'ui/shared/reCaptcha/ReCaptcha';
import useReCaptcha from 'ui/shared/reCaptcha/useReCaptcha'; import useReCaptcha from 'ui/shared/reCaptcha/useReCaptcha';
...@@ -35,7 +37,6 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla ...@@ -35,7 +37,6 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
}, },
}); });
const { handleSubmit, formState } = formApi; const { handleSubmit, formState } = formApi;
const toast = useToast();
const recaptcha = useReCaptcha(); const recaptcha = useReCaptcha();
const onFormSubmit: SubmitHandler<FormFields> = React.useCallback(async(data) => { const onFormSubmit: SubmitHandler<FormFields> = React.useCallback(async(data) => {
...@@ -73,17 +74,13 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla ...@@ -73,17 +74,13 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
downloadBlob(blob, fileName); downloadBlob(blob, fileName);
} catch (error) { } catch (error) {
toast({ toaster.error({
position: 'top-right',
title: 'Error', title: 'Error',
description: (error as Error)?.message || 'Something went wrong. Try again later.', description: (error as Error)?.message || 'Something went wrong. Try again later.',
status: 'error',
variant: 'subtle',
isClosable: true,
}); });
} }
}, [ recaptcha, resource, hash, exportType, filterType, filterValue, fileNameTemplate, toast ]); }, [ recaptcha, resource, hash, exportType, filterType, filterValue, fileNameTemplate ]);
if (!config.services.reCaptchaV2.siteKey) { if (!config.services.reCaptchaV2.siteKey) {
return ( return (
...@@ -110,9 +107,9 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla ...@@ -110,9 +107,9 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
size="lg" size="lg"
type="submit" type="submit"
mt={ 8 } mt={ 8 }
isLoading={ formState.isSubmitting } loading={ formState.isSubmitting }
loadingText="Download" loadingText="Download"
isDisabled={ Boolean(formState.errors.from || formState.errors.to) } disabled={ Boolean(formState.errors.from || formState.errors.to) }
> >
Download Download
</Button> </Button>
......
...@@ -38,12 +38,11 @@ const CsvExportFormField = ({ formApi, name }: Props) => { ...@@ -38,12 +38,11 @@ const CsvExportFormField = ({ formApi, name }: Props) => {
return ( return (
<FormFieldText<FormFields, typeof name> <FormFieldText<FormFields, typeof name>
name={ name } name={ name }
type="date" inputProps={{ type: 'date', max: dayjs().format('YYYY-MM-DD') }}
max={ dayjs().format('YYYY-MM-DD') }
placeholder={ capitalize(name) } placeholder={ capitalize(name) }
isRequired required
rules={{ validate }} rules={{ validate }}
size={{ base: 'md', lg: 'lg' }} size="xl"
maxW={{ base: 'auto', lg: '220px' }} maxW={{ base: 'auto', lg: '220px' }}
/> />
); );
......
...@@ -3,7 +3,7 @@ import React, { useCallback } from 'react'; ...@@ -3,7 +3,7 @@ import React, { useCallback } from 'react';
import type { CustomAbi } from 'types/api/account'; import type { CustomAbi } from 'types/api/account';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
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';
...@@ -33,7 +33,7 @@ const CustomAbiListItem = ({ item, isLoading, onEditClick, onDeleteClick }: Prop ...@@ -33,7 +33,7 @@ const CustomAbiListItem = ({ item, isLoading, onEditClick, onDeleteClick }: Prop
fontWeight="600" fontWeight="600"
isLoading={ isLoading } isLoading={ isLoading }
/> />
<Skeleton fontSize="sm" color="text_secondary" mt={ 0.5 } ml={ 8 } display="inline-block" isLoaded={ !isLoading }> <Skeleton textStyle="sm" color="text.secondary" mt={ 0.5 } ml={ 8 } display="inline-block" loading={ isLoading }>
<span>{ item.name }</span> <span>{ item.name }</span>
</Skeleton> </Skeleton>
</Box> </Box>
......
import {
Table,
Thead,
Tbody,
Tr,
Th,
} from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { CustomAbis, CustomAbi } from 'types/api/account'; import type { CustomAbis, CustomAbi } from 'types/api/account';
import { TableBody, TableColumnHeader, TableHeader, TableRoot, TableRow } from 'toolkit/chakra/table';
import CustomAbiTableItem from './CustomAbiTableItem'; import CustomAbiTableItem from './CustomAbiTableItem';
interface Props { interface Props {
...@@ -20,14 +15,14 @@ interface Props { ...@@ -20,14 +15,14 @@ interface Props {
const CustomAbiTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props) => { const CustomAbiTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props) => {
return ( return (
<Table minWidth="600px"> <TableRoot minWidth="600px">
<Thead> <TableHeader>
<Tr> <TableRow>
<Th>ABI for Smart contract address (0x...)</Th> <TableColumnHeader>ABI for Smart contract address (0x...)</TableColumnHeader>
<Th width="108px"></Th> <TableColumnHeader width="108px"></TableColumnHeader>
</Tr> </TableRow>
</Thead> </TableHeader>
<Tbody> <TableBody>
{ data?.map((item, index) => ( { data?.map((item, index) => (
<CustomAbiTableItem <CustomAbiTableItem
key={ item.id + (isLoading ? String(index) : '') } key={ item.id + (isLoading ? String(index) : '') }
...@@ -37,8 +32,8 @@ const CustomAbiTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props) ...@@ -37,8 +32,8 @@ const CustomAbiTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props)
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
)) } )) }
</Tbody> </TableBody>
</Table> </TableRoot>
); );
}; };
......
import { import { Box } from '@chakra-ui/react';
Tr,
Td,
Box,
} 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 Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import { TableCell, TableRow } from 'toolkit/chakra/table';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TableItemActionButtons from 'ui/shared/TableItemActionButtons'; import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
...@@ -29,23 +26,23 @@ const CustomAbiTableItem = ({ item, isLoading, onEditClick, onDeleteClick }: Pro ...@@ -29,23 +26,23 @@ const CustomAbiTableItem = ({ item, isLoading, onEditClick, onDeleteClick }: Pro
}, [ item, onDeleteClick ]); }, [ item, onDeleteClick ]);
return ( return (
<Tr alignItems="top" key={ item.id }> <TableRow alignItems="top" key={ item.id }>
<Td> <TableCell>
<Box maxW="100%"> <Box maxW="100%">
<AddressEntity <AddressEntity
address={ item.contract_address } address={ item.contract_address }
fontWeight="600" fontWeight="600"
isLoading={ isLoading } isLoading={ isLoading }
/> />
<Skeleton fontSize="sm" color="text_secondary" mt={ 0.5 } ml={ 8 } display="inline-block" isLoaded={ !isLoading }> <Skeleton textStyle="sm" color="text.secondary" mt={ 0.5 } ml={ 8 } display="inline-block" loading={ isLoading }>
<span>{ item.name }</span> <span>{ item.name }</span>
</Skeleton> </Skeleton>
</Box> </Box>
</Td> </TableCell>
<Td> <TableCell>
<TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/> <TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/>
</Td> </TableCell>
</Tr> </TableRow>
); );
}; };
......
...@@ -9,12 +9,12 @@ import useApiFetch from 'lib/api/useApiFetch'; ...@@ -9,12 +9,12 @@ import useApiFetch from 'lib/api/useApiFetch';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
type Props = { type Props = {
isOpen: boolean; open: boolean;
onClose: () => void; onOpenChange: ({ open }: { open: boolean }) => void;
data: CustomAbi; data: CustomAbi;
}; };
const DeleteCustomAbiModal: React.FC<Props> = ({ isOpen, onClose, data }) => { const DeleteCustomAbiModal: React.FC<Props> = ({ open, onOpenChange, data }) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
...@@ -40,8 +40,8 @@ const DeleteCustomAbiModal: React.FC<Props> = ({ isOpen, onClose, data }) => { ...@@ -40,8 +40,8 @@ const DeleteCustomAbiModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
return ( return (
<DeleteModal <DeleteModal
isOpen={ isOpen } open={ open }
onClose={ onClose } onOpenChange={ onOpenChange }
title="Remove custom ABI" title="Remove custom ABI"
renderContent={ renderText } renderContent={ renderText }
mutationFn={ mutationFn } mutationFn={ mutationFn }
......
import { Box, Button, Link, Text, useDisclosure } from '@chakra-ui/react'; import { Box, Text } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { ApiKey } from 'types/api/account'; import type { ApiKey } from 'types/api/account';
...@@ -6,12 +6,15 @@ import type { ApiKey } from 'types/api/account'; ...@@ -6,12 +6,15 @@ import type { ApiKey } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { space } from 'lib/html-entities'; import { space } from 'lib/html-entities';
import { API_KEY } from 'stubs/account'; import { API_KEY } from 'stubs/account';
import { Button } from 'toolkit/chakra/button';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import ApiKeyModal from 'ui/apiKey/ApiKeyModal/ApiKeyModal'; import ApiKeyModal from 'ui/apiKey/ApiKeyModal/ApiKeyModal';
import ApiKeyListItem from 'ui/apiKey/ApiKeyTable/ApiKeyListItem'; import ApiKeyListItem from 'ui/apiKey/ApiKeyTable/ApiKeyListItem';
import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable'; import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable';
import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal'; import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
import AccountPageDescription from 'ui/shared/AccountPageDescription'; import AccountPageDescription from 'ui/shared/AccountPageDescription';
import Skeleton from 'ui/shared/chakra/Skeleton';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import useRedirectForInvalidAuthToken from 'ui/snippets/auth/useRedirectForInvalidAuthToken'; import useRedirectForInvalidAuthToken from 'ui/snippets/auth/useRedirectForInvalidAuthToken';
...@@ -37,9 +40,9 @@ const ApiKeysPage: React.FC = () => { ...@@ -37,9 +40,9 @@ const ApiKeysPage: React.FC = () => {
apiKeyModalProps.onOpen(); apiKeyModalProps.onOpen();
}, [ apiKeyModalProps ]); }, [ apiKeyModalProps ]);
const onApiKeyModalClose = useCallback(() => { const onApiKeyModalOpenChange = useCallback(({ open }: { open: boolean }) => {
setApiKeyModalData(undefined); !open && setApiKeyModalData(undefined);
apiKeyModalProps.onClose(); apiKeyModalProps.onOpenChange({ open });
}, [ apiKeyModalProps ]); }, [ apiKeyModalProps ]);
const onDeleteClick = useCallback((data: ApiKey) => { const onDeleteClick = useCallback((data: ApiKey) => {
...@@ -47,9 +50,9 @@ const ApiKeysPage: React.FC = () => { ...@@ -47,9 +50,9 @@ const ApiKeysPage: React.FC = () => {
deleteModalProps.onOpen(); deleteModalProps.onOpen();
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
const onDeleteModalClose = useCallback(() => { const onDeleteModalOpenChange = useCallback(({ open }: { open: boolean }) => {
setDeleteModalData(undefined); !open && setDeleteModalData(undefined);
deleteModalProps.onClose(); deleteModalProps.onOpenChange({ open });
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
const description = ( const description = (
...@@ -99,7 +102,7 @@ const ApiKeysPage: React.FC = () => { ...@@ -99,7 +102,7 @@ const ApiKeysPage: React.FC = () => {
marginTop={ 8 } marginTop={ 8 }
flexDir={{ base: 'column', lg: 'row' }} flexDir={{ base: 'column', lg: 'row' }}
alignItems={{ base: 'start', lg: 'center' }} alignItems={{ base: 'start', lg: 'center' }}
isLoaded={ !isPlaceholderData } loading={ isPlaceholderData }
display="inline-flex" display="inline-flex"
columnGap={ 5 } columnGap={ 5 }
rowGap={ 5 } rowGap={ 5 }
...@@ -107,18 +110,18 @@ const ApiKeysPage: React.FC = () => { ...@@ -107,18 +110,18 @@ const ApiKeysPage: React.FC = () => {
<Button <Button
size="lg" size="lg"
onClick={ apiKeyModalProps.onOpen } onClick={ apiKeyModalProps.onOpen }
isDisabled={ !canAdd } disabled={ !canAdd }
> >
Add API key Add API key
</Button> </Button>
{ !canAdd && ( { !canAdd && (
<Text fontSize="sm" variant="secondary"> <Text fontSize="sm" color="text.secondary">
{ `You have added the maximum number of API keys (${ DATA_LIMIT }). Contact us to request additional keys.` } { `You have added the maximum number of API keys (${ DATA_LIMIT }). Contact us to request additional keys.` }
</Text> </Text>
) } ) }
</Skeleton> </Skeleton>
<ApiKeyModal { ...apiKeyModalProps } onClose={ onApiKeyModalClose } data={ apiKeyModalData }/> <ApiKeyModal open={ apiKeyModalProps.open } onOpenChange={ onApiKeyModalOpenChange } data={ apiKeyModalData }/>
{ deleteModalData && <DeleteApiKeyModal { ...deleteModalProps } onClose={ onDeleteModalClose } data={ deleteModalData }/> } { deleteModalData && <DeleteApiKeyModal open={ deleteModalProps.open } onOpenChange={ onDeleteModalOpenChange } data={ deleteModalData }/> }
</> </>
); );
})(); })();
......
import { Box, Button, useDisclosure } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { CustomAbi } from 'types/api/account'; import type { CustomAbi } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { CUSTOM_ABI } from 'stubs/account'; import { CUSTOM_ABI } from 'stubs/account';
import { Button } from 'toolkit/chakra/button';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import CustomAbiModal from 'ui/customAbi/CustomAbiModal/CustomAbiModal'; import CustomAbiModal from 'ui/customAbi/CustomAbiModal/CustomAbiModal';
import CustomAbiListItem from 'ui/customAbi/CustomAbiTable/CustomAbiListItem'; import CustomAbiListItem from 'ui/customAbi/CustomAbiTable/CustomAbiListItem';
import CustomAbiTable from 'ui/customAbi/CustomAbiTable/CustomAbiTable'; import CustomAbiTable from 'ui/customAbi/CustomAbiTable/CustomAbiTable';
import DeleteCustomAbiModal from 'ui/customAbi/DeleteCustomAbiModal'; import DeleteCustomAbiModal from 'ui/customAbi/DeleteCustomAbiModal';
import AccountPageDescription from 'ui/shared/AccountPageDescription'; import AccountPageDescription from 'ui/shared/AccountPageDescription';
import Skeleton from 'ui/shared/chakra/Skeleton';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import useRedirectForInvalidAuthToken from 'ui/snippets/auth/useRedirectForInvalidAuthToken'; import useRedirectForInvalidAuthToken from 'ui/snippets/auth/useRedirectForInvalidAuthToken';
...@@ -34,9 +36,9 @@ const CustomAbiPage: React.FC = () => { ...@@ -34,9 +36,9 @@ const CustomAbiPage: React.FC = () => {
customAbiModalProps.onOpen(); customAbiModalProps.onOpen();
}, [ customAbiModalProps ]); }, [ customAbiModalProps ]);
const onCustomAbiModalClose = useCallback(() => { const onCustomAbiModalOpenChange = useCallback(({ open }: { open: boolean }) => {
setCustomAbiModalData(undefined); !open && setCustomAbiModalData(undefined);
customAbiModalProps.onClose(); customAbiModalProps.onOpenChange({ open });
}, [ customAbiModalProps ]); }, [ customAbiModalProps ]);
const onDeleteClick = useCallback((data: CustomAbi) => { const onDeleteClick = useCallback((data: CustomAbi) => {
...@@ -44,9 +46,9 @@ const CustomAbiPage: React.FC = () => { ...@@ -44,9 +46,9 @@ const CustomAbiPage: React.FC = () => {
deleteModalProps.onOpen(); deleteModalProps.onOpen();
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
const onDeleteModalClose = useCallback(() => { const onDeleteModalOpenChange = useCallback(({ open }: { open: boolean }) => {
setDeleteModalData(undefined); !open && setDeleteModalData(undefined);
deleteModalProps.onClose(); deleteModalProps.onOpenChange({ open });
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
const description = ( const description = (
...@@ -88,7 +90,7 @@ const CustomAbiPage: React.FC = () => { ...@@ -88,7 +90,7 @@ const CustomAbiPage: React.FC = () => {
<> <>
{ description } { description }
{ Boolean(data?.length) && list } { Boolean(data?.length) && list }
<Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block"> <Skeleton mt={ 8 } loading={ isPlaceholderData } display="inline-block">
<Button <Button
size="lg" size="lg"
onClick={ customAbiModalProps.onOpen } onClick={ customAbiModalProps.onOpen }
...@@ -96,8 +98,8 @@ const CustomAbiPage: React.FC = () => { ...@@ -96,8 +98,8 @@ const CustomAbiPage: React.FC = () => {
Add custom ABI Add custom ABI
</Button> </Button>
</Skeleton> </Skeleton>
<CustomAbiModal { ...customAbiModalProps } onClose={ onCustomAbiModalClose } data={ customAbiModalData }/> <CustomAbiModal open={ customAbiModalProps.open } onOpenChange={ onCustomAbiModalOpenChange } data={ customAbiModalData }/>
{ deleteModalData && <DeleteCustomAbiModal { ...deleteModalProps } onClose={ onDeleteModalClose } data={ deleteModalData }/> } { deleteModalData && <DeleteCustomAbiModal open={ deleteModalProps.open } onOpenChange={ onDeleteModalOpenChange } data={ deleteModalData }/> }
</> </>
); );
})(); })();
......
import { Box, HStack, Flex, useColorModeValue } from '@chakra-ui/react'; import { Box, HStack, Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -13,17 +13,17 @@ interface Props { ...@@ -13,17 +13,17 @@ interface Props {
const ApiKeySnippet = ({ apiKey, name, isLoading }: Props) => { const ApiKeySnippet = ({ apiKey, name, isLoading }: Props) => {
return ( return (
<HStack spacing={ 2 } alignItems="start"> <HStack gap={ 2 } alignItems="start">
<IconSvg name="key" boxSize={ 6 } color={ useColorModeValue('gray.500', 'gray.400') } isLoading={ isLoading }/> <IconSvg name="key" boxSize={ 6 } color={{ _light: 'gray.500', _dark: 'gray.400' }} isLoading={ isLoading }/>
<Box> <Box>
<Flex alignItems={{ base: 'flex-start', lg: 'center' }}> <Flex alignItems={{ base: 'flex-start', lg: 'center' }}>
<Skeleton isLoaded={ !isLoading } display="inline-block" fontWeight={ 600 } mr={ 1 }> <Skeleton loading={ isLoading } display="inline-block" fontWeight={ 600 } mr={ 1 }>
<span>{ apiKey }</span> <span>{ apiKey }</span>
</Skeleton> </Skeleton>
<CopyToClipboard text={ apiKey } isLoading={ isLoading }/> <CopyToClipboard text={ apiKey } isLoading={ isLoading }/>
</Flex> </Flex>
{ name && ( { name && (
<Skeleton isLoaded={ !isLoading } display="inline-block" fontSize="sm" color="text_secondary" mt={ 1 }> <Skeleton loading={ isLoading } display="inline-block" fontSize="sm" color="text_secondary" mt={ 1 }>
<span>{ name }</span> <span>{ name }</span>
</Skeleton> </Skeleton>
) } ) }
......
...@@ -18,15 +18,15 @@ type AdData = { ...@@ -18,15 +18,15 @@ type AdData = {
}; };
}; };
// const MOCK: AdData = { const MOCK: AdData = {
// ad: { ad: {
// url: 'https://unsplash.com/s/photos/cute-kitten', url: 'https://unsplash.com/s/photos/cute-kitten',
// thumbnail: 'https://placekitten.com/40/40', thumbnail: 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/gnosis.svg',
// name: 'All about kitties', name: 'All about kitties',
// description_short: 'To see millions picture of cute kitties', description_short: 'To see millions picture of cute kitties',
// cta_button: 'click here', cta_button: 'click here',
// }, },
// }; };
const CoinzillaTextAd = ({ className }: { className?: string }) => { const CoinzillaTextAd = ({ className }: { className?: string }) => {
const [ adData, setAdData ] = React.useState<AdData | null>(null); const [ adData, setAdData ] = React.useState<AdData | null>(null);
...@@ -44,7 +44,7 @@ const CoinzillaTextAd = ({ className }: { className?: string }) => { ...@@ -44,7 +44,7 @@ const CoinzillaTextAd = ({ className }: { className?: string }) => {
} }
}) })
.finally(() => { .finally(() => {
// setAdData(MOCK); setAdData(MOCK);
setIsLoading(false); setIsLoading(false);
}); });
} }
...@@ -87,7 +87,7 @@ const CoinzillaTextAd = ({ className }: { className?: string }) => { ...@@ -87,7 +87,7 @@ const CoinzillaTextAd = ({ className }: { className?: string }) => {
src={ adData.ad.thumbnail } src={ adData.ad.thumbnail }
width="20px" width="20px"
height="20px" height="20px"
mb="2px" verticalAlign="text-bottom"
mr={ 1 } mr={ 1 }
display="inline-block" display="inline-block"
alt="" alt=""
......
import { chakra, Tooltip, useColorModeValue } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type * as visualizer from '@blockscout/visualizer-types'; import type * as visualizer from '@blockscout/visualizer-types';
...@@ -8,6 +8,7 @@ import type { ResourceError } from 'lib/api/resources'; ...@@ -8,6 +8,7 @@ import type { ResourceError } from 'lib/api/resources';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import throwOnAbsentParamError from 'lib/errors/throwOnAbsentParamError'; import throwOnAbsentParamError from 'lib/errors/throwOnAbsentParamError';
import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError'; import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
import { Tooltip } from 'toolkit/chakra/tooltip';
import ContentLoader from 'ui/shared/ContentLoader'; import ContentLoader from 'ui/shared/ContentLoader';
interface Props { interface Props {
...@@ -53,7 +54,6 @@ const Sol2UmlDiagram = ({ addressHash }: Props) => { ...@@ -53,7 +54,6 @@ const Sol2UmlDiagram = ({ addressHash }: Props) => {
}); });
const imgUrl = `data:image/svg+xml;base64,${ umlQuery.data?.svg }`; const imgUrl = `data:image/svg+xml;base64,${ umlQuery.data?.svg }`;
const imgFilter = useColorModeValue('invert(0)', 'invert(1)');
const handleClick = React.useCallback(() => { const handleClick = React.useCallback(() => {
const image = new Image(); const image = new Image();
...@@ -76,13 +76,13 @@ const Sol2UmlDiagram = ({ addressHash }: Props) => { ...@@ -76,13 +76,13 @@ const Sol2UmlDiagram = ({ addressHash }: Props) => {
} }
return ( return (
<Tooltip label="Click on image to zoom" placement="top"> <Tooltip content="Click on image to zoom" positioning={{ placement: 'top' }}>
<chakra.img <chakra.img
src={ imgUrl } src={ imgUrl }
alt={ `Contract ${ contractQuery.data.name } UML diagram` } alt={ `Contract ${ contractQuery.data.name } UML diagram` }
onClick={ handleClick } onClick={ handleClick }
cursor="pointer" cursor="pointer"
filter={ imgFilter } filter={{ _light: 'invert(0)', _dark: 'invert(1)' }}
/> />
</Tooltip> </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