Cleanups for AccountName (#2446)

* Cleanus for AccountName

* Remove unused toggle prop

* Re-add toggle
This commit is contained in:
Jaco Greeff 2020-03-23 17:18:31 +01:00 committed by GitHub
parent e36d7c35d7
commit 76b16913c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 147 additions and 123 deletions

View File

@ -2,15 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { DeriveAccountInfo } from '@polkadot/api-derive/types';
import { DeriveAccountInfo, DeriveAccountRegistration } from '@polkadot/api-derive/types';
import { BareProps } from '@polkadot/react-api/types';
import { AccountId, AccountIndex, Address, RegistrarInfo } from '@polkadot/types/interfaces';
import { AccountId, AccountIndex, Address } from '@polkadot/types/interfaces';
import React, { useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import registry from '@polkadot/react-api/typeRegistry';
import { useCall, useAccounts, useApi, useToggle } from '@polkadot/react-hooks';
import { Option } from '@polkadot/types';
import { useCall, useApi, useRegistrars, useToggle } from '@polkadot/react-hooks';
import { stringToU8a } from '@polkadot/util';
import { useTranslation } from './translate';
@ -26,7 +25,8 @@ interface Props extends BareProps {
label?: React.ReactNode;
onClick?: () => void;
override?: React.ReactNode;
toggle?: any;
// this is used by app-account/addresses to toggle editing
toggle?: boolean;
value: AccountId | AccountIndex | Address | string | Uint8Array | null | undefined;
}
@ -68,7 +68,7 @@ function defaultOrAddr (defaultName = '', _address: AccountId | AccountIndex | A
return [[extracted, null], !isAddressExtracted, isAddressExtracted, false];
}
function extractName (address: AccountId | string, accountIndex?: AccountIndex, defaultName?: string): React.ReactNode {
function extractName (address: string, accountIndex?: AccountIndex, defaultName?: string): React.ReactNode {
const [[displayFirst, displaySecond], isLocal, isAddress, isSpecial] = defaultOrAddr(defaultName, address, accountIndex);
return (
@ -90,132 +90,123 @@ function extractName (address: AccountId | string, accountIndex?: AccountIndex,
);
}
function extractIdentity (address: string, identity: DeriveAccountRegistration, onJudge: undefined | (() => void), t: (key: string, opts?: object) => string): React.ReactNode {
const judgements = identity.judgements.filter(([, judgement]): boolean => !judgement.isFeePaid);
const isGood = judgements.some(([, judgement]): boolean => judgement.isKnownGood || judgement.isReasonable);
const isBad = judgements.some(([, judgement]): boolean => judgement.isErroneous || judgement.isLowQuality);
const waitCount = identity.judgements.length - judgements.length;
const hover = (
<div>
<div>
{
judgements.length
? (judgements.length === 1
? t('1 judgement')
: t('{{count}} judgements', { replace: { count: judgements.length } })
)
: t('no judgements')
}{judgements.length ? ': ' : ''}{judgements.map(([, judgement]): string => judgement.toString()).join(', ')}{
waitCount
? t(' ({{count}} waiting)', { replace: { count: waitCount } })
: ''
}
</div>
<table>
<tbody>
{identity.parent && (
<tr>
<td>{t('parent')}</td>
<td><AddressMini value={identity.parent} /></td>
</tr>
)}
{DISPLAY_KEYS
.filter((key): boolean => !!identity[key as 'web'])
.map((key): React.ReactNode => (
<tr key={key}>
<td>{t(key)}</td>
<td>{identity[key as 'web']}</td>
</tr>
))
}
</tbody>
</table>
</div>
);
const displayName = isGood
? identity.display
: (identity.display || '').replace(/[^\x20-\x7E]/g, '');
const displayParent = identity.displayParent
? (
isGood
? identity.displayParent
: identity.displayParent.replace(/[^\x20-\x7E]/g, '')
)
: undefined;
nameCache.set(address, [false, displayParent ? [displayParent, displayName] : [displayName, null]]);
return (
<div className='via-identity'>
<Badge
hover={hover}
info={<Icon name={identity.parent ? 'caret square up outline' : (isGood ? 'check' : 'minus')} />}
isInline
isSmall
isTooltip
onClick={onJudge}
type={
isGood
? 'green'
: isBad
? 'brown'
: 'gray'
}
/>
{
displayParent
? <span className={`name ${isGood && 'isGood'}`}><span className='top'>{displayParent}</span><span className='sub'>/{displayName}</span></span>
: <span className={`name ${isGood && 'isGood'}`}>{displayName}</span>
}
</div>
);
}
function AccountName ({ children, className, defaultName, label, onClick, override, style, toggle, value }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { allAccounts } = useAccounts();
const { isRegistrar, registrars } = useRegistrars();
const [isJudgementOpen, toggleJudgement] = useToggle();
const registrars = useCall<Option<RegistrarInfo>[]>(api.query.identity?.registrars, []);
const info = useCall<DeriveAccountInfo>(api.derive.accounts.info as any, [value]);
const [isRegistrar, setIsRegistrar] = useState(false);
const address = useMemo((): string => (value || '').toString(), [value]);
const [name, setName] = useState<React.ReactNode>((): React.ReactNode => extractName((value || '').toString(), undefined, defaultName));
// determine if we have a registrar or not - registrars are allowed to approve
useEffect((): void => {
allAccounts && registrars && setIsRegistrar(
registrars
.map((registrar): string| null =>
registrar.isSome
? registrar.unwrap().account.toString()
: null
)
.some((regId): boolean => !!regId && allAccounts.includes(regId))
);
}, [allAccounts, registrars]);
// set the actual nickname, local name, accountIndex, accountId
useEffect((): void => {
const { accountId, accountIndex, identity, nickname } = info || {};
const cacheAddr = (accountId || address).toString();
if (api.query.identity?.identityOf) {
if (identity?.display) {
const judgements = identity.judgements.filter(([, judgement]): boolean => !judgement.isFeePaid);
const isGood = judgements.some(([, judgement]): boolean => judgement.isKnownGood || judgement.isReasonable);
const isBad = judgements.some(([, judgement]): boolean => judgement.isErroneous || judgement.isLowQuality);
const waitCount = identity.judgements.length - judgements.length;
const hover = (
<div>
<div>
{
judgements.length
? (judgements.length === 1
? t('1 judgement')
: t('{{count}} judgements', { replace: { count: judgements.length } })
)
: t('no judgements')
}{judgements.length ? ': ' : ''}{judgements.map(([, judgement]): string => judgement.toString()).join(', ')}{
waitCount
? t(' ({{count}} waiting)', { replace: { count: waitCount } })
: ''
}
</div>
<table>
<tbody>
{identity.parent && (
<tr>
<td>{t('parent')}</td>
<td><AddressMini value={identity.parent} /></td>
</tr>
)}
{DISPLAY_KEYS
.filter((key): boolean => !!identity[key as 'web'])
.map((key): React.ReactNode => (
<tr key={key}>
<td>{t(key)}</td>
<td>{identity[key as 'web']}</td>
</tr>
))
}
</tbody>
</table>
</div>
);
const displayName = isGood
? identity.display
: identity.display.replace(/[^\x20-\x7E]/g, '');
const displayParent = identity.displayParent
? (
isGood
? identity.displayParent
: identity.displayParent.replace(/[^\x20-\x7E]/g, '')
)
: undefined;
const name = (
<div className='via-identity'>
<Badge
hover={hover}
info={<Icon name={identity.parent ? 'caret square up outline' : (isGood ? 'check' : 'minus')} />}
isInline
isSmall
isTooltip
onClick={isRegistrar ? toggleJudgement : undefined}
type={
isGood
? 'green'
: isBad
? 'brown'
: 'gray'
}
/>
{
displayParent
? <span className={`name ${isGood && 'isGood'}`}><span className='top'>{displayParent}</span><span className='sub'>/{displayName}</span></span>
: <span className={`name ${isGood && 'isGood'}`}>{displayName}</span>
}
</div>
);
nameCache.set((accountId || address).toString(), [false, displayParent ? [displayParent, displayName] : [displayName, null]]);
setName((): React.ReactNode => name);
} else {
setName((): React.ReactNode => extractName(accountId || address, accountIndex));
}
setName((): React.ReactNode =>
identity?.display
? extractIdentity(cacheAddr, identity, isRegistrar ? toggleJudgement : undefined, t)
: extractName(cacheAddr, accountIndex)
);
} else if (nickname) {
nameCache.set((accountId || address).toString(), [false, [nickname, null]]);
nameCache.set(cacheAddr, [false, [nickname, null]]);
setName(nickname);
} else {
setName(defaultOrAddr(defaultName, accountId || address, accountIndex));
setName(defaultOrAddr(defaultName, cacheAddr, accountIndex));
}
}, [address, info, toggle]);
}, [address, info, isRegistrar, toggle]);
return (
<>
{isJudgementOpen && (
<AccountNameJudgement
address={address}
registrars={registrars}
toggleJudgement={toggleJudgement}
/>
)}

View File

@ -3,11 +3,8 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { BareProps } from '@polkadot/react-api/types';
import { RegistrarInfo } from '@polkadot/types/interfaces';
import React, { useEffect, useState } from 'react';
import { useCall, useApi } from '@polkadot/react-hooks';
import { Option } from '@polkadot/types';
import { useTranslation } from './translate';
import Dropdown from './Dropdown';
@ -18,6 +15,7 @@ import TxButton from './TxButton';
interface Props extends BareProps {
address: string;
registrars: (string | null)[];
toggleJudgement: () => void;
}
@ -30,10 +28,8 @@ const JUDGEMENT_ENUM = [
{ value: 5, text: 'Low quality' }
];
function AccountNameJudgement ({ address, toggleJudgement }: Props): React.ReactElement<Props> {
function AccountNameJudgement ({ address, registrars, toggleJudgement }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const registrars = useCall<Option<RegistrarInfo>[]>(api.query.identity?.registrars, []);
const [judgementAccountId, setJudgementAccountId] = useState<string | null>(null);
const [judgementEnum, setJudgementEnum] = useState(2); // Reasonable
const [registrarIndex, setRegistrarIndex] = useState(-1);
@ -42,13 +38,7 @@ function AccountNameJudgement ({ address, toggleJudgement }: Props): React.React
useEffect((): void => {
if (registrars && judgementAccountId) {
setRegistrarIndex(
registrars
.map((registrar): string| null =>
registrar.isSome
? registrar.unwrap().account.toString()
: null
)
.indexOf(judgementAccountId)
registrars.indexOf(judgementAccountId)
);
} else {
setRegistrarIndex(-1);

View File

@ -15,7 +15,7 @@ interface Props {
defaultName?: string;
onClickName?: () => void;
overrideName?: React.ReactNode;
toggle?: any;
toggle?: boolean;
value?: string | Address | AccountId | null | Uint8Array;
}

View File

@ -17,6 +17,7 @@ export { default as useModal } from './useModal';
export { default as useOwnEraRewards } from './useOwnEraRewards';
export { default as useOwnStashes, useOwnStashIds } from './useOwnStashes';
export { default as usePassword } from './usePassword';
export { default as useRegistrars } from './useRegistrars';
export { default as useSudo } from './useSudo';
export { default as useToggle } from './useToggle';
export { default as useTx } from './useTx';

View File

@ -0,0 +1,42 @@
// Copyright 2017-2020 @polkadot/react-hooks 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 { RegistrarInfo } from '@polkadot/types/interfaces';
import { useEffect, useState } from 'react';
import { Option } from '@polkadot/types';
import useAccounts from './useAccounts';
import useApi from './useApi';
import useCall from './useCall';
interface State {
isRegistrar: boolean;
registrars: (string | null)[];
}
export default function useRegistrars (): State {
const { api } = useApi();
const { allAccounts } = useAccounts();
const query = useCall<Option<RegistrarInfo>[]>(api.query.identity?.registrars, []);
const [state, setState] = useState<State>({ isRegistrar: false, registrars: [] });
// determine if we have a registrar or not - registrars are allowed to approve
useEffect((): void => {
if (allAccounts && query) {
const registrars = query.map((registrar): string| null =>
registrar.isSome
? registrar.unwrap().account.toString()
: null
);
setState({
isRegistrar: registrars.some((registrar) => !!registrar && allAccounts.includes(registrar)),
registrars
});
}
}, [allAccounts, query]);
return state;
}