Commit 69ca5430 authored by tom's avatar tom

fix more ts errors

parent 49a53378
......@@ -2,12 +2,12 @@ import { usePathname } from 'next/navigation';
import { useRouter } from 'next/router';
import React from 'react';
import type { ColorMode } from 'toolkit/chakra/color-mode';
import { useColorMode } from 'toolkit/chakra/color-mode';
import config from 'configs/app';
import * as cookies from 'lib/cookies';
import getQueryParamString from 'lib/router/getQueryParamString';
import { COLOR_THEMES } from 'lib/settings/colorTheme';
import { useColorMode } from 'toolkit/chakra/color-mode';
import type { ColorMode } from 'toolkit/chakra/color-mode';
import getPageType from './getPageType';
import getTabName from './getTabName';
......
......@@ -56,7 +56,7 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
React.useEffect(() => {
setMounted(true);
}, []);
useLoadFeatures(pageProps.uuid);
useNotifyOnNavigation();
......
......@@ -35,6 +35,8 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
...rest
} = props;
const [ isOpen, setIsOpen ] = React.useState(true);
const defaultIcon = <IconSvg name="info_filled" w="100%" h="100%"/>;
const iconElement = (() => {
......@@ -49,6 +51,15 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
return <ChakraAlert.Indicator>{ icon || defaultIcon }</ChakraAlert.Indicator>;
})();
const handleClose = React.useCallback(() => {
setIsOpen(false);
onClose?.();
}, [ onClose ]);
if (closable && !isOpen) {
return null;
}
return (
<Skeleton loading={ loading } asChild>
<ChakraAlert.Root ref={ ref } { ...rest }>
......@@ -67,7 +78,7 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
pos="relative"
size="sm"
alignSelf="flex-start"
onClick={ onClose }
onClick={ handleClose }
/>
) }
</ChakraAlert.Root>
......
......@@ -32,7 +32,7 @@ export interface CheckboxGroupProps extends HTMLChakraProps<'div', ArkCheckbox.G
export const CheckboxGroup = React.forwardRef<HTMLDivElement, CheckboxGroupProps>(
function CheckboxGroup(props, ref) {
const { children, orientation = 'horizontal', ...rest } = props;
const { children, orientation = 'vertical', ...rest } = props;
return (
<ChakraCheckboxGroup
ref={ ref }
......
......@@ -51,6 +51,14 @@ export interface SkeletonProps extends Omit<ChakraSkeletonProps, 'loading'> {
export const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
function Skeleton(props, ref) {
const { loading = false, ...rest } = props;
return <ChakraSkeleton loading={ loading } { ...(loading ? { 'data-loading': true } : {}) } { ...rest } ref={ ref }/>;
return (
<ChakraSkeleton
loading={ loading }
css={ !loading ? { animation: 'none' } : {} }
{ ...(loading ? { 'data-loading': true } : {}) }
{ ...rest }
ref={ ref }
/>
);
},
);
// eslint-disable-next-line no-restricted-imports
/* eslint-disable no-restricted-imports */
import type { UseDisclosureProps } from '@chakra-ui/react';
import { useDisclosure as useDisclosureChakra } from '@chakra-ui/react';
import React from 'react';
export function useDisclosure() {
const { open, onOpen, onClose, onToggle } = useDisclosureChakra();
export function useDisclosure(props?: UseDisclosureProps) {
const { open, onOpen, onClose, onToggle } = useDisclosureChakra(props);
const onOpenChange = React.useCallback(({ open }: { open: boolean }) => {
if (open) {
......@@ -13,11 +14,11 @@ export function useDisclosure() {
}
}, [ onOpen, onClose ]);
return {
return React.useMemo(() => ({
open,
onOpenChange,
onClose,
onOpen,
onToggle,
};
}), [ open, onOpenChange, onClose, onOpen, onToggle ]);
}
......@@ -68,6 +68,6 @@ export const recipe = defineSlotRecipe({
defaultVariants: {
size: 'md',
variant: 'solid',
orientation: 'horizontal',
orientation: 'vertical',
},
});
......@@ -111,7 +111,6 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
</VStack>
<Button
type="submit"
size="lg"
mt={ 8 }
loading={ formState.isSubmitting }
loadingText="Send request"
......
......@@ -114,7 +114,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) =
mt={ 8 }
/>
<Flex alignItems={{ base: 'flex-start', lg: 'center' }} mt={ 8 } columnGap={ 5 } rowGap={ 2 } flexDir={{ base: 'column', lg: 'row' }}>
<Button size="lg" type="submit" loading={ formState.isSubmitting } loadingText="Continue" flexShrink={ 0 }>
<Button type="submit" loading={ formState.isSubmitting } loadingText="Continue" flexShrink={ 0 }>
Continue
</Button>
<AdminSupportText/>
......
......@@ -123,7 +123,6 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
if (signMethod === 'manual') {
return (
<Button
size="lg"
onClick={ handleManualSignClick }
loading={ formState.isSubmitting }
loadingText="Verifying"
......@@ -135,7 +134,6 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
return (
<Button
size="lg"
onClick={ isConnected ? handleWeb3SignClick : handleOpenWeb3Modal }
loading={ formState.isSubmitting || isSigning }
loadingText={ isSigning ? 'Signing' : 'Verifying' }
......
......@@ -21,11 +21,11 @@ const AddressVerificationStepSuccess = ({ onAddTokenInfoClick, onShowListClick,
</Alert>
<p>You may now submit the “Add token information” request</p>
<Flex alignItems="center" mt={ 8 } columnGap={ 5 } flexWrap="wrap" rowGap={ 5 }>
<Button size="lg" variant={ isToken ? 'outline' : 'solid' } onClick={ onShowListClick }>
<Button variant={ isToken ? 'outline' : 'solid' } onClick={ onShowListClick }>
View my verified addresses
</Button>
{ isToken && (
<Button size="lg" onClick={ onAddTokenInfoClick }>
<Button onClick={ onAddTokenInfoClick }>
Add token information
</Button>
) }
......
......@@ -39,7 +39,7 @@ const TypeFilter = ({ value = [ RESET_VALUE ], handleFilterChange }: Props) => {
const onReset = React.useCallback(() => setCurrentValue([ RESET_VALUE ]), []);
const onFilter = React.useCallback(() => {
const value: Array<AdvancedFilterType> = currentValue.filter(item => item !== RESET_VALUE);
const value: Array<AdvancedFilterType> = currentValue.filter(item => item !== RESET_VALUE) as Array<AdvancedFilterType>;
handleFilterChange(FILTER_PARAM, value);
}, [ handleFilterChange, currentValue ]);
......
......@@ -113,7 +113,6 @@ const ApiKeyForm: React.FC<Props> = ({ data, onOpenChange, setAlertVisible }) =>
/>
<Box marginTop={ 8 }>
<Button
size="lg"
type="submit"
disabled={ !formApi.formState.isDirty }
loading={ isPending }
......
......@@ -10,7 +10,6 @@ import { WEI, ZERO_ADDRESS } from 'lib/consts';
import { Link } from 'toolkit/chakra/link';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TokenEntity from 'ui/shared/entities/token/TokenEntity';
import IconSvg from 'ui/shared/IconSvg';
......
......@@ -9,7 +9,6 @@ import { space } from 'lib/html-entities';
import { currencyUnits } from 'lib/units';
import { Tooltip } from 'toolkit/chakra/tooltip';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import IconSvg from 'ui/shared/IconSvg';
import Utilization from 'ui/shared/Utilization/Utilization';
......
import { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, Divider, Grid, GridItem, useColorModeValue } from '@chakra-ui/react';
import { Separator, Grid, GridItem } from '@chakra-ui/react';
import React from 'react';
import type { ZilliqaNestedQuorumCertificate, ZilliqaQuorumCertificate } from 'types/api/block';
import { apos, ndash } from 'lib/html-entities';
import { AccordionRoot, AccordionItem, AccordionItemTrigger, AccordionItemContent } from 'toolkit/chakra/accordion';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import Hint from 'ui/shared/Hint';
function formatSigners(signers: Array<number>) {
......@@ -20,8 +20,6 @@ interface Props {
}
const BlockDetailsZilliqaQuorumCertificate = ({ data }: Props) => {
const nestedBlockBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const hint = (isNested?: boolean) => (
<>
The iteration of the consensus round in which the block was proposed:<br/><br/>
......@@ -46,8 +44,7 @@ const BlockDetailsZilliqaQuorumCertificate = ({ data }: Props) => {
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue rowGap={ 0 }>
<Grid
fontSize="sm"
lineHeight={ 5 }
textStyle="sm"
gridTemplateColumns="min-content 1fr"
columnGap={ 5 }
>
......@@ -61,66 +58,56 @@ const BlockDetailsZilliqaQuorumCertificate = ({ data }: Props) => {
</GridItem>
<DetailedInfo.ItemDivider my={{ base: 2, lg: 2 }} colSpan={ 2 }/>
<GridItem fontWeight={ 600 }>Signers</GridItem>
<GridItem >{ formatSigners(data.signers) }</GridItem>
<GridItem whiteSpace="pre-wrap">{ formatSigners(data.signers) }</GridItem>
</Grid>
{ data.nested_quorum_certificates && data.nested_quorum_certificates.length > 0 && (
<>
<Divider my={ 2 }/>
<Accordion
allowToggle
<Separator my={ 2 }/>
<AccordionRoot
multiple
w="100%"
fontSize="sm"
lineHeight={ 5 }
textStyle="sm"
>
<AccordionItem borderWidth={ 0 } _last={{ borderBottomWidth: 0 }}>
{ ({ isExpanded }) => (
<>
<AccordionButton
fontSize="sm"
lineHeight={ 5 }
fontWeight={ 600 }
display="flex"
alignItems="center"
columnGap={ 1 }
px={ 0 }
pt={ 0 }
pb={ 2 }
_hover={{ bgColor: 'inherit' }}
<AccordionItem
value="nested-quorum-certificates"
borderWidth={ 0 }
_last={{ borderBottomWidth: 0 }}
>
<AccordionItemTrigger
textStyle="sm"
fontWeight={ 600 }
>
<span>Nested quorum certificates</span>
<Hint label={ hint(true) }/>
</AccordionItemTrigger>
<AccordionItemContent display="flex" flexDirection="column" rowGap={ 2 } p={ 0 }>
{ data.nested_quorum_certificates?.map((item, index) => (
<Grid
key={ index }
gridTemplateColumns="90px 1fr"
columnGap={ 3 }
rowGap={ 2 }
bgColor={{ _light: 'blackAlpha.50', _dark: 'whiteAlpha.50' }}
p={ 4 }
borderRadius="md"
_first={{ borderTopRightRadius: 0, borderTopLeftRadius: 0 }}
>
<span>Nested quorum certificates</span>
<Hint label={ hint(true) }/>
<AccordionIcon flexShrink={ 0 } boxSize={ 5 } transform={ isExpanded ? 'rotate(0deg)' : 'rotate(-90deg)' } color="gray.500"/>
</AccordionButton>
<AccordionPanel display="flex" flexDirection="column" rowGap={ 2 } p={ 0 }>
{ data.nested_quorum_certificates?.map((item, index) => (
<Grid
key={ index }
gridTemplateColumns="90px 1fr"
columnGap={ 3 }
rowGap={ 2 }
bgColor={ nestedBlockBgColor }
p={ 4 }
borderRadius="md"
_first={{ borderTopRightRadius: 0, borderTopLeftRadius: 0 }}
>
<GridItem>View</GridItem>
<GridItem>{ item.view }</GridItem>
<GridItem>Signature</GridItem>
<GridItem whiteSpace="pre-wrap" wordBreak="break-word" display="flex" alignItems="flex-start" columnGap={ 3 }>
{ item.signature }
<CopyToClipboard text={ item.signature }/>
</GridItem>
<GridItem>Signers</GridItem>
<GridItem >{ formatSigners(item.signers) }</GridItem>
<GridItem whiteSpace="pre-wrap">Proposed by validator</GridItem>
<GridItem >{ item.proposed_by_validator_index }</GridItem>
</Grid>
)) }
</AccordionPanel>
</>
) }
<GridItem>View</GridItem>
<GridItem>{ item.view }</GridItem>
<GridItem>Signature</GridItem>
<GridItem whiteSpace="pre-wrap" wordBreak="break-word" display="flex" alignItems="flex-start" columnGap={ 3 }>
{ item.signature }
<CopyToClipboard text={ item.signature }/>
</GridItem>
<GridItem>Signers</GridItem>
<GridItem >{ formatSigners(item.signers) }</GridItem>
<GridItem whiteSpace="pre-wrap">Proposed by validator</GridItem>
<GridItem >{ item.proposed_by_validator_index }</GridItem>
</Grid>
)) }
</AccordionItemContent>
</AccordionItem>
</Accordion>
</AccordionRoot>
</>
) }
</DetailedInfo.ItemValue>
......
......@@ -3,8 +3,8 @@ import React from 'react';
import { useFormContext } from 'react-hook-form';
import type { FormFields } from '../types';
import type { Option } from 'ui/shared/forms/inputs/select/types';
import type { SelectOption } from 'toolkit/chakra/select';
import FormFieldSelect from 'ui/shared/forms/fields/FormFieldSelect';
import ContractVerificationFormRow from '../ContractVerificationFormRow';
......@@ -12,7 +12,7 @@ import ContractVerificationFormRow from '../ContractVerificationFormRow';
const SOURCIFY_ERROR_REGEXP = /\(([^()]*)\)/;
const ContractVerificationFieldContractIndex = () => {
const [ options, setOptions ] = React.useState<Array<Option>>([]);
const [ options, setOptions ] = React.useState<Array<SelectOption>>([]);
const { formState, watch } = useFormContext<FormFields>();
const sources = watch('sources');
......
......@@ -104,7 +104,6 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
<ReCaptcha ref={ recaptcha.ref }/>
<Button
variant="solid"
size="lg"
type="submit"
mt={ 8 }
loading={ formState.isSubmitting }
......
......@@ -135,7 +135,6 @@ const CustomAbiForm: React.FC<Props> = ({ data, onOpenChange, onSuccess, setAler
/>
<Box>
<Button
size="lg"
type="submit"
disabled={ !formApi.formState.isDirty }
loading={ isPending }
......
import { Link } from '@chakra-ui/react';
import React from 'react';
import type { MarketplaceAppSocialInfo } from 'types/client/marketplace';
import { Link } from 'toolkit/chakra/link';
import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg';
......@@ -23,7 +23,7 @@ const SocialLink = ({ href, icon, title }: Props) => {
display="inline-flex"
alignItems="center"
>
<IconSvg name={ icon } boxSize={ 5 } mr={ 2 } color="text_secondary"/>
<IconSvg name={ icon } boxSize={ 5 } mr={ 2 } color="text.secondary"/>
<span>{ title }</span>
</Link>
);
......
import { Box, CheckboxGroup, Fieldset, Flex, HStack, Text, chakra, createListCollection } from '@chakra-ui/react';
import { Box, Fieldset, Flex, HStack, Text, chakra, createListCollection } from '@chakra-ui/react';
import React from 'react';
import type * as bens from '@blockscout/bens-types';
......@@ -7,7 +7,7 @@ import type { PaginationParams } from 'ui/shared/pagination/types';
import useIsInitialLoading from 'lib/hooks/useIsInitialLoading';
import { Button } from 'toolkit/chakra/button';
import { Checkbox } from 'toolkit/chakra/checkbox';
import { Checkbox, CheckboxGroup } from 'toolkit/chakra/checkbox';
import { Image } from 'toolkit/chakra/image';
import ActionBar from 'ui/shared/ActionBar';
import FilterInput from 'ui/shared/filters/FilterInput';
......@@ -95,32 +95,28 @@ const NameDomainsActionBar = ({
Reset
</Button>
</Flex>
<Fieldset.Root>
<CheckboxGroup defaultValue={ protocolsFilterValue } onValueChange={ onProtocolsFilterChange } value={ protocolsFilterValue } name="token_type">
<Fieldset.Content gap={ 5 } alignItems="flex-start">
{ protocolsData.map((protocol) => {
const topLevelDomains = protocol.tld_list.map((domain) => `.${ domain }`).join(' ');
return (
<Checkbox key={ protocol.id } value={ protocol.id }>
<Flex alignItems="center">
<Image
src={ protocol.icon_url }
boxSize={ 5 }
borderRadius="sm"
mr={ 2 }
alt={ `${ protocol.title } protocol icon` }
fallback={ <IconSvg name="ENS_slim" boxSize={ 5 } mr={ 2 }/> }
// fallbackStrategy={ protocol.icon_url ? 'onError' : 'beforeLoadOrError' }
/>
<span>{ protocol.short_name }</span>
<chakra.span color="text_secondary" whiteSpace="pre"> { topLevelDomains }</chakra.span>
</Flex>
</Checkbox>
);
}) }
</Fieldset.Content>
</CheckboxGroup>
</Fieldset.Root>
<CheckboxGroup defaultValue={ protocolsFilterValue } onValueChange={ onProtocolsFilterChange } value={ protocolsFilterValue } name="token_type">
{ protocolsData.map((protocol) => {
const topLevelDomains = protocol.tld_list.map((domain) => `.${ domain }`).join(' ');
return (
<Checkbox key={ protocol.id } value={ protocol.id }>
<Flex alignItems="center">
<Image
src={ protocol.icon_url }
boxSize={ 5 }
borderRadius="sm"
mr={ 2 }
alt={ `${ protocol.title } protocol icon` }
fallback={ <IconSvg name="ENS_slim" boxSize={ 5 } mr={ 2 }/> }
// fallbackStrategy={ protocol.icon_url ? 'onError' : 'beforeLoadOrError' }
/>
<span>{ protocol.short_name }</span>
<chakra.span color="text.secondary" whiteSpace="pre"> { topLevelDomains }</chakra.span>
</Flex>
</Checkbox>
);
}) }
</CheckboxGroup>
{ filterGroupDivider }
</>
) }
......@@ -133,7 +129,7 @@ const NameDomainsActionBar = ({
</Checkbox>
<Checkbox
value="resolved_to"
mt={ 5 }
mt={ 3 }
disabled={ !isAddressSearch }
>
Resolved to address
......
......@@ -108,7 +108,6 @@ const ApiKeysPage: React.FC = () => {
rowGap={ 5 }
>
<Button
size="lg"
onClick={ apiKeyModalProps.onOpen }
disabled={ !canAdd }
>
......
......@@ -92,7 +92,6 @@ const CustomAbiPage: React.FC = () => {
{ Boolean(data?.length) && list }
<Skeleton mt={ 8 } loading={ isPlaceholderData } display="inline-block">
<Button
size="lg"
onClick={ customAbiModalProps.onOpen }
>
Add custom ABI
......
import { VStack, Textarea, Alert, Code, Flex, Box } from '@chakra-ui/react';
import { VStack, Textarea, Code, Flex, Box } from '@chakra-ui/react';
import mixpanel from 'mixpanel-browser';
import type { ChangeEvent } from 'react';
import React from 'react';
......@@ -8,6 +8,7 @@ import * as cookies from 'lib/cookies';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import useGradualIncrement from 'lib/hooks/useGradualIncrement';
import { useRollbar } from 'lib/rollbar';
import { Alert } from 'toolkit/chakra/alert';
import { Button } from 'toolkit/chakra/button';
import { toaster } from 'toolkit/chakra/toaster';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -64,16 +65,15 @@ const Login = () => {
<PageTitle title="Login page 😂"/>
{ isFormVisible && (
<>
<Alert.Root status="error" flexDirection="column" alignItems="flex-start">
<Alert.Title fontSize="md">
!!! Temporary solution for authentication on localhost !!!
</Alert.Title>
<Alert.Description mt={ 3 }>
To Sign in go to production instance first, sign in there, copy obtained API token from cookie
<Code ml={ 1 }>{ cookies.NAMES.API_TOKEN }</Code> and paste it in the form below. After submitting the form you should be successfully
authenticated in current environment
</Alert.Description>
</Alert.Root>
<Alert
status="warning"
title="!!! Temporary solution for authentication on localhost !!!"
inline={ false }
>
To Sign in go to production instance first, sign in there, copy obtained API token from cookie
<Code ml={ 1 }>{ cookies.NAMES.API_TOKEN }</Code> and paste it in the form below. After submitting the form you should be successfully
authenticated in current environment
</Alert>
<Textarea value={ token } onChange={ handleTokenChange } placeholder="API token"/>
<Button onClick={ handleSetTokenClick }>Set cookie</Button>
</>
......
......@@ -113,14 +113,14 @@ const VerifiedAddresses = () => {
const addButton = (() => {
if (userWithoutEmail) {
return (
<Button size="lg" disabled mt={ 8 }>
<Button disabled mt={ 8 }>
Add address
</Button>
);
}
return (
<Button size="lg" onClick={ modalProps.onOpen } loadingSkeleton={ isLoading } mt={ 8 }>
<Button onClick={ modalProps.onOpen } loadingSkeleton={ isLoading } mt={ 8 }>
Add address
</Button>
);
......@@ -206,7 +206,7 @@ const VerifiedAddresses = () => {
<chakra.p fontWeight={ 600 } mt={ 5 }>
Before starting, make sure that:
</chakra.p>
<List.Root ml={ 6 } as="ol">
<List.Root pl={ 5 } as="ol">
<List.Item>The source code for the smart contract is deployed on “{ config.chain.name }”.</List.Item>
<List.Item>
<span>The source code is verified (if not yet verified, you can use </span>
......
......@@ -122,7 +122,6 @@ const WatchList: React.FC = () => {
</DataListDisplay>
<Skeleton mt={ 8 } loading={ isPlaceholderData } display="inline-block">
<Button
size="lg"
onClick={ addressModalProps.onOpen }
>
Add address
......
......@@ -99,7 +99,6 @@ const AddressForm: React.FC<Props> = ({ data, onOpenChange, onSuccess, setAlertV
mb={ 8 }
/>
<Button
size="lg"
type="submit"
disabled={ !formApi.formState.isDirty }
loading={ pending }
......
......@@ -99,7 +99,6 @@ const PrivateAddressTags = () => {
</DataListDisplay>
<Skeleton mt={ 8 } loading={ isPlaceholderData } display="inline-block">
<Button
size="lg"
onClick={ addressModalProps.onOpen }
>
Add address tag
......
......@@ -98,7 +98,6 @@ const PrivateTransactionTags = () => {
</DataListDisplay>
<Skeleton mt={ 8 } loading={ isPlaceholderData } display="inline-block">
<Button
size="lg"
onClick={ transactionModalProps.onOpen }
>
Add transaction tag
......
......@@ -110,7 +110,6 @@ const TransactionForm: React.FC<Props> = ({ data, onOpenChange, onSuccess, setAl
/>
<Box marginTop={ 8 }>
<Button
size="lg"
type="submit"
disabled={ !formApi.formState.isDirty }
loading={ pending }
......
......@@ -135,7 +135,6 @@ const PublicTagsSubmitForm = ({ config, userInfo, onSubmitResult }: Props) => {
<Button
variant="solid"
size="lg"
type="submit"
mt={ 3 }
loading={ formApi.formState.isSubmitting }
......
......@@ -71,13 +71,13 @@ const PublicTagsSubmitResult = ({ data }: Props) => {
<Flex flexDir={{ base: 'column', lg: 'row' }} columnGap={ 6 } mt={ 8 } rowGap={ 3 }>
{ hasErrors && (
<Link href={ route({ pathname: '/public-tags/submit', query: startOverButtonQuery }) } asChild>
<Button size="lg" variant="outline">
<Button variant="outline">
Start over
</Button>
</Link>
) }
<Link href={ route({ pathname: '/public-tags/submit' }) } asChild>
<Button size="lg">Add new tag</Button>
<Button>Add new tag</Button>
</Link>
</Flex>
</div>
......
......@@ -18,13 +18,13 @@ import PrivateTagMenuItem from './items/PrivateTagMenuItem';
import PublicTagMenuItem from './items/PublicTagMenuItem';
import TokenInfoMenuItem from './items/TokenInfoMenuItem';
// TODO @tom2drum fix account modals
interface Props {
isLoading?: boolean;
className?: string;
showUpdateMetadataItem?: boolean;
}
// TODO @tom2drum fix modal open on menu item click
const AccountActionsMenu = ({ isLoading, className, showUpdateMetadataItem }: Props) => {
const router = useRouter();
......@@ -46,10 +46,10 @@ const AccountActionsMenu = ({ isLoading, className, showUpdateMetadataItem }: Pr
render: (props: ItemProps) => <MetadataUpdateMenuItem { ...props }/>,
enabled: isTokenInstancePage && showUpdateMetadataItem,
},
// {
// render: (props: ItemProps) => <TokenInfoMenuItem { ...props }/>,
// enabled: config.features.account.isEnabled && isTokenPage && config.features.addressVerification.isEnabled && !userWithoutEmail,
// },
{
render: (props: ItemProps) => <TokenInfoMenuItem { ...props }/>,
enabled: config.features.account.isEnabled && isTokenPage && config.features.addressVerification.isEnabled && !userWithoutEmail,
},
{
render: (props: ItemProps) => <PrivateTagMenuItem { ...props } entityType={ isTxPage ? 'tx' : 'address' }/>,
enabled: config.features.account.isEnabled,
......
......@@ -84,7 +84,7 @@ const TokenInfoMenuItem = ({ hash, type }: ItemProps) => {
{ ({ onClick }) => (
<MenuItem onClick={ onClick } value="add-token-info">
{ icon }
<chakra.span ml={ 2 }>{ label }</chakra.span>
<chakra.span>{ label }</chakra.span>
</MenuItem>
) }
</AuthGuard>
......@@ -99,8 +99,8 @@ const TokenInfoMenuItem = ({ hash, type }: ItemProps) => {
<AddressVerificationModal
defaultAddress={ hash }
pageType={ PAGE_TYPE_DICT['/token/[hash]'] }
isOpen={ modal.open }
onClose={ modal.onClose }
open={ modal.open }
onOpenChange={ modal.onOpenChange }
onSubmit={ handleVerifiedAddressSubmit }
onAddTokenInfoClick={ handleAddApplicationClick }
onShowListClick={ handleShowMyAddressesClick }
......
import { Box, Button, Text } from '@chakra-ui/react';
import { Box, Text } from '@chakra-ui/react';
import React from 'react';
import { route } from 'nextjs-routes';
......@@ -8,6 +8,8 @@ import getErrorCause from 'lib/errors/getErrorCause';
import getErrorCauseStatusCode from 'lib/errors/getErrorCauseStatusCode';
import getErrorObjStatusCode from 'lib/errors/getErrorObjStatusCode';
import getResourceErrorPayload from 'lib/errors/getResourceErrorPayload';
import { Button } from 'toolkit/chakra/button';
import { Link } from 'toolkit/chakra/link';
import AdBannerContent from 'ui/shared/ad/AdBannerContent';
import AppErrorIcon from './AppErrorIcon';
......@@ -87,16 +89,18 @@ const AppError = ({ error, className }: Props) => {
<>
<AppErrorIcon statusCode={ statusCode }/>
<AppErrorTitle title={ title }/>
<Text variant="secondary" mt={ 3 }>{ text }</Text>
<Button
mt={ 8 }
size="lg"
variant="outline"
as="a"
<Text color="text.secondary" mt={ 3 }>{ text }</Text>
<Link
href={ route({ pathname: '/' }) }
asChild
>
Back to home
</Button>
<Button
mt={ 8 }
variant="outline"
>
Back to home
</Button>
</Link>
{ statusCode === 404 && adBannerProvider && <AdBannerContent mt={ 12 } provider={ adBannerProvider }/> }
</>
);
......
import { Heading } from '@chakra-ui/react';
import React from 'react';
import { Heading } from 'toolkit/chakra/heading';
interface Props {
title: string;
}
const AppErrorTitle = ({ title }: Props) => {
return <Heading mt={ 8 } size="2xl" fontFamily="body">{ title }</Heading>;
return <Heading mt={ 8 } textStyle="heading.xl" as="h1">{ title }</Heading>;
};
export default AppErrorTitle;
import { Button } from '@chakra-ui/react';
import React from 'react';
import { route } from 'nextjs-routes';
import { Button } from 'toolkit/chakra/button';
import { Link } from 'toolkit/chakra/link';
import AppErrorIcon from '../AppErrorIcon';
import AppErrorTitle from '../AppErrorTitle';
......@@ -15,15 +17,14 @@ const AppErrorBlockConsensus = ({ hash }: Props) => {
<>
<AppErrorIcon statusCode={ 404 }/>
<AppErrorTitle title="Block removed due to chain reorganization"/>
<Button
mt={ 8 }
size="lg"
variant="outline"
as="a"
href={ hash ? route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: hash } }) : route({ pathname: '/' }) }
>
{ hash ? 'View reorg' : 'Back to home' }
</Button>
<Link href={ hash ? route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: hash } }) : route({ pathname: '/' }) } asChild>
<Button
mt={ 8 }
variant="outline"
>
{ hash ? 'View reorg' : 'Back to home' }
</Button>
</Link>
</>
);
};
......
import { Button, Text } from '@chakra-ui/react';
import { Text } from '@chakra-ui/react';
import React from 'react';
import { toaster } from 'toolkit/chakra/toaster';
import config from 'configs/app';
import buildUrl from 'lib/api/buildUrl';
import useFetch from 'lib/hooks/useFetch';
import { Button } from 'toolkit/chakra/button';
import { toaster } from 'toolkit/chakra/toaster';
import ReCaptcha from 'ui/shared/reCaptcha/ReCaptcha';
import useReCaptcha from 'ui/shared/reCaptcha/useReCaptcha';
......@@ -48,7 +49,7 @@ const AppErrorTooManyRequests = () => {
<>
<AppErrorIcon statusCode={ 429 }/>
<AppErrorTitle title="Too many requests"/>
<Text variant="secondary" mt={ 3 }>
<Text color="text.secondary" mt={ 3 }>
You have exceeded the request rate for a given time period. Please reduce the number of requests and try again soon.
</Text>
<ReCaptcha ref={ recaptcha.ref }/>
......
/* eslint-disable max-len */
import { Box, OrderedList, ListItem, useColorModeValue, Flex, chakra, Button } from '@chakra-ui/react';
import { Box, Flex, List, chakra } from '@chakra-ui/react';
import React from 'react';
import { route } from 'nextjs-routes';
import { Button } from 'toolkit/chakra/button';
import { Link } from 'toolkit/chakra/link';
import IconSvg from 'ui/shared/IconSvg';
import AppErrorTitle from '../AppErrorTitle';
const AppErrorTxNotFound = () => {
const snippet = {
borderColor: useColorModeValue('blackAlpha.300', 'whiteAlpha.300'),
iconBg: useColorModeValue('blackAlpha.800', 'whiteAlpha.800'),
iconColor: useColorModeValue('white', 'black'),
borderColor: { _light: 'blackAlpha.300', _dark: 'whiteAlpha.300' },
iconBg: { _light: 'blackAlpha.800', _dark: 'whiteAlpha.800' },
iconColor: { _light: 'white', _dark: 'black' },
};
return (
......@@ -37,31 +39,30 @@ const AppErrorTxNotFound = () => {
</Flex>
</Box>
<AppErrorTitle title="Sorry, we are unable to locate this transaction hash"/>
<OrderedList mt={ 3 } spacing={ 3 }>
<ListItem>
<List.Root mt={ 3 } gap={ 3 } as="ol" pl={ 5 }>
<List.Item>
If you have just submitted this transaction please wait for at least 30 seconds before refreshing this page.
</ListItem>
<ListItem>
</List.Item>
<List.Item>
It could still be in the TX Pool of a different node, waiting to be broadcasted.
</ListItem>
<ListItem>
</List.Item>
<List.Item>
During times when the network is busy (i.e during ICOs) it can take a while for your transaction to propagate through the network and for us to index it.
</ListItem>
<ListItem>
</List.Item>
<List.Item>
<span>If it still does not show up after 1 hour, please check with your </span>
<chakra.span fontWeight={ 600 }>sender/exchange/wallet/transaction provider</chakra.span>
<span> for additional information.</span>
</ListItem>
</OrderedList>
<Button
mt={ 8 }
size="lg"
variant="outline"
as="a"
href={ route({ pathname: '/' }) }
>
Back to home
</Button>
</List.Item>
</List.Root>
<Link href={ route({ pathname: '/' }) } asChild>
<Button
mt={ 8 }
variant="outline"
>
Back to home
</Button>
</Link>
</>
);
};
......
......@@ -59,7 +59,6 @@ const DeleteModal: React.FC<Props> = ({
</DialogBody>
<DialogFooter>
<Button
size="lg"
onClick={ onDeleteClick }
loading={ isPending }
>
......
import { chakra, Image } from '@chakra-ui/react';
import { chakra } from '@chakra-ui/react';
import React from 'react';
import type { EntityTag as TEntityTag } from './types';
import { Image } from 'toolkit/chakra/image';
import IconSvg from 'ui/shared/IconSvg';
interface Props {
data: TEntityTag;
iconColor?: string;
......
import type { SkeletonProps } from '@chakra-ui/react';
// eslint-disable-next-line no-restricted-imports
import { Skeleton as ChakraSkeleton } from '@chakra-ui/react';
import { forwardRef } from 'react';
const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>((props, ref) => {
if (props.isLoaded) {
return <ChakraSkeleton ref={ ref } { ...props } sx={{ animation: 'none' }}/>;
}
return <ChakraSkeleton ref={ ref } { ...props }/>;
});
Skeleton.displayName = 'Skeleton';
export default Skeleton;
import { CheckboxGroup, Text, Flex, useCheckboxGroup, Fieldset } from '@chakra-ui/react';
import { Text, Flex, useCheckboxGroup, Fieldset } from '@chakra-ui/react';
import React from 'react';
import type { NFTTokenType, TokenType } from 'types/api/token';
import { TOKEN_TYPES, TOKEN_TYPE_IDS, NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import { Button } from 'toolkit/chakra/button';
import { Checkbox } from 'toolkit/chakra/checkbox';
import { Checkbox, CheckboxGroup } from 'toolkit/chakra/checkbox';
type Props<T extends TokenType | NFTTokenType> = {
onChange: (nextValue: Array<T>) => void;
......
import React from 'react';
import type { Path, FieldValues } from 'react-hook-form';
import { useController, useFormContext } from 'react-hook-form';
import type { FormFieldPropsBase } from './types';
// import type { Option } from 'ui/shared/forms/inputs/select/types';
import useIsMobile from 'lib/hooks/useIsMobile';
import type { Props as FancySelectProps } from 'ui/shared/forms/inputs/select/FancySelect';
import FancySelect from 'ui/shared/forms/inputs/select/FancySelect';
// FIXME: Try to get this to work to add more constraints to the props type
// this type only works for plain objects, not for nested objects or arrays (e.g. ui/publicTags/submit/types.ts:FormFields)
// type SelectField<O> = { [K in keyof O]: NonNullable<O[K]> extends Option ? K : never }[keyof O];
// TODO @tom2drum remove this component
type Props<
FormFields extends FieldValues,
Name extends Path<FormFields>,
> = Omit<FormFieldPropsBase<FormFields, Name>, 'bgColor' | 'size'> & Partial<FancySelectProps> & {
size?: 'md' | 'lg';
};
const FormFieldFancySelect = <
FormFields extends FieldValues,
Name extends Path<FormFields>,
>(props: Props<FormFields, Name>) => {
const isMobile = useIsMobile();
const defaultSize = isMobile ? 'md' : 'lg';
const { control } = useFormContext<FormFields>();
const { field, fieldState, formState } = useController<FormFields, typeof props.name>({
control,
name: props.name,
rules: { ...props.rules, required: props.isRequired },
});
const isDisabled = formState.isSubmitting;
return (
<FancySelect
{ ...field }
{ ...props }
size={ props.size || defaultSize }
error={ fieldState.error }
isDisabled={ isDisabled }
/>
);
};
export default React.memo(FormFieldFancySelect) as typeof FormFieldFancySelect;
import { FormLabel, chakra } from '@chakra-ui/react';
import React from 'react';
import type { FieldError } from 'react-hook-form';
interface Props {
text: string;
icon?: React.ReactNode;
error?: Partial<FieldError>;
isFancy?: boolean;
}
// TODO @tom2drum remove this component
const FormInputPlaceholder = ({ text, icon, error, isFancy }: Props) => {
let errorMessage = error?.message;
if (!errorMessage && error?.type === 'pattern') {
errorMessage = 'Invalid format';
}
return (
<FormLabel
alignItems="center"
{ ...(isFancy ? { 'data-fancy': true } : {}) }
variant="floating"
>
{ icon }
<chakra.span>{ text }</chakra.span>
{ errorMessage && (
<chakra.span order={ 3 } whiteSpace="pre">
{ ' ' }
- { errorMessage }
</chakra.span>
) }
</FormLabel>
);
};
export default React.memo(FormInputPlaceholder);
import { noop } from 'es-toolkit';
import React from 'react';
import { test, expect } from 'playwright/lib';
import FancySelect from './FancySelect';
const OPTIONS = [
{ value: 'v0.8.17+commit.8df45f5f', label: 'v0.8.17+commit.8df45f5f' },
{ value: 'v0.8.16+commit.07a7930e', label: 'v0.8.16+commit.07a7930e' },
{ value: 'v0.8.15+commit.e14f2714', label: 'v0.8.15+commit.e14f2714' },
];
test.use({ viewport: { width: 500, height: 300 } });
const defaultProps = {
options: OPTIONS,
isRequired: true,
placeholder: 'Compiler',
name: 'compiler',
onChange: noop,
};
[ 'md' as const, 'lg' as const ].forEach((size) => {
test.describe(`size ${ size } +@dark-mode`, () => {
test('empty', async({ render, page }) => {
const component = await render(
<FancySelect
{ ...defaultProps }
size={ size }
value={ null }
/>,
);
await expect(component).toHaveScreenshot();
await component.getByLabel(/compiler/i).focus();
await component.getByLabel(/compiler/i).type('1');
await expect(page).toHaveScreenshot();
});
test('filled', async({ render }) => {
const component = await render(
<FancySelect
{ ...defaultProps }
size={ size }
value={ OPTIONS[0] }
/>,
);
await expect(component).toHaveScreenshot();
});
test('error', async({ render }) => {
const component = await render(
<FancySelect
{ ...defaultProps }
size={ size }
value={ null }
error={{
type: 'unknown',
message: 'cannot be empty',
}}
/>,
);
await expect(component).toHaveScreenshot();
await component.getByLabel(/compiler/i).focus();
await component.getByLabel(/compiler/i).type('1');
await expect(component).toHaveScreenshot();
});
test('disabled', async({ render }) => {
const component = await render(
<FancySelect
{ ...defaultProps }
size={ size }
value={ OPTIONS[0] }
isDisabled
/>,
);
await expect(component).toHaveScreenshot();
});
test('read-only', async({ render }) => {
const component = await render(
<FancySelect
{ ...defaultProps }
size={ size }
value={ OPTIONS[0] }
isReadOnly
/>,
);
await expect(component).toHaveScreenshot();
});
});
});
import { FormControl, useToken, useColorMode } from '@chakra-ui/react';
import React from 'react';
import type { FieldError, FieldErrorsImpl, Merge } from 'react-hook-form';
import type { Option } from './types';
import { Select, AsyncSelect } from 'chakra-react-select';
import type { CSSObjectWithLabel, GroupBase, SingleValue, MultiValue, AsyncProps, Props as SelectProps } from 'chakra-react-select';
import FormInputPlaceholder from 'ui/shared/forms/inputs/FormInputPlaceholder';
import { getChakraStyles } from 'ui/shared/forms/inputs/select/utils';
interface CommonProps {
error?: Merge<FieldError, FieldErrorsImpl<Option>> | undefined;
placeholderIcon?: React.ReactNode;
}
interface RegularSelectProps extends SelectProps<Option, boolean, GroupBase<Option>>, CommonProps {
isAsync?: false;
onChange: (newValue: SingleValue<Option> | MultiValue<Option>) => void;
}
interface AsyncSelectProps extends AsyncProps<Option, boolean, GroupBase<Option>>, CommonProps {
isAsync: true;
onChange: (newValue: SingleValue<Option> | MultiValue<Option>) => void;
}
export type Props = RegularSelectProps | AsyncSelectProps;
const FancySelect = (props: Props, ref: React.LegacyRef<HTMLDivElement>) => {
const menuZIndex = useToken('zIndices', 'dropdown');
const { colorMode } = useColorMode();
const styles = React.useMemo(() => ({
menuPortal: (provided: CSSObjectWithLabel) => ({ ...provided, zIndex: menuZIndex }),
}), [ menuZIndex ]);
const chakraStyles = React.useMemo(() => getChakraStyles(colorMode), [ colorMode ]);
const SelectComponent = props.isAsync ? AsyncSelect : Select;
return (
<FormControl
variant="floating"
size={ props.size || 'md' }
isRequired={ props.isRequired }
ref={ ref }
{ ...(props.error ? { 'aria-invalid': true } : {}) }
{ ...(props.isDisabled ? { 'aria-disabled': true } : {}) }
{ ...(props.value ? { 'data-active': true } : {}) }
>
<SelectComponent
{ ...props }
size={ props.size || 'md' }
menuPortalTarget={ window.document.body }
placeholder=""
styles={ styles }
chakraStyles={ chakraStyles }
isInvalid={ Boolean(props.error) }
useBasicStyles
/>
<FormInputPlaceholder
text={ typeof props.placeholder === 'string' ? props.placeholder : '' }
icon={ props.placeholderIcon }
error={ props.error }
isFancy
/>
</FormControl>
);
};
export default React.memo(React.forwardRef(FancySelect));
export interface Option<T extends string = string> {
label: string;
value: T;
}
import type { ColorMode } from '@chakra-ui/react';
import type { Option } from './types';
import type { Size, ChakraStylesConfig } from 'chakra-react-select';
import theme from 'theme/theme';
import getFormStyles from 'theme/utils/getFormStyles';
function getValueContainerStyles(size?: Size) {
switch (size) {
case 'sm':
case 'md': {
return {
paddingLeft: 4,
};
}
case 'lg': {
return {
paddingLeft: 6,
};
}
default: {
return {};
}
}
}
function getSingleValueStyles(size?: Size) {
switch (size) {
case 'sm':
case 'md': {
return {
top: '26px',
};
}
case 'lg': {
return {
top: '38px',
};
}
default: {
return {};
}
}
}
const getChakraStyles: (colorMode: ColorMode) => ChakraStylesConfig<Option> = (colorMode) => {
const formColor = getFormStyles({ colorMode, colorScheme: 'blue', theme });
return {
control: (provided, state) => ({
...provided,
borderColor: state.hasValue ? formColor.input.filled.borderColor : formColor.input.empty.borderColor,
}),
inputContainer: (provided) => ({
...provided,
py: 0,
mx: 0,
}),
valueContainer: (provided, state) => ({
...provided,
...getValueContainerStyles(state.selectProps.size),
py: 0,
}),
singleValue: (provided, state) => ({
...provided,
mx: 0,
transform: 'none',
...getSingleValueStyles(state.selectProps.size),
}),
};
};
export { getChakraStyles };
......@@ -4,12 +4,12 @@ import React from 'react';
import type { Route } from 'nextjs-routes';
import { toaster } from 'toolkit/chakra/toaster';
import config from 'configs/app';
import useApiFetch from 'lib/api/useApiFetch';
import { getResourceKey } from 'lib/api/useApiQuery';
import * as cookies from 'lib/cookies';
import * as mixpanel from 'lib/mixpanel';
import { toaster } from 'toolkit/chakra/toaster';
const PROTECTED_ROUTES: Array<Route['pathname']> = [
'/account/api-key',
......
import type { GridProps, HTMLChakraProps } from '@chakra-ui/react';
import { Box, Grid, Flex, Text, Link, VStack } from '@chakra-ui/react';
import { Box, Grid, Flex, Text, VStack } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React from 'react';
......@@ -11,6 +11,7 @@ import useApiQuery from 'lib/api/useApiQuery';
import useFetch from 'lib/hooks/useFetch';
import useIssueUrl from 'lib/hooks/useIssueUrl';
import { copy } from 'lib/html-entities';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import IconSvg from 'ui/shared/IconSvg';
import { CONTENT_MAX_WIDTH } from 'ui/shared/layout/utils';
......@@ -174,9 +175,9 @@ const Footer = () => {
return (
<Box gridArea={ gridArea } textStyle="xs" mt={ 6 }>
<span>This site is protected by reCAPTCHA and the Google </span>
<Link href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Privacy Policy</Link>
<Link href="https://policies.google.com/privacy" external noIcon>Privacy Policy</Link>
<span> and </span>
<Link href="https://policies.google.com/terms" target="_blank" rel="noopener noreferrer">Terms of Service</Link>
<Link href="https://policies.google.com/terms" external noIcon>Terms of Service</Link>
<span> apply.</span>
</Box>
);
......
import { Flex, Link, chakra } from '@chakra-ui/react';
import { Flex, chakra } from '@chakra-ui/react';
import React from 'react';
import config from 'configs/app';
......@@ -6,6 +6,7 @@ import useApiQuery from 'lib/api/useApiQuery';
import dayjs from 'lib/date/dayjs';
import useIsMobile from 'lib/hooks/useIsMobile';
import { HOMEPAGE_STATS } from 'stubs/stats';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import GasInfoTooltip from 'ui/shared/gas/GasInfoTooltip';
import GasPrice from 'ui/shared/gas/GasPrice';
......
......@@ -21,6 +21,8 @@ const SettingsAddressFormat = () => {
onChange={ toggleAddressFormat } mt={ 4 }
size="sm"
flexDirection="row-reverse"
justifyContent="space-between"
w="100%"
gap={ 2 }
fontWeight="400"
color="text.secondary"
......
import { FormLabel, FormControl, Switch, Box } from '@chakra-ui/react';
import { Box } from '@chakra-ui/react';
import React from 'react';
import config from 'configs/app';
import { useAppContext } from 'lib/contexts/app';
import * as cookies from 'lib/cookies';
import { Switch } from 'toolkit/chakra/switch';
const SettingsScamTokens = () => {
const { cookies: appCookies } = useAppContext();
......@@ -28,12 +29,20 @@ const SettingsScamTokens = () => {
return (
<>
<Box borderColor="divider" borderTopWidth="1px" my={ 3 }/>
<FormControl display="flex" alignItems="center" columnGap={ 2 } mt={ 4 }>
<FormLabel htmlFor="scam-tokens" m="0" fontWeight={ 400 } fontSize="sm" lineHeight={ 5 }>
Hide scam tokens
</FormLabel>
<Switch id="scam-tokens" isChecked={ isChecked } onChange={ handleChange }/>
</FormControl>
<Switch
id="scam-tokens"
checked={ isChecked }
onChange={ handleChange }
size="sm"
flexDirection="row-reverse"
justifyContent="space-between"
w="100%"
gap={ 2 }
fontWeight="400"
color="text.secondary"
>
Hide scam tokens
</Switch>
</>
);
};
......
import { Box, Separator, Flex, Link, VStack } from '@chakra-ui/react';
import { Box, Separator, Flex, VStack } from '@chakra-ui/react';
import React from 'react';
import type { NavLink } from './types';
......@@ -10,6 +10,7 @@ import config from 'configs/app';
import { useMarketplaceContext } from 'lib/contexts/marketplace';
import shortenString from 'lib/shortenString';
import { Button } from 'toolkit/chakra/button';
import { Link } from 'toolkit/chakra/link';
import Hint from 'ui/shared/Hint';
import TruncatedValue from 'ui/shared/TruncatedValue';
import useLogout from 'ui/snippets/auth/useLogout';
......@@ -96,7 +97,7 @@ const UserProfileContent = ({ data, onClose, onLogin, onAddEmail, onAddAddress }
/>
{ data?.address_hash ?
<Box ml="auto">{ shortenString(data?.address_hash) }</Box> :
<Link ml="auto" onClick={ onAddAddress } _hover={{ color: 'link.primary.hover' }}>Add address</Link>
<Link ml="auto" onClick={ onAddAddress }>Add address</Link>
}
</Flex>
) }
......@@ -104,7 +105,7 @@ const UserProfileContent = ({ data, onClose, onLogin, onAddEmail, onAddAddress }
<Box mr="auto">Email</Box>
{ data?.email ?
<TruncatedValue value={ data.email }/> :
<Link onClick={ onAddEmail } _hover={{ color: 'link.primary.hover' }}>Add email</Link>
<Link onClick={ onAddEmail }>Add email</Link>
}
</Flex>
</Box>
......
import { Alert, CloseButton, Link, Text, useDisclosure } from '@chakra-ui/react';
import { Text } from '@chakra-ui/react';
import React from 'react';
import { apos } from 'lib/html-entities';
import { Alert } from 'toolkit/chakra/alert';
import { Link } from 'toolkit/chakra/link';
function ChartsLoadingErrorAlert() {
const {
isOpen: isVisible,
onClose,
} = useDisclosure({ defaultIsOpen: true });
return isVisible ? (
<Alert status="warning" mb={ 4 }>
return (
<Alert status="warning" mb={ 4 } closable>
<Text mr={ 2 }>
{ `Some of the charts did not load because the server didn${ apos }t respond. To reload charts ` }
<Link href={ window.document.location.href }>click once again.</Link>
</Text>
<CloseButton
alignSelf={{ base: 'flex-start', lg: 'center' }}
ml="auto"
onClick={ onClose }
/>
</Alert>
) : null;
);
}
export default ChartsLoadingErrorAlert;
......@@ -187,7 +187,6 @@ const TokenInfoForm = ({ address, tokenName, application, onSubmit }: Props) =>
</Grid>
<Button
type="submit"
size="lg"
mt={ 8 }
loading={ formState.isSubmitting }
loadingText="Send request"
......
import { CheckboxGroup, Text, Flex, useCheckboxGroup, chakra, Fieldset } from '@chakra-ui/react';
import { Text, Flex, useCheckboxGroup, chakra } from '@chakra-ui/react';
import React from 'react';
import config from 'configs/app';
import { Button } from 'toolkit/chakra/button';
import { Checkbox } from 'toolkit/chakra/checkbox';
import { Checkbox, CheckboxGroup } from 'toolkit/chakra/checkbox';
const feature = config.features.bridgedTokens;
......@@ -44,18 +44,14 @@ const TokensBridgedChainsFilter = ({ onChange, defaultValue }: Props) => {
Reset
</Button>
</Flex>
<Fieldset.Root>
<CheckboxGroup defaultValue={ defaultValue } onValueChange={ handleChange } value={ value } name="bridged_token_chain">
<Fieldset.Content>
{ feature.chains.map(({ title, id, short_title: shortTitle }) => (
<Checkbox key={ id } value={ id } textStyle="md" whiteSpace="pre-wrap">
<span>{ title }</span>
<chakra.span color="text_secondary"> ({ shortTitle })</chakra.span>
</Checkbox>
)) }
</Fieldset.Content>
</CheckboxGroup>
</Fieldset.Root>
<CheckboxGroup defaultValue={ defaultValue } onValueChange={ handleChange } value={ value } name="bridged_token_chain">
{ feature.chains.map(({ title, id, short_title: shortTitle }) => (
<Checkbox key={ id } value={ id } whiteSpace="pre-wrap">
<span>{ title }</span>
<chakra.span color="text.secondary"> ({ shortTitle })</chakra.span>
</Checkbox>
)) }
</CheckboxGroup>
</>
);
};
......
......@@ -9,7 +9,6 @@ import { currencyUnits } from 'lib/units';
import { Badge } from 'toolkit/chakra/badge';
import CurrencyValue from 'ui/shared/CurrencyValue';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData';
......
......@@ -10,7 +10,6 @@ import { generateListStub } from 'stubs/utils';
import ActionBar, { ACTION_BAR_HEIGHT_DESKTOP } from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
// import FilterInput from 'ui/shared/filters/FilterInput';
// import TxInternalsFilter from 'ui/tx/internals/TxInternalsFilter';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import { default as getNextSortValueShared } from 'ui/shared/sort/getNextSortValue';
......@@ -117,7 +116,6 @@ const TxInternals = ({ txQuery }: Props) => {
const actionBar = pagination.isVisible ? (
<ActionBar mt={ -6 }>
{ /* <TxInternalsFilter onFilterChange={ handleFilterChange } defaultFilters={ filters } appliedFiltersNum={ filters.length }/> */ }
{ /* <FilterInput onChange={ setSearchTerm } maxW="360px" ml={ 3 } size="xs" placeholder="Search by addresses, hash, method..."/> */ }
<Pagination ml="auto" { ...pagination }/>
</ActionBar>
......
import { CheckboxGroup, Checkbox, Text } from '@chakra-ui/react';
import React from 'react';
import type { TxInternalsType } from 'types/api/internalTransaction';
import PopoverFilter from 'ui/shared/filters/PopoverFilter';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
interface Props {
appliedFiltersNum?: number;
defaultFilters: Array<TxInternalsType>;
onFilterChange: (nextValue: Array<TxInternalsType>) => void;
}
const TxInternalsFilter = ({ onFilterChange, defaultFilters, appliedFiltersNum }: Props) => {
return (
<PopoverFilter appliedFiltersNum={ appliedFiltersNum } contentProps={{ w: { md: '100%', lg: '438px' } }}>
<CheckboxGroup size="lg" onChange={ onFilterChange } defaultValue={ defaultFilters }>
{ TX_INTERNALS_ITEMS.map(({ title, id }) => <Checkbox key={ id } value={ id }><Text fontSize="md">{ title }</Text></Checkbox>) }
</CheckboxGroup>
</PopoverFilter>
);
};
export default React.memo(TxInternalsFilter);
import {
Checkbox,
CheckboxGroup,
Grid,
Text,
} from '@chakra-ui/react';
import React, { useCallback, useState } from 'react';
import type { TTxsFilters, TypeFilter, MethodFilter } from 'types/api/txsFilters';
import PopoverFilter from 'ui/shared/filters/PopoverFilter';
interface Props {
appliedFiltersNum?: number;
filters: Partial<TTxsFilters>;
onFiltersChange: (val: Partial<TTxsFilters>) => void;
}
const TYPE_OPTIONS = [
{ title: 'Token transfer', id: 'token_transfer' },
{ title: 'Contract Creation', id: 'contract_creation' },
{ title: 'Contract Call', id: 'contract_call' },
{ title: 'Coin Transfer', id: 'coin_transfer' },
{ title: 'Token Creation', id: 'token_creation' },
];
const METHOD_OPTIONS = [
{ title: 'Approve', id: 'approve' },
{ title: 'Transfer', id: 'transfer' },
{ title: 'Multicall', id: 'multicall' },
{ title: 'Mint', id: 'mint' },
{ title: 'Commit', id: 'commit' },
];
const TxsFilters = ({ filters, appliedFiltersNum }: Props) => {
const [ typeFilter, setTypeFilter ] = useState<Array<TypeFilter>>(filters.type || []);
const [ methodFilter, setMethodFilter ] = useState<Array<MethodFilter>>(filters.method || []);
const onTypeFilterChange = useCallback((val: Array<TypeFilter>) => {
setTypeFilter(val);
}, []);
const onMethodFilterChange = useCallback((val: Array<MethodFilter>) => {
setMethodFilter(val);
}, []);
return (
<PopoverFilter contentProps={{ w: { md: '100%', lg: '438px' } }} appliedFiltersNum={ appliedFiltersNum }>
<Text variant="secondary" fontWeight="600" fontSize="sm">Type</Text>
<Grid gridTemplateColumns="1fr 1fr" rowGap={ 5 } mt={ 4 } mb={ 4 } pb={ 6 } borderBottom="1px solid" borderColor="border.divider">
<CheckboxGroup size="lg" onChange={ onTypeFilterChange } defaultValue={ typeFilter }>
{ TYPE_OPTIONS.map(({ title, id }) => <Checkbox key={ id } value={ id }><Text fontSize="md">{ title }</Text></Checkbox>) }
</CheckboxGroup>
</Grid>
<Text variant="secondary" fontWeight="600" fontSize="sm">Method</Text>
<Grid gridTemplateColumns="1fr 1fr" rowGap={ 5 } mt={ 4 } mb={ 4 } pb={ 6 } borderBottom="1px solid" borderColor="border.divider">
<CheckboxGroup size="lg" onChange={ onMethodFilterChange } defaultValue={ methodFilter }>
{ METHOD_OPTIONS.map(({ title, id }) => <Checkbox key={ id } value={ id }><Text fontSize="md">{ title }</Text></Checkbox>) }
</CheckboxGroup>
</Grid>
</PopoverFilter>
);
};
export default React.memo(TxsFilters);
......@@ -12,8 +12,6 @@ import Sort from 'ui/shared/sort/Sort';
import { SORT_OPTIONS } from './useTxsSort';
// import TxsFilters from './TxsFilters';
type Props = {
sorting: TransactionsSortingValue;
setSorting: (val: TransactionsSortingValue) => void;
......
......@@ -180,16 +180,14 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
/>
</>
) }
<Box marginTop={ 8 }>
<Button
size="lg"
type="submit"
loading={ pending }
disabled={ !formApi.formState.isDirty }
>
{ !isAdd ? 'Save changes' : 'Add address' }
</Button>
</Box>
<Button
type="submit"
loading={ pending }
disabled={ !formApi.formState.isDirty }
mt={ 8 }
>
{ !isAdd ? 'Save changes' : 'Add address' }
</Button>
</form>
</FormProvider>
);
......
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