From 8f44faa209df3b88a2fae2593d8026695a9d9927 Mon Sep 17 00:00:00 2001 From: Tien Nam Dao Date: Thu, 13 Oct 2022 11:37:22 +0700 Subject: [PATCH] feat: add token detail - part1 --- api/api_list.ts | 6 +- components/Button/QrButton.tsx | 2 +- pages/accounts.tsx | 4 +- pages/token/[token].tsx | 10 +- pages/tokens.tsx | 2 +- project.d.ts | 168 ------------------ types/address.d.ts | 134 ++++++++++++++ types/token.d.ts | 68 +++++++ types/transactions.d.ts | 21 +++ views/accounts/HolderRow.tsx | 8 +- views/accounts/hook/useAddressTransaction.ts | 10 +- .../AddressTransaction.tsx | 129 ++++++++++++++ .../tabs/AddressTransactionTab/index.tsx | 20 ++- .../AddressTransactionTab/style.module.scss | 67 +++++++ views/tokens/TokenDetailTabs.tsx | 28 +++ views/tokens/TokenOverview.tsx | 94 ++++++++++ views/tokens/TokenRow.tsx | 6 +- views/tokens/hook/useTokenHolders.ts | 30 ++++ views/tokens/hook/useTokenTransactions.ts | 28 +++ .../tabs/TokenHolderTab/TokenHolder.tsx | 53 ++++++ views/tokens/tabs/TokenHolderTab/index.tsx | 41 +++++ .../tabs/TokenHolderTab/style.module.scss | 35 ++++ .../TokenTransactionTab/TokenTransaction.tsx | 129 ++++++++++++++ .../tokens/tabs/TokenTransactionTab/index.tsx | 40 +++++ .../TokenTransactionTab/style.module.scss | 67 +++++++ 25 files changed, 1011 insertions(+), 189 deletions(-) create mode 100644 types/token.d.ts create mode 100644 views/accounts/tabs/AddressTransactionTab/AddressTransaction.tsx create mode 100644 views/tokens/TokenDetailTabs.tsx create mode 100644 views/tokens/TokenOverview.tsx create mode 100644 views/tokens/hook/useTokenHolders.ts create mode 100644 views/tokens/hook/useTokenTransactions.ts create mode 100644 views/tokens/tabs/TokenHolderTab/TokenHolder.tsx create mode 100644 views/tokens/tabs/TokenHolderTab/index.tsx create mode 100644 views/tokens/tabs/TokenHolderTab/style.module.scss create mode 100644 views/tokens/tabs/TokenTransactionTab/TokenTransaction.tsx create mode 100644 views/tokens/tabs/TokenTransactionTab/index.tsx create mode 100644 views/tokens/tabs/TokenTransactionTab/style.module.scss diff --git a/api/api_list.ts b/api/api_list.ts index 0d0044c0..6154a13f 100644 --- a/api/api_list.ts +++ b/api/api_list.ts @@ -34,7 +34,11 @@ const API_LIST = { ADDRESS_COIN_BALANCE_HISTORY_CHART: 'evm_/address', // address, page, offset=? ADDRESS_TRANSACTION: 'http://128.199.238.171:8080/api/v1/accounts', ADDRESS_INTERNAL_TRANSACTION: 'evm_/api/v1?module=account&action=txlistinternal', // address, page, offset - ADDRESS_TOKEN_TRANSFER: 'evm_/api/v1?module=account&action=tokentx' // address=? + ADDRESS_TOKEN_TRANSFER: 'evm_/api/v1?module=account&action=tokentx', // address=? + + TOKEN_DETAIL: '', + TOKEN_TRANSACTIONS: '', + TOKEN_HOLDERS: 'evm_/api/v1?module=token&action=getTokenHolders' // contractaddress=0x60baCCdfdCa114f97F32121f6b2879fB555Df4d0&page=1&offset=20 } export default API_LIST diff --git a/components/Button/QrButton.tsx b/components/Button/QrButton.tsx index dec626a2..01280d26 100644 --- a/components/Button/QrButton.tsx +++ b/components/Button/QrButton.tsx @@ -25,7 +25,7 @@ const QrButton = ({ textTitle, textClasses, content, classes }: Props) => { return ( {textTitle && {textTitle}} - + ) } diff --git a/pages/accounts.tsx b/pages/accounts.tsx index 33da019f..763a0d51 100644 --- a/pages/accounts.tsx +++ b/pages/accounts.tsx @@ -40,8 +40,8 @@ const AstraHolderPage: React.FC = _ => { ) : (
- {accounts?.map((item: AstraHolder, index: number) => { - return + {accounts?.map((item: Holder, index: number) => { + return })}
)} diff --git a/pages/token/[token].tsx b/pages/token/[token].tsx index e88d8980..daec431e 100644 --- a/pages/token/[token].tsx +++ b/pages/token/[token].tsx @@ -2,7 +2,9 @@ import { Breadcumbs } from '@astraprotocol/astra-ui' import Container from 'components/Container' import Head from 'next/head' import React from 'react' -import { LinkMaker } from 'utils/helper' +import { ellipseBetweenText, LinkMaker } from 'utils/helper' +import TokenDetailTab from 'views/tokens/TokenDetailTabs' +import TokenOverview from 'views/tokens/TokenOverview' import Layout from '../../components/Layout' type Props = { @@ -21,7 +23,11 @@ const TokenDetailPage: React.FC = props => { - + + + ) diff --git a/pages/tokens.tsx b/pages/tokens.tsx index 28ad56a0..97b35b19 100644 --- a/pages/tokens.tsx +++ b/pages/tokens.tsx @@ -43,7 +43,7 @@ const AllTokensPage: React.FC = _ => { ) : (
{tokens?.map((item: Token, index: number) => { - return + return })} {/* */}
diff --git a/project.d.ts b/project.d.ts index 8b094761..6b3dc00f 100644 --- a/project.d.ts +++ b/project.d.ts @@ -149,171 +149,3 @@ interface Proposer { powerPercentage: string cumulativePowerPercentage: string } - -interface Token { - cataloged?: boolean - contractAddressHash: string - decimals: string - holderCount?: number - name: string - symbol: string - totalSupply: string - type: string -} - -interface AstraHolder { - address: string - balance: string - txnCount: number -} - -interface TokenTransfer { - value: string - blockHash: string - blockNumber: string - confirmations: string - contractAddress: string - cumulativeGasUsed: string - from: string - gas: string - gasPrice: string - gasUsed: string - hash: string - input: string - logIndex: string - nonce: string - timeStamp: string - to: string - tokenDecimal: string - tokenName: string - tokenSymbol: string - transactionIndex: string -} - -interface AddressToken { - balance: string - contractAddress: string - decimals: string - name: string - symbol: string - type: string -} - -interface AddressCoinBalanceHistory { - addressHash: string - blockNumber: number - blockTimestamp: string - delta: string - insertedAt: string - transactionHash: string - transactionValue: string - updatedAt: string - value: string - valueFetchedAt: string -} - -interface AddressCoinBalanceHistoryChartData { - date: string - value: number -} - -interface UseTokenHookData { - result: Token[] - hasNextPage: boolean -} - -interface UseAstraHolderData { - result: AstraHolder[] - hasNextPage: boolean -} - -interface UseAddressTransactionData { - result: any[] - pagination: Pagination -} - -interface UseAddressTokenTransferData { - result: TokenTransfer[] - hasNextPage: boolean -} - -interface UseAddressTokenData { - result: AddressToken[] - hasNextPage: boolean -} - -interface UseAddressInternalTransactionData { - result: TransactionRowProps[] | [] - hasNextPage: boolean -} - -interface UseAddressBalanceData { - balance: string - lastBalanceUpdate: number -} - -interface AddressCounterData { - gasUsageCount?: number - tokenTransferCount?: number - transactionCount?: number - validationCount?: number -} - -interface UseAddressCoinBalanceHistoryData { - result: AddressCoinBalanceHistory[] | [] - hasNextPage: boolean -} - -interface UseAddressCoinBalanceHistoryChartData { - result: AddressCoinBalanceHistoryChartData[] | [] -} - -interface TokenResponse { - hasNextPage: boolean - result: Token[] -} - -interface TopAstraHolderResponse { - hasNextPage: boolean - nextPageParams: { - offset: number - page: number - } - result: AstraHolder[] -} - -interface AddressCounterResponse { - message: string - result: AddressCounterData - status: string -} - -interface AddressBalanceResponse { - message: string - result: UseAddressBalanceData - status: string -} - -interface AddressTokenTransferResponse { - message: string - result: TokenTransfer[] - status: string -} - -interface AddressTokenResponse { - hasNextPage: boolean - nextPageParams: any - result: AddressToken[] -} - -interface AddressInternalTransactionResponse { - message: string - result: InternalTransactionItem[] - status: string -} - -interface AddressCoinBalanceHistoryResponse { - hasNextPage: boolean - nextPageParams: any - result: AddressCoinBalanceHistory[] -} diff --git a/types/address.d.ts b/types/address.d.ts index 667509ed..d58a3b1e 100644 --- a/types/address.d.ts +++ b/types/address.d.ts @@ -3,3 +3,137 @@ interface AbiResponse { result: string status: string } + +interface AddressCounterResponse { + message: string + result: AddressCounterData + status: string +} + +interface AddressBalanceResponse { + message: string + result: UseAddressBalanceData + status: string +} + +interface AddressTokenTransferResponse { + message: string + result: TokenTransfer[] + status: string +} + +interface AddressTokenResponse { + hasNextPage: boolean + nextPageParams: any + result: AddressToken[] +} + +interface AddressInternalTransactionResponse { + message: string + result: InternalTransactionItem[] + status: string +} + +interface AddressCoinBalanceHistoryResponse { + hasNextPage: boolean + nextPageParams: any + result: AddressCoinBalanceHistory[] +} + +interface AddressTransactionResponse { + result: AddressTransactionData[] + pagination: Pagination +} + +interface UseAstraHolderData { + result: Holder[] + hasNextPage: boolean +} + +interface UseAddressTransactionData { + result: AddressTransactionData[] + pagination: Pagination +} + +interface UseAddressTokenTransferData { + result: TokenTransfer[] + hasNextPage: boolean +} + +interface UseAddressTokenData { + result: AddressToken[] + hasNextPage: boolean +} + +interface UseAddressInternalTransactionData { + result: TransactionRowProps[] | [] + hasNextPage: boolean +} + +interface UseAddressBalanceData { + balance: string + lastBalanceUpdate: number +} + +interface UseAddressCoinBalanceHistoryData { + result: AddressCoinBalanceHistory[] | [] + hasNextPage: boolean +} + +interface UseAddressCoinBalanceHistoryChartData { + result: AddressCoinBalanceHistoryChartData[] | [] +} + +interface AddressToken { + balance: string + contractAddress: string + decimals: string + name: string + symbol: string + type: string +} + +interface AddressCoinBalanceHistory { + addressHash: string + blockNumber: number + blockTimestamp: string + delta: string + insertedAt: string + transactionHash: string + transactionValue: string + updatedAt: string + value: string + valueFetchedAt: string +} + +interface AddressCoinBalanceHistoryChartData { + date: string + value: number +} + +interface AddressCounterData { + gasUsageCount?: number + tokenTransferCount?: number + transactionCount?: number + validationCount?: number +} + +interface AddressTransactionData { + account: string + blockHeight: number + blockHash: string + blockTime: string + hash: string + messageTypes: string[] + success: boolean + code: number + log: string + fee: TokenAmount[] + feePayer: string + feeGranter: string + gasWanted: number + gasUsed: number + memo: string + timeoutHeight: number + messages: Message +} diff --git a/types/token.d.ts b/types/token.d.ts new file mode 100644 index 00000000..8102ec9e --- /dev/null +++ b/types/token.d.ts @@ -0,0 +1,68 @@ +interface TokenResponse { + hasNextPage: boolean + result: Token[] +} + +interface TokenHolderResponse { + hasNextPage: boolean + result: Holder[] +} + +interface TopAstraHolderResponse { + hasNextPage: boolean + nextPageParams: { + offset: number + page: number + } + result: Holder[] +} + +interface UseTokenHookData { + result: Token[] + hasNextPage: boolean +} + +interface UseTokenHolderData { + result: Holder[] + hasNextPage: boolean +} + +interface Token { + cataloged?: boolean + contractAddressHash: string + decimals: string + holderCount?: number + name: string + symbol: string + totalSupply: string + type: string +} + +interface Holder { + address: string + balance: string + txnCount?: number +} + +interface TokenTransfer { + value: string + blockHash: string + blockNumber: string + confirmations: string + contractAddress: string + cumulativeGasUsed: string + from: string + gas: string + gasPrice: string + gasUsed: string + hash: string + input: string + logIndex: string + nonce: string + timeStamp: string + to: string + tokenDecimal: string + tokenName: string + tokenSymbol: string + transactionIndex: string +} diff --git a/types/transactions.d.ts b/types/transactions.d.ts index 17b7dfa7..1df9a239 100644 --- a/types/transactions.d.ts +++ b/types/transactions.d.ts @@ -8,6 +8,27 @@ interface Signer { accountSequence: number } +interface TokenAmount { + denom: string + amount: string +} + +interface Message { + type: string + content: { + name: string + txHash: string + msgIndex: number + msgName: string + version: number + toAddress: string + fromAddress: string + uuid: string + amount: TokenAmount[] + height: number + } +} + interface EVMTransactionContent { msgIndex: number name: string diff --git a/views/accounts/HolderRow.tsx b/views/accounts/HolderRow.tsx index e4a8089c..19b89343 100644 --- a/views/accounts/HolderRow.tsx +++ b/views/accounts/HolderRow.tsx @@ -1,11 +1,11 @@ import clsx from 'clsx' import Typography from 'components/Typography' -import { LinkMaker } from 'utils/helper' +import { convertBalanceToView, LinkMaker } from 'utils/helper' import styles from './style.module.scss' type Props = { index: number - account: AstraHolder + account: Holder } export default function HolderRow({ index, account }: Props) { @@ -26,7 +26,9 @@ export default function HolderRow({ index, account }: Props) {
- {account.balance} + + {convertBalanceToView(account.balance)} + ASA
diff --git a/views/accounts/hook/useAddressTransaction.ts b/views/accounts/hook/useAddressTransaction.ts index 4c7410f3..d4084d4e 100644 --- a/views/accounts/hook/useAddressTransaction.ts +++ b/views/accounts/hook/useAddressTransaction.ts @@ -1,13 +1,17 @@ +import { ethToAstra } from '@astradefi/address-converter' import API_LIST from 'api/api_list' import { useEffect, useState } from 'react' import useSWR from 'swr' export default function useAddressTransactions(address: string, page: number) { - const [hookData, setState] = useState() + const [hookData, setState] = useState({ + result: [], + pagination: { total_record: 0, total_page: 0, current_page: 0, limit: 0 } + }) const _fetchCondition = () => { return [ - `${API_LIST.ADDRESS_TRANSACTION}/${address}`, + `${API_LIST.ADDRESS_TRANSACTION}/${ethToAstra(address)}/transactions`, { pagination: 'offset', order: 'height.desc', @@ -16,7 +20,7 @@ export default function useAddressTransactions(address: string, page: number) { } ] } - const { data } = useSWR(_fetchCondition()) + const { data } = useSWR(_fetchCondition()) useEffect(() => { if (data) { diff --git a/views/accounts/tabs/AddressTransactionTab/AddressTransaction.tsx b/views/accounts/tabs/AddressTransactionTab/AddressTransaction.tsx new file mode 100644 index 00000000..568c2f56 --- /dev/null +++ b/views/accounts/tabs/AddressTransactionTab/AddressTransaction.tsx @@ -0,0 +1,129 @@ +import clsx from 'clsx' +import GradientRow from 'components/Row/GradientRow' +import Timer from 'components/Timer' +import Typography from 'components/Typography' +import { ellipseRightText, LinkMaker } from 'utils/helper' +import styles from './style.module.scss' + +interface Props { + transaction: AddressTransactionData +} + +const AddressTransaction = ({ transaction }: Props) => { + return ( + +
+
+
+ + {ellipseRightText(transaction.hash, 30)} + + +
+ {/* {(transaction.from || transaction.to) && ( +
+ {transaction.from && ( + <> + + From + + + {evmAddressName(fromName, ellipseBetweenText(from, 6, 6))} + + + )} + {transaction.to && ( + <> + + To + + + {evmAddressName(toName, ellipseBetweenText(to, 6, 6))} + + + )} +
+ )} */} +
+
+ +
+
+ + #{transaction.blockHeight} + +
+
+ {/*
+ {Number(value) >= 0 && ( + <> + } + /> +
+ + )} + + {Number(fee) >= 0 && ( + Fee:} + size="2xs" + value={convertBalanceToView(fee)} + fixNumber={7} + currency={feeToken.toUpperCase()} + classes="contrast-color-70" + /> + )} + +
*/} +
+
+ +
+
+ {transaction.success ? ( + Success + ) : ( + Error + )} +
+
+
+ ) +} +export default AddressTransaction diff --git a/views/accounts/tabs/AddressTransactionTab/index.tsx b/views/accounts/tabs/AddressTransactionTab/index.tsx index 64f58a04..a0567d72 100644 --- a/views/accounts/tabs/AddressTransactionTab/index.tsx +++ b/views/accounts/tabs/AddressTransactionTab/index.tsx @@ -1,8 +1,8 @@ -import { PaginationLite } from '@astraprotocol/astra-ui' import Row from 'components/Grid/Row' +import Empty from 'components/Typography/Empty' import { useState } from 'react' -import useAddressTokenTransfers from 'views/accounts/hook/useAddressTokenTransfer' -import { Transactions } from 'views/transactions/TransactionTabs' +import useAddressTransactions from 'views/accounts/hook/useAddressTransaction' +import AddressTransaction from './AddressTransaction' interface Props { address: string @@ -10,7 +10,7 @@ interface Props { const AddressTransactionTab = ({ address }: Props) => { const [currentPage, setPage] = useState(1) - const { result, hasNextPage } = useAddressTokenTransfers(address, currentPage) + const { data, pagination } = useAddressTransactions(address, currentPage) const onPagingChange = (value: number) => setPage(value) @@ -20,11 +20,19 @@ const AddressTransactionTab = ({ address }: Props) => { Transactions
{/* Select Component */} - + {/* */}
- + {!data || data.length == 0 ? ( + + ) : ( + <> + {data?.map((item, index) => ( + + ))} + + )} ) } diff --git a/views/accounts/tabs/AddressTransactionTab/style.module.scss b/views/accounts/tabs/AddressTransactionTab/style.module.scss index e69de29b..82cefbd4 100644 --- a/views/accounts/tabs/AddressTransactionTab/style.module.scss +++ b/views/accounts/tabs/AddressTransactionTab/style.module.scss @@ -0,0 +1,67 @@ +.rowBrief { + display: flex; + min-height: 88.9px; + align-items: center; + .iconCetner { + display: flex; + align-items: center; + } + .content { + width: 100%; + .info { + display: flex; + justify-content: space-between; + width: 100%; + } + } +} + +.rowHeight { + display: flex; + min-height: 70px; +} + +.borderWidthPadding { + &::after { + content: ''; + height: 1px; + width: calc(100% - 56px); + background-color: var(--border-color); + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + } +} +.verifyContract { + display: flex; + align-items: center; + padding: 6px 16px; + min-height: 48px; + background: rgba(255, 200, 42, 0.16); + border: 1px solid rgba(255, 200, 42, 0.1); + border-radius: 8px; + a { + color: var(--link-color-useful); + } +} + +.hr { + margin: 60px 0px; + border-top: 1px solid rgba(var(--contrast-color-theme--raw), 0.2); +} + +.logItemLeftBorder { + position: relative; + &::before { + content: ''; + position: absolute; + left: 0; + top: 0; + width: 4px; + height: 100%; + background: rgba(255, 200, 42, 0.16); + border: 1px solid rgba(255, 200, 42, 0.1); + border-radius: 8px; + } +} diff --git a/views/tokens/TokenDetailTabs.tsx b/views/tokens/TokenDetailTabs.tsx new file mode 100644 index 00000000..6c00cb0f --- /dev/null +++ b/views/tokens/TokenDetailTabs.tsx @@ -0,0 +1,28 @@ +import BackgroundCard from 'components/Card/Background/BackgroundCard' +import Tabs from 'components/Tabs/Tabs' +import TokenHolderTab from './tabs/TokenHolderTab' +import AddressTransactionTab from './tabs/TokenTransactionTab' + +interface Props { + token: string +} + +const TokenDetailTab = ({ token }: Props) => { + return ( + + , + '2': + }} + > + + ) +} + +export default TokenDetailTab diff --git a/views/tokens/TokenOverview.tsx b/views/tokens/TokenOverview.tsx new file mode 100644 index 00000000..d98b8945 --- /dev/null +++ b/views/tokens/TokenOverview.tsx @@ -0,0 +1,94 @@ +import { CryptoIcon, Typography as TypographyUI } from '@astraprotocol/astra-ui' +import clsx from 'clsx' +import CopyButton from 'components/Button/CopyButton' +import QrButton from 'components/Button/QrButton' +import BackgroundCard from 'components/Card/Background/BackgroundCard' +import Row from 'components/Grid/Row' +import { LinkText } from 'components/Typography/LinkText' +import { LinkMaker } from 'utils/helper' +import styles from './style.module.scss' + +interface Props { + token: string +} + +const TokenOverview = ({ token }: Props) => { + // const addressCounter = useAddressCounter(token) + // const addressBalance = useAddressBalance(token) + // const astraSummary = useAppSelector(getAstraSummary) + + return ( + + +
+ Wallet Address: +
+ {token} +
+
+ + +
+
+ +
+ Contract: +
+ {token} +
+
+ Total Supply: +
+ } + // value={ + // addressBalance.balance + // ? convertBalanceToView(addressBalance.balance) + // : addressBalance.balance + // } + fixNumber={5} + /> +
+
+ Holders: +
+ {/* + {addressCounter.transactionCount + ? numeral(addressCounter.transactionCount).format('0,0') + : 'NaN'} + */} +
+
+ Transfers: +
+ + {/* {isUndefined(addressCounter?.tokenTransferCount) ? 'NaN' : addressCounter?.tokenTransferCount} */} + +
+
+ Decimals: +
+ + {/* {addressCounter.transactionCount ? numeral(addressCounter.gasUsageCount).format('0,0') : 'NaN'} */} + +
+
+ Token Type: +
+ + {/* {addressBalance.lastBalanceUpdate ? ( + + {addressBalance.lastBalanceUpdate} + + ) : ( + NaN + )} */} +
+
+
+ ) +} + +export default TokenOverview diff --git a/views/tokens/TokenRow.tsx b/views/tokens/TokenRow.tsx index f2896c50..8f7ff5e5 100644 --- a/views/tokens/TokenRow.tsx +++ b/views/tokens/TokenRow.tsx @@ -1,6 +1,6 @@ import clsx from 'clsx' import Typography from 'components/Typography' -import { LinkMaker } from 'utils/helper' +import { convertBalanceToView, LinkMaker } from 'utils/helper' import styles from './style.module.scss' type Props = { @@ -35,7 +35,9 @@ export default function TokenRow({ index, token }: Props) {
- {token.totalSupply} + + {convertBalanceToView(token.totalSupply)} + {token.symbol}
diff --git a/views/tokens/hook/useTokenHolders.ts b/views/tokens/hook/useTokenHolders.ts new file mode 100644 index 00000000..01458308 --- /dev/null +++ b/views/tokens/hook/useTokenHolders.ts @@ -0,0 +1,30 @@ +import API_LIST from 'api/api_list' +import { useEffect, useState } from 'react' +import useSWR from 'swr' + +export default function useTokenHolders(token: string, page: number) { + const [hookData, setState] = useState() + + const _fetchCondition = () => { + return [ + API_LIST.TOKEN_HOLDERS, + { + contractaddress: token, + page, + offset: 20 + } + ] + } + const { data } = useSWR(_fetchCondition()) + + useEffect(() => { + if (data?.result) { + const tokens: any = data.result.map(d => ({ address: d.address, balance: d.value })) + setState({ result: tokens, hasNextPage: data.hasNextPage }) + } + }, [data]) + return { + tokens: hookData?.result, + hasNextPage: hookData?.hasNextPage + } +} diff --git a/views/tokens/hook/useTokenTransactions.ts b/views/tokens/hook/useTokenTransactions.ts new file mode 100644 index 00000000..6151c153 --- /dev/null +++ b/views/tokens/hook/useTokenTransactions.ts @@ -0,0 +1,28 @@ +import API_LIST from 'api/api_list' +import { useEffect, useState } from 'react' +import useSWR from 'swr' + +export default function useTokenTransactions(page: number) { + const [hookData, setState] = useState() + + const _fetchCondition = () => { + return [ + API_LIST.TOKEN_TRANSACTIONS, + { + page, + offset: 20 + } + ] + } + const { data } = useSWR(_fetchCondition()) + + useEffect(() => { + if (data?.result) { + setState(data) + } + }, [data]) + return { + tokens: hookData?.result, + hasNextPage: hookData?.hasNextPage + } +} diff --git a/views/tokens/tabs/TokenHolderTab/TokenHolder.tsx b/views/tokens/tabs/TokenHolderTab/TokenHolder.tsx new file mode 100644 index 00000000..a8489971 --- /dev/null +++ b/views/tokens/tabs/TokenHolderTab/TokenHolder.tsx @@ -0,0 +1,53 @@ +import { CryptoIcon, Typography as TypographyUI } from '@astraprotocol/astra-ui' +import clsx from 'clsx' +import Typography from 'components/Typography' +import { convertBalanceToView, LinkMaker } from 'utils/helper' +import styles from './style.module.scss' + +type Props = { + index: number + account: Holder +} + +export default function TokenHolder({ index, account }: Props) { + return ( +
+
{index}
+
+ + {account.address} + +
+
+ {/* + {convertBalanceToView(account.balance)} + + ASA */} + } + value={account.balance ? convertBalanceToView(account.balance) : account.balance} + fixNumber={5} + /> +
+ +
+ aa/totalsupply %{/* {account.txnCount} */} +
+
+ ) +} diff --git a/views/tokens/tabs/TokenHolderTab/index.tsx b/views/tokens/tabs/TokenHolderTab/index.tsx new file mode 100644 index 00000000..0bb0cbbb --- /dev/null +++ b/views/tokens/tabs/TokenHolderTab/index.tsx @@ -0,0 +1,41 @@ +import { PaginationLite } from '@astraprotocol/astra-ui' +import Row from 'components/Grid/Row' +import Empty from 'components/Typography/Empty' +import { useState } from 'react' +import useTokenHolders from 'views/tokens/hook/useTokenHolders' +import TokenHolder from './TokenHolder' + +interface Props { + token: string +} + +const TokenHolderTab = ({ token }: Props) => { + const [currentPage, setPage] = useState(1) + const { tokens, hasNextPage } = useTokenHolders(token, currentPage) + + const onPagingChange = (value: number) => setPage(value) + + return ( +
+ + Top Holders +
+ {/* Select Component */} + +
+
+ + {!tokens || tokens.length == 0 ? ( + + ) : ( +
+ {tokens?.map((item: Holder, index: number) => { + return + })} +
+ )} +
+ ) +} + +export default TokenHolderTab diff --git a/views/tokens/tabs/TokenHolderTab/style.module.scss b/views/tokens/tabs/TokenHolderTab/style.module.scss new file mode 100644 index 00000000..8d4b3bb3 --- /dev/null +++ b/views/tokens/tabs/TokenHolderTab/style.module.scss @@ -0,0 +1,35 @@ +.holderRow { + background: rgba(var(--contrast-color-theme--raw), 0.05); + border: 1px solid rgba(var(--contrast-color-theme--raw), 0.05); + backdrop-filter: blur(42px); + display: flex; + align-items: center; + .indexCenter { + display: flex; + align-items: center; + } + .content { + width: 100%; + .info { + display: flex; + justify-content: space-between; + } + } + + .currency { + font-family: 'TitilliumWeb-SemiBold'; + color: var(--contrast-color-theme-70); + } + .borderLeft { + border-left: 1px solid rgba(var(--contrast-color-theme--raw), 0.05); + } + + .topRow { + display: flex; + justify-content: space-between; + } +} + +.borderBottom { + border-bottom: 1px solid var(--border-color); +} diff --git a/views/tokens/tabs/TokenTransactionTab/TokenTransaction.tsx b/views/tokens/tabs/TokenTransactionTab/TokenTransaction.tsx new file mode 100644 index 00000000..568c2f56 --- /dev/null +++ b/views/tokens/tabs/TokenTransactionTab/TokenTransaction.tsx @@ -0,0 +1,129 @@ +import clsx from 'clsx' +import GradientRow from 'components/Row/GradientRow' +import Timer from 'components/Timer' +import Typography from 'components/Typography' +import { ellipseRightText, LinkMaker } from 'utils/helper' +import styles from './style.module.scss' + +interface Props { + transaction: AddressTransactionData +} + +const AddressTransaction = ({ transaction }: Props) => { + return ( + +
+
+
+ + {ellipseRightText(transaction.hash, 30)} + + +
+ {/* {(transaction.from || transaction.to) && ( +
+ {transaction.from && ( + <> + + From + + + {evmAddressName(fromName, ellipseBetweenText(from, 6, 6))} + + + )} + {transaction.to && ( + <> + + To + + + {evmAddressName(toName, ellipseBetweenText(to, 6, 6))} + + + )} +
+ )} */} +
+
+ +
+
+ + #{transaction.blockHeight} + +
+
+ {/*
+ {Number(value) >= 0 && ( + <> + } + /> +
+ + )} + + {Number(fee) >= 0 && ( + Fee:} + size="2xs" + value={convertBalanceToView(fee)} + fixNumber={7} + currency={feeToken.toUpperCase()} + classes="contrast-color-70" + /> + )} + +
*/} +
+
+ +
+
+ {transaction.success ? ( + Success + ) : ( + Error + )} +
+
+
+ ) +} +export default AddressTransaction diff --git a/views/tokens/tabs/TokenTransactionTab/index.tsx b/views/tokens/tabs/TokenTransactionTab/index.tsx new file mode 100644 index 00000000..52323d14 --- /dev/null +++ b/views/tokens/tabs/TokenTransactionTab/index.tsx @@ -0,0 +1,40 @@ +import Row from 'components/Grid/Row' +import Empty from 'components/Typography/Empty' +import { useState } from 'react' +import useTokenTransactions from 'views/tokens/hook/useTokenTransactions' +import AddressTransaction from './TokenTransaction' + +interface Props { + token: string +} + +const TokenTransactionTab = ({ token }: Props) => { + const [currentPage, setPage] = useState(1) + const { data, pagination } = useTokenTransactions(token) + + const onPagingChange = (value: number) => setPage(value) + + return ( +
+ + Transactions +
+ {/* Select Component */} + {/* */} +
+
+ + {!data || data.length == 0 ? ( + + ) : ( + <> + {data?.map((item, index) => ( + + ))} + + )} +
+ ) +} + +export default TokenTransactionTab diff --git a/views/tokens/tabs/TokenTransactionTab/style.module.scss b/views/tokens/tabs/TokenTransactionTab/style.module.scss new file mode 100644 index 00000000..82cefbd4 --- /dev/null +++ b/views/tokens/tabs/TokenTransactionTab/style.module.scss @@ -0,0 +1,67 @@ +.rowBrief { + display: flex; + min-height: 88.9px; + align-items: center; + .iconCetner { + display: flex; + align-items: center; + } + .content { + width: 100%; + .info { + display: flex; + justify-content: space-between; + width: 100%; + } + } +} + +.rowHeight { + display: flex; + min-height: 70px; +} + +.borderWidthPadding { + &::after { + content: ''; + height: 1px; + width: calc(100% - 56px); + background-color: var(--border-color); + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + } +} +.verifyContract { + display: flex; + align-items: center; + padding: 6px 16px; + min-height: 48px; + background: rgba(255, 200, 42, 0.16); + border: 1px solid rgba(255, 200, 42, 0.1); + border-radius: 8px; + a { + color: var(--link-color-useful); + } +} + +.hr { + margin: 60px 0px; + border-top: 1px solid rgba(var(--contrast-color-theme--raw), 0.2); +} + +.logItemLeftBorder { + position: relative; + &::before { + content: ''; + position: absolute; + left: 0; + top: 0; + width: 4px; + height: 100%; + background: rgba(255, 200, 42, 0.16); + border: 1px solid rgba(255, 200, 42, 0.1); + border-radius: 8px; + } +}