Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/react-components/src/AddressToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
41 changes: 31 additions & 10 deletions packages/react-components/src/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Props> | null {
function Badge ({ className, hover, info, isInline, isSmall, isTooltip, type }: Props): React.ReactElement<Props> | null {
const [key] = useState(`${Date.now()}-${badgeId++}`);

return (
<div
className={`ui--Badge ${isInline && 'isInline'} ${isTooltip && 'isTooltip'} ${type} ${className}`}
className={`ui--Badge ${isInline && 'isInline'} ${isTooltip && 'isTooltip'} ${isSmall && 'isSmall'} ${type} ${className}`}
data-for={`badge-status-${key}`}
data-tip={true}
data-tip-disable={!isTooltip}
Expand Down Expand Up @@ -55,6 +56,20 @@ export default styled(Badge)`
text-align: center;
width: 22px;

i.icon {
margin: 0;
width: 1em;
}

&.isSmall {
box-shadow: none;
font-size: 10px;
height: 16px;
line-height: 16px;
padding: 0;
width: 16px;
}

&:not(.isInline) {
display: flex;
justify-content: center;
Expand All @@ -66,7 +81,8 @@ export default styled(Badge)`
margin-right: 0.25rem;
}

&.next {
&.next,
&.blue {
background: steelblue;
}

Expand All @@ -80,24 +96,29 @@ export default styled(Badge)`
vertical-align: middle;
}

&.runnerup {
&.gray {
background: #eee;
color: #888;
}

&.runnerup,
&.brown {
background: brown;
}

&.online,
&.selected {
&.selected,
&.green {
background: green;
}

& > * {
line-height: 22px;
overflow: hidden;
transition: all ease 0.25;
}

.badge {
font-weight: bold;
width: auto;
&.isSmall > * {
line-height: 16px;
}

.detail {
Expand Down
89 changes: 79 additions & 10 deletions packages/react-query/src/AccountName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -21,14 +23,14 @@ interface Props extends BareProps {
withShort?: boolean;
}

const nameCache: Map<string, string> = new Map();
const nameCache: Map<string, React.ReactNode> = 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();
Expand All @@ -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<Props> {
function AccountName ({ children, className, defaultName, label, onClick, override, style, toggle, value, withShort }: Props): React.ReactElement<Props> {
const { api } = useApi();
const info = useCall<DeriveAccountInfo>(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 (
<div className='via-identity'>
<div className={`name ${isLocal ? '' : 'other'}`}>{name}</div>
</div>
);
};

const [name, setName] = useState<React.ReactNode>((): 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 = (
<div className='via-identity'>
<Badge
hover={hover}
info={<Icon name={isGood ? 'check' : 'minus'} />}
isInline
isSmall
isTooltip
type={
isGood
? 'green'
: isBad
? 'brown'
: 'gray'
}
/>
<div className='name'>{displayName.toUpperCase()}</div>
</div>
);

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);
Expand All @@ -77,3 +123,26 @@ export default function AccountName ({ children, className, defaultName, label,
</div>
);
}

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;
}
}
`;