import { ArrowOutwardRounded } from '@mui/icons-material' import clsx from 'clsx' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { HugeDecimal } from '@dao-dao/math' import { PopupTriggerCustomComponent, ValidatorPickerProps, } from '@dao-dao/types' import { formatPercentOf100 } from '@dao-dao/utils' import { Button } from './buttons' import { CopyToClipboard } from './CopyToClipboard' import { IconButtonLink } from './icon_buttons' import { InputThemedText } from './inputs' import { FilterableItemPopup } from './popup' import { TokenAmountDisplay } from './token' import { Tooltip } from './tooltip' export const ValidatorPicker = ({ validators, stakes, selectedAddress, readOnly = false, onSelect, token, displayClassName, }: ValidatorPickerProps) => { const { t } = useTranslation() const selectedValidator = validators.find( (validator) => validator.address === selectedAddress ) // Map validator address to staked amount. const validatorStakedAmountMap = stakes?.reduce( (acc, stake) => ({ ...acc, [stake.validator.address]: stake.amount, }), {} as Record ) // Sort staked first, then by total staked tokens (i.e. voting power and // popularity). const sortedValidators = [...validators].sort((a, b) => { // Get the staked amount for each validator address. const aStake = validatorStakedAmountMap?.[a.address] const bStake = validatorStakedAmountMap?.[b.address] // If both validators have a stake, sort by stake. if (aStake && bStake) { return bStake.minus(aStake).toNumber() } // If only one validator has a stake, sort that one first. else if (aStake) { return -1 } else if (bStake) { return 1 } // If neither validator has a stake, sort by total tokens staked (i.e. // popularity). return b.tokens.minus(a.tokens).toNumber() }) const TriggerRenderer: PopupTriggerCustomComponent = useCallback( ({ open, ...props }) => (
{selectedAddress ? ( {!readOnly && ( )} ) : !readOnly ? ( ) : null}
), [displayClassName, readOnly, selectedAddress, selectedValidator?.moniker, t] ) return ( { const { address, moniker, details, website, commission, tokens, status, } = validator const existingStake = stakes?.find( (stake) => stake.validator.address === address ) return { validator, key: address, label: moniker, description: (

{t('title.commission')}:{' '} {formatPercentOf100(commission * 100)}

{details &&

{details}

} {existingStake && ( <>

{t('title.staked')}:

{t('info.pendingRewards')}:

)} {status !== 'BOND_STATUS_BONDED' && (

{t('error.notInActiveSet')}

)}
), searchableDescription: commission + details, rightNode: website ? ( { // Don't click on item button. event.stopPropagation() }} variant="ghost" /> ) : undefined, selected: address === selectedAddress, } })} onSelect={({ validator }) => onSelect(validator)} searchPlaceholder={t('info.searchValidatorsPlaceholder')} trigger={{ type: 'custom', Renderer: TriggerRenderer, }} /> ) } const FILTERABLE_KEYS = ['label', 'searchableDescription']