import Close from '@mui/icons-material/Close'
import ContentCopyRounded from '@mui/icons-material/ContentCopyRounded'
import OpenInNewRounded from '@mui/icons-material/OpenInNewRounded'
import { Box, IconButton, Link, Skeleton, Typography } from '@mui/material'
import { forwardRef, type PropsWithChildren, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useAvailableChains } from '../../hooks/useAvailableChains.js'
import { useExplorer } from '../../hooks/useExplorer.js'
import { useToken } from '../../hooks/useToken.js'
import { shortenAddress } from '../../utils/wallet.js'
import { TokenAvatar } from '../Avatar/TokenAvatar.js'
import { CardIconButton } from '../Card/CardIconButton.js'
import {
Label,
MetricContainer,
TokenDetailsSheetContainer,
TokenDetailsSheetHeader,
} from './TokenDetailsSheetContent.style.js'
import type { TokenDetailsSheetBase } from './types.js'
interface TokenDetailsSheetContentProps {
tokenAddress: string | undefined
chainId: number | undefined
withoutContractAddress: boolean
}
const noDataLabel = '-'
export const TokenDetailsSheetContent = forwardRef<
TokenDetailsSheetBase,
TokenDetailsSheetContentProps
>(({ tokenAddress, chainId, withoutContractAddress }, ref) => {
const { t } = useTranslation()
const { getAddressLink } = useExplorer()
const { getChainById } = useAvailableChains()
const { token, isLoading } = useToken(chainId, tokenAddress, true)
const chain = useMemo(() => getChainById(chainId), [chainId, getChainById])
const copyContractAddress = async (e: React.MouseEvent) => {
e.stopPropagation()
try {
// Clipboard API may throw if access is denied (e.g., in insecure contexts or older browsers)
await navigator.clipboard.writeText(tokenAddress || '')
} catch {
// Silently fail to avoid crashing the UI if clipboard write fails
}
}
return (
{isLoading ? (
<>
>
) : (
<>
{token?.symbol || noDataLabel}
>
)}
{
e.stopPropagation()
if (ref && typeof ref !== 'function') {
ref.current?.close()
}
}}
sx={{ mt: '-8px', mr: '-8px' }}
>
{token?.priceUSD
? t('format.currency', {
value: token.priceUSD,
})
: noDataLabel}
{!withoutContractAddress && (
{shortenAddress(tokenAddress)}
{tokenAddress && (
)}
{tokenAddress && (
e.stopPropagation()}
>
)}
)}
{token?.marketCapUSD
? t('format.currency', {
value: token.marketCapUSD,
notation: 'compact',
compactDisplay: 'short',
maximumFractionDigits: 2,
})
: noDataLabel}
{token?.volumeUSD24H
? t('format.currency', {
value: token.volumeUSD24H,
notation: 'compact',
compactDisplay: 'short',
maximumFractionDigits: 2,
})
: noDataLabel}
)
})
interface MetricWithSkeletonProps {
label: string
isLoading: boolean
width: number
height: number
}
const MetricWithSkeleton = ({
label,
width,
height,
isLoading,
children,
}: PropsWithChildren) => {
return (
{isLoading ? (
) : (
children
)}
)
}