diff --git a/packages/apps/src/SideBar/ChainInfo.tsx b/packages/apps/src/SideBar/ChainInfo.tsx index a74ba3cc77..8b4ce51f2d 100644 --- a/packages/apps/src/SideBar/ChainInfo.tsx +++ b/packages/apps/src/SideBar/ChainInfo.tsx @@ -6,7 +6,7 @@ import { RuntimeVersion } from '@polkadot/types/interfaces'; import React from 'react'; import styled from 'styled-components'; -import { ChainImg } from '@polkadot/react-components'; +import { ChainImg, Icon } from '@polkadot/react-components'; import { useCall, useApi } from '@polkadot/react-hooks'; import { BestNumber, Chain } from '@polkadot/react-query'; @@ -36,6 +36,7 @@ function ChainInfo ({ className, onClick }: Props): React.ReactElement { )} + ); @@ -43,26 +44,39 @@ function ChainInfo ({ className, onClick }: Props): React.ReactElement { export default React.memo(styled(ChainInfo)` border-top: 0.5rem solid transparent; + box-sizing: border-box; cursor: pointer; - padding: 0.75rem 1rem; - margin: 0 0 0.5rem -0.75rem; + padding: 0.75rem; + margin: 0 0 0.5rem -1rem; .apps--SideBar-logo-inner { display: flex; align-items: center; justify-content: space-between; - width: 10rem; + width: 10.5rem; img { + flex: 0; height: 2.75rem; width: 2.75rem; } + .icon.dropdown, > div.info { color: white; opacity: 0.75; text-align: right; vertical-align: middle; + } + + .icon.dropdown { + flex: 0; + margin: 0; + } + + > div.info { + flex: 1; + padding-right: 0.5rem; > div.chain { font-size: 0.9rem; diff --git a/packages/page-accounts/src/Sidebar/Identity.tsx b/packages/page-accounts/src/Sidebar/Identity.tsx new file mode 100644 index 0000000000..42d70460ab --- /dev/null +++ b/packages/page-accounts/src/Sidebar/Identity.tsx @@ -0,0 +1,182 @@ +// Copyright 2017-2020 @polkadot/app-accounts authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { AddressIdentity } from '@polkadot/react-hooks/types'; + +import React from 'react'; +import { AddressMini, AvatarItem, Icon, IconLink, Tag } from '@polkadot/react-components'; +import { useApi, useRegistrars, useToggle } from '@polkadot/react-hooks'; +import { isHex } from '@polkadot/util'; + +import { useTranslation } from '../translate'; +import RegistrarJudgement from './RegistrarJudgement'; + +interface Props { + address: string; + identity?: AddressIdentity; +} + +function Identity ({ address, identity }: Props): React.ReactElement | null { + const { t } = useTranslation(); + const { api } = useApi(); + const { isRegistrar, registrars } = useRegistrars(); + const [isJudgementOpen, toggleIsJudgementOpen] = useToggle(); + + if (!identity || !identity.isExistent || !api.query.identity?.identityOf) { + return null; + } + + return ( + <> +
+
+
+ +   + {t('identity')} +
+ + {identity.judgements.length}  + { + identity.judgements.length + ? (identity.isGood + ? (identity.isKnownGood ? t('Known good') : t('Reasonable')) + : (identity.isErroneous ? t('Erroneous') : t('Low quality')) + ) + : t('No judgments') + } + + } + size='tiny' + /> +
+
+ + // : + // + + } + subtitle={identity.legal} + title={identity.display} + /> +
+ {identity.parent && ( +
+
{t('parent')}
+
+ +
+
+ )} + {identity.email && ( +
+
{t('email')}
+
+ {isHex(identity.email) + ? identity.email + : ( + + {identity.email} + + )} +
+
+ )} + {identity.web && ( +
+
{t('website')}
+
+ {isHex(identity.web) + ? identity.web + : ( + + {identity.web} + + )} +
+
+ )} + {identity.twitter && ( +
+
{t('twitter')}
+
+ {isHex(identity.twitter) + ? identity.twitter + : ( + + {identity.twitter} + + )} +
+
+ )} + {identity.riot && ( +
+
{t('riot')}
+
+ {identity.riot} +
+
+ )} +
+
+
+ {isRegistrar && ( +
+
+
    +
  • + +
  • +
+
+
+ )} + {isJudgementOpen && isRegistrar && ( + + )} + + ); +} + +export default React.memo(Identity); diff --git a/packages/page-accounts/src/Sidebar/Sidebar.tsx b/packages/page-accounts/src/Sidebar/Sidebar.tsx index 071801ed0e..1a5960f441 100644 --- a/packages/page-accounts/src/Sidebar/Sidebar.tsx +++ b/packages/page-accounts/src/Sidebar/Sidebar.tsx @@ -6,16 +6,14 @@ import { BareProps } from '@polkadot/react-components/types'; import React, { useCallback } from 'react'; import styled from 'styled-components'; -import { useAccountInfo, useApi, useRegistrars, useToggle } from '@polkadot/react-hooks'; -import { classes } from '@polkadot/react-components/util'; +import { useAccountInfo, useToggle } from '@polkadot/react-hooks'; import { colorLink } from '@polkadot/react-components/styles/theme'; -import { AccountName, AddressMini, AvatarItem, Button, Icon, IconLink, IdentityIcon, Input, InputTags, LinkExternal, Tag } from '@polkadot/react-components'; -import { isHex } from '@polkadot/util'; +import { AccountName, Button, Icon, IdentityIcon, Input, InputTags, LinkExternal, Tag } from '@polkadot/react-components'; import Transfer from '../Accounts/modals/Transfer'; import { useTranslation } from '../translate'; import Flags from './Flags'; -import RegistrarJudgement from './RegistrarJudgement'; +import Identity from './Identity'; interface Props extends BareProps { address: string; @@ -23,14 +21,15 @@ interface Props extends BareProps { onUpdateName: () => void; } -function Sidebar ({ address, className, onClose, onUpdateName, style }: Props): React.ReactElement { +const TAG_OPTS = { + autoFocus: true +}; + +function Sidebar ({ address, className, onClose, onUpdateName }: Props): React.ReactElement { const { t } = useTranslation(); - const { api } = useApi(); - const { isRegistrar, registrars } = useRegistrars(); const { flags, identity, isEditingName, isEditingTags, name, onForgetAddress, onSaveName, onSaveTags, setName, setTags, tags, toggleIsEditingName, toggleIsEditingTags } = useAccountInfo(address); const [isHoveringButton, toggleIsHoveringButton] = useToggle(); const [isTransferOpen, toggleIsTransferOpen] = useToggle(); - const [isJudgementOpen, toggleIsJudgementOpen] = useToggle(); const _onForgetAddress = useCallback( (): void => { @@ -48,317 +47,166 @@ function Sidebar ({ address, className, onClose, onUpdateName, style }: Props): [onSaveName, onUpdateName] ); - const useIdentity = !!api.query.identity?.identityOf; - return ( - <> -
- - )} - -
- - {useIdentity && identity?.isExistent && ( -
-
-
- -   - {t('identity')} + > + {tags.length + ? tags.map((tag): React.ReactNode => ( + + )) + : + }
- - {identity.judgements.length}  - { - identity.judgements.length - ? (identity.isGood - ? (identity.isKnownGood ? t('Known good') : t('Reasonable')) - : (identity.isErroneous ? t('Erroneous') : t('Low quality')) - ) - : t('No judgments') - } - - } + ) + } + {(!isEditingTags && (flags.isInContacts || flags.isOwned)) && ( + + )} +
+ +
+ +
-
- - // : - // - - } - subtitle={identity.legal} - title={identity.display} + )} + {!flags.isOwned && !flags.isInContacts && ( +
-
- )} - {address && identity?.isExistent && isRegistrar && ( -
-
-
    -
  • - -
  • -
-
-
- )} -
- + )} + {!flags.isOwned && flags.isInContacts && ( + + )} + + {isTransferOpen && ( + + )}
- {isTransferOpen && ( - +
+ - )} - {(!!address && isJudgementOpen && isRegistrar && useIdentity) && ( - - )} - +
+ ); } diff --git a/packages/react-hooks/src/types.ts b/packages/react-hooks/src/types.ts index 400836ec67..885810b9fc 100644 --- a/packages/react-hooks/src/types.ts +++ b/packages/react-hooks/src/types.ts @@ -2,11 +2,12 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import { SubmittableExtrinsic } from '@polkadot/api/promise/types'; import { DeriveAccountFlags, DeriveAccountRegistration } from '@polkadot/api-derive/types'; import { ConstructTxFn, StringOrNull, VoidFn } from '@polkadot/react-components/types'; import { AccountId, Balance, BlockNumber, Call, Exposure, Hash, SessionIndex, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces'; import { IExtrinsic } from '@polkadot/types/types'; -import { SubmittableExtrinsic } from '@polkadot/api/promise/types'; +import { KeyringJson$Meta } from '@polkadot/ui-keyring/types'; export type CallParam = any; @@ -106,6 +107,7 @@ export interface UseAccountInfo { genesisHash: StringOrNull; identity?: AddressIdentity; isEditingName: boolean; + meta?: KeyringJson$Meta; toggleIsEditingName: VoidFn; isEditingTags: boolean; toggleIsEditingTags: VoidFn; diff --git a/packages/react-hooks/src/useAccountInfo.ts b/packages/react-hooks/src/useAccountInfo.ts index 7c89f4b658..34159c92ca 100644 --- a/packages/react-hooks/src/useAccountInfo.ts +++ b/packages/react-hooks/src/useAccountInfo.ts @@ -4,6 +4,7 @@ import { DeriveAccountFlags, DeriveAccountInfo } from '@polkadot/api-derive/types'; import { StringOrNull } from '@polkadot/react-components/types'; +import { KeyringJson$Meta } from '@polkadot/ui-keyring/types'; import { AddressFlags, AddressIdentity, UseAccountInfo } from './types'; import { useCallback, useEffect, useState } from 'react'; @@ -42,6 +43,7 @@ export default function useAccountInfo (value: string): UseAccountInfo { const [genesisHash, setGenesisHash] = useState(null); const [identity, setIdentity] = useState(); const [flags, setFlags] = useState(IS_NONE); + const [meta, setMeta] = useState(); const [isEditingName, toggleIsEditingName] = useToggle(); const [isEditingTags, toggleIsEditingTags] = useToggle(); @@ -106,6 +108,7 @@ export default function useAccountInfo (value: string): UseAccountInfo { isMultisig: accountOrAddress?.meta.isMultisig || false, isOwned })); + setMeta(accountOrAddress?.meta); setName(accountOrAddress?.meta.name || ''); setSortedTags(accountOrAddress?.meta.tags ? accountOrAddress.meta.tags.sort() : []); }, [identity, isAccount, isAddress, value]); @@ -199,6 +202,7 @@ export default function useAccountInfo (value: string): UseAccountInfo { identity, isEditingName, isEditingTags, + meta, name, onForgetAddress, onSaveName,