Commit efbff6e4 authored by tom's avatar tom

tag name, url and description

parent b9ea29b6
......@@ -31,7 +31,7 @@ export interface AddressMetadataTagApi extends Omit<AddressMetadataTag, 'meta'>
// TAG SUBMISSION
interface PublicTagType {
export interface PublicTagType {
id: string;
type: AddressMetadataTagType;
description: string;
......
......@@ -12,6 +12,7 @@ import PublicTagsSubmitFieldAddresses from './fields/PublicTagsSubmitFieldAddres
import PublicTagsSubmitFieldDescription from './fields/PublicTagsSubmitFieldDescription';
import PublicTagsSubmitFieldRequesterEmail from './fields/PublicTagsSubmitFieldRequesterEmail';
import PublicTagsSubmitFieldRequesterName from './fields/PublicTagsSubmitFieldRequesterName';
import PublicTagsSubmitFieldTags from './fields/PublicTagsSubmitFieldTags';
interface Props {
config: PublicTagTypesResponse | undefined;
......@@ -22,6 +23,7 @@ const PublicTagsSubmitForm = ({ config }: Props) => {
mode: 'onBlur',
defaultValues: {
addresses: [ { hash: '' } ],
tags: [ { name: '', type: 'name', url: undefined, bgColor: undefined, textColor: undefined } ],
},
});
......@@ -56,10 +58,7 @@ const PublicTagsSubmitForm = ({ config }: Props) => {
<Hint label="Submit a public tag proposal for our moderation team to review" ml={ 1 } color="link"/>
</GridItem>
<PublicTagsSubmitFieldAddresses/>
<chakra.div bgColor="blue.100" h={ 20 }/>
<chakra.div bgColor="blue.100" h={ 20 }/>
<chakra.div bgColor="yellow.100" h={ 20 }/>
<PublicTagsSubmitFieldTags tagTypes={ config?.tagTypes }/>
<GridItem colSpan={{ base: 1, lg: 2 }}>
<PublicTagsSubmitFieldDescription/>
</GridItem>
......
......@@ -8,7 +8,7 @@ import { ADDRESS_REGEXP } from 'lib/validations/address';
import IconSvg from 'ui/shared/IconSvg';
import InputPlaceholder from 'ui/shared/InputPlaceholder';
const LIMIT = 10;
const LIMIT = 20;
const PublicTagsSubmitFieldAddresses = () => {
const { control, formState, register } = useFormContext<FormFields>();
......@@ -51,14 +51,13 @@ const PublicTagsSubmitFieldAddresses = () => {
<InputPlaceholder text="Smart contract / Address (0x...)" error={ error }/>
</FormControl>
</GridItem>
<GridItem display="flex" alignItems="center" columnGap={ 5 }>
<GridItem display="flex" alignItems="center" columnGap={ 5 } justifyContent={{ base: 'flex-end', lg: 'flex-start' }}>
{ fields.length < LIMIT && !(fields.length > 1 && index === 0) && (
<IconButton
aria-label="add"
data-index={ index }
variant="outline"
w="30px"
h="30px"
boxSize="30px"
onClick={ handleAddFieldClick }
icon={ <IconSvg name="plus" boxSize={ 5 }/> }
isDisabled={ isDisabled }
......@@ -69,8 +68,7 @@ const PublicTagsSubmitFieldAddresses = () => {
aria-label="delete"
data-index={ index }
variant="outline"
w="30px"
h="30px"
boxSize="30px"
onClick={ handleRemoveFieldClick }
icon={ <IconSvg name="minus" boxSize={ 5 }/> }
isDisabled={ isDisabled }
......
import { chakra, Flex, FormControl, Grid, GridItem, IconButton, Input, Textarea, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import type { FieldError, FieldErrorsImpl, Merge, UseFormRegister } from 'react-hook-form';
import type { FormFields, FormFieldTag } from '../types';
import type { PublicTagType } from 'types/api/addressMetadata';
import useIsMobile from 'lib/hooks/useIsMobile';
import { validator as urlValidator } from 'lib/validations/url';
import FancySelect from 'ui/shared/FancySelect/FancySelect';
import IconSvg from 'ui/shared/IconSvg';
import InputPlaceholder from 'ui/shared/InputPlaceholder';
interface Props {
index: number;
tagTypes: Array<PublicTagType> | undefined;
register: UseFormRegister<FormFields>;
errors: Merge<FieldError, FieldErrorsImpl<FormFieldTag>> | undefined;
isDisabled: boolean;
onAddClick?: (index: number) => void;
onRemoveClick?: (index: number) => void;
}
const PublicTagsSubmitFieldTag = ({ index, isDisabled, register, errors, onAddClick, onRemoveClick, tagTypes }: Props) => {
const isMobile = useIsMobile();
const bgColorDefault = useColorModeValue('blackAlpha.50', 'whiteAlpha.100');
const inputBgColor = useColorModeValue('white', 'gray.900');
const handleAddClick = React.useCallback(() => {
onAddClick?.(index);
}, [ index, onAddClick ]);
const handleRemoveClick = React.useCallback(() => {
onRemoveClick?.(index);
}, [ index, onRemoveClick ]);
const typeOptions = React.useMemo(() => tagTypes?.map((type) => ({
value: type.type,
label: type.type,
})), [ tagTypes ]);
return (
<>
<GridItem colSpan={{ base: 1, lg: 2 }} p="10px" borderRadius="base" bgColor={ bgColorDefault }>
<Grid
rowGap={ 2 }
columnGap={ 2 }
templateColumns={{ base: '1fr', lg: 'repeat(4, 1fr)' }}
>
<GridItem colSpan={{ base: 1, lg: 2 }}>
<FormControl variant="floating" isRequired size={{ base: 'md', lg: 'lg' }}>
<Input
{ ...register(`tags.${ index }.name`, { required: true, maxLength: 35 }) }
isInvalid={ Boolean(errors?.name) }
isDisabled={ isDisabled }
autoComplete="off"
bgColor={ inputBgColor }
/>
<InputPlaceholder text="Tag (max 35 characters)" error={ errors?.name }/>
</FormControl>
</GridItem>
<GridItem colSpan={{ base: 1, lg: 2 }}>
<FancySelect
{ ...register(`tags.${ index }.type`) }
options={ typeOptions }
size={ isMobile ? 'md' : 'lg' }
placeholder="Tag type"
isDisabled={ isDisabled }
isRequired
isAsync={ false }
bgColor={ inputBgColor }
/>
</GridItem>
<GridItem colSpan={{ base: 1, lg: 2 }}>
<FormControl variant="floating" size={{ base: 'md', lg: 'lg' }}>
<Input
{ ...register(`tags.${ index }.url`, { validate: urlValidator }) }
isInvalid={ Boolean(errors?.url) }
isDisabled={ isDisabled }
autoComplete="off"
bgColor={ inputBgColor }
/>
<InputPlaceholder text="Label URL" error={ errors?.url }/>
</FormControl>
</GridItem>
<chakra.div bgColor="blue.100" h={ 20 }/>
<chakra.div bgColor="blue.100" h={ 20 }/>
<GridItem colSpan={{ base: 1, lg: 4 }}>
<FormControl variant="floating" size={{ base: 'md', lg: 'lg' }}>
<Textarea
{ ...register(`tags.${ index }.tooltipDescription`, { maxLength: 80 }) }
isInvalid={ Boolean(errors?.tooltipDescription) }
isDisabled={ isDisabled }
autoComplete="off"
bgColor={ inputBgColor }
maxH="160px"
/>
<InputPlaceholder text="Label description - any text to be shown on label hover (max 80 characters)" error={ errors?.tooltipDescription }/>
</FormControl>
</GridItem>
</Grid>
</GridItem>
<GridItem py={{ lg: '10px' }}>
<Flex
alignItems="center"
columnGap={ 5 }
justifyContent={{ base: 'flex-end', lg: 'flex-start' }}
h={{ base: 'auto', lg: '80px' }}
>
{ onAddClick && (
<IconButton
aria-label="add"
data-index={ index }
variant="outline"
boxSize="30px"
onClick={ handleAddClick }
icon={ <IconSvg name="plus" boxSize={ 5 }/> }
isDisabled={ isDisabled }
/>
) }
{ onRemoveClick && (
<IconButton
aria-label="delete"
data-index={ index }
variant="outline"
boxSize="30px"
onClick={ handleRemoveClick }
icon={ <IconSvg name="minus" boxSize={ 5 }/> }
isDisabled={ isDisabled }
/>
) }
</Flex>
{ !isMobile && <chakra.div bgColor="yellow.100" h={ 40 } mt="10px"/> }
</GridItem>
</>
);
};
export default React.memo(PublicTagsSubmitFieldTag);
import React from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import type { FormFields } from '../types';
import type { PublicTagType } from 'types/api/addressMetadata';
import PublicTagsSubmitFieldTag from './PublicTagsSubmitFieldTag';
const LIMIT = 5;
interface Props {
tagTypes: Array<PublicTagType> | undefined;
}
const PublicTagsSubmitFieldTags = ({ tagTypes }: Props) => {
const { control, formState, register } = useFormContext<FormFields>();
const { fields, insert, remove } = useFieldArray<FormFields, 'tags'>({
name: 'tags',
control,
});
const isDisabled = formState.isSubmitting;
const handleAddFieldClick = React.useCallback((index: number) => {
insert(index + 1, { name: '', type: 'name', url: undefined, bgColor: undefined, textColor: undefined, tooltipDescription: undefined });
}, [ insert ]);
const handleRemoveFieldClick = React.useCallback((index: number) => {
remove(index);
}, [ remove ]);
return (
<>
{ fields.map((field, index) => {
const errors = formState.errors?.tags?.[ index ];
return (
<PublicTagsSubmitFieldTag
key={ field.id }
index={ index }
tagTypes={ tagTypes }
register={ register }
errors={ errors }
isDisabled={ isDisabled }
onAddClick={ fields.length < LIMIT && !(fields.length > 1 && index === 0) ? handleAddFieldClick : undefined }
onRemoveClick={ fields.length > 1 ? handleRemoveFieldClick : undefined }
/>
);
}) }
</>
);
};
export default React.memo(PublicTagsSubmitFieldTags);
import type { AddressMetadataTagType } from 'types/api/addressMetadata';
export interface FormFields {
requesterName: string;
requesterEmail: string;
addresses: Array<{ hash: string }>;
tags: Array<FormFieldTag>;
description: string;
}
export interface FormFieldTag {
name: string;
type: AddressMetadataTagType;
url: string | undefined;
bgColor: string | undefined;
textColor: string | undefined;
tooltipDescription: string | undefined;
}
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