import React, { useState, useContext, useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useSelector } from 'react-redux'; import { toChecksumHexAddress } from '@metamask/controller-utils'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { shortenAddress } from '../../../helpers/utils/util'; import { AccountListItemMenu } from '..'; import { AvatarAccount, Box, AvatarFavicon, Tag, ButtonIcon, IconName, IconSize, AvatarAccountVariant, Text, } from '../../component-library'; import { Color, TextAlign, AlignItems, TextVariant, FlexDirection, BorderRadius, JustifyContent, Size, BorderColor, Display, BackgroundColor, BlockSize, } from '../../../helpers/constants/design-system'; import { HardwareKeyringNames } from '../../../../shared/constants/hardware-wallets'; import { KeyringType } from '../../../../shared/constants/keyring'; import UserPreferencedCurrencyDisplay from '../../app/user-preferenced-currency-display/user-preferenced-currency-display.component'; import { SECONDARY, PRIMARY } from '../../../helpers/constants/common'; import { findKeyringForAddress } from '../../../ducks/metamask/metamask'; import Tooltip from '../../ui/tooltip/tooltip'; import { MetaMetricsEventCategory, MetaMetricsEventName, } from '../../../../shared/constants/metametrics'; import { MetaMetricsContext } from '../../../contexts/metametrics'; const MAXIMUM_CURRENCY_DECIMALS = 3; const MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP = 17; function getLabel(keyring = {}, t) { const { type } = keyring; switch (type) { case KeyringType.qr: return HardwareKeyringNames.qr; case KeyringType.imported: return t('imported'); case KeyringType.trezor: return HardwareKeyringNames.trezor; case KeyringType.ledger: return HardwareKeyringNames.ledger; case KeyringType.lattice: return HardwareKeyringNames.lattice; ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) case KeyringType.snap: return t('snaps'); ///: END:ONLY_INCLUDE_IN default: return null; } } export const AccountListItem = ({ identity, selected = false, onClick, closeMenu, connectedAvatar, connectedAvatarName, }) => { const t = useI18nContext(); const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false); const [accountListItemMenuElement, setAccountListItemMenuElement] = useState(); const useBlockie = useSelector((state) => state.metamask.useBlockie); const setAccountListItemMenuRef = (ref) => { setAccountListItemMenuElement(ref); }; // If this is the selected item in the Account menu, // scroll the item into view const itemRef = useRef(null); useEffect(() => { if (selected) { itemRef.current?.scrollIntoView?.(); } }, [itemRef, selected]); const keyring = useSelector((state) => findKeyringForAddress(state, identity.address), ); const label = getLabel(keyring, t); const trackEvent = useContext(MetaMetricsContext); return ( { // Without this check, the account will be selected after // the account options menu closes if (!accountOptionsMenuOpen) { onClick(); } }} > {selected && ( )} { e.stopPropagation(); onClick(); }} variant={TextVariant.bodyMdMedium} className="multichain-account-list-item__account-name__button" padding={0} backgroundColor={BackgroundColor.transparent} width={BlockSize.Full} textAlign={TextAlign.Left} ellipsis > {identity.name.length > MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP ? ( {identity.name} ) : ( identity.name )} {connectedAvatar ? ( ) : null} {shortenAddress(toChecksumHexAddress(identity.address))} {label ? ( ) : null} { e.stopPropagation(); if (!accountOptionsMenuOpen) { trackEvent({ event: MetaMetricsEventName.AccountDetailMenuOpened, category: MetaMetricsEventCategory.Navigation, properties: { location: 'Account Options', }, }); } setAccountOptionsMenuOpen(!accountOptionsMenuOpen); }} data-testid="account-list-item-menu-button" /> setAccountOptionsMenuOpen(false)} isOpen={accountOptionsMenuOpen} isRemovable={keyring?.type !== KeyringType.hdKeyTree} closeMenu={closeMenu} /> ); }; AccountListItem.propTypes = { /** * Identity of the account */ identity: PropTypes.shape({ name: PropTypes.string.isRequired, address: PropTypes.string.isRequired, balance: PropTypes.string.isRequired, }).isRequired, /** * Represents if this account is currently selected */ selected: PropTypes.bool, /** * Function to execute when the item is clicked */ onClick: PropTypes.func.isRequired, /** * Function that closes the menu */ closeMenu: PropTypes.func, /** * File location of the avatar icon */ connectedAvatar: PropTypes.string, /** * Text used as the avatar alt text */ connectedAvatarName: PropTypes.string, }; AccountListItem.displayName = 'AccountListItem';