Provide judgement via account hover (#2078)
* Provide judgement via account hover * Click to provide judgement
This commit is contained in:
parent
364e50f6c5
commit
08adfbc43f
@ -32,11 +32,12 @@ function WarmUp (): React.ReactElement {
|
||||
const { api, isApiReady } = useApi();
|
||||
const fees = useCall<any>(isApiReady ? api.derive.balances.fees : undefined, []);
|
||||
const indexes = useCall<any>(isApiReady ? api.derive.accounts.indexes : undefined, []);
|
||||
const registrars = useCall<any>(isApiReady ? api.query.identity?.registrars : undefined, []);
|
||||
const staking = useCall<any>(isApiReady ? api.derive.staking.overview : undefined, []);
|
||||
const [hasValues, setHasValues] = useState(false);
|
||||
|
||||
useEffect((): void => {
|
||||
setHasValues(!!fees || !!indexes || !!staking);
|
||||
setHasValues(!!fees || !!indexes || !!registrars || !!staking);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@ -4,15 +4,23 @@
|
||||
|
||||
import { DeriveAccountInfo } from '@polkadot/api-derive/types';
|
||||
import { BareProps } from '@polkadot/react-api/types';
|
||||
import { AccountId, AccountIndex, Address } from '@polkadot/types/interfaces';
|
||||
import { AccountId, AccountIndex, Address, RegistrarInfo } 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';
|
||||
import { useCall, useAccounts, useApi, useToggle } from '@polkadot/react-hooks';
|
||||
import { Option } from '@polkadot/types';
|
||||
|
||||
import { useTranslation } from './translate';
|
||||
import { getAddressName } from './util';
|
||||
import Badge from './Badge';
|
||||
import Button from './Button';
|
||||
import Dropdown from './Dropdown';
|
||||
import Icon from './Icon';
|
||||
import Input from './Input';
|
||||
import InputAddress from './InputAddress';
|
||||
import Modal from './Modal';
|
||||
import TxButton from './TxButton';
|
||||
|
||||
interface Props extends BareProps {
|
||||
children?: React.ReactNode;
|
||||
@ -50,7 +58,15 @@ function defaultOrAddr (defaultName = '', _address: AccountId | AccountIndex | A
|
||||
function AccountName ({ children, className, defaultName, label, onClick, override, style, toggle, value, withShort }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { allAccounts } = useAccounts();
|
||||
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 [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [isRegistrar, setIsRegistrar] = useState(false);
|
||||
const [judgementAccountId, setJudgementAccountId] = useState<string | null>(null);
|
||||
const [judgementEnum, setJudgementEnum] = useState(0);
|
||||
const [registrarIndex, setRegistrarIndex] = useState(-1);
|
||||
const address = useMemo((): string => (value || '').toString(), [value]);
|
||||
|
||||
const _extractName = (accountId?: AccountId, accountIndex?: AccountIndex): React.ReactNode => {
|
||||
@ -65,9 +81,43 @@ function AccountName ({ children, className, defaultName, label, onClick, overri
|
||||
|
||||
const [name, setName] = useState<React.ReactNode>((): React.ReactNode => _extractName());
|
||||
|
||||
useEffect((): void => {
|
||||
if (allAccounts && registrars) {
|
||||
setIsRegistrar(
|
||||
registrars
|
||||
.map((registrar): string| null =>
|
||||
registrar.isSome
|
||||
? registrar.unwrap().account.toString()
|
||||
: null
|
||||
)
|
||||
.some((regId): boolean => !!regId && allAccounts.includes(regId))
|
||||
);
|
||||
}
|
||||
}, [allAccounts, registrars]);
|
||||
|
||||
useEffect((): void => {
|
||||
if (registrars && judgementAccountId) {
|
||||
setRegistrarIndex(
|
||||
registrars
|
||||
.map((registrar): string| null =>
|
||||
registrar.isSome
|
||||
? registrar.unwrap().account.toString()
|
||||
: null
|
||||
)
|
||||
.indexOf(judgementAccountId)
|
||||
);
|
||||
} else {
|
||||
setRegistrarIndex(-1);
|
||||
}
|
||||
}, [judgementAccountId, registrars]);
|
||||
|
||||
useEffect((): void => {
|
||||
const { accountId, accountIndex, identity, nickname } = info || {};
|
||||
|
||||
if (accountId) {
|
||||
setAccountId(accountId.toString());
|
||||
}
|
||||
|
||||
if (api.query.identity?.identityOf) {
|
||||
if (identity?.display) {
|
||||
const isGood = identity.judgements.some(([, judgement]): boolean => judgement.isKnownGood || judgement.isReasonable);
|
||||
@ -120,6 +170,7 @@ function AccountName ({ children, className, defaultName, label, onClick, overri
|
||||
isInline
|
||||
isSmall
|
||||
isTooltip
|
||||
onClick={isRegistrar ? toggleJudgement : undefined}
|
||||
type={
|
||||
isGood
|
||||
? 'green'
|
||||
@ -148,17 +199,71 @@ function AccountName ({ children, className, defaultName, label, onClick, overri
|
||||
}, [info, toggle]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
onClick={
|
||||
override
|
||||
? undefined
|
||||
: onClick
|
||||
}
|
||||
style={style}
|
||||
>
|
||||
{label || ''}{override || name}{children}
|
||||
</div>
|
||||
<>
|
||||
{isJudgementOpen && (
|
||||
<Modal
|
||||
header={t('Provide judgement')}
|
||||
open
|
||||
size='small'
|
||||
>
|
||||
<Modal.Content>
|
||||
<InputAddress
|
||||
label={t('registrar account')}
|
||||
onChange={setJudgementAccountId}
|
||||
/>
|
||||
<Input
|
||||
isDisabled
|
||||
label={t('registrar index')}
|
||||
value={registrarIndex === -1 ? t('invalid/unknown registrar account') : registrarIndex}
|
||||
/>
|
||||
<Dropdown
|
||||
label={t('judgement')}
|
||||
onChange={setJudgementEnum}
|
||||
options={[
|
||||
{ value: 0, text: 'Unknown' },
|
||||
{ value: 1, text: 'Fee paid' },
|
||||
{ value: 2, text: 'Reasonable' },
|
||||
{ value: 3, text: 'Known good' },
|
||||
{ value: 4, text: 'Out of date' },
|
||||
{ value: 5, text: 'Low quality' }
|
||||
]}
|
||||
value={judgementEnum}
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='cancel'
|
||||
isNegative
|
||||
label={t('Cancel')}
|
||||
onClick={toggleJudgement}
|
||||
/>
|
||||
<Button.Or />
|
||||
<TxButton
|
||||
accountId={judgementAccountId}
|
||||
icon='check'
|
||||
isDisabled={registrarIndex === -1}
|
||||
label={t('Judge')}
|
||||
onClick={toggleJudgement}
|
||||
params={[registrarIndex, accountId, judgementEnum]}
|
||||
tx='identity.provideJudgement'
|
||||
/>
|
||||
</Button.Group>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
)}
|
||||
<div
|
||||
className={className}
|
||||
onClick={
|
||||
override
|
||||
? undefined
|
||||
: onClick
|
||||
}
|
||||
style={style}
|
||||
>
|
||||
{label || ''}{override || name}{children}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -8,10 +8,10 @@ import { BareProps } from './types';
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { AccountName } from '@polkadot/react-query';
|
||||
import { KeyringItemType } from '@polkadot/ui-keyring/types';
|
||||
|
||||
import { classes, toShortAddress } from './util';
|
||||
import AccountName from './AccountName';
|
||||
import BalanceDisplay from './Balance';
|
||||
import BondedDisplay from './Bonded';
|
||||
import IdentityIcon from './IdentityIcon';
|
||||
|
||||
@ -6,8 +6,9 @@ import { Address, AccountId } from '@polkadot/types/interfaces';
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { AccountIndex, AccountName } from '@polkadot/react-query';
|
||||
import { AccountIndex } from '@polkadot/react-query';
|
||||
|
||||
import AccountName from './AccountName';
|
||||
import IdentityIcon from './IdentityIcon';
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -14,20 +14,22 @@ interface Props {
|
||||
isInline?: boolean;
|
||||
isSmall?: boolean;
|
||||
isTooltip?: boolean;
|
||||
onClick?: () => void;
|
||||
type: 'counter' | 'online' | 'offline' | 'next' | 'runnerup' | 'selected' | 'green' | 'blue' | 'brown' | 'gray';
|
||||
}
|
||||
|
||||
let badgeId = 0;
|
||||
|
||||
function Badge ({ className, hover, info, isInline, isSmall, isTooltip, type }: Props): React.ReactElement<Props> | null {
|
||||
function Badge ({ className, hover, info, isInline, isSmall, isTooltip, onClick, type }: Props): React.ReactElement<Props> | null {
|
||||
const [key] = useState(`${Date.now()}-${badgeId++}`);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`ui--Badge ${isInline && 'isInline'} ${isTooltip && 'isTooltip'} ${isSmall && 'isSmall'} ${type} ${className}`}
|
||||
className={`ui--Badge ${isInline && 'isInline'} ${isTooltip && 'isTooltip'} ${isSmall && 'isSmall'} ${onClick && 'isClickable'} ${type} ${className}`}
|
||||
data-for={`badge-status-${key}`}
|
||||
data-tip={true}
|
||||
data-tip-disable={!isTooltip}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className='badge'>
|
||||
{info}
|
||||
@ -57,10 +59,15 @@ export default styled(Badge)`
|
||||
width: 22px;
|
||||
|
||||
i.icon {
|
||||
cursor: inherit !important;
|
||||
margin: 0;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
&.isClickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.isSmall {
|
||||
box-shadow: none;
|
||||
font-size: 10px;
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { AccountName } from '@polkadot/react-query';
|
||||
|
||||
import AccountName from '../AccountName';
|
||||
import IdentityIcon from '../IdentityIcon';
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -59,7 +59,6 @@ function Tooltip ({ className, effect = 'solid', offset, place = 'bottom', text,
|
||||
export default styled(Tooltip)`
|
||||
table {
|
||||
border: 0;
|
||||
margin-top: 0.75rem;
|
||||
|
||||
td {
|
||||
text-align: left;
|
||||
@ -72,4 +71,9 @@ export default styled(Tooltip)`
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
div+table,
|
||||
table+div {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export { default as AccountName } from './AccountName';
|
||||
export { default as ActionItem } from './ActionItem';
|
||||
export { default as AddressInfo } from './AddressInfo';
|
||||
export { default as AddressMini } from './AddressMini';
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export { default as AccountIndex } from './AccountIndex';
|
||||
export { default as AccountName } from './AccountName';
|
||||
export { default as Available } from './Available';
|
||||
export { default as Balance } from './Balance';
|
||||
export { default as BalanceFree } from './BalanceFree';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user