diff --git a/packages/react-components/src/AddressToggle.tsx b/packages/react-components/src/AddressToggle.tsx index b5688f6d84..d6708b50f7 100644 --- a/packages/react-components/src/AddressToggle.tsx +++ b/packages/react-components/src/AddressToggle.tsx @@ -34,9 +34,10 @@ function AddressToggle ({ address, className, filter, onChange, value }: Props): if (!filter || address.includes(filter) || extracted.toLowerCase().includes(filter)) { isFiltered = false; } else if (info) { - const { accountId, accountIndex, nickname } = info; + const { accountId, accountIndex, identity, nickname } = info; + const filterLower = filter.toLowerCase(); - if (accountId?.toString().includes(filter) || accountIndex?.toString().includes(filter) || nickname?.toLowerCase().includes(filter)) { + if (identity.displayName?.toLowerCase().includes(filterLower) || accountId?.toString().includes(filter) || accountIndex?.toString().includes(filter) || nickname?.toLowerCase().includes(filterLower)) { isFiltered = false; } } diff --git a/packages/react-components/src/Badge.tsx b/packages/react-components/src/Badge.tsx index 606e011d1b..f54ba44df7 100644 --- a/packages/react-components/src/Badge.tsx +++ b/packages/react-components/src/Badge.tsx @@ -12,18 +12,19 @@ interface Props { hover?: React.ReactNode; info: React.ReactNode; isInline?: boolean; + isSmall?: boolean; isTooltip?: boolean; - type: 'counter' | 'online' | 'offline' | 'next' | 'runnerup' | 'selected'; + type: 'counter' | 'online' | 'offline' | 'next' | 'runnerup' | 'selected' | 'green' | 'blue' | 'brown' | 'gray'; } let badgeId = 0; -function Badge ({ className, hover, info, isInline, isTooltip, type }: Props): React.ReactElement | null { +function Badge ({ className, hover, info, isInline, isSmall, isTooltip, type }: Props): React.ReactElement | null { const [key] = useState(`${Date.now()}-${badgeId++}`); return (
* { line-height: 22px; overflow: hidden; - transition: all ease 0.25; } - .badge { - font-weight: bold; - width: auto; + &.isSmall > * { + line-height: 16px; } .detail { diff --git a/packages/react-query/src/AccountName.tsx b/packages/react-query/src/AccountName.tsx index 4f93c2a3b9..92a0c277a3 100644 --- a/packages/react-query/src/AccountName.tsx +++ b/packages/react-query/src/AccountName.tsx @@ -7,6 +7,8 @@ import { BareProps } from '@polkadot/react-api/types'; import { AccountId, AccountIndex, Address } from '@polkadot/types/interfaces'; import React, { useEffect, useMemo, useState } from 'react'; +import styled from 'styled-components'; +import { Badge, Icon } from '@polkadot/react-components'; import { getAddressName } from '@polkadot/react-components/util'; import { useCall, useApi } from '@polkadot/react-hooks'; @@ -21,14 +23,14 @@ interface Props extends BareProps { withShort?: boolean; } -const nameCache: Map = new Map(); +const nameCache: Map = new Map(); -function defaultOrAddr (defaultName = '', _address: AccountId | AccountIndex | Address | string | Uint8Array, _accountIndex?: AccountIndex | null): string { +function defaultOrAddr (defaultName = '', _address: AccountId | AccountIndex | Address | string | Uint8Array, _accountIndex?: AccountIndex | null): [React.ReactNode, boolean] { const accountId = _address.toString(); const cached = nameCache.get(accountId); if (cached) { - return cached; + return [cached, false]; } const accountIndex = (_accountIndex || '').toString(); @@ -37,24 +39,68 @@ function defaultOrAddr (defaultName = '', _address: AccountId | AccountIndex | A if (isAddress && accountIndex) { nameCache.set(accountId, accountIndex); - return accountIndex; + return [accountIndex, false]; } - return extracted; + return [extracted, !isAddress]; } -export default function AccountName ({ children, className, defaultName, label, onClick, override, style, toggle, value, withShort }: Props): React.ReactElement { +function AccountName ({ children, className, defaultName, label, onClick, override, style, toggle, value, withShort }: Props): React.ReactElement { const { api } = useApi(); const info = useCall(api.derive.accounts.info as any, [value]); const address = useMemo((): string => (value || '').toString(), [value]); - const [name, setName] = useState(defaultOrAddr(defaultName, address)); + + const _extractName = (accountId?: AccountId, accountIndex?: AccountIndex): React.ReactNode => { + const [name, isLocal] = defaultOrAddr(defaultName, accountId || address, withShort ? null : accountIndex); + + return ( +
+
{name}
+
+ ); + }; + + const [name, setName] = useState((): React.ReactNode => _extractName()); useEffect((): void => { const { accountId, accountIndex, identity, nickname } = info || {}; - const retrieved = identity?.displayName || nickname; - if (retrieved) { - const name = retrieved.toUpperCase(); + if (api.query.identity?.identityOf) { + if (identity?.displayName) { + const { judgements, displayName } = identity; + const isGood = judgements.some(([, judgement]): boolean => judgement.isKnownGood || judgement.isReasonable); + const isBad = judgements.some(([, judgement]): boolean => judgement.isErroneous || judgement.isLowQuality); + + // FIXME This needs to be i18n, with plurals + const hover = `${judgements.length ? judgements.length : 'no'} judgement${judgements.length === 1 ? '' : 's'}${judgements.length ? ': ' : ''}${judgements.map(([, judgement]): string => judgement.toString()).join(', ')}`; + + const name = ( +
+ } + isInline + isSmall + isTooltip + type={ + isGood + ? 'green' + : isBad + ? 'brown' + : 'gray' + } + /> +
{displayName.toUpperCase()}
+
+ ); + + nameCache.set(address, name); + setName((): React.ReactNode => name); + } else { + setName((): React.ReactNode => _extractName(accountId, accountIndex)); + } + } else if (nickname) { + const name = nickname.toUpperCase(); nameCache.set(address, name); setName(name); @@ -77,3 +123,26 @@ export default function AccountName ({ children, className, defaultName, label,
); } + +export default styled(AccountName)` + .via-identity { + display: inline-block; + + .name { + display: inline-block; + + &.other { + opacity: 0.6; + } + } + + > * { + line-height: 1em; + vertical-align: middle; + } + + .ui--Badge { + margin-top: -2px; + } + } +`;