Commit cf97a102 authored by tom's avatar tom

ui changes

parent 3ebdf002
import { Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay } from '@chakra-ui/react'; import { Icon, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay, Alert, Link } 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';
...@@ -6,6 +6,8 @@ import { useForm, FormProvider } from 'react-hook-form'; ...@@ -6,6 +6,8 @@ import { useForm, FormProvider } from 'react-hook-form';
import type { AddressVerificationFormFields } from './types'; import type { AddressVerificationFormFields } from './types';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import eastArrowIcon from 'icons/arrows/east.svg';
import type { ResourceError } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import Web3ModalProvider from 'ui/shared/Web3ModalProvider'; import Web3ModalProvider from 'ui/shared/Web3ModalProvider';
...@@ -20,6 +22,7 @@ interface Props { ...@@ -20,6 +22,7 @@ interface Props {
const AddressVerificationModal = ({ isOpen, onClose }: Props) => { const AddressVerificationModal = ({ isOpen, onClose }: Props) => {
const [ stepIndex, setStepIndex ] = React.useState(0); const [ stepIndex, setStepIndex ] = React.useState(0);
const [ error, setError ] = React.useState('');
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
const formApi = useForm<AddressVerificationFormFields>({ const formApi = useForm<AddressVerificationFormFields>({
...@@ -31,12 +34,20 @@ const AddressVerificationModal = ({ isOpen, onClose }: Props) => { ...@@ -31,12 +34,20 @@ const AddressVerificationModal = ({ isOpen, onClose }: Props) => {
setStepIndex((prev) => prev + 1); setStepIndex((prev) => prev + 1);
}, []); }, []);
const handleGoToPrevStep = React.useCallback(() => {
setStepIndex((prev) => prev - 1);
}, []);
const handleClose = React.useCallback(() => { const handleClose = React.useCallback(() => {
onClose(); onClose();
setStepIndex(0); setStepIndex(0);
formApi.reset(); formApi.reset();
}, [ formApi, onClose ]); }, [ formApi, onClose ]);
const handleSignClick = React.useCallback(() => {
setError('');
}, []);
const onFormSubmit: SubmitHandler<AddressVerificationFormFields> = React.useCallback(async(data) => { const onFormSubmit: SubmitHandler<AddressVerificationFormFields> = React.useCallback(async(data) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('__>__', data); console.log('__>__', data);
...@@ -45,17 +56,23 @@ const AddressVerificationModal = ({ isOpen, onClose }: Props) => { ...@@ -45,17 +56,23 @@ const AddressVerificationModal = ({ isOpen, onClose }: Props) => {
message: data.message, message: data.message,
signature: data.signature, signature: data.signature,
}; };
await apiFetch('address_verification', {
fetchParams: { method: 'POST', body }, try {
pathParams: { chainId: appConfig.network.id }, await apiFetch('address_verification', {
}); fetchParams: { method: 'POST', body },
pathParams: { chainId: appConfig.network.id },
});
} catch (error: unknown) {
const _error = error as ResourceError<{message: string}>;
setError(_error.payload?.message || 'Oops! Something went wrong');
}
}, [ apiFetch ]); }, [ apiFetch ]);
const onSubmit = handleSubmit(onFormSubmit); const onSubmit = handleSubmit(onFormSubmit);
const steps = [ const steps = [
{ title: 'Verify new address ownership', content: <AddressVerificationStepAddress onContinue={ handleGoToNextStep }/> }, { title: 'Verify new address ownership', content: <AddressVerificationStepAddress onContinue={ handleGoToNextStep }/> },
{ title: 'Copy message to sign', content: <AddressVerificationStepSignature onContinue={ handleGoToNextStep } onSubmit={ onSubmit }/> }, { title: 'Sign message', content: <AddressVerificationStepSignature onSubmit={ onSubmit } onSign={ handleSignClick }/> },
{ title: 'Congrats! Address is verified.', content: <AddressVerificationStepSuccess onShowListClick={ handleClose } onAddTokenClick={ handleClose }/> }, { title: 'Congrats! Address is verified.', content: <AddressVerificationStepSuccess onShowListClick={ handleClose } onAddTokenClick={ handleClose }/> },
]; ];
const step = steps[stepIndex]; const step = steps[stepIndex];
...@@ -64,12 +81,20 @@ const AddressVerificationModal = ({ isOpen, onClose }: Props) => { ...@@ -64,12 +81,20 @@ const AddressVerificationModal = ({ isOpen, onClose }: Props) => {
<Modal isOpen={ isOpen } onClose={ handleClose } size={{ base: 'full', lg: 'md' }}> <Modal isOpen={ isOpen } onClose={ handleClose } size={{ base: 'full', lg: 'md' }}>
<ModalOverlay/> <ModalOverlay/>
<ModalContent> <ModalContent>
<ModalHeader fontWeight="500" textStyle="h3" mb={ 6 }>{ step.title }</ModalHeader> <ModalHeader fontWeight="500" textStyle="h3" mb={ 6 }>
{ stepIndex !== 0 && (
<Link mr={ 3 } onClick={ handleGoToPrevStep }>
<Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)" verticalAlign="middle"/>
</Link>
) }
<span>{ step.title }</span>
</ModalHeader>
<ModalCloseButton/> <ModalCloseButton/>
<ModalBody mb={ 0 }> <ModalBody mb={ 0 }>
<Web3ModalProvider> <Web3ModalProvider>
<FormProvider { ...formApi }> <FormProvider { ...formApi }>
<form noValidate onSubmit={ onSubmit }> <form noValidate onSubmit={ onSubmit }>
{ error && <Alert status="warning" mb={ 6 }>{ error }</Alert> }
{ step.content } { step.content }
</form> </form>
</FormProvider> </FormProvider>
......
...@@ -5,7 +5,6 @@ import { Controller, useFormContext } from 'react-hook-form'; ...@@ -5,7 +5,6 @@ import { Controller, useFormContext } from 'react-hook-form';
import type { AddressVerificationFormFields } from '../types'; import type { AddressVerificationFormFields } from '../types';
import appConfig from 'configs/app/config';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import InputPlaceholder from 'ui/shared/InputPlaceholder'; import InputPlaceholder from 'ui/shared/InputPlaceholder';
...@@ -36,7 +35,7 @@ const AddressVerificationFieldMessage = ({ isDisabled }: Props) => { ...@@ -36,7 +35,7 @@ const AddressVerificationFieldMessage = ({ isDisabled }: Props) => {
const address = getValues('address'); const address = getValues('address');
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const defaultValue = `[${ appConfig.host } ${ dayjs().format('YYYY-MM-DD HH:mm:ss') }] I hereby verify that I am the owner/creator of the address ${ address }.`; const defaultValue = `[Blockscout.com] [${ dayjs().format('YYYY-MM-DD HH:mm:ss') }] I, hereby verify that I am the owner/creator of the address [${ address }]`;
return ( return (
<Controller <Controller
......
import { Box, Button, Flex, Link } from '@chakra-ui/react'; import { Alert, Box, Button, Flex, Radio, RadioGroup } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { useFormContext } from 'react-hook-form'; import { useFormContext } from 'react-hook-form';
import { useSignMessage } from 'wagmi'; import { useSignMessage } from 'wagmi';
import type { AddressVerificationFormFields } from '../types'; import type { AddressVerificationFormFields } from '../types';
import useToast from 'lib/hooks/useToast';
import AddressVerificationFieldAddress from '../fields/AddressVerificationFieldAddress';
import AddressVerificationFieldMessage from '../fields/AddressVerificationFieldMessage'; import AddressVerificationFieldMessage from '../fields/AddressVerificationFieldMessage';
import AddressVerificationFieldSignature from '../fields/AddressVerificationFieldSignature'; import AddressVerificationFieldSignature from '../fields/AddressVerificationFieldSignature';
interface Props { interface Props {
onContinue: () => void;
onSubmit: () => void; onSubmit: () => void;
onSign: () => void;
} }
const AddressVerificationStepSignature = ({ onContinue, onSubmit }: Props) => { const AddressVerificationStepSignature = ({ onSubmit, onSign }: Props) => {
const [ isManualSigning, setIsManualSigning ] = React.useState(false); const [ signMethod, setSignMethod ] = React.useState<'wallet' | 'manually'>('wallet');
const [ error, setError ] = React.useState('');
const toast = useToast(); const { getValues, setValue, formState } = useFormContext<AddressVerificationFormFields>();
const { formState, trigger, getValues, setValue } = useFormContext<AddressVerificationFormFields>(); const { signMessage, isLoading: isSigning } = useSignMessage({
const { signMessage } = useSignMessage({
onSuccess: (data) => { onSuccess: (data) => {
setValue('signature', data); setValue('signature', data);
onSubmit(); onSubmit();
}, },
onError: (error) => { onError: (error) => {
toast({ setError((error as Error)?.message || 'Something went wrong');
position: 'top-right',
title: 'Error',
description: (error as Error)?.message || 'Something went wrong',
status: 'error',
variant: 'subtle',
isClosable: true,
});
}, },
}); });
const handleVerifyButtonClick = React.useCallback(() => { const handleSignMethodChange = React.useCallback((value: typeof signMethod) => {
if (!formState.isValid) { setSignMethod(value);
trigger('signature'); setError('');
trigger('message'); }, []);
return;
}
onContinue();
}, [ formState, onContinue, trigger ]);
const handleWeb3SignClick = React.useCallback(() => { const handleWeb3SignClick = React.useCallback(() => {
onSign();
const message = getValues('message'); const message = getValues('message');
signMessage({ message }); signMessage({ message });
}, [ getValues, signMessage ]); }, [ getValues, onSign, signMessage ]);
const handleManualSignClick = React.useCallback(() => { const handleManualSignClick = React.useCallback(() => {
setIsManualSigning(true); onSign();
}, []); onSubmit();
}, [ onSign, onSubmit ]);
const buttons = isManualSigning ? (
<>
<Button size="lg" onClick={ handleVerifyButtonClick }>
Verify ownership
</Button>
<Box>
<span>Contact </span>
<Link>support@blockscout.com</Link>
</Box>
</>
) : (
<>
<Button size="lg" onClick={ handleManualSignClick }>
Sign manually
</Button>
<Button size="lg" onClick={ handleWeb3SignClick }>
Sign via web3 wallet
</Button>
</>
);
return ( return (
<Box> <Box>
{ error && <Alert status="warning" mb={ 6 }>{ error }</Alert> }
<Box mb={ 8 }> <Box mb={ 8 }>
Copy the message below and sign it using the Blockscout sign message provider of your choice. Please select the address to sign and copy the message below and sign it using the Blockscout sign message provider of your choice...
</Box> </Box>
<Flex rowGap={ 5 } flexDir="column"> <Flex rowGap={ 5 } flexDir="column">
<AddressVerificationFieldAddress isDisabled/> <AddressVerificationFieldMessage isDisabled/>
<AddressVerificationFieldMessage isDisabled={ !isManualSigning }/> <RadioGroup onChange={ handleSignMethodChange } value={ signMethod } display="flex" flexDir="column" rowGap={ 4 }>
{ isManualSigning && <AddressVerificationFieldSignature/> } <Radio value="wallet">Sign via Web3 wallet</Radio>
<Radio value="manually">Sign manually</Radio>
</RadioGroup>
{ signMethod === 'manually' && <AddressVerificationFieldSignature/> }
</Flex> </Flex>
<Box mt={ 8 }>
<span>{ `Check our article on "` }</span>
<Link>How to sign message?</Link>
<span>{ `" if you have not done before.` }</span>
</Box>
<Flex alignItems="center" mt={ 8 } columnGap={ 5 }> <Flex alignItems="center" mt={ 8 } columnGap={ 5 }>
{ buttons } <Button
size="lg"
onClick={ signMethod === 'manually' ? handleManualSignClick : handleWeb3SignClick }
isLoading={ formState.isSubmitting || isSigning }
loadingText={ isSigning ? 'Signing' : 'Verifying' }
>
{ signMethod === 'manually' ? 'Verify' : 'Sign and verify' }
</Button>
</Flex> </Flex>
</Box> </Box>
); );
......
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