From 5374a784f4b197d2946b9b3fe5cb6056b02cc8f1 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 15 Jun 2020 16:48:34 +0200 Subject: [PATCH] Show proxied with no accounts (#2959) * Display proxied with no local attached * Allow anybody to submit call on final * Proxy indicator --- .../page-accounts/src/Accounts/Account.tsx | 13 ++++- packages/page-accounts/src/Accounts/index.tsx | 1 - .../src/Accounts/modals/MultisigApprove.tsx | 9 ++- .../src/Accounts/modals/ProxyAdd.tsx | 47 ++------------- .../page-accounts/src/Accounts/useProxies.ts | 58 +++++++++++++++++++ 5 files changed, 81 insertions(+), 47 deletions(-) create mode 100644 packages/page-accounts/src/Accounts/useProxies.ts diff --git a/packages/page-accounts/src/Accounts/Account.tsx b/packages/page-accounts/src/Accounts/Account.tsx index 6a218f07b2..afaab1affe 100644 --- a/packages/page-accounts/src/Accounts/Account.tsx +++ b/packages/page-accounts/src/Accounts/Account.tsx @@ -29,6 +29,7 @@ import RecoverAccount from './modals/RecoverAccount'; import RecoverSetup from './modals/RecoverSetup'; import Transfer from './modals/Transfer'; import useMultisigApprovals from './useMultisigApprovals'; +import useProxies from './useProxies'; interface Props extends SortedAccount { className?: string; @@ -73,7 +74,8 @@ function Account ({ account: { address, meta }, className = '', filter, isFavori transform: (opt: Option) => opt.unwrapOr(null) }); const multiInfos = useMultisigApprovals(address); - const { flags: { isDevelopment, isExternal, isHardware, isInjected, isMultisig }, genesisHash, name: accName, onSetGenesisHash, tags } = useAccountInfo(address); + const proxyInfo = useProxies(address); + const { flags: { isDevelopment, isExternal, isHardware, isInjected, isMultisig, isProxied }, genesisHash, name: accName, onSetGenesisHash, tags } = useAccountInfo(address); const [{ democracyUnlockTx }, setUnlockableIds] = useState({ democracyUnlockTx: null, ids: [] }); const [isVisible, setIsVisible] = useState(true); const [isBackupOpen, toggleBackup] = useToggle(); @@ -227,6 +229,15 @@ function Account ({ account: { address, meta }, className = '', filter, isFavori type='brown' /> )} + {isProxied && !proxyInfo.hasOwned && ( + ('Proxied account has no owned proxies')} + info='0' + isInline + isTooltip + type='brown' + /> + )} diff --git a/packages/page-accounts/src/Accounts/index.tsx b/packages/page-accounts/src/Accounts/index.tsx index 0cc4b0ba15..828f0b9f68 100644 --- a/packages/page-accounts/src/Accounts/index.tsx +++ b/packages/page-accounts/src/Accounts/index.tsx @@ -240,7 +240,6 @@ function Overview ({ className = '', onStatusChange }: Props): React.ReactElemen footer={footer} header={header} > - {} {sortedAccounts.map(({ account, isFavorite }): React.ReactNode => ( { + const hasThreshold = multisig && (multisig.approvals.length >= threshold); + setWhoFilter( who .map((w) => registry.createType('AccountId', w).toString()) .filter((w) => allAccounts.some((a) => a === w) && multisig && ( type === 'nay' ? multisig.approvals[0].eq(w) - : !multisig.approvals.some((a) => a.eq(w)) + : hasThreshold || !multisig.approvals.some((a) => a.eq(w)) )) ); - }, [allAccounts, multisig, type, who]); + }, [allAccounts, multisig, threshold, type, who]); // based on the type, multisig, others create the tx. This can be either an approval or final call useEffect((): void => { diff --git a/packages/page-accounts/src/Accounts/modals/ProxyAdd.tsx b/packages/page-accounts/src/Accounts/modals/ProxyAdd.tsx index 7170d40d0f..7b2b7d3e98 100644 --- a/packages/page-accounts/src/Accounts/modals/ProxyAdd.tsx +++ b/packages/page-accounts/src/Accounts/modals/ProxyAdd.tsx @@ -2,16 +2,16 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { ProxyType } from '@polkadot/types/interfaces'; import { ActionStatus } from '@polkadot/react-components/Status/types'; import { ModalProps } from '../../types'; -import React, { useCallback, useState, useEffect } from 'react'; +import React, { useCallback, useState } from 'react'; import { Button, Input, InputAddressSimple, Modal } from '@polkadot/react-components'; -import { useAccounts, useApi } from '@polkadot/react-hooks'; +import { useApi } from '@polkadot/react-hooks'; import keyring from '@polkadot/ui-keyring'; import { useTranslation } from '../../translate'; +import useProxies from '../useProxies'; interface Props extends ModalProps { className?: string; @@ -24,17 +24,6 @@ interface CreateOptions { tags?: string[]; } -interface Proxy { - address: string; - isOwned: boolean; - type: ProxyType; -} - -interface ProxyState { - hasOwned: boolean; - proxies: Proxy[]; -} - function createProxy (address: string, { genesisHash, name, tags = [] }: CreateOptions, success: string): ActionStatus { // we will fill in all the details below const status = { action: 'create' } as ActionStatus; @@ -55,28 +44,10 @@ function createProxy (address: string, { genesisHash, name, tags = [] }: CreateO function ProxyAdd ({ className = '', onClose, onStatusChange }: Props): React.ReactElement { const { api, isDevelopment } = useApi(); - const { allAccounts } = useAccounts(); const { t } = useTranslation(); const [{ isNameValid, name }, setName] = useState({ isNameValid: false, name: '' }); const [stashAddress, setStashAddress] = useState(null); - const [{ hasOwned }, setProxies] = useState({ hasOwned: false, proxies: [] }); - - useEffect((): void => { - if (stashAddress) { - api.query.proxy - .proxies(stashAddress) - .then(([_proxies]): void => { - const proxies = _proxies.map(([accountId, type]): Proxy => ({ - address: accountId.toString(), - isOwned: allAccounts.includes(accountId.toString()), - type - })); - - setProxies({ hasOwned: proxies.some(({ isOwned }) => isOwned), proxies }); - }) - .catch(console.error); - } - }, [allAccounts, api, stashAddress]); + const { hasOwned } = useProxies(stashAddress); const _createProxied = useCallback( (): void => { @@ -96,14 +67,6 @@ function ProxyAdd ({ className = '', onClose, onStatusChange }: Props): React.Re [] ); - const _onChangeStash = useCallback( - (address: string | null): void => { - setProxies({ hasOwned: false, proxies: [] }); - setStashAddress(address); - }, - [] - ); - const isValid = isNameValid && !!stashAddress && hasOwned; return ( @@ -120,7 +83,7 @@ function ProxyAdd ({ className = '', onClose, onStatusChange }: Props): React.Re help={t('The address that you have a valid proxy setup for.')} isError={!hasOwned} label={t('proxied account')} - onChange={_onChangeStash} + onChange={setStashAddress} placeholder={t('stash address')} /> diff --git a/packages/page-accounts/src/Accounts/useProxies.ts b/packages/page-accounts/src/Accounts/useProxies.ts new file mode 100644 index 0000000000..5026084220 --- /dev/null +++ b/packages/page-accounts/src/Accounts/useProxies.ts @@ -0,0 +1,58 @@ +// 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 { ProxyType } from '@polkadot/types/interfaces'; + +import { useEffect, useState } from 'react'; +import { useAccounts, useApi, useIsMountedRef } from '@polkadot/react-hooks'; + +interface Proxy { + address: string; + isOwned: boolean; + type: ProxyType; +} + +interface State { + hasOwned: boolean; + owned: Proxy[]; + proxies: Proxy[]; +} + +const EMPTY_STATE: State = { + hasOwned: false, + owned: [], + proxies: [] +}; + +export default function useProxies (address?: string | null): State { + const { api } = useApi(); + const { allAccounts } = useAccounts(); + const mountedRef = useIsMountedRef(); + const [known, setState] = useState(EMPTY_STATE); + + useEffect((): void => { + setState(EMPTY_STATE); + + address && + api.query.proxy + .proxies(address) + .then(([_proxies]): void => { + const proxies = _proxies.map(([accountId, type]): Proxy => ({ + address: accountId.toString(), + isOwned: allAccounts.includes(accountId.toString()), + type + })); + const owned = proxies.filter(({ isOwned }) => isOwned); + + mountedRef.current && setState({ + hasOwned: owned.length !== 0, + owned, + proxies + }); + }) + .catch(console.error); + }, [allAccounts, api, address, mountedRef]); + + return known; +}