Skip to content

Commit

Permalink
fix: display NFT instance
Browse files Browse the repository at this point in the history
  • Loading branch information
Tien Nam Dao committed Nov 17, 2022
1 parent 87e2f0a commit 9739a6a
Show file tree
Hide file tree
Showing 14 changed files with 431 additions and 27 deletions.
2 changes: 1 addition & 1 deletion api/api_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const API_LIST = {
TOKEN_TRANSACTIONS: 'evm_/api/v1?module=token&action=getlisttokentransfers',
TOKEN_HOLDERS: 'evm_/api/v1?module=token&action=getTokenHolders', // contractaddress=0x60baCCdfdCa114f97F32121f6b2879fB555Df4d0&page=1&offset=20
TOKEN_INVENTORY: 'evm_/api/v1?module=token&action=getinventory', // contractaddress=0x60baCCdfdCa114f97F32121f6b2879fB555Df4d0
TOKEN_METADATA: 'evm_/api/v1?module=token&action=getmetadata&contractaddress=',
TOKEN_METADATA: '/api/v1?module=token&action=getmetadata&contractaddress=',

CONTRACT_CODE: 'evm_/api/v1?module=contract&action=getsourcecode',
VERIFY_CONTRACT: 'https://blockscout.astranaut.dev/verify_smart_contract/contract_verifications',
Expand Down
2 changes: 1 addition & 1 deletion components/Search/SearchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default function SearchModal({ open, closeModal }: SearchModalProps) {
: transactions[0].cosmosHash
: undefined
const block = blocks?.[0] ? blocks[0].blockHash : undefined
const address = addresses?.[0] ? addresses[0].address : undefined
const address = addresses?.[0] ? addresses[0].addressHash : undefined
const validator = validators?.[0] ? validators[0].operatorAddress : undefined
const token = tokens?.[0] ? tokens[0].addressHash : undefined

Expand Down
3 changes: 2 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const nextConfig = {
NEXT_PUBLIC_EVM_TOKEN: 'asa',
NEXT_PUBLIC_PAGE_OFFSET: 10,
NEXT_PUBLIC_MAXIMUM_FRACTION_DIGITS: 4,
NEXT_PUBLIC_FEE_TOKEN: 'ASA'
NEXT_PUBLIC_FEE_TOKEN: 'ASA',
NEXT_PUBLIC_CHAIN_ID: 11115
},
images: {
domains: ['ipfs.io']
Expand Down
8 changes: 5 additions & 3 deletions pages/token/[token].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ const TokenDetailPage: React.FC<Props> = props => {
const { isMobile } = useMobileLayout()
const { token, tokenData, errorMessage } = props

const title = tokenData ? `${tokenData.name} (${tokenData.symbol}) - ${process.env.NEXT_PUBLIC_TITLE}` : token
const title = tokenData
? `${tokenData.name} (${tokenData.symbol}) - ${process.env.NEXT_PUBLIC_TITLE}`
: `Token ${token}`
return (
<Layout>
<Head>
Expand All @@ -31,7 +33,7 @@ const TokenDetailPage: React.FC<Props> = props => {
<Container>
<Breadcumbs
items={[
{ label: 'Address', link: LinkMaker.token() },
{ label: 'Token', link: LinkMaker.token() },
{ label: isMobile ? ellipseBetweenText(token) : token }
]}
/>
Expand All @@ -56,7 +58,7 @@ export async function getServerSideProps({ params }) {
if (tokenData.data.result) {
return {
props: {
errorMessage: '404 Not Found',
errorMessage: '',
token,
tokenData: tokenData.data.result
}
Expand Down
63 changes: 50 additions & 13 deletions pages/token/[token]/instance/[index].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,42 @@ import { Breadcumbs, useMobileLayout } from '@astraprotocol/astra-ui'
import { evmApi } from 'api'
import API_LIST from 'api/api_list'
import { AxiosError } from 'axios'
import CardInfo, { CardRowItem } from 'components/Card/CardInfo'
import Container from 'components/Container'
import Head from 'next/head'
import React from 'react'
import React, { useCallback } from 'react'
import { ellipseBetweenText, LinkMaker } from 'utils/helper'
import NftDetailTab from 'views/tokens/[instance]/NftDetailTab'
import NftOverview from 'views/tokens/[instance]/NftOverview'
import Web3 from 'web3'
import Layout from '../../../../components/Layout'

type Props = {
token: string
tokenData: Token
tokenId: string
tokenData: TokenNFTMetadata
errorMessage?: string
}

const TokenInstanceDetailPage: React.FC<Props> = props => {
const { isMobile } = useMobileLayout()
const { token, tokenData, errorMessage } = props
// console.log(tokenData)
const { token, tokenData, tokenId, errorMessage } = props
const title = tokenData ? `${tokenData.name} (${tokenId}) - ${process.env.NEXT_PUBLIC_TITLE}` : `Token ${token}`

const title = tokenData ? `${tokenData.name} (${tokenData.symbol}) - ${process.env.NEXT_PUBLIC_TITLE}` : token
const _convertRawDataToCardData = useCallback((data: TokenNFTAttributes[]): CardRowItem[] => {
if (!data) return []
let items: CardRowItem[] = []
for (let item of data) {
if (item !== undefined && item !== null)
items.push({
label: item.trait_type,
type: 'text',
contents: [{ value: item.value }]
})
}

return items
}, [])
return (
<Layout>
<Head>
Expand All @@ -30,35 +47,54 @@ const TokenInstanceDetailPage: React.FC<Props> = props => {
<Container>
<Breadcumbs
items={[
{ label: 'Address', link: LinkMaker.token() },
{ label: isMobile ? ellipseBetweenText(token) : token }
{ label: 'Token', link: LinkMaker.token() },
{ label: isMobile ? ellipseBetweenText(token) : token, link: LinkMaker.token(token) },
{ label: tokenId }
]}
/>

<h1 className="text contrast-color-70 margin-top-sm">{'In Development'}</h1>
{tokenData ? (
<>
<NftOverview token={token} tokenId={tokenId} tokenData={tokenData} />
<CardInfo
topElement={<span className="text text-xl padding-2xl">Properties</span>}
items={_convertRawDataToCardData(tokenData.attributes)}
classes={['margin-top-sm padding-top-md']}
/>
<NftDetailTab token={token} tokenData={tokenData} />
</>
) : (
<h1 className="text contrast-color-70 margin-top-sm">{errorMessage || 'Token Not Found'}</h1>
)}
</Container>
</Layout>
)
}

export async function getServerSideProps({ params }) {
const { token } = params
if (Web3.utils.isAddress(token, 11115)) {
const { token, index } = params

if (Web3.utils.isAddress(token, parseInt(process.env.NEXT_PUBLIC_CHAIN_ID) || 11115)) {
try {
const tokenData = await evmApi.get<TokenDetailResponse>(`${API_LIST.TOKEN_DETAIL}${token}`)
const tokenData = await evmApi.get<TokenInstanceResponse>(
`${API_LIST.TOKEN_METADATA}${token}&tokenid=${index}`
)

if (tokenData.data.result) {
return {
props: {
errorMessage: '404 Not Found',
errorMessage: '',
token,
tokenData: tokenData.data.result
tokenId: index,
tokenData: tokenData.data.result.result
}
}
}
return {
props: {
errorMessage: tokenData.data.message,
token,
tokenId: index,
tokenData: null
}
}
Expand All @@ -72,6 +108,7 @@ export async function getServerSideProps({ params }) {
props: {
errorMessage: err.message,
token,
tokenId: index,
tokenData: null
}
}
Expand Down
22 changes: 16 additions & 6 deletions types/token.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,15 @@ interface TokenNFTAttributes {
value: string
}

interface TokenNFTMetadata {
attributes: TokenNFTAttributes[]
description: string
image: string
name: string
}

interface TokenNFTInstance {
metadata: {
attributes: TokenNFTAttributes[]
description: string
image: string
name: string
}
metadata: TokenNFTMetadata
ownerAddress: string
tokenId: string
}
Expand Down Expand Up @@ -139,6 +141,14 @@ interface TokenDetailResponse {
status: string
}

interface TokenInstanceResponse {
message: string
result: {
result: TokenNFTMetadata
}
status: string
}

interface TokenSearchResponse {
addressHash: string
holderCount: number
Expand Down
2 changes: 1 addition & 1 deletion views/tokens/TokenDetailTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const TokenDetailTab = ({ token, tokenData }: Props) => {
contents={{
'token-transfers': <AddressTransactionTab token={token} tokenData={tokenData} />,
'token-holders': <TokenHolderTab token={token} tokenData={tokenData} />,
'inventory': isNFT ? <InventoryTab token={token} tokenData={tokenData} /> : <div />
'inventory': isNFT ? <InventoryTab token={token} /> : <div />
}}
></Tabs>
</BackgroundCard>
Expand Down
29 changes: 29 additions & 0 deletions views/tokens/[instance]/NftDetailTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import BackgroundCard from 'components/Card/Background/BackgroundCard'
import Tabs from 'components/Tabs/Tabs'
import useRouterTag from 'hooks/useRouterTag'
import NftTransferTab from './tabs/NftTransfers'

interface Props {
token: string
tokenData: TokenNFTMetadata
}

const NftDetailTab = ({ token, tokenData }: Props) => {
const [defaultTag, setTag] = useRouterTag()

return (
<BackgroundCard classes="margin-top-lg padding-bottom-lg">
<Tabs
tabChange={setTag}
defaultTab={defaultTag}
classes="none"
tabs={[{ title: 'Token Transfers', id: 'token-transfers' }]}
contents={{
'token-transfers': <NftTransferTab token={token} tokenData={tokenData} />
}}
></Tabs>
</BackgroundCard>
)
}

export default NftDetailTab
39 changes: 39 additions & 0 deletions views/tokens/[instance]/NftOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import BackgroundCard from 'components/Card/Background/BackgroundCard'
import Row from 'components/Grid/Row'
import Image from 'next/image'

interface Props {
token: string
tokenId: string
tokenData: TokenNFTMetadata
}

const NftOverview = ({ token, tokenData, tokenId }: Props) => {
const tokenImage = tokenData?.image.replace('ipfs://', 'https://ipfs.io/ipfs/')
return (
<BackgroundCard classes="padding-top-lg padding-bottom-lg margin-top-2xl padding-left-2xl padding-right-2xl">
<Row>
<div className="col-6 margin-right-md">
<Row style={{ justifyContent: 'space-between' }}>
<span className="text text-base contrast-color-50">Token ID:</span>
<span className="text text-base">{tokenId}</span>
</Row>
<Row style={{ justifyContent: 'space-between' }}>
<span className="text text-base contrast-color-50">Name:</span>
<span className="text text-base">{tokenData.name}</span>
</Row>

<Row style={{ justifyContent: 'space-between' }}>
<span className="text text-base contrast-color-50">Description:</span>
<span className="text text-base">{tokenData.description}</span>
</Row>
</div>
<div className="col-6 flex flex-justify-end">
<Image src={tokenImage} alt={tokenData.name} height={100} width={120} layout="fixed" />
</div>
</Row>
</BackgroundCard>
)
}

export default NftOverview
68 changes: 68 additions & 0 deletions views/tokens/[instance]/hook/useNftTransfers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import API_LIST from 'api/api_list'
import { useEffect, useState } from 'react'
import useSWR from 'swr'
import { ZERO_ADDRESS } from 'utils/constants'
import { getEnvNumber } from 'utils/helper'

/**
* @todo: Not implement yet
* @param token
* @param params
* @returns
*/
export default function useNftTransfer(token: string, params: string | undefined): UseTokenTransactionHookData {
const [hookData, setState] = useState({
result: [],
hasNextPage: false,
nextPagePath: undefined
})

const _fetchCondition = () => {
if (params) {
return [
`${API_LIST.TOKEN_TRANSACTIONS}${params}`,
{
contractaddress: token
}
]
}

return [
API_LIST.TOKEN_TRANSACTIONS,
{
contractaddress: token,
page: 1,
offset: getEnvNumber('NEXT_PUBLIC_PAGE_OFFSET')
}
]
}
const { data } = useSWR<TokenTransactionResponse>(_fetchCondition())

const convertData = (_data: TokenTransactionResponse): TokenTransaction[] => {
return data.result.map((d: TokenTransaction) => {
const isMint = d.fromAddress === ZERO_ADDRESS
const isBurn = d.toAddress === ZERO_ADDRESS

return {
...d,
type: d.type || (isMint && 'Mint') || (isBurn && 'Burn')
}
})
}

useEffect(() => {
if (data?.result) {
setState({
result: convertData(data),
hasNextPage: data.hasNextPage,
nextPagePath: data.nextPagePath
})
}
}, [data])

return {
result: hookData.result,
hasNextPage: hookData.hasNextPage,
nextPagePath: hookData.nextPagePath
}
}
Loading

0 comments on commit 9739a6a

Please sign in to comment.