Commit 03c9e582 authored by tom's avatar tom

contract method form

parent 3a9f3d18
...@@ -22,6 +22,13 @@ const globalCss: SystemConfig['globalCss'] = { ...@@ -22,6 +22,13 @@ const globalCss: SystemConfig['globalCss'] = {
form: { form: {
w: '100%', w: '100%',
}, },
input: {
// hide number input arrows in Google Chrome
'&::-webkit-outer-spin-button, &::-webkit-inner-spin-button': {
WebkitAppearance: 'none',
margin: 0,
},
},
...recaptcha, ...recaptcha,
...scrollbar, ...scrollbar,
...addressEntity, ...addressEntity,
......
...@@ -12,7 +12,7 @@ export const recipe = defineSlotRecipe({ ...@@ -12,7 +12,7 @@ export const recipe = defineSlotRecipe({
display: 'flex', display: 'flex',
width: '100%', width: '100%',
position: 'relative', position: 'relative',
gap: '1.5', gap: '1',
}, },
label: { label: {
display: 'flex', display: 'flex',
...@@ -36,11 +36,11 @@ export const recipe = defineSlotRecipe({ ...@@ -36,11 +36,11 @@ export const recipe = defineSlotRecipe({
fontWeight: 'medium', fontWeight: 'medium',
gap: '1', gap: '1',
color: 'input.fg.error', color: 'input.fg.error',
textStyle: 'xs', textStyle: 'sm',
}, },
helperText: { helperText: {
color: 'fg.muted', color: 'fg.muted',
textStyle: 'xs', textStyle: 'sm',
}, },
}, },
......
...@@ -6,7 +6,7 @@ export const recipe = defineRecipe({ ...@@ -6,7 +6,7 @@ export const recipe = defineRecipe({
minWidth: '0', minWidth: '0',
outline: '0', outline: '0',
position: 'relative', position: 'relative',
appearance: 'none', appearance: 'textfield',
textAlign: 'start', textAlign: 'start',
borderRadius: 'base', borderRadius: 'base',
height: 'var(--input-height)', height: 'var(--input-height)',
...@@ -27,7 +27,7 @@ export const recipe = defineRecipe({ ...@@ -27,7 +27,7 @@ export const recipe = defineRecipe({
variants: { variants: {
size: { size: {
sm: { sm: {
textStyle: 'sm', textStyle: 'md',
px: '2', px: '2',
'--input-height': 'sizes.8', '--input-height': 'sizes.8',
}, },
......
import { Accordion, Box, Flex, Link } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { range } from 'es-toolkit'; import { range } from 'es-toolkit';
import React from 'react'; import React from 'react';
...@@ -7,7 +7,8 @@ import type { SmartContractMethod } from './types'; ...@@ -7,7 +7,8 @@ import type { SmartContractMethod } from './types';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import LinkInternal from 'ui/shared/links/LinkInternal'; import { AccordionRoot } from 'toolkit/chakra/accordion';
import { Link } from 'toolkit/chakra/link';
import ContractAbiItem from './ContractAbiItem'; import ContractAbiItem from './ContractAbiItem';
import useFormSubmit from './useFormSubmit'; import useFormSubmit from './useFormSubmit';
...@@ -22,15 +23,15 @@ interface Props { ...@@ -22,15 +23,15 @@ interface Props {
} }
const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Props) => { const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Props) => {
const [ expandedSections, setExpandedSections ] = React.useState<Array<number>>(abi.length === 1 ? [ 0 ] : []); const [ expandedSections, setExpandedSections ] = React.useState<Array<string>>(abi.length === 1 ? [ '0' ] : []);
const [ id, setId ] = React.useState(0); const [ id, setId ] = React.useState(0);
useScrollToMethod(abi, setExpandedSections); useScrollToMethod(abi, setExpandedSections);
const handleFormSubmit = useFormSubmit({ addressHash }); const handleFormSubmit = useFormSubmit({ addressHash });
const handleAccordionStateChange = React.useCallback((newValue: Array<number>) => { const handleAccordionStateChange = React.useCallback(({ value }: { value: Array<string> }) => {
setExpandedSections(newValue); setExpandedSections(value);
}, []); }, []);
const handleExpandAll = React.useCallback(() => { const handleExpandAll = React.useCallback(() => {
...@@ -39,7 +40,7 @@ const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Pro ...@@ -39,7 +40,7 @@ const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Pro
} }
if (expandedSections.length < abi.length) { if (expandedSections.length < abi.length) {
setExpandedSections(range(0, abi.length)); setExpandedSections(range(0, abi.length).map(String));
} else { } else {
setExpandedSections([]); setExpandedSections([]);
} }
...@@ -62,13 +63,14 @@ const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Pro ...@@ -62,13 +63,14 @@ const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Pro
) } ) }
<Link onClick={ handleReset } ml={ 3 }>Reset</Link> <Link onClick={ handleReset } ml={ 3 }>Reset</Link>
</Flex> </Flex>
<Accordion allowMultiple position="relative" onChange={ handleAccordionStateChange } index={ expandedSections }> <AccordionRoot multiple lazyMount position="relative" onValueChange={ handleAccordionStateChange } value={ expandedSections }>
{ abi.map((item, index) => ( { abi.map((item, index) => (
<ContractAbiItem <ContractAbiItem
key={ index } key={ index }
id={ id } id={ id }
index={ index } index={ index }
data={ item } data={ item }
isOpen={ expandedSections.includes(String(index)) }
isVisible={ !visibleItems || visibleItems.includes(index) } isVisible={ !visibleItems || visibleItems.includes(index) }
addressHash={ addressHash } addressHash={ addressHash }
sourceAddress={ sourceAddress } sourceAddress={ sourceAddress }
...@@ -76,18 +78,18 @@ const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Pro ...@@ -76,18 +78,18 @@ const ContractAbi = ({ abi, addressHash, sourceAddress, tab, visibleItems }: Pro
onSubmit={ handleFormSubmit } onSubmit={ handleFormSubmit }
/> />
)) } )) }
</Accordion> </AccordionRoot>
{ !hasVisibleItems && ( { !hasVisibleItems && (
<div> <div>
<div>Couldn{ apos }t find any method that matches your query.</div> <div>Couldn{ apos }t find any method that matches your query.</div>
<div> <div>
You can use custom ABI for this contract without verifying the contract in the{ ' ' } You can use custom ABI for this contract without verifying the contract in the{ ' ' }
<LinkInternal <Link
href={ route({ pathname: '/address/[hash]', query: { hash: addressHash, tab: 'read_write_custom_methods' } }) } href={ route({ pathname: '/address/[hash]', query: { hash: addressHash, tab: 'read_write_custom_methods' } }) }
scroll={ false } scroll={ false }
> >
Custom ABI Custom ABI
</LinkInternal> </Link>
{ ' ' }tab. { ' ' }tab.
</div> </div>
</div> </div>
......
import { AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, Alert, Box, Tag } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { Element } from 'react-scroll'; import { Element } from 'react-scroll';
...@@ -7,6 +7,9 @@ import type { FormSubmitHandler, SmartContractMethod } from './types'; ...@@ -7,6 +7,9 @@ import type { FormSubmitHandler, SmartContractMethod } from './types';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import { AccordionItem, AccordionItemContent, AccordionItemTrigger } from 'toolkit/chakra/accordion';
import { Alert } from 'toolkit/chakra/alert';
import { Badge } from 'toolkit/chakra/badge';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import Hint from 'ui/shared/Hint'; import Hint from 'ui/shared/Hint';
...@@ -23,9 +26,10 @@ interface Props { ...@@ -23,9 +26,10 @@ interface Props {
tab: string; tab: string;
onSubmit: FormSubmitHandler; onSubmit: FormSubmitHandler;
isVisible?: boolean; isVisible?: boolean;
isOpen: boolean;
} }
const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onSubmit, isVisible = true }: Props) => { const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onSubmit, isVisible = true, isOpen }: Props) => {
const [ attempt, setAttempt ] = React.useState(0); const [ attempt, setAttempt ] = React.useState(0);
const url = React.useMemo(() => { const url = React.useMemo(() => {
...@@ -47,24 +51,27 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS ...@@ -47,24 +51,27 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS
const isRead = isReadMethod(data); const isRead = isReadMethod(data);
return ( return (
<AccordionItem as="section" _first={{ borderTopWidth: 0 }} _last={{ borderBottomWidth: 0 }} display={ isVisible ? 'block' : 'none' }> <AccordionItem
{ ({ isExpanded }) => ( as="section"
<> value={ String(index) }
_first={{ borderTopWidth: 0 }}
_last={{ borderBottomWidth: 0 }}
display={ isVisible ? 'block' : 'none' }
>
<Element as="h2" name={ getElementName(data) }> <Element as="h2" name={ getElementName(data) }>
<AccordionButton <AccordionItemTrigger
px={ 0 } px={ 0 }
py={ 3 } py={ 3 }
_hover={{ bgColor: 'inherit' }} _hover={{ bgColor: 'inherit' }}
wordBreak="break-all" wordBreak="break-all"
textAlign="left" textAlign="left"
as="div"
cursor="pointer" cursor="pointer"
display="flex" display="flex"
alignItems="center" alignItems="center"
columnGap={ 2 } columnGap={ 2 }
> >
<CopyToClipboard text={ url } type="link" ml={ 0 } color="text_secondary"/> <CopyToClipboard text={ url } type="link" ml={ 0 } color="text_secondary" as="div"/>
<Box as="div" fontWeight={ 500 } display="flex" alignItems="center"> <Box fontWeight={ 500 } display="flex" alignItems="center">
{ index + 1 }. { data.type === 'fallback' || data.type === 'receive' ? data.type : data.name } { index + 1 }. { data.type === 'fallback' || data.type === 'receive' ? data.type : data.name }
{ data.type === 'fallback' && ( { data.type === 'fallback' && (
<Hint <Hint
...@@ -74,6 +81,7 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS ...@@ -74,6 +81,7 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS
The fallback function always receives data, but in order to also receive Ether it must be marked payable.` The fallback function always receives data, but in order to also receive Ether it must be marked payable.`
} }
ml={ 1 } ml={ 1 }
as="div"
/> />
) } ) }
{ data.type === 'receive' && ( { data.type === 'receive' && (
...@@ -86,20 +94,20 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS ...@@ -86,20 +94,20 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS
the contract cannot receive Ether through regular transactions and throws an exception.` the contract cannot receive Ether through regular transactions and throws an exception.`
} }
ml={ 1 } ml={ 1 }
as="div"
/> />
) } ) }
</Box> </Box>
<Tag colorScheme={ isRead ? 'black-purple' : 'black-blue' } flexShrink={ 0 }>{ isRead ? 'read' : 'write' }</Tag> <Badge colorPalette={ isRead ? 'purple_alt' : 'blue_alt' } flexShrink={ 0 }>{ isRead ? 'read' : 'write' }</Badge>
{ 'method_id' in data && ( { 'method_id' in data && (
<Tag display="inline-flex" alignItems="center" flexShrink={ 0 }> <Badge display="inline-flex" alignItems="center" flexShrink={ 0 }>
{ data.method_id } { data.method_id }
<CopyToClipboard text={ data.method_id }/> <CopyToClipboard text={ data.method_id } as="div"/>
</Tag> </Badge>
) } ) }
<AccordionIcon transform={ isExpanded ? 'rotate(0deg)' : 'rotate(-90deg)' } color="gray.500"/> </AccordionItemTrigger>
</AccordionButton>
</Element> </Element>
<AccordionPanel pb={ 4 } pr={ 0 } pl="28px" w="calc(100% - 6px)"> <AccordionItemContent pb={ 4 } pr={ 0 } pl="28px" w="calc(100% - 6px)">
{ 'is_invalid' in data && data.is_invalid ? ( { 'is_invalid' in data && data.is_invalid ? (
<Alert status="warning">An error occurred while parsing the method signature.</Alert> <Alert status="warning">An error occurred while parsing the method signature.</Alert>
) : ( ) : (
...@@ -109,12 +117,10 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS ...@@ -109,12 +117,10 @@ const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onS
attempt={ attempt } attempt={ attempt }
onSubmit={ onSubmit } onSubmit={ onSubmit }
onReset={ handleReset } onReset={ handleReset }
isOpen={ isExpanded } isOpen={ isOpen }
/> />
) } ) }
</AccordionPanel> </AccordionItemContent>
</>
) }
</AccordionItem> </AccordionItem>
); );
}; };
......
...@@ -55,7 +55,7 @@ const ContractConnectWallet = ({ isLoading }: Props) => { ...@@ -55,7 +55,7 @@ const ContractConnectWallet = ({ isLoading }: Props) => {
return ( return (
<Skeleton loading={ isLoading }> <Skeleton loading={ isLoading }>
<Alert status={ web3Wallet.address ? 'success' : 'warning' }> <Alert status={ web3Wallet.address ? 'success' : 'warning' } descriptionProps={{ alignItems: 'center' }}>
{ content } { content }
</Alert> </Alert>
</Skeleton> </Skeleton>
......
...@@ -93,9 +93,9 @@ const ContractMethodsCustom = ({ isLoading: isLoadingProp }: Props) => { ...@@ -93,9 +93,9 @@ const ContractMethodsCustom = ({ isLoading: isLoadingProp }: Props) => {
onChange={ filters.onChange } onChange={ filters.onChange }
isLoading={ isLoading } isLoading={ isLoading }
/> />
{ /* <ContractMethodsContainer isLoading={ isLoading } isEmpty={ abi.length === 0 } type={ filters.methodType }> <ContractMethodsContainer isLoading={ isLoading } isEmpty={ abi.length === 0 } type={ filters.methodType }>
<ContractAbi abi={ abi } tab={ tab } addressHash={ addressHash } visibleItems={ filters.visibleItems }/> <ContractAbi abi={ abi } tab={ tab } addressHash={ addressHash } visibleItems={ filters.visibleItems }/>
</ContractMethodsContainer> */ } </ContractMethodsContainer>
</> </>
) : ( ) : (
<> <>
......
...@@ -58,7 +58,7 @@ const ContractMethodsProxy = ({ implementations, isLoading: isInitialLoading }: ...@@ -58,7 +58,7 @@ const ContractMethodsProxy = ({ implementations, isLoading: isInitialLoading }:
isLoading={ isInitialLoading } isLoading={ isInitialLoading }
/> />
</div> </div>
{ /* <ContractMethodsContainer <ContractMethodsContainer
key={ selectedItem.address } key={ selectedItem.address }
isLoading={ isInitialLoading || contractQuery.isPending } isLoading={ isInitialLoading || contractQuery.isPending }
isEmpty={ abi.length === 0 } isEmpty={ abi.length === 0 }
...@@ -72,7 +72,7 @@ const ContractMethodsProxy = ({ implementations, isLoading: isInitialLoading }: ...@@ -72,7 +72,7 @@ const ContractMethodsProxy = ({ implementations, isLoading: isInitialLoading }:
visibleItems={ filters.visibleItems } visibleItems={ filters.visibleItems }
sourceAddress={ selectedItem.address } sourceAddress={ selectedItem.address }
/> />
</ContractMethodsContainer> */ } </ContractMethodsContainer>
</Flex> </Flex>
); );
}; };
......
...@@ -36,9 +36,9 @@ const ContractMethodsRegular = ({ abi, isLoading }: Props) => { ...@@ -36,9 +36,9 @@ const ContractMethodsRegular = ({ abi, isLoading }: Props) => {
onChange={ filters.onChange } onChange={ filters.onChange }
isLoading={ isLoading } isLoading={ isLoading }
/> />
{ /* <ContractMethodsContainer isLoading={ isLoading } isEmpty={ formattedAbi.length === 0 } type={ filters.methodType }> <ContractMethodsContainer isLoading={ isLoading } isEmpty={ formattedAbi.length === 0 } type={ filters.methodType }>
<ContractAbi abi={ formattedAbi } tab={ tab } addressHash={ addressHash } visibleItems={ filters.visibleItems }/> <ContractAbi abi={ formattedAbi } tab={ tab } addressHash={ addressHash } visibleItems={ filters.visibleItems }/>
</ContractMethodsContainer> */ } </ContractMethodsContainer>
</Flex> </Flex>
); );
}; };
......
import { Button, Tooltip } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import useAccount from 'lib/web3/useAccount'; import useAccount from 'lib/web3/useAccount';
import { Button } from 'toolkit/chakra/button';
import { Tooltip } from 'toolkit/chakra/tooltip';
interface Props { interface Props {
onClick: (address: string) => void; onClick: (address: string) => void;
...@@ -16,16 +17,15 @@ const ContractMethodAddressButton = ({ onClick, isDisabled }: Props) => { ...@@ -16,16 +17,15 @@ const ContractMethodAddressButton = ({ onClick, isDisabled }: Props) => {
}, [ address, onClick ]); }, [ address, onClick ]);
return ( return (
<Tooltip label={ !address ? 'Connect your wallet to enter your address.' : undefined }> <Tooltip content={ !address ? 'Connect your wallet to enter your address.' : undefined }>
<Button <Button
variant="subtle" variant="subtle"
colorScheme="gray"
size="xs" size="xs"
fontSize="normal" textStyle="md"
fontWeight={ 500 } fontWeight={ 500 }
ml={ 1 } ml={ 1 }
onClick={ handleClick } onClick={ handleClick }
isDisabled={ isDisabled || !address } disabled={ isDisabled || !address }
> >
Self Self
</Button> </Button>
......
import { IconButton, chakra } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { IconButton } from 'toolkit/chakra/icon-button';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
...@@ -12,19 +13,26 @@ interface Props { ...@@ -12,19 +13,26 @@ interface Props {
} }
const ContractMethodArrayButton = ({ className, type, index, onClick, isDisabled }: Props) => { const ContractMethodArrayButton = ({ className, type, index, onClick, isDisabled }: Props) => {
const handleClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation();
onClick(event);
}, [ onClick ]);
return ( return (
<IconButton <IconButton
as="div"
className={ className } className={ className }
aria-label={ type } aria-label={ type }
data-index={ index } data-index={ index }
variant="outline" variant="outline"
w="20px" boxSize={ 5 }
h="20px"
flexShrink={ 0 } flexShrink={ 0 }
onClick={ onClick } onClick={ handleClick }
icon={ <IconSvg name={ type === 'remove' ? 'minus' : 'plus' } boxSize={ 3 }/> } disabled={ isDisabled }
isDisabled={ isDisabled } >
/> <IconSvg name={ type === 'remove' ? 'minus' : 'plus' } boxSize={ 3 }/>
</IconButton>
); );
}; };
......
import { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, Box, useColorModeValue } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { AccordionItem, AccordionItemContent, AccordionItemTrigger, AccordionRoot } from 'toolkit/chakra/accordion';
import ContractMethodArrayButton from './ContractMethodArrayButton'; import ContractMethodArrayButton from './ContractMethodArrayButton';
export interface Props { export interface Props {
...@@ -14,37 +16,31 @@ export interface Props { ...@@ -14,37 +16,31 @@ export interface Props {
} }
const ContractMethodFieldAccordion = ({ label, level, children, onAddClick, onRemoveClick, index, isInvalid }: Props) => { const ContractMethodFieldAccordion = ({ label, level, children, onAddClick, onRemoveClick, index, isInvalid }: Props) => {
const bgColorLevel0 = useColorModeValue('blackAlpha.50', 'whiteAlpha.50'); const bgColorLevel0 = { _light: 'blackAlpha.50', _dark: 'whiteAlpha.50' };
const bgColor = useColorModeValue('whiteAlpha.700', 'blackAlpha.700'); const bgColor = { _light: 'whiteAlpha.700', _dark: 'blackAlpha.700' };
return ( return (
<Accordion allowToggle w="100%" bgColor={ level === 0 ? bgColorLevel0 : bgColor } borderRadius="base"> <AccordionRoot w="100%" bgColor={ level === 0 ? bgColorLevel0 : bgColor } borderRadius="base" lazyMount>
<AccordionItem _first={{ borderTopWidth: 0 }} _last={{ borderBottomWidth: 0 }}> <AccordionItem value="default" _first={{ borderTopWidth: 0 }} _last={{ borderBottomWidth: 0 }}>
{ ({ isExpanded }) => ( <AccordionItemTrigger
<> indicatorPlacement="start"
<AccordionButton
as="div"
cursor="pointer"
px="6px" px="6px"
py="6px" py="6px"
wordBreak="break-all" wordBreak="break-all"
textAlign="left" textAlign="left"
_hover={{ bgColor: 'inherit' }} _hover={{ bgColor: 'inherit' }}
> >
<AccordionIcon transform={ isExpanded ? 'rotate(0deg)' : 'rotate(-90deg)' } color="gray.500"/> <Box textStyle="sm" fontWeight={ 700 } mr="auto" color={ isInvalid ? 'error' : undefined }>
<Box fontSize="sm" lineHeight={ 5 } fontWeight={ 700 } mr="auto" ml={ 1 } color={ isInvalid ? 'error' : undefined }>
{ label } { label }
</Box> </Box>
{ onRemoveClick && <ContractMethodArrayButton index={ index } onClick={ onRemoveClick } type="remove"/> } { onRemoveClick && index !== undefined && <ContractMethodArrayButton index={ index } onClick={ onRemoveClick } type="remove"/> }
{ onAddClick && <ContractMethodArrayButton index={ index } onClick={ onAddClick } type="add" ml={ 2 }/> } { onAddClick && index !== undefined && <ContractMethodArrayButton index={ index } onClick={ onAddClick } type="add" ml={ 2 }/> }
</AccordionButton> </AccordionItemTrigger>
<AccordionPanel display="flex" flexDir="column" rowGap={ 1 } pl="18px" pr="6px"> <AccordionItemContent display="flex" flexDir="column" rowGap={ 1 } pl="18px" pr="6px">
{ children } { children }
</AccordionPanel> </AccordionItemContent>
</>
) }
</AccordionItem> </AccordionItem>
</Accordion> </AccordionRoot>
); );
}; };
......
import { Box, Button, Flex, FormControl, Input, InputGroup, InputRightElement, chakra, useColorModeValue } from '@chakra-ui/react'; import { Flex, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { useController, useFormContext } from 'react-hook-form'; import { useController, useFormContext } from 'react-hook-form';
import { NumericFormat } from 'react-number-format'; // import { NumericFormat } from 'react-number-format';
import type { ContractAbiItemInput } from '../types'; import type { ContractAbiItemInput } from '../types';
import { HOUR, SECOND } from 'lib/consts'; import { HOUR, SECOND } from 'lib/consts';
import { Button } from 'toolkit/chakra/button';
import { Field } from 'toolkit/chakra/field';
import { Input } from 'toolkit/chakra/input';
import { InputGroup } from 'toolkit/chakra/input-group';
import ClearButton from 'ui/shared/ClearButton'; import ClearButton from 'ui/shared/ClearButton';
import ContractMethodAddressButton from './ContractMethodAddressButton'; import ContractMethodAddressButton from './ContractMethodAddressButton';
...@@ -43,8 +47,8 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi ...@@ -43,8 +47,8 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
const { control, setValue, getValues } = useFormContext(); const { control, setValue, getValues } = useFormContext();
const { field, fieldState } = useController({ control, name, rules: { validate } }); const { field, fieldState } = useController({ control, name, rules: { validate } });
const inputBgColor = useColorModeValue('white', 'black'); const inputBgColor = { _light: 'white', _dark: 'black' };
const nativeCoinRowBgColor = useColorModeValue('gray.100', 'gray.700'); const nativeCoinRowBgColor = { _light: 'gray.100', _dark: 'gray.700' };
const hasMultiplyButton = argTypeMatchInt && Number(argTypeMatchInt.power) >= 64; const hasMultiplyButton = argTypeMatchInt && Number(argTypeMatchInt.power) >= 64;
...@@ -125,70 +129,31 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi ...@@ -125,70 +129,31 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
const error = fieldState.error; const error = fieldState.error;
return ( const inputEndElement = (
<Flex <Flex alignItems="center">
className={ className } { field.value !== undefined && field.value !== '' && <ClearButton onClick={ handleClear } isDisabled={ isDisabled } boxSize={ 6 }/> }
flexDir={{ base: 'column', md: 'row' }}
alignItems="flex-start"
columnGap={ 3 }
w="100%"
bgColor={ isNativeCoin ? nativeCoinRowBgColor : undefined }
borderRadius="base"
px="6px"
py={ isNativeCoin ? 1 : 0 }
>
{ !hideLabel && <ContractMethodFieldLabel data={ data } isOptional={ isOptional } level={ level }/> }
<FormControl isDisabled={ isDisabled }>
<InputGroup size="xs">
<Input
{ ...field }
{ ...(argTypeMatchInt ? {
as: NumericFormat,
thousandSeparator: ' ',
decimalScale: 0,
allowNegative: !argTypeMatchInt.isUnsigned,
getInputRef: (element: HTMLInputElement) => {
ref.current = element;
},
} : {}) }
// as we use mutable ref, we have to cast it to React.LegacyRef<HTMLInputElement> to trick chakra and typescript
ref={ ref as React.LegacyRef<HTMLInputElement> | undefined }
onChange={ handleChange }
onPaste={ handlePaste }
required={ !isOptional }
isInvalid={ Boolean(error) }
placeholder={ data.type }
autoComplete="off"
data-1p-ignore
bgColor={ inputBgColor }
paddingRight={ hasMultiplyButton ? '120px' : '40px' }
/>
<InputRightElement w="auto" right={ 1 } bgColor={ inputBgColor } h="calc(100% - 4px)" top="2px" borderRadius="base">
{ field.value !== undefined && field.value !== '' && <ClearButton onClick={ handleClear } isDisabled={ isDisabled }/> }
{ data.type === 'address' && <ContractMethodAddressButton onClick={ handleAddressButtonClick } isDisabled={ isDisabled }/> } { data.type === 'address' && <ContractMethodAddressButton onClick={ handleAddressButtonClick } isDisabled={ isDisabled }/> }
{ argTypeMatchInt && !isNativeCoin && (hasTimestampButton ? ( { argTypeMatchInt && !isNativeCoin && (hasTimestampButton ? (
<Button <Button
variant="subtle" variant="subtle"
colorScheme="gray"
size="xs" size="xs"
fontSize="normal" textStyle="md"
fontWeight={ 500 } fontWeight={ 500 }
ml={ 1 } ml={ 1 }
onClick={ handleTimestampButtonClick } onClick={ handleTimestampButtonClick }
isDisabled={ isDisabled } disabled={ isDisabled }
> >
Now+1h Now+1h
</Button> </Button>
) : ( ) : (
<Button <Button
variant="subtle" variant="subtle"
colorScheme="gray"
size="xs" size="xs"
fontSize="normal" textStyle="md"
fontWeight={ 500 } fontWeight={ 500 }
ml={ 1 } ml={ 1 }
onClick={ handleMaxIntButtonClick } onClick={ handleMaxIntButtonClick }
isDisabled={ isDisabled } disabled={ isDisabled }
> >
Max Max
</Button> </Button>
...@@ -201,10 +166,53 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi ...@@ -201,10 +166,53 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
onChange={ setIntPower } onChange={ setIntPower }
/> />
) } ) }
</InputRightElement> </Flex>
);
return (
<Flex
className={ className }
flexDir={{ base: 'column', md: 'row' }}
alignItems="flex-start"
columnGap={ 3 }
w="100%"
bgColor={ isNativeCoin ? nativeCoinRowBgColor : undefined }
borderRadius="base"
px="6px"
py={ isNativeCoin ? 1 : 0 }
>
{ !hideLabel && <ContractMethodFieldLabel data={ data } isOptional={ isOptional } level={ level }/> }
<Field invalid={ Boolean(error) } errorText={ error?.message } disabled={ isDisabled }>
<InputGroup
endElement={ inputEndElement }
endElementProps={{ pl: 0, pr: 1 }}
>
<Input
{ ...field }
// TODO @tom2drum fix formatting of numeric input
// { ...(argTypeMatchInt ? {
// as: NumericFormat,
// thousandSeparator: ' ',
// decimalScale: 0,
// allowNegative: !argTypeMatchInt.isUnsigned,
// getInputRef: (element: HTMLInputElement) => {
// ref.current = element;
// },
// } : {}) }
// as we use mutable ref, we have to cast it to React.LegacyRef<HTMLInputElement> to trick chakra and typescript
ref={ ref as React.LegacyRef<HTMLInputElement> | undefined }
size="sm"
onChange={ handleChange }
onPaste={ handlePaste }
required={ !isOptional }
placeholder={ data.type }
autoComplete="off"
data-1p-ignore
bgColor={ inputBgColor }
paddingRight={ hasMultiplyButton ? '120px' : '40px' }
/>
</InputGroup> </InputGroup>
{ error && <Box color="error" fontSize="sm" lineHeight={ 5 } mt={ 1 }>{ error.message }</Box> } </Field>
</FormControl>
</Flex> </Flex>
); );
}; };
......
import { Box, useColorModeValue } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { ContractAbiItemInput } from '../types'; import type { ContractAbiItemInput } from '../types';
...@@ -12,17 +12,14 @@ interface Props { ...@@ -12,17 +12,14 @@ interface Props {
} }
const ContractMethodFieldLabel = ({ data, isOptional, level }: Props) => { const ContractMethodFieldLabel = ({ data, isOptional, level }: Props) => {
const color = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
return ( return (
<Box <Box
w="250px" w="250px"
fontSize="sm" textStyle="sm"
lineHeight={ 5 }
py="6px" py="6px"
flexShrink={ 0 } flexShrink={ 0 }
fontWeight={ 500 } fontWeight={ 500 }
color={ level > 1 ? color : undefined } color={ level > 1 ? { _light: 'blackAlpha.600', _dark: 'whiteAlpha.600' } : undefined }
> >
{ getFieldLabel(data, !isOptional) } { getFieldLabel(data, !isOptional) }
</Box> </Box>
......
import { Box, Button, Flex, Tooltip, chakra, useDisclosure } from '@chakra-ui/react'; import { Box, Flex, chakra } 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';
...@@ -9,6 +9,9 @@ import type { FormSubmitHandler, FormSubmitResult, MethodCallStrategy, SmartCont ...@@ -9,6 +9,9 @@ import type { FormSubmitHandler, FormSubmitResult, MethodCallStrategy, SmartCont
import config from 'configs/app'; import config from 'configs/app';
import { SECOND } from 'lib/consts'; import { SECOND } from 'lib/consts';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import { Button } from 'toolkit/chakra/button';
import { Tooltip } from 'toolkit/chakra/tooltip';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import { isReadMethod } from '../utils'; import { isReadMethod } from '../utils';
...@@ -139,10 +142,10 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props) ...@@ -139,10 +142,10 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props)
const buttonCallStrategy = methodType === 'write' ? 'write' : 'read'; const buttonCallStrategy = methodType === 'write' ? 'write' : 'read';
return ( return (
<Tooltip label={ isDisabled ? NO_WALLET_CLIENT_TEXT : undefined } maxW="300px"> <Tooltip content={ NO_WALLET_CLIENT_TEXT } disabled={ !isDisabled }>
<Button <Button
isLoading={ callStrategy === buttonCallStrategy && isLoading } loading={ callStrategy === buttonCallStrategy && isLoading }
isDisabled={ isLoading || isDisabled } disabled={ isLoading || isDisabled }
onClick={ handleButtonClick } onClick={ handleButtonClick }
loadingText={ text } loadingText={ text }
variant="outline" variant="outline"
...@@ -174,8 +177,8 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props) ...@@ -174,8 +177,8 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props)
return ( return (
<Button <Button
isLoading={ callStrategy === buttonCallStrategy && isLoading } loading={ callStrategy === buttonCallStrategy && isLoading }
isDisabled={ isLoading } disabled={ isLoading }
onClick={ handleButtonClick } onClick={ handleButtonClick }
loadingText={ text } loadingText={ text }
variant="outline" variant="outline"
...@@ -183,7 +186,6 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props) ...@@ -183,7 +186,6 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props)
flexShrink={ 0 } flexShrink={ 0 }
width="min-content" width="min-content"
px={ 4 } px={ 4 }
mr={ 3 }
type="submit" type="submit"
data-call-strategy={ buttonCallStrategy } data-call-strategy={ buttonCallStrategy }
> >
...@@ -210,15 +212,14 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props) ...@@ -210,15 +212,14 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props)
return ( return (
<Tooltip <Tooltip
isDisabled={ isDisabled } disabled={ isDisabled }
label="Copied" content="Copied"
closeDelay={ SECOND } closeDelay={ SECOND }
isOpen={ calldataButtonTooltip.isOpen } open={ calldataButtonTooltip.open }
onClose={ calldataButtonTooltip.onClose }
> >
<Button <Button
isLoading={ callStrategy === buttonCallStrategy && isLoading } loading={ callStrategy === buttonCallStrategy && isLoading }
isDisabled={ isDisabled } disabled={ isDisabled }
onClick={ handleButtonClick } onClick={ handleButtonClick }
loadingText={ text } loadingText={ text }
variant="outline" variant="outline"
...@@ -226,7 +227,6 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props) ...@@ -226,7 +227,6 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props)
flexShrink={ 0 } flexShrink={ 0 }
width="min-content" width="min-content"
px={ 4 } px={ 4 }
ml={ 3 }
type="submit" type="submit"
data-call-strategy={ buttonCallStrategy } data-call-strategy={ buttonCallStrategy }
> >
...@@ -282,21 +282,22 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props) ...@@ -282,21 +282,22 @@ const ContractMethodForm = ({ data, attempt, onSubmit, onReset, isOpen }: Props)
return <ContractMethodFieldInput key={ index } { ...props } path={ `${ index }` }/>; return <ContractMethodFieldInput key={ index } { ...props } path={ `${ index }` }/>;
}) } }) }
</Flex> </Flex>
<Flex flexDir="row" gap={ 3 }>
{ secondaryButton } { secondaryButton }
{ primaryButton } { primaryButton }
{ copyCallDataButton } { copyCallDataButton }
{ result && !isLoading && ( { result && !isLoading && (
<Button <Button
variant="simple" variant="link"
colorScheme="blue"
size="sm" size="sm"
onClick={ onReset } onClick={ onReset }
ml={ 1 } gap={ 1 }
> >
<IconSvg name="repeat" boxSize={ 5 } mr={ 1 }/> <IconSvg name="repeat" boxSize={ 5 }/>
Reset Reset
</Button> </Button>
) } ) }
</Flex>
</chakra.form> </chakra.form>
</FormProvider> </FormProvider>
{ result && result.source === 'wallet_client' && ( { result && result.source === 'wallet_client' && (
......
import { import { chakra, List, Input, ListItem } from '@chakra-ui/react';
chakra,
PopoverBody,
PopoverContent,
PopoverTrigger,
Portal,
Button,
List,
ListItem,
useDisclosure,
Input,
useColorModeValue,
} from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { times } from 'lib/html-entities'; import { times } from 'lib/html-entities';
import Popover from 'ui/shared/chakra/Popover'; import { Button } from 'toolkit/chakra/button';
import { IconButton } from 'toolkit/chakra/icon-button';
import { PopoverBody, PopoverContent, PopoverRoot, PopoverTrigger } from 'toolkit/chakra/popover';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
...@@ -27,19 +18,17 @@ interface Props { ...@@ -27,19 +18,17 @@ interface Props {
const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onChange }: Props) => { const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onChange }: Props) => {
const [ selectedOption, setSelectedOption ] = React.useState<number | undefined>(initialValue); const [ selectedOption, setSelectedOption ] = React.useState<number | undefined>(initialValue);
const [ customValue, setCustomValue ] = React.useState<number>(); const [ customValue, setCustomValue ] = React.useState<number>();
const { isOpen, onToggle, onClose } = useDisclosure(); const { open, onOpenChange } = useDisclosure();
const dividerColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
const handleOptionClick = React.useCallback((event: React.MouseEvent) => { const handleOptionClick = React.useCallback((event: React.MouseEvent) => {
const id = Number((event.currentTarget as HTMLDivElement).getAttribute('data-id')); const id = Number((event.currentTarget as HTMLDivElement).getAttribute('data-id'));
if (!Object.is(id, NaN)) { if (!Object.is(id, NaN)) {
setSelectedOption((prev) => prev === id ? undefined : id); setSelectedOption((prev) => prev === id ? undefined : id);
setCustomValue(undefined); setCustomValue(undefined);
onClose(); onOpenChange({ open: false });
onChange(id); onChange(id);
} }
}, [ onClose, onChange ]); }, [ onOpenChange, onChange ]);
const handleInputChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => { const handleInputChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(event.target.value); const value = Number(event.target.value);
...@@ -59,55 +48,50 @@ const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onCha ...@@ -59,55 +48,50 @@ const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onCha
{ Boolean(value) && ( { Boolean(value) && (
<Button <Button
px={ 1 } px={ 1 }
lineHeight={ 6 } textStyle="md"
h={ 6 } size="xs"
fontWeight={ 500 } fontWeight={ 500 }
ml={ 1 } ml={ 1 }
variant="subtle" variant="subtle"
colorScheme="gray"
display="inline" display="inline"
onClick={ handleButtonClick } onClick={ handleButtonClick }
isDisabled={ isDisabled } disabled={ isDisabled }
borderBottomRightRadius={ 0 } borderBottomRightRadius={ 0 }
borderTopRightRadius={ 0 } borderTopRightRadius={ 0 }
> >
{ times } { times }
<chakra.span>10</chakra.span> <chakra.span>10</chakra.span>
<chakra.span fontSize="xs" lineHeight={ 4 } verticalAlign="super">{ value }</chakra.span> <chakra.span fontSize="xs" lineHeight="16px" verticalAlign="super">{ value }</chakra.span>
</Button> </Button>
) } ) }
<Popover placement="bottom-end" isLazy isOpen={ isOpen } onClose={ onClose }> <PopoverRoot open={ open } onOpenChange={ onOpenChange } positioning={{ placement: 'bottom-end' }}>
<PopoverTrigger> <PopoverTrigger>
<Button <IconButton
variant="subtle" variant="subtle"
colorScheme="gray"
size="xs" size="xs"
cursor="pointer" cursor="pointer"
p={ 0 } p={ 0 }
onClick={ onToggle } disabled={ isDisabled }
isActive={ isOpen }
isDisabled={ isDisabled }
borderBottomLeftRadius={ 0 } borderBottomLeftRadius={ 0 }
borderTopLeftRadius={ 0 } borderTopLeftRadius={ 0 }
borderLeftWidth="1px" borderLeftWidth="1px"
borderLeftColor={ dividerColor } borderLeftColor="border.divider"
> >
<IconSvg <IconSvg
name="arrows/east-mini" name="arrows/east-mini"
transitionDuration="fast" transitionDuration="fast"
transitionProperty="transform" transitionProperty="transform"
transitionTimingFunction="ease-in-out" transitionTimingFunction="ease-in-out"
transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transform={ open ? 'rotate(90deg)' : 'rotate(-90deg)' }
boxSize={ 6 } boxSize={ 6 }
/> />
</Button> </IconButton>
</PopoverTrigger> </PopoverTrigger>
<Portal>
<PopoverContent w="110px"> <PopoverContent w="110px">
<PopoverBody py={ 2 }> <PopoverBody textStyle="md" py={ 2 }>
<List> <List.Root>
{ [ 8, 12, 16, 18, 20 ].map((id) => ( { [ 8, 12, 16, 18, 20 ].map((id) => (
<ListItem <List.Item
key={ id } key={ id }
py={ 2 } py={ 2 }
data-id={ id } data-id={ id }
...@@ -119,7 +103,7 @@ const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onCha ...@@ -119,7 +103,7 @@ const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onCha
> >
<span>10*{ id }</span> <span>10*{ id }</span>
{ selectedOption === id && <IconSvg name="check" boxSize={ 6 } color="blue.600"/> } { selectedOption === id && <IconSvg name="check" boxSize={ 6 } color="blue.600"/> }
</ListItem> </List.Item>
)) } )) }
<ListItem <ListItem
py={ 2 } py={ 2 }
...@@ -133,16 +117,15 @@ const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onCha ...@@ -133,16 +117,15 @@ const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onCha
min={ 0 } min={ 0 }
max={ 100 } max={ 100 }
ml={ 3 } ml={ 3 }
size="xs" size="sm"
onChange={ handleInputChange } onChange={ handleInputChange }
value={ customValue || '' } value={ customValue || '' }
/> />
</ListItem> </ListItem>
</List> </List.Root>
</PopoverBody> </PopoverBody>
</PopoverContent> </PopoverContent>
</Portal> </PopoverRoot>
</Popover>
</> </>
); );
}; };
......
import { Alert, Flex, useColorModeValue } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { AbiFunction } from 'viem'; import type { AbiFunction } from 'viem';
import type { FormSubmitResultPublicClient, ResultViewMode } from '../types'; import type { FormSubmitResultPublicClient, ResultViewMode } from '../types';
import { Alert } from 'toolkit/chakra/alert';
import ResultItem from './resultPublicClient/Item'; import ResultItem from './resultPublicClient/Item';
export interface Props { export interface Props {
...@@ -14,8 +16,6 @@ export interface Props { ...@@ -14,8 +16,6 @@ export interface Props {
} }
const ContractMethodResultPublicClient = ({ data, abiItem, onSettle, mode: modeProps }: Props) => { const ContractMethodResultPublicClient = ({ data, abiItem, onSettle, mode: modeProps }: Props) => {
const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
React.useEffect(() => { React.useEffect(() => {
if (modeProps === 'result') { if (modeProps === 'result') {
onSettle(); onSettle();
...@@ -32,7 +32,7 @@ const ContractMethodResultPublicClient = ({ data, abiItem, onSettle, mode: modeP ...@@ -32,7 +32,7 @@ const ContractMethodResultPublicClient = ({ data, abiItem, onSettle, mode: modeP
return ( return (
<> <>
{ isError && ( { isError && (
<Alert status="error" mt={ 3 } p={ 4 } borderRadius="md" fontSize="sm" wordBreak="break-word" whiteSpace="pre-wrap"> <Alert status="error" mt={ 3 } p={ 4 } borderRadius="md" textStyle="sm" wordBreak="break-word" whiteSpace="pre-wrap">
{ 'shortMessage' in data && typeof data.shortMessage === 'string' ? data.shortMessage : data.message } { 'shortMessage' in data && typeof data.shortMessage === 'string' ? data.shortMessage : data.message }
</Alert> </Alert>
) } ) }
...@@ -42,7 +42,7 @@ const ContractMethodResultPublicClient = ({ data, abiItem, onSettle, mode: modeP ...@@ -42,7 +42,7 @@ const ContractMethodResultPublicClient = ({ data, abiItem, onSettle, mode: modeP
mt={ 3 } mt={ 3 }
p={ 4 } p={ 4 }
borderRadius="md" borderRadius="md"
bgColor={ bgColor } bgColor={{ _light: 'blackAlpha.50', _dark: 'whiteAlpha.50' }}
color={ mode === 'preview' ? 'gray.500' : undefined } color={ mode === 'preview' ? 'gray.500' : undefined }
fontSize="sm" fontSize="sm"
lineHeight="20px" lineHeight="20px"
......
import { chakra, Spinner, Box, Alert } from '@chakra-ui/react'; import { chakra, Spinner, Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { UseWaitForTransactionReceiptReturnType } from 'wagmi'; import type { UseWaitForTransactionReceiptReturnType } from 'wagmi';
import { useWaitForTransactionReceipt } from 'wagmi'; import { useWaitForTransactionReceipt } from 'wagmi';
...@@ -7,7 +7,8 @@ import type { FormSubmitResultWalletClient } from '../types'; ...@@ -7,7 +7,8 @@ import type { FormSubmitResultWalletClient } from '../types';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import LinkInternal from 'ui/shared/links/LinkInternal'; import { Alert } from 'toolkit/chakra/alert';
import { Link } from 'toolkit/chakra/link';
interface Props { interface Props {
data: FormSubmitResultWalletClient['data']; data: FormSubmitResultWalletClient['data'];
...@@ -45,13 +46,13 @@ export const ContractMethodResultWalletClientDumb = ({ data, onSettle, txInfo }: ...@@ -45,13 +46,13 @@ export const ContractMethodResultWalletClientDumb = ({ data, onSettle, txInfo }:
const isErrorResult = 'message' in data; const isErrorResult = 'message' in data;
const txLink = txHash ? ( const txLink = txHash ? (
<LinkInternal href={ route({ pathname: '/tx/[hash]', query: { hash: txHash } }) }>View transaction details</LinkInternal> <Link href={ route({ pathname: '/tx/[hash]', query: { hash: txHash } }) }>View transaction details</Link>
) : null; ) : null;
const content = (() => { const content = (() => {
if (isErrorResult) { if (isErrorResult) {
return ( return (
<Alert status="error"> <Alert status="error" textStyle="sm">
{ data.message } { data.message }
</Alert> </Alert>
); );
...@@ -81,7 +82,7 @@ export const ContractMethodResultWalletClientDumb = ({ data, onSettle, txInfo }: ...@@ -81,7 +82,7 @@ export const ContractMethodResultWalletClientDumb = ({ data, onSettle, txInfo }:
case 'error': { case 'error': {
return ( return (
<Alert status="error" flexDir="column" alignItems="flex-start" rowGap={ 1 }> <Alert status="error" textStyle="sm" descriptionProps={{ flexDir: 'column', alignItems: 'flex-start', rowGap: 1 }}>
Error: { txInfo.error ? txInfo.error.message : 'Something went wrong' } { txLink } Error: { txInfo.error ? txInfo.error.message : 'Something went wrong' } { txLink }
</Alert> </Alert>
); );
...@@ -91,7 +92,7 @@ export const ContractMethodResultWalletClientDumb = ({ data, onSettle, txInfo }: ...@@ -91,7 +92,7 @@ export const ContractMethodResultWalletClientDumb = ({ data, onSettle, txInfo }:
return ( return (
<Box <Box
fontSize="sm" textStyle="sm"
mt={ 3 } mt={ 3 }
alignItems="center" alignItems="center"
whiteSpace="pre-wrap" whiteSpace="pre-wrap"
......
import { Tooltip } from '@chakra-ui/react';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import React from 'react'; import React from 'react';
import type { AbiParameter } from 'viem'; import type { AbiParameter } from 'viem';
...@@ -6,8 +5,9 @@ import type { AbiParameter } from 'viem'; ...@@ -6,8 +5,9 @@ import type { AbiParameter } from 'viem';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import { WEI } from 'lib/consts'; import { WEI } from 'lib/consts';
import { Link } from 'toolkit/chakra/link';
import { Tooltip } from 'toolkit/chakra/tooltip';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { matchInt } from '../utils'; import { matchInt } from '../utils';
import ItemLabel from './ItemLabel'; import ItemLabel from './ItemLabel';
...@@ -44,8 +44,8 @@ const ItemPrimitive = ({ abiParameter, data, level, hideLabel }: Props) => { ...@@ -44,8 +44,8 @@ const ItemPrimitive = ({ abiParameter, data, level, hideLabel }: Props) => {
if (abiParameter.type === 'address' && typeof data === 'string') { if (abiParameter.type === 'address' && typeof data === 'string') {
return ( return (
<> <>
<LinkInternal href={ route({ pathname: '/address/[hash]', query: { hash: data } }) }>{ data }</LinkInternal> <Link href={ route({ pathname: '/address/[hash]', query: { hash: data } }) }>{ data }</Link>
<CopyToClipboard text={ data } size={ 4 } verticalAlign="sub"/> <CopyToClipboard text={ data } boxSize={ 4 } verticalAlign="sub"/>
</> </>
); );
} }
...@@ -54,7 +54,7 @@ const ItemPrimitive = ({ abiParameter, data, level, hideLabel }: Props) => { ...@@ -54,7 +54,7 @@ const ItemPrimitive = ({ abiParameter, data, level, hideLabel }: Props) => {
if (intMatch && typeof data === 'bigint' && intMatch.max > INT_TOOLTIP_THRESHOLD && data > INT_TOOLTIP_THRESHOLD) { if (intMatch && typeof data === 'bigint' && intMatch.max > INT_TOOLTIP_THRESHOLD && data > INT_TOOLTIP_THRESHOLD) {
const dividedValue = BigNumber(data.toString()).div(WEI); const dividedValue = BigNumber(data.toString()).div(WEI);
return ( return (
<Tooltip label={ dividedValue.toLocaleString() + ' ETH' }> <Tooltip content={ dividedValue.toLocaleString() + ' ETH' }>
<span>{ castValueToString(data) }</span> <span>{ castValueToString(data) }</span>
</Tooltip> </Tooltip>
); );
......
...@@ -16,7 +16,7 @@ interface Props { ...@@ -16,7 +16,7 @@ interface Props {
const ItemTuple = ({ abiParameter, data, mode, level }: Props) => { const ItemTuple = ({ abiParameter, data, mode, level }: Props) => {
return ( return (
<div> <p>
<p> <p>
<span>{ printRowOffset(level) }</span> <span>{ printRowOffset(level) }</span>
<chakra.span fontWeight={ 500 }>{ abiParameter.name || abiParameter.internalType }</chakra.span> <chakra.span fontWeight={ 500 }>{ abiParameter.name || abiParameter.internalType }</chakra.span>
...@@ -48,7 +48,7 @@ const ItemTuple = ({ abiParameter, data, mode, level }: Props) => { ...@@ -48,7 +48,7 @@ const ItemTuple = ({ abiParameter, data, mode, level }: Props) => {
); );
}) } }) }
<p>{ printRowOffset(level) }{ '}' }</p> <p>{ printRowOffset(level) }{ '}' }</p>
</div> </p>
); );
}; };
......
...@@ -19,7 +19,7 @@ export const getElementName = (data: SmartContractMethod) => { ...@@ -19,7 +19,7 @@ export const getElementName = (data: SmartContractMethod) => {
return `method_${ getElementId(data) }`; return `method_${ getElementId(data) }`;
}; };
export default function useScrollToMethod(data: Array<SmartContractMethod>, onScroll: (indices: Array<number>) => void) { export default function useScrollToMethod(data: Array<SmartContractMethod>, onScroll: (indices: Array<string>) => void) {
React.useEffect(() => { React.useEffect(() => {
const hash = window.location.hash.replace('#', ''); const hash = window.location.hash.replace('#', '');
...@@ -34,7 +34,7 @@ export default function useScrollToMethod(data: Array<SmartContractMethod>, onSc ...@@ -34,7 +34,7 @@ export default function useScrollToMethod(data: Array<SmartContractMethod>, onSc
smooth: true, smooth: true,
offset: -100, offset: -100,
}); });
onScroll([ index ]); onScroll([ String(index) ]);
} }
}, [ data, onScroll ]); }, [ data, onScroll ]);
} }
...@@ -11,9 +11,10 @@ interface Props { ...@@ -11,9 +11,10 @@ interface Props {
className?: string; className?: string;
tooltipProps?: Partial<TooltipProps>; tooltipProps?: Partial<TooltipProps>;
isLoading?: boolean; isLoading?: boolean;
as?: React.ElementType;
} }
const Hint = ({ label, className, tooltipProps, isLoading }: Props) => { const Hint = ({ label, className, tooltipProps, isLoading, as }: Props) => {
return ( return (
<Tooltip <Tooltip
content={ label } content={ label }
...@@ -27,6 +28,7 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => { ...@@ -27,6 +28,7 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => {
className={ className } className={ className }
loading={ isLoading } loading={ isLoading }
borderRadius="sm" borderRadius="sm"
as={ as }
> >
<IconSvg name="info" w="100%" h="100%" color="icon_info" _hover={{ color: 'link.primary.hover' }}/> <IconSvg name="info" w="100%" h="100%" color="icon_info" _hover={{ color: 'link.primary.hover' }}/>
</IconButton> </IconButton>
......
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