Filter self-proxies in helper dialog (#4288)

This commit is contained in:
Jaco Greeff 2020-12-29 14:12:13 +01:00 committed by GitHub
parent f5d98f8b1f
commit 77ddd24cb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -6,12 +6,12 @@ import type { SubmittableExtrinsic } from '@polkadot/api/types';
import type { AccountId, ProxyDefinition, ProxyType } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import { BatchWarning, Button, Dropdown, InputAddress, Modal, TxButton } from '@polkadot/react-components';
import { useApi } from '@polkadot/react-hooks';
import { isFunction } from '@polkadot/util';
import { BN_ZERO, isFunction } from '@polkadot/util';
import { useTranslation } from '../translate';
@ -34,12 +34,15 @@ interface NewProxyProps extends ValueProps {
onChangeAccount: (index: number, value: string | null) => void;
onChangeType: (index: number, value: number | undefined) => void;
onRemove: (index: number) => void;
proxiedAccount: string;
}
interface PrevProxyProps extends ValueProps {
onRemove: (accountId: AccountId, type: ProxyType, index: number) => void;
}
const EMPTY_EXISTING: [ProxyDefinition[], BN] = [[], BN_ZERO];
function createExtrinsic (api: ApiPromise, batchPrevious: SubmittableExtrinsic<'promise'>[], batchAdded: SubmittableExtrinsic<'promise'>[]): SubmittableExtrinsic<'promise'> | null {
if (batchPrevious.length + batchAdded.length === 1) {
return batchPrevious.length
@ -102,7 +105,7 @@ function PrevProxy ({ index, onRemove, typeOpts, value: [accountId, type] }: Pre
);
}
function NewProxy ({ index, onChangeAccount, onChangeType, onRemove, typeOpts, value: [accountId, type] }: NewProxyProps): React.ReactElement<NewProxyProps> {
function NewProxy ({ index, onChangeAccount, onChangeType, onRemove, proxiedAccount, typeOpts, value: [accountId, type] }: NewProxyProps): React.ReactElement<NewProxyProps> {
const { t } = useTranslation();
const _onChangeAccount = useCallback(
@ -132,6 +135,11 @@ function NewProxy ({ index, onChangeAccount, onChangeType, onRemove, typeOpts, v
type='account'
value={accountId}
/>
{accountId.eq(proxiedAccount) && (
<article className='error'>
{t<string>('You should not setup proxies to act as a self-proxy.')}
</article>
)}
<Dropdown
help={'Type of proxy'}
label={'type'}
@ -150,113 +158,84 @@ function NewProxy ({ index, onChangeAccount, onChangeType, onRemove, typeOpts, v
);
}
function ProxyOverview ({ className, onClose, previousProxy, proxiedAccount }: Props): React.ReactElement<Props> {
function ProxyOverview ({ className, onClose, previousProxy: [existing] = EMPTY_EXISTING, proxiedAccount }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [batchStackPrevious, setBatchStackPrevious] = useState<SubmittableExtrinsic<'promise'>[]>([]);
const [batchStackAdded, setBatchStackAdded] = useState<SubmittableExtrinsic<'promise'>[]>([]);
const [batchPrevious, setBatchPrevious] = useState<SubmittableExtrinsic<'promise'>[]>([]);
const [batchAdded, setBatchAdded] = useState<SubmittableExtrinsic<'promise'>[]>([]);
const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
const [previousProxyDisplay, setPreviousProxyDisplay] = useState<PrevProxy[] | undefined>(
previousProxy?.[0].map(({ delegate, proxyType }): [AccountId, ProxyType] => [delegate, proxyType]) || undefined
const [previous, setPrevious] = useState<PrevProxy[]>(
existing.map(({ delegate, proxyType }): [AccountId, ProxyType] => [delegate, proxyType])
);
const [addedProxies, setAddedProxies] = useState<PrevProxy[]>([]);
const [added, setAdded] = useState<PrevProxy[]>([]);
useEffect(() => {
if (batchStackPrevious.length || batchStackAdded.length) {
setExtrinsic(() => createExtrinsic(api, batchStackPrevious, batchStackAdded));
}
}, [api, batchStackPrevious, batchStackAdded]);
const typeOpts = useMemo(
() => api.createType('ProxyType').defKeys.map((text, value) => ({ text, value })),
[api]
const typeOpts = useRef(
api.createType('ProxyType').defKeys.map((text, value) => ({ text, value }))
);
useEffect((): void => {
setBatchAdded(
added.map(([newAccount, newType]) => createAddProxy(api, newAccount, newType))
);
}, [api, added]);
useEffect((): void => {
(batchPrevious.length || batchAdded.length) &&
setExtrinsic(() => createExtrinsic(api, batchPrevious, batchAdded));
}, [api, batchPrevious, batchAdded]);
const _addProxy = useCallback(
() => {
const newAccount = api.createType('AccountId', proxiedAccount);
const newType = api.createType('ProxyType', 0);
setAddedProxies((prevState) => {
const newProxy: [AccountId, ProxyType] = [newAccount, newType];
return !prevState
? [newProxy]
: [...prevState, newProxy];
});
setBatchStackAdded((prev) => prev.concat(createAddProxy(api, newAccount, newType)));
},
[api, proxiedAccount]
() => setAdded((added) =>
[...added, [
added.length
? added[added.length - 1][0]
: previous.length
? previous[previous.length - 1][0]
: api.createType('AccountId', proxiedAccount),
api.createType('ProxyType', 0)
]]
),
[api, previous, proxiedAccount]
);
const _delProxy = useCallback(
(index: number) => {
setAddedProxies((addedProxies) => addedProxies.filter((_, i) => i !== index));
setBatchStackAdded((batchStackAdded) => batchStackAdded.filter((_, i) => i !== index));
},
(index: number) => setAdded((added) => added.filter((_, i) => i !== index)),
[]
);
const _delPrev = useCallback(
(accountId: AccountId, type: ProxyType, index: number) => {
setPreviousProxyDisplay((previousProxyDisplay) => previousProxyDisplay?.filter((_, i) => i !== index));
setBatchStackPrevious((batchStackPrevious) => [...batchStackPrevious, createRmProxy(api, accountId, type)]);
(accountId: AccountId, type: ProxyType, index: number): void => {
setPrevious((previous) => previous.filter((_, i) => i !== index));
setBatchPrevious((previous) => [...previous, createRmProxy(api, accountId, type)]);
},
[api]
);
const _changeProxyAccount = useCallback(
(index: number, address: string | null) => {
const accountId = api.createType('AccountId', address);
const oldType = addedProxies[index][1];
(index: number, address: string | null) => setAdded((prevState) => {
const newState = [...prevState];
// update the UI with the new selected account
setAddedProxies((prevState) => {
const newState = [...prevState];
newState[index][0] = api.createType('AccountId', address);
newState[index][0] = accountId;
return newState;
});
// Then add the new extrinsic to the batch stack with the new account
setBatchStackAdded((batchStackAdded): SubmittableExtrinsic<'promise'>[] => {
const newBatchAdded = batchStackAdded.filter((_, i) => i !== index);
newBatchAdded.push(createAddProxy(api, accountId, oldType));
return newBatchAdded;
});
},
[addedProxies, api]
return newState;
}),
[api]
);
const _changeProxyType = useCallback(
(index: number, newTypeNumber: number | undefined) => {
const newType = api.createType('ProxyType', newTypeNumber);
const oldAccount = addedProxies[index][0];
(index: number, newTypeNumber: number | undefined): void =>
setAdded((added) => {
const newState = [...added];
// update the UI with the new selected type
setAddedProxies((prevState) => {
const newState = [...prevState];
newState[index][1] = newType;
newState[index][1] = api.createType('ProxyType', newTypeNumber);
return newState;
});
// The Batch stack needs to be updated wit the new type
// First, delete the corresponding extrinsic in the batch stack
const newBatchStackAdded = batchStackAdded.filter((_, i) => i !== index);
// Then add the new extrinsic to the batch stack with the new account
newBatchStackAdded.push(createAddProxy(api, oldAccount, newType));
setBatchStackAdded(newBatchStackAdded);
},
[addedProxies, api, batchStackAdded]
}),
[api]
);
const isSameAdd = added.some(([accountId]) => accountId.eq(proxiedAccount));
return (
<Modal
className={className}
@ -279,23 +258,24 @@ function ProxyOverview ({ className, onClose, previousProxy, proxiedAccount }: P
</Modal.Columns>
<Modal.Columns>
<Modal.Column>
{previousProxyDisplay?.map((value, index) => (
{previous.map((value, index) => (
<PrevProxy
index={index}
key={`${value.toString()}-${index}`}
onRemove={_delPrev}
typeOpts={typeOpts}
typeOpts={typeOpts.current}
value={value}
/>
))}
{addedProxies.map((value, index) => (
{added.map((value, index) => (
<NewProxy
index={index}
key={`${value.toString()}-${index}`}
onChangeAccount={_changeProxyAccount}
onChangeType={_changeProxyType}
onRemove={_delProxy}
typeOpts={typeOpts}
proxiedAccount={proxiedAccount}
typeOpts={typeOpts.current}
value={value}
/>
))}
@ -318,7 +298,7 @@ function ProxyOverview ({ className, onClose, previousProxy, proxiedAccount }: P
</Modal.Columns>
</Modal.Content>
<Modal.Actions onCancel={onClose}>
{previousProxy && previousProxy[0].length !== 0 && (
{existing.length !== 0 && (
<TxButton
accountId={proxiedAccount}
icon='trash-alt'
@ -331,7 +311,7 @@ function ProxyOverview ({ className, onClose, previousProxy, proxiedAccount }: P
accountId={proxiedAccount}
extrinsic={extrinsic}
icon='sign-in-alt'
isDisabled={!batchStackPrevious.length && !batchStackAdded.length}
isDisabled={isSameAdd || (!batchPrevious.length && !batchAdded.length)}
onStart={onClose}
/>
</Modal.Actions>