polkadot-js/apps

View on GitHub
packages/react-components/src/AccountSidebar/Identity.tsx

Summary

Maintainability
A
1 hr
Test Coverage
// Copyright 2017-2024 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { AddressIdentity } from '@polkadot/react-hooks/types';

import React, { useMemo } from 'react';

import { useApi, useRegistrars, useSubidentities, useToggle } from '@polkadot/react-hooks';
import { AddressIdentityOtherDiscordKey } from '@polkadot/react-hooks/types';
import { isHex } from '@polkadot/util';

import AddressMini from '../AddressMini.js';
import AvatarItem from '../AvatarItem.js';
import Expander from '../Expander.js';
import IconLink from '../IconLink.js';
import { useTranslation } from '../translate.js';
import Judgements from './Judgements.js';
import RegistrarJudgement from './RegistrarJudgement.js';
import UserIcon from './UserIcon.js';

interface Props {
  address: string;
  identity?: AddressIdentity;
}

const SUBS_DISPLAY_THRESHOLD = 4;

function Identity ({ address, identity }: Props): React.ReactElement<Props> | null {
  const { t } = useTranslation();
  const { apiIdentity } = useApi();
  const { isRegistrar, registrars } = useRegistrars();
  const [isJudgementOpen, toggleIsJudgementOpen] = useToggle();
  const subs = useSubidentities(address);

  const subsList = useMemo(() =>
    subs?.map((sub) =>
      <AddressMini
        className='subs'
        isPadded={false}
        key={sub.toString()}
        value={sub}
      />
    )
  , [subs]
  );

  if (!identity || !identity.isExistent || !apiIdentity.query.identity?.identityOf) {
    return null;
  }

  return (
    <section
      className='withDivider'
      data-testid='identity-section'
    >
      <div className='ui--AddressMenu-section ui--AddressMenu-identity'>
        <div className='ui--AddressMenu-sectionHeader'>
          {t('identity')}
        </div>
        <div>
          <AvatarItem
            icon={
              // This won't work - images are IPFS hashes
              // identity.image
              //   ? <img src={identity.image} />
              //   : <i className='icon user ui--AddressMenu-identityIcon' />
              //
              <UserIcon />
            }
            subtitle={identity.legal}
            title={identity.display}
          />
          <Judgements address={address} />
          <div className='ui--AddressMenu-identityTable'>
            {identity.parent && (
              <div className='tr parent'>
                <div className='th'>{t('parent')}</div>
                <div className='td'>
                  <AddressMini
                    className='parent'
                    isPadded={false}
                    value={identity.parent}
                  />
                </div>
              </div>
            )}
            {identity.email && (
              <div className='tr'>
                <div className='th'>{t('email')}</div>
                <div className='td'>
                  {isHex(identity.email) || !identity.isKnownGood
                    ? identity.email
                    : (
                      <a
                        href={`mailto:${identity.email}`}
                        rel='noopener noreferrer'
                        target='_blank'
                      >
                        {identity.email}
                      </a>
                    )}
                </div>
              </div>
            )}
            {identity.web && (
              <div className='tr'>
                <div className='th'>{t('website')}</div>
                <div className='td'>
                  {isHex(identity.web) || !identity.isKnownGood
                    ? identity.web
                    : (
                      <a
                        href={(identity.web).replace(/^(https?:\/\/)?/g, 'https://')}
                        rel='noopener noreferrer'
                        target='_blank'
                      >
                        {identity.web}
                      </a>
                    )}
                </div>
              </div>
            )}
            {identity.twitter && (
              <div className='tr'>
                <div className='th'>{t('twitter')}</div>
                <div className='td'>
                  {isHex(identity.twitter) || !identity.isKnownGood
                    ? identity.twitter
                    : (
                      <a
                        href={
                          (identity.twitter).startsWith('https://twitter.com/')
                            ? (identity.twitter)
                            : `https://twitter.com/${identity.twitter}`
                        }
                        rel='noopener noreferrer'
                        target='_blank'
                      >
                        {identity.twitter}
                      </a>
                    )}
                </div>
              </div>
            )}
            {identity.other && AddressIdentityOtherDiscordKey in identity.other && (
              <div className='tr'>
                <div className='th'>{t('discord')}</div>
                <div className='td'>
                  {identity.other[AddressIdentityOtherDiscordKey]}
                </div>
              </div>
            )}
            {identity.riot && (
              <div className='tr'>
                <div className='th'>{t('riot')}</div>
                <div className='td'>
                  {identity.riot}
                </div>
              </div>
            )}
            {!!subs?.length && (
              <div className='tr'>
                <div className='th top'>{t('subs')}</div>
                <div
                  className='td'
                  data-testid='subs'
                >
                  {subs.length > SUBS_DISPLAY_THRESHOLD
                    ? (
                      <Expander summary={subs.length}>
                        {subsList}
                      </Expander>
                    )
                    : (
                      <>
                        <div className='subs-number'>{subs.length}</div>
                        {subsList}
                      </>
                    )
                  }
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
      {isRegistrar && (
        <div className='ui--AddressMenu-section'>
          <div className='ui--AddressMenu-actions'>
            <ul>
              <li>
                <IconLink
                  icon='address-card'
                  label={t('Add identity judgment')}
                  onClick={toggleIsJudgementOpen}
                />
              </li>
            </ul>
          </div>
        </div>
      )}
      {isJudgementOpen && isRegistrar && (
        <RegistrarJudgement
          address={address}
          key='modal-judgement'
          registrars={registrars}
          toggleJudgement={toggleIsJudgementOpen}
        />
      )}
    </section>
  );
}

export default React.memo(Identity);