polkadot-js/extension

View on GitHub
packages/extension-ui/src/partials/MenuAdd.tsx

Summary

Maintainability
B
4 hrs
Test Coverage
// Copyright 2019-2024 @polkadot/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { faUsb } from '@fortawesome/free-brands-svg-icons';
import { faCodeBranch, faFileExport, faFileUpload, faKey, faPlusCircle, faQrcode } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { useCallback, useContext } from 'react';

import { AccountContext, Link, MediaContext, Menu, MenuDivider, MenuItem } from '../components/index.js';
import { useIsPopup, useLedger, useTranslation } from '../hooks/index.js';
import { windowOpen } from '../messaging.js';
import { styled } from '../styled.js';

interface Props {
  className?: string;
  reference: React.MutableRefObject<null>;
}

const jsonPath = '/account/restore-json';
const ledgerPath = '/account/import-ledger';

function MenuAdd ({ className, reference }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { master } = useContext(AccountContext);
  const mediaAllowed = useContext(MediaContext);
  const { isLedgerCapable, isLedgerEnabled } = useLedger();
  const isPopup = useIsPopup();

  const _openJson = useCallback(
    (): void => {
      windowOpen(jsonPath).catch(console.error);
    }, []
  );

  const _onOpenLedgerConnect = useCallback(
    (): void => {
      windowOpen(ledgerPath).catch(console.error);
    }, []
  );

  return (
    <Menu
      className={className}
      reference={reference}
    >
      <MenuItem className='menuItem'>
        <Link to={'/account/create'}>
          <FontAwesomeIcon icon={faPlusCircle} />
          <span>{ t('Create new account')}</span>
        </Link>
      </MenuItem>
      <MenuDivider />
      {!!master && (
        <>
          <MenuItem className='menuItem'>
            <Link to={`/account/derive/${master.address}`}>
              <FontAwesomeIcon icon={faCodeBranch} />
              <span>{t('Derive from an account')}</span>
            </Link>
          </MenuItem>
          <MenuDivider />
        </>
      )}
      <MenuItem className='menuItem'>
        <Link to={'/account/export-all'}>
          <FontAwesomeIcon icon={faFileExport} />
          <span>{t('Export all accounts')}</span>
        </Link>
      </MenuItem>
      <MenuItem className='menuItem'>
        <Link to='/account/import-seed'>
          <FontAwesomeIcon icon={faKey} />
          <span>{t('Import account from pre-existing seed')}</span>
        </Link>
      </MenuItem>
      <MenuItem className='menuItem'>
        <Link
          onClick={isPopup ? _openJson : undefined}
          to={isPopup ? undefined : jsonPath}
        >
          <FontAwesomeIcon icon={faFileUpload} />
          <span>{t('Restore account from backup JSON file')}</span>
        </Link>
      </MenuItem>
      <MenuDivider />
      <MenuItem className='menuItem'>
        <Link
          isDisabled={!mediaAllowed}
          title={!mediaAllowed
            ? t('Camera access must be first enabled in the settings')
            : ''
          }
          to='/account/import-qr'
        >
          <FontAwesomeIcon icon={faQrcode} />
          <span>{t('Attach external QR-signer account')}</span>
        </Link>
      </MenuItem>
      <MenuItem className='menuItem ledger'>
        {isLedgerEnabled
          ? (
            <Link
              isDisabled={!isLedgerCapable}
              title={ (!isLedgerCapable && t('Ledger devices can only be connected with Chrome browser')) || ''}
              to={ledgerPath}
            >
              <FontAwesomeIcon
                icon={faUsb}
                rotation={270}
              />
              <span>{ t('Attach ledger account')}</span>
            </Link>
          )
          : (
            <Link onClick={_onOpenLedgerConnect}>
              <FontAwesomeIcon
                icon={faUsb}
                rotation={270}
              />
              <span>{ t('Connect Ledger device')}</span>
            </Link>
          )
        }
      </MenuItem>
    </Menu>
  );
}

export default React.memo(styled(MenuAdd)<Props>`
  margin-top: 50px;
  right: 50px; // 24 + 18 + 8
  user-select: none;

  .menuItem {
    span:first-child {
      height: 20px;
      margin-right: 8px;
      opacity: 0.5;
      width: 20px;
    }

    span {
      vertical-align: middle;
    }

    .svg-inline--fa {
      color: var(--iconNeutralColor);
      margin-right: 0.3rem;
      width: 0.875em;
    }
  }
`);