/ src / components / UserDisplay.tsx
UserDisplay.tsx
  1  import { Box } from '@mui/material';
  2  import { blo } from 'blo';
  3  import { useMemo } from 'react';
  4  import useGetEns from 'src/libs/hooks/use-get-ens';
  5  import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
  6  import { useRootStore } from 'src/store/root';
  7  import { useShallow } from 'zustand/shallow';
  8  
  9  import { Avatar, AvatarProps } from './Avatar';
 10  import { BadgeSize, ExclamationBadge } from './badges/ExclamationBadge';
 11  import { UserNameText, UserNameTextProps } from './UserNameText';
 12  
 13  type UserDisplayProps = {
 14    oneLiner?: boolean;
 15    avatarProps?: AvatarProps;
 16    titleProps?: Omit<UserNameTextProps, 'address' | 'domainName'>;
 17    subtitleProps?: Omit<UserNameTextProps, 'address' | 'domainName'>;
 18    withLink?: boolean;
 19    funnel?: string;
 20  };
 21  
 22  export const UserDisplay: React.FC<UserDisplayProps> = ({
 23    oneLiner = false,
 24    avatarProps,
 25    titleProps,
 26    subtitleProps,
 27    withLink,
 28    funnel,
 29  }) => {
 30    const [account, defaultDomain, domainsLoading] = useRootStore(
 31      useShallow((state) => [state.account, state.defaultDomain, state.domainsLoading])
 32    );
 33    const { readOnlyMode } = useWeb3Context();
 34  
 35    const fallbackImage = useMemo(
 36      () => (account ? blo(account as `0x${string}`) : undefined),
 37      [account]
 38    );
 39    const loading = domainsLoading;
 40  
 41    return (
 42      <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
 43        <Avatar
 44          fallbackImage={fallbackImage}
 45          image={defaultDomain?.avatar}
 46          loading={loading}
 47          badge={<ExclamationBadge size={BadgeSize.SM} />}
 48          invisibleBadge={!readOnlyMode}
 49          {...avatarProps}
 50        />
 51        <Box sx={{ display: 'flex', flexDirection: 'column' }}>
 52          {!oneLiner && defaultDomain?.name ? (
 53            <>
 54              <UserNameText
 55                address={account}
 56                loading={loading}
 57                domainName={defaultDomain.name}
 58                variant="h4"
 59                link={withLink ? `https://etherscan.io/address/${account}` : undefined}
 60                funnel={funnel}
 61                {...titleProps}
 62              />
 63              <UserNameText
 64                address={account}
 65                loading={loading}
 66                variant="caption"
 67                {...subtitleProps}
 68              />
 69            </>
 70          ) : (
 71            <UserNameText
 72              address={account}
 73              domainName={defaultDomain?.name}
 74              loading={loading}
 75              variant="h4"
 76              link={withLink ? `https://etherscan.io/address/${account}` : undefined}
 77              funnel={funnel}
 78              {...titleProps}
 79            />
 80          )}
 81        </Box>
 82      </Box>
 83    );
 84  };
 85  
 86  interface ExternalUserDisplayProps {
 87    avatarProps?: AvatarProps;
 88    titleProps?: Omit<UserNameTextProps, 'address'>;
 89    address: string;
 90  }
 91  
 92  export const ExternalUserDisplay: React.FC<ExternalUserDisplayProps> = ({
 93    avatarProps,
 94    titleProps,
 95    address,
 96  }) => {
 97    const { name, avatar } = useGetEns(address);
 98  
 99    const fallbackImage = useMemo(
100      () => (address ? blo(address as `0x${string}`) : undefined),
101      [address]
102    );
103    return (
104      <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
105        <Avatar image={avatar} fallbackImage={fallbackImage} {...avatarProps} />
106        <UserNameText
107          variant="h4"
108          address={address}
109          domainName={name}
110          link={`https://etherscan.io/address/${address}`}
111          iconSize={14}
112          {...titleProps}
113          funnel={'Delegation power panel: Governance'}
114        />
115      </Box>
116    );
117  };