Remove ote duplication on treasury (#3488)
This commit is contained in:
parent
02c8a8b37f
commit
926aa6e1f5
@ -3,7 +3,6 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { SubmittableExtrinsic } from '@polkadot/api/types';
|
||||
import { DeriveCollectiveProposal } from '@polkadot/api-derive/types';
|
||||
import { ProposalIndex } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
@ -14,7 +13,6 @@ import { useApi, useToggle } from '@polkadot/react-hooks';
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
councilProposals: DeriveCollectiveProposal[];
|
||||
id: ProposalIndex;
|
||||
isDisabled: boolean;
|
||||
members: string[];
|
||||
@ -25,14 +23,13 @@ interface ProposalState {
|
||||
proposalLength: number;
|
||||
}
|
||||
|
||||
function Submission ({ councilProposals, id, isDisabled, members }: Props): React.ReactElement<Props> | null {
|
||||
function Council ({ id, isDisabled, members }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [isOpen, toggleOpen] = useToggle();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [councilType, setCouncilType] = useState('reject');
|
||||
const [{ proposal, proposalLength }, setProposal] = useState<ProposalState>({ proposalLength: 0 });
|
||||
const [hasProposals, setHasProposals] = useState(true);
|
||||
|
||||
const threshold = Math.ceil((members?.length || 0) * getTreasuryThreshold(api));
|
||||
|
||||
@ -41,15 +38,6 @@ function Submission ({ councilProposals, id, isDisabled, members }: Props): Reac
|
||||
{ text: t<string>('Rejection proposal to council'), value: 'reject' }
|
||||
]);
|
||||
|
||||
useEffect((): void => {
|
||||
setHasProposals(
|
||||
!!councilProposals
|
||||
.map(({ votes }) => votes ? votes.index.toNumber() : -1)
|
||||
.filter((index) => index !== -1)
|
||||
.length
|
||||
);
|
||||
}, [councilProposals]);
|
||||
|
||||
useEffect((): void => {
|
||||
const proposal = councilType === 'reject'
|
||||
? api.tx.treasury.rejectProposal(id)
|
||||
@ -58,10 +46,6 @@ function Submission ({ councilProposals, id, isDisabled, members }: Props): Reac
|
||||
setProposal({ proposal, proposalLength: proposal.length });
|
||||
}, [api, councilType, id]);
|
||||
|
||||
if (hasProposals) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isOpen && (
|
||||
@ -127,4 +111,4 @@ function Submission ({ councilProposals, id, isDisabled, members }: Props): Reac
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Submission);
|
||||
export default React.memo(Council);
|
||||
@ -4,13 +4,13 @@
|
||||
|
||||
import { DeriveTreasuryProposal } from '@polkadot/api-derive/types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { AddressMini, AddressSmall, LinkExternal } from '@polkadot/react-components';
|
||||
import { FormatBalance } from '@polkadot/react-query';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
|
||||
import Submission from './Submission';
|
||||
import Voting from './Voting';
|
||||
import { useTranslation } from '../translate';
|
||||
import Council from './Council';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
@ -21,7 +21,17 @@ interface Props {
|
||||
withSend: boolean;
|
||||
}
|
||||
|
||||
function ProposalDisplay ({ className = '', isMember, members, proposal: { council, id, proposal }, withSend }: Props): React.ReactElement<Props> | null {
|
||||
function ProposalDisplay ({ className = '', isMember, members, proposal: { council, id, proposal }, withSend }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const hasProposals = useMemo(
|
||||
() => !!council
|
||||
.map(({ votes }) => votes ? votes.index.toNumber() : -1)
|
||||
.filter((index) => index !== -1)
|
||||
.length,
|
||||
[council]
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={className}>
|
||||
<td className='number'>
|
||||
@ -39,22 +49,17 @@ function ProposalDisplay ({ className = '', isMember, members, proposal: { counc
|
||||
<td className='number'>
|
||||
<FormatBalance value={proposal.bond} />
|
||||
</td>
|
||||
<td className='button'>
|
||||
{withSend && (
|
||||
<>
|
||||
<Submission
|
||||
councilProposals={council}
|
||||
<td className={hasProposals ? 'middle' : 'button'}>
|
||||
{hasProposals
|
||||
? <a href='#/council/motions'>{t('Voting')}</a>
|
||||
: withSend && (
|
||||
<Council
|
||||
id={id}
|
||||
isDisabled={!isMember}
|
||||
members={members}
|
||||
/>
|
||||
<Voting
|
||||
councilProposals={council}
|
||||
isDisabled={!isMember}
|
||||
members={members}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
)
|
||||
}
|
||||
</td>
|
||||
<td className='mini'>
|
||||
<LinkExternal
|
||||
|
||||
@ -1,148 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/app-treasury 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 { DeriveCollectiveProposal } from '@polkadot/api-derive/types';
|
||||
import { BlockNumber, Hash, ProposalIndex } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Button, Dropdown, Input, Modal, VoteAccount, VoteActions, VoteToggle } from '@polkadot/react-components';
|
||||
import { useAccounts, useApi, useCall, useToggle } from '@polkadot/react-hooks';
|
||||
import { isBoolean } from '@polkadot/util';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface CouncilInfo {
|
||||
councilHash: Hash | null;
|
||||
councilId: ProposalIndex | null;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
councilProposals: DeriveCollectiveProposal[];
|
||||
isDisabled?: boolean;
|
||||
members: string[];
|
||||
}
|
||||
|
||||
interface Option {
|
||||
text: React.ReactNode;
|
||||
value: number;
|
||||
}
|
||||
|
||||
function Voting ({ councilProposals, isDisabled, members }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { hasAccounts } = useAccounts();
|
||||
const { api } = useApi();
|
||||
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
|
||||
const [councilOpts, setCouncilOpts] = useState<Option[]>([]);
|
||||
const [councilOptId, setCouncilOptId] = useState<number>(0);
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [{ councilHash, councilId }, setCouncilInfo] = useState<CouncilInfo>({ councilHash: null, councilId: null });
|
||||
const [isOpen, toggleOpen] = useToggle();
|
||||
const [voteValue, setVoteValue] = useState(true);
|
||||
|
||||
useEffect((): void => {
|
||||
isOpen && setVoteValue(true);
|
||||
}, [isOpen]);
|
||||
|
||||
useEffect((): void => {
|
||||
const available = councilProposals
|
||||
.filter(({ votes }) => bestNumber && votes && (!votes.end || votes.end.gt(bestNumber)))
|
||||
.map(({ proposal: { methodName, sectionName }, votes }): Option => ({
|
||||
text: `Council #${votes?.index.toNumber() || '-'}: ${sectionName}.${methodName} `,
|
||||
value: votes ? votes?.index.toNumber() : -1
|
||||
}))
|
||||
.filter(({ value }) => value !== -1);
|
||||
|
||||
setCouncilOptId(available.length ? available[0].value : 0);
|
||||
setCouncilOpts(available);
|
||||
}, [bestNumber, councilProposals]);
|
||||
|
||||
const _onChangeVote = useCallback(
|
||||
(vote?: boolean) => setVoteValue(isBoolean(vote) ? vote : true),
|
||||
[]
|
||||
);
|
||||
|
||||
const _onChangeProposal = useCallback(
|
||||
(optionId: number): void => {
|
||||
const councilProp = councilProposals.find(({ votes }) => votes?.index.eq(optionId));
|
||||
|
||||
if (councilProp && councilProp.votes) {
|
||||
setCouncilInfo({ councilHash: councilProp.hash, councilId: councilProp.votes.index });
|
||||
setCouncilOptId(councilOptId);
|
||||
} else {
|
||||
setCouncilInfo({ councilHash: null, councilId: null });
|
||||
}
|
||||
},
|
||||
[councilOptId, councilProposals]
|
||||
);
|
||||
|
||||
if (!hasAccounts || !councilOpts.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isOpen && (
|
||||
<Modal
|
||||
header={t<string>('Vote on proposal')}
|
||||
size='small'
|
||||
>
|
||||
<Modal.Content>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<VoteAccount
|
||||
filter={members}
|
||||
onChange={setAccountId}
|
||||
/>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<Dropdown
|
||||
help={t<string>('The council proposal to make the vote on')}
|
||||
label={t<string>('council proposal')}
|
||||
onChange={_onChangeProposal}
|
||||
options={councilOpts}
|
||||
value={councilOptId}
|
||||
/>
|
||||
<Input
|
||||
help={t<string>('The hash for the proposal this vote applies to')}
|
||||
isDisabled
|
||||
label={t<string>('proposal hash')}
|
||||
value={councilHash?.toString()}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t<string>('Multiple council proposals could exist, both approval and rejection. Apply your vote to the correct council proposal (also available on council motions page)')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<VoteToggle
|
||||
onChange={_onChangeVote}
|
||||
value={voteValue}
|
||||
/>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<VoteActions
|
||||
accountId={accountId}
|
||||
aye={voteValue}
|
||||
isDisabled={!councilHash}
|
||||
onClick={toggleOpen}
|
||||
params={[councilHash, councilId, voteValue]}
|
||||
tx='council.vote'
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
<Button
|
||||
icon='check'
|
||||
isDisabled={isDisabled}
|
||||
label={t<string>('Vote')}
|
||||
onClick={toggleOpen}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Voting);
|
||||
Loading…
Reference in New Issue
Block a user