Skip to content

Commit

Permalink
Merge pull request #685 from oasisprotocol/csillag/show-type-in-token…
Browse files Browse the repository at this point in the history
…-table

Display type in tokens table
  • Loading branch information
csillag committed Jul 9, 2023
2 parents dbbeaa1 + 3985b5b commit 40e64d2
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 27 deletions.
1 change: 1 addition & 0 deletions .changelog/685.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Display type in tokens table
6 changes: 6 additions & 0 deletions src/app/components/Tokens/TokenDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { DashboardLink } from '../../pages/ParatimeDashboardPage/DashboardLink'
import { DelayedContractVerificationIcon } from '../ContractVerificationIcon'
import Box from '@mui/material/Box'
import { COLORS } from '../../../styles/theme/colors'
import { TokenTypeTag } from './TokenList'

export const TokenDetails: FC<{
isLoading?: boolean
Expand Down Expand Up @@ -40,6 +41,11 @@ export const TokenDetails: FC<{
<Box sx={{ ml: 3, fontWeight: 700, color: COLORS.grayMedium }}>({token.symbol})</Box>
</dd>

<dt>{t('common.type')}</dt>
<dd>
<TokenTypeTag tokenType={token.type} />
</dd>

<dt>{t(isMobile ? 'common.smartContract_short' : 'common.smartContract')}</dt>
<dd>
<span>
Expand Down
46 changes: 44 additions & 2 deletions src/app/components/Tokens/TokenList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { useTranslation } from 'react-i18next'
import { EvmToken } from '../../../oasis-nexus/api'
import { EvmToken, EvmTokenType } from '../../../oasis-nexus/api'
import { Table, TableCellAlign, TableColProps } from '../../components/Table'
import { TablePaginationProps } from '../Table/TablePagination'
import { AccountLink } from '../Account/AccountLink'
import { TokenLink } from './TokenLink'
import { CopyToClipboard } from '../CopyToClipboard'
import { DelayedContractVerificationIcon } from '../ContractVerificationIcon'
import { DelayedContractVerificationIcon, verificationIconBoxHeight } from '../ContractVerificationIcon'
import Box from '@mui/material/Box'
import {
getTokenTypeDescription,
getTokenTypeStrictName,
tokenBackgroundColor,
tokenBorderColor,
} from '../../../types/tokens'
import { FC } from 'react'
import Typography from '@mui/material/Typography'
import { COLORS } from '../../../styles/theme/colors'
import { SxProps } from '@mui/material/styles'

type TokensProps = {
tokens?: EvmToken[]
Expand All @@ -15,12 +25,40 @@ type TokensProps = {
pagination: false | TablePaginationProps
}

export const TokenTypeTag: FC<{ tokenType: EvmTokenType; sx?: SxProps }> = ({ tokenType, sx = {} }) => {
const { t } = useTranslation()
return (
<Box
sx={{
background: tokenBackgroundColor[tokenType],
border: `1px solid ${tokenBorderColor[tokenType]}`,
display: 'inline-block',
borderRadius: 2,
py: 1,
px: 3,
fontSize: 12,
height: verificationIconBoxHeight,
verticalAlign: 'middle',
textAlign: 'center',
...sx,
}}
>
<Typography component="span">{getTokenTypeDescription(t, tokenType)}</Typography>
&nbsp;
<Typography component="span" color={COLORS.grayMedium}>
{t('common.parentheses', { subject: getTokenTypeStrictName(t, tokenType) })}
</Typography>
</Box>
)
}

export const TokenList = (props: TokensProps) => {
const { isLoading, tokens, pagination, limit } = props
const { t } = useTranslation()
const tableColumns: TableColProps[] = [
{ key: 'index', content: '' },
{ key: 'name', content: t('common.name') },
{ key: 'type', content: t('common.type') },
{ key: 'contract', content: t('common.smartContract') },
{ key: 'verification', content: t('contract.verification.title') },
{
Expand Down Expand Up @@ -54,6 +92,10 @@ export const TokenList = (props: TokensProps) => {
),
key: 'name',
},
{
key: 'type',
content: <TokenTypeTag tokenType={token.type} sx={{ width: '100%' }} />,
},
{
content: (
<span>
Expand Down
15 changes: 12 additions & 3 deletions src/app/pages/AccountDetailsPage/AccountTokensCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { useAccount } from './hook'
import { TokenLink } from '../../components/Tokens/TokenLink'
import { AccountLink } from '../../components/Account/AccountLink'
import {
getTokenTypePluralDescription,
getTokenTypePluralName,
getTokenTypeStrictName,
} from '../../../types/tokens'

type AccountTokensCardProps = {
type: EvmTokenType
Expand All @@ -28,8 +33,7 @@ export const AccountTokensCard: FC<AccountTokensCardProps> = ({ type }) => {
const address = useLoaderData() as string
const { t } = useTranslation()
const locationHash = useLocation().hash.replace('#', '')
const tokenLabel = t(`account.${type}` as any)
const tokenListLabel = t('account.tokensListTitle', { token: tokenLabel })
const tokenListLabel = getTokenTypePluralName(t, type)
const tableColumns: TableColProps[] = [
{ key: 'name', content: t('common.name') },
{ key: 'contract', content: t('common.smartContract') },
Expand Down Expand Up @@ -86,7 +90,12 @@ export const AccountTokensCard: FC<AccountTokensCardProps> = ({ type }) => {
<CardHeader disableTypography component="h3" title={tokenListLabel} />
<CardContent>
{!isLoading && !account?.tokenBalances[type]?.length && (
<CardEmptyState label={t('account.emptyTokenList', { token: tokenLabel })} />
<CardEmptyState
label={t('account.emptyTokenList', {
spec: getTokenTypeStrictName(t, type),
description: getTokenTypePluralDescription(t, type),
})}
/>
)}

<Table
Expand Down
5 changes: 3 additions & 2 deletions src/app/pages/AccountDetailsPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { CardEmptyState } from './CardEmptyState'
import { contractCodeContainerId } from './ContractCodeCard'
import { useTokenInfo } from '../TokenDashboardPage/hook'
import { accountTokenTransfersContainerId } from './AccountTokenTransfersCard'
import { getTokenTypePluralName } from '../../../types/tokens'

export const AccountDetailsPage: FC = () => {
const { t } = useTranslation()
Expand Down Expand Up @@ -65,12 +66,12 @@ export const AccountDetailsPage: FC = () => {
{ label: t('common.transactions'), to: txLink, visible: showTxs },
{ label: t('tokens.transfers'), to: tokenTransfersLink, visible: showTokenTransfers },
{
label: t('account.tokensListTitle', { token: t(`account.ERC20`) }),
label: getTokenTypePluralName(t, EvmTokenType.ERC20),
to: erc20Link,
visible: showErc20,
},
{
label: t('account.tokensListTitle', { token: t(`account.ERC721`) }),
label: getTokenTypePluralName(t, EvmTokenType.ERC721),
to: erc721Link,
visible: showErc721,
},
Expand Down
6 changes: 4 additions & 2 deletions src/app/pages/TokenDashboardPage/TokenDetailsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import { useTranslation } from 'react-i18next'
import { AccountLink } from '../../components/Account/AccountLink'
import { CopyToClipboard } from '../../components/CopyToClipboard'
import { DelayedContractVerificationIcon } from '../../components/ContractVerificationIcon'
import { getTokenTypeName } from './TokenTypeCard'
import { getNameForTicker, Ticker } from '../../../types/ticker'
import { DelayedContractCreatorInfo } from '../../components/Account/ContractCreatorInfo'
import CardContent from '@mui/material/CardContent'
import { TokenTypeTag } from '../../components/Tokens/TokenList'

export const TokenDetailsCard: FC = () => {
const { t } = useTranslation()
Expand Down Expand Up @@ -57,7 +57,9 @@ export const TokenDetailsCard: FC = () => {
</dd>

<dt>{t('common.type')} </dt>
<dd>{getTokenTypeName(t, token.type)} </dd>
<dd>
<TokenTypeTag tokenType={token.type} />
</dd>

<dt>{t('contract.creator')}</dt>
<dd>
Expand Down
18 changes: 2 additions & 16 deletions src/app/pages/TokenDashboardPage/TokenTypeCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,7 @@ import { COLORS } from '../../../styles/theme/colors'
import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { useTokenInfo } from './hook'
import { useLoaderData } from 'react-router-dom'
import { EvmTokenType } from '../../../oasis-nexus/api'
import { TFunction } from 'i18next'
import { exhaustedTypeWarning } from '../../../types/errors'

export const getTokenTypeName = (t: TFunction, type: EvmTokenType): string => {
switch (type) {
case 'ERC20':
return t('account.ERC20')
case 'ERC721':
return t('account.ERC721')
default:
exhaustedTypeWarning('Unknown token type', type)
return type
}
}
import { getTokenTypeName } from '../../../types/tokens'

export const TokenTypeCard: FC = () => {
const { t } = useTranslation()
Expand All @@ -32,7 +18,7 @@ export const TokenTypeCard: FC = () => {
const { token, isFetched } = useTokenInfo(scope, address)

return (
<SnapshotCard title={t('tokens.type')} withConstantHeight>
<SnapshotCard title={t('common.type')} withConstantHeight>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
{isFetched && (
<>
Expand Down
7 changes: 5 additions & 2 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
"appName": "Oasis Explorer",
"account": {
"cantLoadDetails": "Unfortunately we couldn't load the account details at this time. Please try again later.",
"emptyTokenList": "This account holds no {{token}} tokens.",
"emptyTokenList": "This account holds no {{spec}} {{description}}.",
"emptyTransactionList": "There are no transactions on record for this account.",
"emptyTokenTransferList": "There are no token transfers on record for this account.",
"ERC20": "ERC-20",
"ERC721": "ERC-721",
"noTokens": "This account holds no tokens",
"showMore": "+ {{counter}} more",
"title": "Account",
"tokensListTitle": "{{token}} Tokens",
"transactionsListTitle": "Account Transactions",
"totalReceived": "Total Received",
"totalSent": "Total Sent"
Expand Down Expand Up @@ -65,8 +64,11 @@
"lessThanAmount": "< {{value}} {{ticker}}",
"missing": "n/a",
"name": "Name",
"nft": "NFT",
"nfts": "NFTs",
"oasis": "Oasis",
"paratime": "Paratime",
"parentheses":"({{subject}})",
"percentage": "Percentage",
"rank": "Rank",
"select": "Select",
Expand Down Expand Up @@ -203,6 +205,7 @@
"request": "Request test tokens"
},
"tokens": {
"typeDescription": "{{description}} ({{spec}})",
"emptyTokenHolderList": "There are no token holders on record for this token.",
"holders": "Token Holders",
"holdersValue": "{{ value, number }}",
Expand Down
3 changes: 3 additions & 0 deletions src/styles/theme/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const COLORS = {
brandExtraLight: '#e5e5ef',
brandLight: '#6665d8',
brandMedium: '#0092f6',
brandMedium15: '#d9effe',
brightGray2: '#ececec',
brightGray: '#e6edf3',
ceil: '#8f8cdf',
Expand Down Expand Up @@ -51,4 +52,6 @@ export const COLORS = {
graphLabel: '#191932',
graphLine: '#01F1E3',
paraTimeStatus: '#8081ac',
pink: '#ed32fa',
pink15: '#fce0fe',
} satisfies { [colorName: string]: string }
62 changes: 62 additions & 0 deletions src/types/tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { EvmTokenType } from '../oasis-nexus/api'
import { TFunction } from 'i18next'
import { exhaustedTypeWarning } from './errors'
import { COLORS } from '../styles/theme/colors'

export const getTokenTypeDescription = (t: TFunction, tokenType: EvmTokenType): string => {
switch (tokenType) {
case 'ERC20':
return t('common.token')
case 'ERC721':
return t('common.nft')
default:
exhaustedTypeWarning('Unknown token type', tokenType)
return '???'
}
}

export const tokenBackgroundColor: Record<EvmTokenType, string> = {
ERC20: COLORS.brandMedium15,
ERC721: COLORS.pink15,
}

export const tokenBorderColor: Record<EvmTokenType, string> = {
ERC20: COLORS.brandMedium,
ERC721: COLORS.pink,
}

export const getTokenTypePluralDescription = (t: TFunction, tokenType: EvmTokenType): string => {
switch (tokenType) {
case 'ERC20':
return t('common.tokens')
case 'ERC721':
return t('common.nfts')
default:
exhaustedTypeWarning('Unknown token type', tokenType)
return '???'
}
}

export const getTokenTypeStrictName = (t: TFunction, tokenType: EvmTokenType): string => {
switch (tokenType) {
case 'ERC20':
return t('account.ERC20')
case 'ERC721':
return t('account.ERC721')
default:
exhaustedTypeWarning('Unknown token type', tokenType)
return tokenType
}
}

export const getTokenTypeName = (t: TFunction, tokenType: EvmTokenType): string =>
t('tokens.typeDescription', {
spec: getTokenTypeStrictName(t, tokenType),
description: getTokenTypeDescription(t, tokenType),
})

export const getTokenTypePluralName = (t: TFunction, tokenType: EvmTokenType): string =>
t('tokens.typeDescription', {
spec: getTokenTypeStrictName(t, tokenType),
description: getTokenTypePluralDescription(t, tokenType),
})

0 comments on commit 40e64d2

Please sign in to comment.