import { CopyAll, WarningRounded } from '@mui/icons-material' import clsx from 'clsx' import { useState } from 'react' import toast from 'react-hot-toast' import { useTranslation } from 'react-i18next' import { AccountType, ProfileWalletProps, TokenCardInfo, ValenceAccount, } from '@dao-dao/types' import { abbreviateAddress, areAccountsEqual, getDisplayNameForChainId, getImageUrlForChainId, sortTokensValueDescending, } from '@dao-dao/utils' import { Button } from '../buttons' import { ErrorPage } from '../error' import { DropdownIconButton } from '../icon_buttons' import { LineLoaders } from '../LineLoader' import { NoContent } from '../NoContent' import { FilterableItemPopup } from '../popup' import { TokenLineHeader } from '../token/TokenLineHeader' import { ValenceAccountDisplay } from '../ValenceAccountDisplay' export const ProfileWallet = ({ readOnly, accounts, tokens, hiddenTokens, TokenLine, ProfileAddChains, ...valenceAccountTreasuryProps }: ProfileWalletProps) => { const { t } = useTranslation() const valenceAccounts = accounts.loading || accounts.errored ? [] : accounts.data.filter( (account): account is ValenceAccount => account.type === AccountType.Valence ) // Separate valence from non-valence account tokens and display valence // separately. const nonValenceTokens = tokens.loading || tokens.errored ? [] : tokens.data.filter(({ owner }) => owner.type !== AccountType.Valence) const visibleBalances = tokens.loading || tokens.errored || hiddenTokens.loading || hiddenTokens.errored ? [] : nonValenceTokens .filter( ({ token }) => !hiddenTokens.data.includes(token.denomOrAddress) ) .sort(sortTokensValueDescending) const hiddenBalances = tokens.loading || tokens.errored || hiddenTokens.loading || hiddenTokens.errored ? [] : nonValenceTokens .filter(({ token }) => hiddenTokens.data.includes(token.denomOrAddress) ) .sort(sortTokensValueDescending) const [showingHidden, setShowingHidden] = useState(false) return (

{t('title.tokens')}

({ key: chainId + address, label: getDisplayNameForChainId(chainId), iconUrl: getImageUrlForChainId(chainId), description: abbreviateAddress(address), rightNode: (

{t(`accountTypeLabel.${type}`)}

), iconClassName: '!h-8 !w-8', contentContainerClassName: '!gap-4', chainId, address, })) } onSelect={({ chainId, address }) => { navigator.clipboard.writeText(address) toast.success( t('info.copiedChainAddress', { chain: getDisplayNameForChainId(chainId), }) ) }} searchPlaceholder={t('info.searchForChain')} trigger={{ type: 'button', props: { className: 'self-start', variant: 'secondary', contentContainerClassName: '!gap-1', loading: accounts.loading, disabled: accounts.loading || accounts.errored || accounts.data.length === 0, children: ( <> {t('button.copyAddress')} ), }, }} />
{tokens.loading || hiddenTokens.loading || (!tokens.errored && nonValenceTokens.length > 0) ? (
{tokens.loading || hiddenTokens.loading ? ( ) : (
{visibleBalances.map((props, index) => ( ))}
)}
) : tokens.errored ? ( ) : ( )} {hiddenBalances.length > 0 && !readOnly && (
setShowingHidden((s) => !s)} />
{hiddenBalances.map((props, index) => ( ))}
)}
{!readOnly && ( )} {/* Valence Accounts */} {valenceAccounts.map((account) => ( {...valenceAccountTreasuryProps} key={account.address} TokenLine={TokenLine} account={account} className="mt-6" tokens={ tokens.loading || tokens.errored ? tokens : { loading: false, errored: false, updating: tokens.updating, data: tokens.data.filter(({ owner }) => areAccountsEqual(owner, account) ), } } /> ))}
) } const FILTERABLE_KEYS = ['label', 'chainId', 'address']