Commit 37c411a6 authored by tom's avatar tom

array value type and refactor

parent 01232014
import { Accordion } from '@chakra-ui/react'; import { Accordion } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import MetadataAccordionItem from './MetadataAccordionItem'; import MetadataItemArray from './MetadataItemArray';
import MetadataItemObject from './MetadataItemObject';
import MetadataItemPrimitive from './MetadataItemPrimitive';
interface Props { interface Props {
data: Record<string, unknown>; data: Record<string, unknown>;
...@@ -22,10 +24,38 @@ const MetadataAccordion = ({ data, level = 0 }: Props) => { ...@@ -22,10 +24,38 @@ const MetadataAccordion = ({ data, level = 0 }: Props) => {
return 24; return 24;
})(); })();
const renderItem = React.useCallback((name: string, value: unknown) => {
switch (typeof value) {
case 'string':
case 'number':
case 'boolean': {
return <MetadataItemPrimitive name={ name } value={ value }/>;
}
case 'object': {
if (value === null) {
return <MetadataItemPrimitive name={ name } value={ value }/>;
}
if (Array.isArray(value) && value.length > 0) {
return <MetadataItemArray name={ name } value={ value }/>;
}
if (Object.keys(value).length > 0) {
return <MetadataItemObject name={ name } value={ value as Record<string, unknown> } level={ level }/>;
}
}
// eslint-disable-next-line no-fallthrough
default: {
return <MetadataItemPrimitive name={ name } value={ String(value) }/>;
}
}
}, [ level ]);
return ( return (
<Accordion allowMultiple fontSize="sm" ml={ `${ ml }px` } defaultIndex={ level === 0 ? [ 0 ] : undefined }> <Accordion allowMultiple fontSize="sm" ml={ `${ ml }px` } defaultIndex={ level === 0 ? [ 0 ] : undefined }>
{ Object.entries(data).map(([ key, value ]) => { { Object.entries(data).map(([ key, value ]) => {
return <MetadataAccordionItem key={ key } name={ key } value={ value } level={ level }/>; return renderItem(key, value);
}) } }) }
</Accordion> </Accordion>
); );
......
import type { ChakraProps } from '@chakra-ui/react'; import { AccordionItem, chakra } from '@chakra-ui/react';
import { Box, AccordionItem, AccordionIcon, AccordionPanel, AccordionButton } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import LinkExternal from 'ui/shared/LinkExternal';
import MetadataAccordion from './MetadataAccordion';
import { formatName } from './utils';
interface Props { interface Props {
name: string; children: React.ReactNode;
value: unknown; level?: number;
level: number; className?: string;
} }
const MetadataAccordionItem = ({ name, value, level }: Props) => { const MetadataAccordionItem = ({ children, className, level }: Props) => {
const title = <Box w="90px" flexShrink={ 0 } fontWeight={ 600 } wordBreak="break-word">{ formatName(name) }</Box>;
const commonProps: ChakraProps = {
display: 'flex',
alignItems: 'flex-start',
py: 2,
pl: { base: 0, lg: 6 },
columnGap: 3,
borderTopWidth: '1px',
borderColor: 'divider',
wordBreak: 'break-all',
_last: {
borderBottomWidth: level === 0 ? '1px' : '0px',
},
_first: {
borderTopWidth: level === 0 ? '1px' : '0px',
},
};
switch (typeof value) {
case 'string': {
try {
if (!value.includes('http')) {
throw new Error();
}
const url = new URL(value);
return (
<AccordionItem { ...commonProps }>
{ title }
<LinkExternal href={ url.toString() }>{ value }</LinkExternal>
</AccordionItem>
);
} catch (error) {
return (
<AccordionItem { ...commonProps }>
{ title }
<Box>{ value }</Box>
</AccordionItem>
);
}
}
case 'number':
case 'boolean': {
return (
<AccordionItem { ...commonProps }>
{ title }
<Box>{ value }</Box>
</AccordionItem>
);
}
case 'object': {
if (!value) {
break;
}
if (Array.isArray(value)) {
break;
}
if (Object.keys(value).length === 0) {
break;
}
if (level >= 4) {
return (
<AccordionItem { ...commonProps }>
{ title }
<Box whiteSpace="pre-wrap">{ JSON.stringify(value, undefined, 2) }</Box>
</AccordionItem>
);
}
return (
<AccordionItem
{ ...commonProps }
flexDir="column"
alignItems="stretch"
pl={ 0 }
py={ 0 }
>
<AccordionButton
px={ 0 }
py={ 2 }
_hover={{ bgColor: 'inherit' }}
fontSize="sm"
textAlign="left"
_expanded={{
borderColor: 'divider',
borderBottomWidth: '1px',
}}
>
<AccordionIcon boxSize={ 6 } p={ 1 }/>
{ title }
</AccordionButton>
<AccordionPanel p={ 0 }>
<MetadataAccordion data={ value as Record<string, unknown> } level={ level + 1 }/>
</AccordionPanel>
</AccordionItem>
);
}
}
return ( return (
<AccordionItem { ...commonProps }> <AccordionItem
{ title } className={ className }
<Box>-</Box> display="flex"
alignItems="flex-start"
py={ 2 }
pl={{ base: 0, lg: 6 }}
columnGap={ 3 }
borderTopWidth="1px"
borderColor="divider"
wordBreak="break-all"
_last={{
borderBottomWidth: level === 0 ? '1px' : '0px',
}}
_first={{
borderTopWidth: level === 0 ? '1px' : '0px',
}}
>
{ children }
</AccordionItem> </AccordionItem>
); );
}; };
export default React.memo(MetadataAccordionItem); export default React.memo(chakra(MetadataAccordionItem));
import { Box, chakra } from '@chakra-ui/react';
import React from 'react';
import { formatName } from './utils';
interface Props {
name: string;
className?: string;
}
const MetadataAccordionItemTitle = ({ name, className }: Props) => {
return (
<Box w="90px" flexShrink={ 0 } fontWeight={ 600 } wordBreak="break-word" className={ className }>
{ formatName(name) }
</Box>
);
};
export default React.memo(chakra(MetadataAccordionItemTitle));
import { AccordionButton, AccordionIcon, AccordionPanel, Box, Flex } from '@chakra-ui/react';
import React from 'react';
import MetadataAccordionItem from './MetadataAccordionItem';
import MetadataAccordionItemTitle from './MetadataAccordionItemTitle';
interface Props {
name: string;
value: Array<unknown>;
}
const MetadataItemArray = ({ name, value }: Props) => {
return (
<MetadataAccordionItem
flexDir="column"
alignItems="stretch"
pl={{ base: 0, lg: 0 }}
py={ 0 }
>
<AccordionButton
px={ 0 }
py={ 2 }
_hover={{ bgColor: 'inherit' }}
fontSize="sm"
textAlign="left"
_expanded={{
borderColor: 'divider',
borderBottomWidth: '1px',
}}
>
<AccordionIcon boxSize={ 6 } p={ 1 }/>
<MetadataAccordionItemTitle name={ name }/>
</AccordionButton>
<AccordionPanel p={ 0 } ml={ 126 }>
{ value.map((item, index) => {
const content = (() => {
switch (typeof item) {
case 'object': {
if (item && !Array.isArray(item)) {
return Object.entries(item).map(([ name, value ], index) => (
<Flex key={ index } columnGap={ 3 }>
<MetadataAccordionItemTitle name={ name } w="70px" fontWeight={ 400 }/>
<Box>{ value }</Box>
</Flex>
));
}
}
// eslint-disable-next-line no-fallthrough
default: {
return <span>{ JSON.stringify(item) }</span>;
}
}
})();
return (
<Flex
key={ index }
py={ 2 }
_notFirst={{ borderColor: 'divider', borderTopWidth: '1px' }}
flexDir="column"
rowGap={ 2 }
>
{ content }
</Flex>
);
}) }
</AccordionPanel>
</MetadataAccordionItem>
);
};
export default React.memo(MetadataItemArray);
import { AccordionButton, AccordionIcon, AccordionPanel, Box } from '@chakra-ui/react';
import React from 'react';
import MetadataAccordion from './MetadataAccordion';
import MetadataAccordionItem from './MetadataAccordionItem';
import MetadataAccordionItemTitle from './MetadataAccordionItemTitle';
interface Props {
name: string;
value: Record<string, unknown>;
level: number;
}
const MetadataItemObject = ({ name, value, level }: Props) => {
if (level >= 4) {
return (
<MetadataAccordionItem level={ level }>
<MetadataAccordionItemTitle name={ name }/>
<Box whiteSpace="pre-wrap">{ JSON.stringify(value, undefined, 2) }</Box>
</MetadataAccordionItem>
);
}
return (
<MetadataAccordionItem
flexDir="column"
alignItems="stretch"
pl={{ base: 0, lg: 0 }}
py={ 0 }
level={ level }
>
<AccordionButton
px={ 0 }
py={ 2 }
_hover={{ bgColor: 'inherit' }}
fontSize="sm"
textAlign="left"
_expanded={{
borderColor: 'divider',
borderBottomWidth: '1px',
}}
>
<AccordionIcon boxSize={ 6 } p={ 1 }/>
<MetadataAccordionItemTitle name={ name }/>
</AccordionButton>
<AccordionPanel p={ 0 }>
<MetadataAccordion data={ value as Record<string, unknown> } level={ level + 1 }/>
</AccordionPanel>
</MetadataAccordionItem>
);
};
export default React.memo(MetadataItemObject);
import React from 'react';
import type { Primitive } from 'react-hook-form';
import LinkExternal from 'ui/shared/LinkExternal';
import MetadataAccordionItem from './MetadataAccordionItem';
import MetadataAccordionItemTitle from './MetadataAccordionItemTitle';
interface Props {
name?: string;
value: Primitive;
}
const MetadataItemPrimitive = ({ name, value }: Props) => {
const content = (() => {
switch (typeof value) {
case 'string': {
try {
if (!value.includes('http')) {
throw new Error();
}
const url = new URL(value);
return <LinkExternal href={ url.toString() }>{ value }</LinkExternal>;
} catch (error) {}
}
// eslint-disable-next-line no-fallthrough
default: {
return <div>{ String(value) }</div>;
}
}
})();
return (
<MetadataAccordionItem>
{ name && <MetadataAccordionItemTitle name={ name }/> }
{ content }
</MetadataAccordionItem>
);
};
export default React.memo(MetadataItemPrimitive);
/* eslint-disable max-len */
import type { TokenInstance } from 'types/api/token';
import type { ExcludeNull } from 'types/utils/ExcludeNull';
const data = {
background_color: '000000',
chain: 'MATIC',
chain_address: '0x66edbdb80001da74cbf3e6c01ba91154f6e2fb7c',
name: 'Carmelo Anthony',
total_nfts: 0,
animation_url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/dee8734bbefb0d63d6156b6fa0e1385822480589daa1862cbd37a94f6bc2ba3a',
series_key: 'Series',
nft_id: 'c746af09-8dcb-4cec-aa8a-5ff02fffc3f1',
description: 'All-Conference and All-American honors await Carmelo Anthony during his Freshman season for Syracuse. However, Anthony must first defeat a worthy opponent in Georgetown with a double-double effort of 30 points and 15 rebounds.\n \n\n© Syracuse University',
immutable_uri: 'https://nftu.com/nft-content/metadata/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/7741920',
contract_address: '0x63cf7b3d5808cb190aa301b55aafd6b4bb95efbb',
is_pack: false,
pack_open_locked_until: '2022-03-05T16:58:30.998Z',
rarity_key: 'Rarity',
images: {
png: {
xs_3: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/xs_3.png',
},
xs_2: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/xs_2.png',
},
xs_1: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/xs_1.png',
},
xl3_3: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/xl3_3.png',
},
xl3_2: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/xl3_2.png',
},
xl3_1: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/xl3_1.png',
},
thumb_3: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/thumb_3.png',
},
thumb_2: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/thumb_2.png',
},
thumb_1: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/thumb_1.png',
},
sm_xl_3: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/sm_xl_3.png',
},
sm_xl_2: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/sm_xl_2.png',
},
sm_xl_1: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/sm_xl_1.png',
},
primary: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3',
cid: 'Qmf9hHAP884ZwYngk3VdVU7rhKDToykTy24WmcoegapnG8',
},
pfp_3: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/pfp_3.png',
},
pfp_2: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/pfp_2.png',
},
pfp_1: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/pfp_1.png',
},
md_2xl_3: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/md_2xl_3.png',
},
md_2xl_2: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/md_2xl_2.png',
},
md_2xl_1: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/md_2xl_1.png',
},
lg_3: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/lg_3.png',
},
lg_2: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/lg_2.png',
},
lg_1: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/0c66645c4e119f9c5def80273b768138d797f00583f557065a50bb0dd491e8e3/lg_1.png',
},
},
mp4: {
primary: {
url: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/dee8734bbefb0d63d6156b6fa0e1385822480589daa1862cbd37a94f6bc2ba3a',
cid: 'QmPGMksnyQemncHKQ67zGiuTAsnFi8HTJkY9ebQ6eVVQLv',
},
},
'default': 'mp4',
primary: [
'QmPGMksnyQemncHKQ67zGiuTAsnFi8HTJkY9ebQ6eVVQLv',
'https://nftu.com/nft/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/949',
],
},
royalty_amount: 1000,
rarity: 'Premium',
set_key: 'Set',
external_url: 'https://nftu.com/nft/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/949',
attributes: [
{
value: 'NCAABB',
trait_type: 'Sport',
},
{
value: 'Player',
trait_type: 'Type',
},
// {
// value: 'Limelight',
// trait_type: 'Category',
// },
// {
// value: 'Portrait',
// trait_type: 'Play Type',
// },
// {
// value: 'Carmelo Anthony',
// trait_type: 'Player Name',
// },
// {
// value: 'F',
// trait_type: 'Player Position',
// },
// {
// value: '15',
// trait_type: 'Player Jersey Number',
// display_type: 'number',
// },
// {
// value: 'Freshman',
// trait_type: 'Player Year',
// },
// {
// value: 'SYR',
// trait_type: 'Team Name',
// },
// {
// value: 'ACC',
// trait_type: 'Team Conference',
// },
// {
// value: '3/1/2003',
// trait_type: 'Game Date',
// },
// {
// value: 'GTWN',
// trait_type: 'Opposing Team',
// },
// {
// value: '93-84',
// trait_type: 'Final Score',
// },
// {
// value: 'Regular Season',
// trait_type: 'Game Type',
// },
// {
// value: '2002-03',
// trait_type: 'Season',
// },
// {
// value: 949,
// trait_type: 'Serial',
// },
],
tags: [ 'foo', 123, true ],
token_id: '7741920',
serial_total: 1100,
blockchain_state: 'BURNING',
image: 'https://nftu.com/nft-content/media/PAPAYA/92ee5f5c-bce9-4d64-8a25-c7e1e6305572/dee8734bbefb0d63d6156b6fa0e1385822480589daa1862cbd37a94f6bc2ba3a',
revealed_nfts: null,
pack_token_id: '7885344',
nft_data_id: '92ee5f5c-bce9-4d64-8a25-c7e1e6305572',
serial_key: 'Serial',
withdrawal_locked_until: '2022-03-05T16:58:30.998Z',
series: 'Tip-Off',
immutable_cid: 'QmVigZH1P3D6QWvp2SWVreTPKmDvUYUidNzcUrcYzATpyJ',
serial: 949,
status: null,
circulation_count: 970,
set: 'Tip-Off',
transfer_locked_until: '2022-03-05T16:58:30.998Z',
brand: 'NFTU',
user_display_name: null,
} as ExcludeNull<TokenInstance['metadata']>;
export default data;
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