Commit ce6b8be1 authored by tom's avatar tom

file errors

parent ba13aab9
import { Text, Button, Box, chakra, Flex } from '@chakra-ui/react';
import React from 'react';
import type { ControllerRenderProps } from 'react-hook-form';
import type { ControllerRenderProps, FieldPathValue, ValidateResult } from 'react-hook-form';
import { Controller, useFormContext } from 'react-hook-form';
import type { FormFields } from '../types';
import DragAndDropArea from 'ui/shared/forms/DragAndDropArea';
import FieldError from 'ui/shared/forms/FieldError';
import FileInput from 'ui/shared/forms/FileInput';
import FileSnippet from 'ui/shared/forms/FileSnippet';
import ContractVerificationFormRow from '../ContractVerificationFormRow';
type FileTypes = '.sol' | '.yul' | '.json' | '.vy'
interface Props {
accept?: string;
fileTypes: Array<FileTypes>;
multiple?: boolean;
title: string;
className?: string;
hint: string;
}
const ContractVerificationFieldSources = ({ accept, multiple, title, className, hint }: Props) => {
const ContractVerificationFieldSources = ({ fileTypes, multiple, title, className, hint }: Props) => {
const { setValue, getValues, control, formState, clearErrors } = useFormContext<FormFields>();
const error = 'sources' in formState.errors ? formState.errors.sources : undefined;
const commonError = !error?.type?.startsWith('file_') ? error : undefined;
const fileError = error?.type?.startsWith('file_') ? error : undefined;
const handleFileRemove = React.useCallback((index?: number) => {
if (index === undefined) {
......@@ -37,25 +42,29 @@ const ContractVerificationFieldSources = ({ accept, multiple, title, className,
}, [ getValues, clearErrors, setValue ]);
const renderFiles = React.useCallback((files: Array<File>) => {
const errorList = fileError?.message?.split(';');
return (
<Box display="grid" gridTemplateColumns={{ base: '1fr', lg: '1fr 1fr' }} columnGap={ 3 } rowGap={ 3 }>
{ files.map((file, index) => (
<Box key={ file.name + file.lastModified + index }>
<FileSnippet
key={ file.name + file.lastModified + index }
file={ file }
maxW="initial"
onRemove={ handleFileRemove }
index={ index }
isDisabled={ formState.isSubmitting }
/>
{ errorList?.[index] && <FieldError message={ errorList?.[index] } mt={ 1 } px={ 3 }/> }
</Box>
)) }
</Box>
);
}, [ formState.isSubmitting, handleFileRemove ]);
}, [ formState.isSubmitting, handleFileRemove, fileError ]);
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<FormFields, 'sources'>}) => (
<>
<FileInput<FormFields, 'sources'> accept={ accept } multiple={ multiple } field={ field }>
<FileInput<FormFields, 'sources'> accept={ fileTypes.join(',') } multiple={ multiple } field={ field }>
{ ({ onChange }) => (
<Flex
flexDir="column"
......@@ -77,13 +86,38 @@ const ContractVerificationFieldSources = ({ accept, multiple, title, className,
) }
</FileInput>
{ field.value && field.value.length > 0 && renderFiles(field.value) }
{ error && (
<Box fontSize="sm" mt={ 2 } color="error">
{ error.type === 'required' ? 'Field is required' : error.message }
</Box>
) }
{ commonError?.message && <FieldError message={ commonError.type === 'required' ? 'Field is required' : commonError.message }/> }
</>
), [ accept, error, multiple, renderFiles ]);
), [ fileTypes, commonError, multiple, renderFiles ]);
const validateFileType = React.useCallback(async(value: FieldPathValue<FormFields, 'sources'>): Promise<ValidateResult> => {
if (Array.isArray(value)) {
const errors = value.map(({ name }) => fileTypes.some((ext) => name.endsWith(ext)) ? '' : 'Wrong file type');
if (errors.some((item) => item !== '')) {
return errors.join(';');
}
}
return true;
}, [ fileTypes ]);
const validateFileSize = React.useCallback(async(value: FieldPathValue<FormFields, 'sources'>): Promise<ValidateResult> => {
if (Array.isArray(value)) {
const FILE_SIZE_LIMIT = 260;
const errors = value.map(({ size }) => size > FILE_SIZE_LIMIT ? 'File is too big' : '');
if (errors.some((item) => item !== '')) {
return errors.join(';');
}
}
return true;
}, []);
const rules = React.useMemo(() => ({
required: true,
validate: {
file_type: validateFileType,
file_size: validateFileSize,
},
}), [ validateFileSize, validateFileType ]);
return (
<>
......@@ -95,7 +129,7 @@ const ContractVerificationFieldSources = ({ accept, multiple, title, className,
name="sources"
control={ control }
render={ renderControl }
rules={{ required: true }}
rules={ rules }
/>
{ hint ? <span>{ hint }</span> : null }
</ContractVerificationFormRow>
......
......@@ -7,6 +7,8 @@ import ContractVerificationFieldLibraries from '../fields/ContractVerificationFi
import ContractVerificationFieldOptimization from '../fields/ContractVerificationFieldOptimization';
import ContractVerificationFieldSources from '../fields/ContractVerificationFieldSources';
const FILE_TYPES = [ '.sol' as const, '.yul' as const ];
const ContractVerificationMultiPartFile = () => {
return (
<ContractVerificationMethod title="New Solidity/Yul Smart Contract Verification">
......@@ -14,7 +16,7 @@ const ContractVerificationMultiPartFile = () => {
<ContractVerificationFieldEvmVersion/>
<ContractVerificationFieldOptimization/>
<ContractVerificationFieldSources
accept=".sol,.yul"
fileTypes={ FILE_TYPES }
multiple
title="Sources *.sol or *.yul files"
hint="Upload all Solidity or Yul contract source files."
......
......@@ -3,11 +3,13 @@ import React from 'react';
import ContractVerificationMethod from '../ContractVerificationMethod';
import ContractVerificationFieldSources from '../fields/ContractVerificationFieldSources';
const FILE_TYPES = [ '.json' as const ];
const ContractVerificationSourcify = () => {
return (
<ContractVerificationMethod title="New Smart Contract Verification">
<ContractVerificationFieldSources
accept=".json"
fileTypes={ FILE_TYPES }
multiple
title="Sources and Metadata JSON" mt={ 0 }
hint="Upload all Solidity contract source files and JSON metadata file(s) created during contract compilation."
......
......@@ -6,13 +6,15 @@ import ContractVerificationFieldCompiler from '../fields/ContractVerificationFie
import ContractVerificationFieldName from '../fields/ContractVerificationFieldName';
import ContractVerificationFieldSources from '../fields/ContractVerificationFieldSources';
const FILE_TYPES = [ '.json' as const ];
const ContractVerificationStandardInput = () => {
return (
<ContractVerificationMethod title="New Smart Contract Verification">
<ContractVerificationFieldName/>
<ContractVerificationFieldCompiler/>
<ContractVerificationFieldSources
accept=".json"
fileTypes={ FILE_TYPES }
title="Standard Input JSON"
hint="Upload the standard input JSON file created during contract compilation."
/>
......
......@@ -5,13 +5,15 @@ import ContractVerificationFieldCompiler from '../fields/ContractVerificationFie
import ContractVerificationFieldEvmVersion from '../fields/ContractVerificationFieldEvmVersion';
import ContractVerificationFieldSources from '../fields/ContractVerificationFieldSources';
const FILE_TYPES = [ '.vy' as const ];
const ContractVerificationVyperMultiPartFile = () => {
return (
<ContractVerificationMethod title="New Vyper Smart Contract Verification">
<ContractVerificationFieldCompiler isVyper/>
<ContractVerificationFieldEvmVersion isVyper/>
<ContractVerificationFieldSources
accept=".vy"
fileTypes={ FILE_TYPES }
multiple
title="Sources *.vy files"
hint="Upload all Vyper contract source files."
......
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