Commit 0499c291 authored by tom's avatar tom

group submit result data

parent d44c84a0
...@@ -15,9 +15,7 @@ type Screen = 'form' | 'result' | 'initializing' | 'error'; ...@@ -15,9 +15,7 @@ type Screen = 'form' | 'result' | 'initializing' | 'error';
const PublicTagsSubmit = () => { const PublicTagsSubmit = () => {
const [ screen, setScreen ] = React.useState<Screen>('result'); const [ screen, setScreen ] = React.useState<Screen>('result');
const [ submitResult, setSubmitResult ] = React.useState<FormSubmitResult>([ const [ submitResult, setSubmitResult ] = React.useState<FormSubmitResult>(mocks.allSuccessResponses);
mocks.item1,
]);
const configQuery = useApiQuery('address_metadata_tag_types'); const configQuery = useApiQuery('address_metadata_tag_types');
......
...@@ -10,14 +10,16 @@ import LinkExternal from 'ui/shared/LinkExternal'; ...@@ -10,14 +10,16 @@ import LinkExternal from 'ui/shared/LinkExternal';
import PublicTagsSubmitResultSuccess from './result/PublicTagsSubmitResultSuccess'; import PublicTagsSubmitResultSuccess from './result/PublicTagsSubmitResultSuccess';
import PublicTagsSubmitResultWithErrors from './result/PublicTagsSubmitResultWithErrors'; import PublicTagsSubmitResultWithErrors from './result/PublicTagsSubmitResultWithErrors';
import { groupSubmitResult } from './utils';
interface Props { interface Props {
data: FormSubmitResult; data: FormSubmitResult;
} }
const PublicTagsSubmitResult = ({ data }: Props) => { const PublicTagsSubmitResult = ({ data }: Props) => {
const hasErrors = data.some((item) => item.error !== null); const groupedData = React.useMemo(() => groupSubmitResult(data), [ data ]);
const companyWebsite = makePrettyLink(data[0].payload.companyWebsite); const hasErrors = groupedData.items.length > 0 && groupedData.items[0].error !== null;
const companyWebsite = makePrettyLink(groupedData.companyWebsite);
return ( return (
<div> <div>
...@@ -30,13 +32,13 @@ const PublicTagsSubmitResult = ({ data }: Props) => { ...@@ -30,13 +32,13 @@ const PublicTagsSubmitResult = ({ data }: Props) => {
<Box as="h2" textStyle="h4">Company info</Box> <Box as="h2" textStyle="h4">Company info</Box>
<Grid rowGap={ 3 } columnGap={ 6 } gridTemplateColumns="170px 1fr" mt={ 6 }> <Grid rowGap={ 3 } columnGap={ 6 } gridTemplateColumns="170px 1fr" mt={ 6 }>
<GridItem>Your name</GridItem> <GridItem>Your name</GridItem>
<GridItem>{ data[0].payload.requesterName }</GridItem> <GridItem>{ groupedData.requesterName }</GridItem>
<GridItem>Email</GridItem> <GridItem>Email</GridItem>
<GridItem>{ data[0].payload.requesterEmail }</GridItem> <GridItem>{ groupedData.requesterEmail }</GridItem>
{ data[0].payload.companyName && ( { groupedData.companyName && (
<> <>
<GridItem>Company name</GridItem> <GridItem>Company name</GridItem>
<GridItem>{ data[0].payload.companyName }</GridItem> <GridItem>{ groupedData.companyName }</GridItem>
</> </>
) } ) }
{ companyWebsite && ( { companyWebsite && (
...@@ -50,7 +52,7 @@ const PublicTagsSubmitResult = ({ data }: Props) => { ...@@ -50,7 +52,7 @@ const PublicTagsSubmitResult = ({ data }: Props) => {
</Grid> </Grid>
<Box as="h2" textStyle="h4" mt={ 8 } mb={ 5 }>Public tags/labels</Box> <Box as="h2" textStyle="h4" mt={ 8 } mb={ 5 }>Public tags/labels</Box>
{ hasErrors ? <PublicTagsSubmitResultWithErrors data={ data }/> : <PublicTagsSubmitResultSuccess data={ data }/> } { hasErrors ? <PublicTagsSubmitResultWithErrors data={ data }/> : <PublicTagsSubmitResultSuccess data={ groupedData }/> }
<Button size="lg" mt={ 8 } as="a" href={ route({ pathname: '/public-tags/submit' }) }>Add new tag</Button> <Button size="lg" mt={ 8 } as="a" href={ route({ pathname: '/public-tags/submit' }) }>Add new tag</Button>
</div> </div>
......
import type { FormSubmitResultItem } from './types'; import type { FormSubmitResultItem } from './types';
export const item1: FormSubmitResultItem = { const address1 = '0xd789a607CEac2f0E14867de4EB15b15C9FFB5859';
error: null, const address2 = '0xd789a607CEac2f0E14867de4EB15b15C9FFB5858';
payload: { const address3 = '0xd789a607CEac2f0E14867de4EB15b15C9FFB5857';
addresses: [ const address4 = '0xd789a607CEac2f0E14867de4EB15b15C9FFB5856';
{ hash: '0xa8FCe579a11E551635b9c9CB915BEcd873C51254' }, const address5 = '0xd789a607CEac2f0E14867de4EB15b15C9FFB5855';
{ hash: '0xa8FCe579a11E551635b9c9CB915BEcd873C51255' },
{ hash: '0xa8FCe579a11E551635b9c9CB915BEcd873C51256' }, const responseBaseFields = {
{ hash: '0xa8FCe579a11E551635b9c9CB915BEcd873C51257' }, requesterName: 'John Doe',
], requesterEmail: 'jonh.doe@duck.me',
tags: [ companyName: 'DuckDuckMe',
{ companyWebsite: 'https://duck.me',
name: 'hello', description: 'Quack quack',
type: { label: 'name', value: 'name' }, };
url: 'https://ohhhh.me',
tooltipDescription: 'hello again', const tag1 = {
bgColor: 'add', name: 'Unicorn Uproar',
textColor: '00aa11', tagType: 'name' as const,
}, meta: {
{ tagUrl: 'https://example.com',
name: 'hello it is me.. i was wondering if after all these years you would like to meet', bgColor: '#ff1493',
type: { label: 'generic', value: 'generic' }, textColor: '#FFFFFF',
url: undefined, tooltipDescription: undefined,
tooltipDescription: undefined, },
bgColor: undefined, };
textColor: undefined,
}, const tag2 = {
], name: 'Hello',
requesterName: 'tommasdf jalskdfj asdflkjkas lasdfkj ', tagType: 'generic' as const,
requesterEmail: 'tom@ohhhh.me', meta: {
companyName: 'OHHHH', tooltipDescription: 'Hello, it is me... I was wondering if after all these years you would like to meet',
companyWebsite: 'https://ohhhh.me',
description: 'chao',
reCaptcha: 'xxxx',
}, },
}; };
const tag3 = {
name: 'duck owner 🦆',
tagType: 'classifier' as const,
meta: {
bgColor: '#fff300',
},
};
export const allSuccessResponses: Array<FormSubmitResultItem> = [
address1,
address2,
address3,
address4,
address5,
]
.map((address) => ([ tag1, tag2, tag3 ].map((tag) => ({
error: null,
payload: {
...responseBaseFields,
...tag,
address,
},
}))))
.flat();
import { Box, Flex, Grid, GridItem } from '@chakra-ui/react'; import { Box, Flex, Grid, GridItem } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { FormSubmitResult } from '../types'; import type { FormSubmitResultGrouped } from '../types';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import EntityTag from 'ui/shared/EntityTags/EntityTag'; import EntityTag from 'ui/shared/EntityTags/EntityTag';
interface Props { interface Props {
data: FormSubmitResult; data: FormSubmitResultGrouped;
} }
const PublicTagsSubmitResultSuccess = (props: Props) => { const PublicTagsSubmitResultSuccess = ({ data }: Props) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
return ( return (
...@@ -19,32 +19,32 @@ const PublicTagsSubmitResultSuccess = (props: Props) => { ...@@ -19,32 +19,32 @@ const PublicTagsSubmitResultSuccess = (props: Props) => {
<GridItem> <GridItem>
<Box fontSize="sm" color="text_secondary" fontWeight={ 500 }>Smart contract / Address (0x...)</Box> <Box fontSize="sm" color="text_secondary" fontWeight={ 500 }>Smart contract / Address (0x...)</Box>
<Flex flexDir="column" rowGap={ 3 } mt={ 2 }> <Flex flexDir="column" rowGap={ 3 } mt={ 2 }>
{ props.data { data.items
.map((item) => item.payload.addresses) .map(({ addresses }) => addresses)
.flat() .flat()
.map((item) => <AddressEntity key={ item.hash } address={ item } noIcon truncation={ isMobile ? 'constant' : 'dynamic' }/>) } .map((hash) => (
<AddressEntity
key={ hash }
address={{ hash }}
noIcon
truncation={ isMobile ? 'constant' : 'dynamic' }
/>
)) }
</Flex> </Flex>
</GridItem> </GridItem>
<GridItem> <GridItem>
<Box fontSize="sm" color="text_secondary" fontWeight={ 500 }>Tag</Box> <Box fontSize="sm" color="text_secondary" fontWeight={ 500 }>Tag</Box>
<Flex rowGap={ 2 } columnGap={ 2 } mt={ 2 } justifyContent="flex-start" flexWrap="wrap"> <Flex rowGap={ 2 } columnGap={ 2 } mt={ 2 } justifyContent="flex-start" flexWrap="wrap">
{ props.data { data.items
.map((item) => item.payload.tags) .map(({ tags }) => tags)
.flat() .flat()
.map((item) => ( .map((tag) => (
<EntityTag <EntityTag
key={ item.name } key={ tag.name }
truncate truncate
data={{ data={{
name: item.name, ...tag,
tagType: item.type.value, slug: '',
meta: {
bgColor: item.bgColor ? `#${ item.bgColor }` : undefined,
textColor: item.textColor ? `#${ item.textColor }` : undefined,
tooltipDescription: item.tooltipDescription,
tagUrl: item.url,
},
slug: item.name,
ordinal: 0, ordinal: 0,
}}/> }}/>
)) } )) }
......
...@@ -23,9 +23,40 @@ export interface FormFieldTag { ...@@ -23,9 +23,40 @@ export interface FormFieldTag {
tooltipDescription: string | undefined; tooltipDescription: string | undefined;
} }
export interface SubmitRequestBody {
requesterName: string;
requesterEmail: string;
companyName?: string;
companyWebsite?: string;
address: string;
name: string;
tagType: AddressMetadataTagType;
description?: string;
meta: {
bgColor?: string;
textColor?: string;
tagUrl?: string;
tooltipDescription?: string;
};
}
export interface FormSubmitResultItem { export interface FormSubmitResultItem {
error: unknown | null; error: string | null;
payload: FormFields; payload: SubmitRequestBody;
} }
export type FormSubmitResult = Array<FormSubmitResultItem>; export type FormSubmitResult = Array<FormSubmitResultItem>;
export interface FormSubmitResultGrouped {
requesterName: string;
requesterEmail: string;
companyName?: string;
companyWebsite?: string;
items: Array<FormSubmitResultItemGrouped>;
}
export interface FormSubmitResultItemGrouped {
error: string | null;
addresses: Array<string>;
tags: Array<Pick<SubmitRequestBody, 'name' | 'tagType' | 'meta'>>;
}
import type { FormSubmitResult, FormSubmitResultGrouped, FormSubmitResultItemGrouped } from './types';
const tagIdentity = (tag: FormSubmitResultItemGrouped['tags'][number]) => tag.name + ':' + tag.tagType;
export function groupSubmitResult(data: FormSubmitResult): FormSubmitResultGrouped {
const _items: Array<FormSubmitResultItemGrouped> = [];
// group by error and address
for (const item of data) {
const existingItem = _items.find(({ error, addresses }) => error === item.error && addresses.length === 1 && addresses[0] === item.payload.address);
if (existingItem) {
existingItem.tags.push({ name: item.payload.name, tagType: item.payload.tagType, meta: item.payload.meta });
continue;
}
_items.push({
error: item.error,
addresses: [ item.payload.address ],
tags: [ { name: item.payload.name, tagType: item.payload.tagType, meta: item.payload.meta } ],
});
}
const items: Array<FormSubmitResultItemGrouped> = [];
// merge items with the same error and tags
for (const item of _items) {
const existingItem = items.find(({ error, tags }) => error === item.error &&
tags.length === item.tags.length && tags.every(tagIdentity),
);
if (existingItem) {
existingItem.addresses.push(...item.addresses);
continue;
}
items.push(item);
}
return {
requesterName: data[0].payload.requesterName,
requesterEmail: data[0].payload.requesterEmail,
companyName: data[0].payload.companyName,
companyWebsite: data[0].payload.companyWebsite,
items,
};
}
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