Adjust council modals with column layout (#2666)
* Adjust council modals with column layout * Adjust to council icon * Tip endorsement columns, remove duplicated Transfer modal
This commit is contained in:
parent
478910b32b
commit
92a6af7983
@ -8,11 +8,12 @@ import { ActionStatus } from '@polkadot/react-components/Status/types';
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { AddressSmall, AddressInfo, Button, ChainLock, Icon, LinkExternal, Forget, Menu, Popup, Tag, Transfer } from '@polkadot/react-components';
|
||||
import { AddressSmall, AddressInfo, Button, ChainLock, Icon, LinkExternal, Forget, Menu, Popup, Tag } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
|
||||
import Transfer from '../Accounts/modals/Transfer';
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -9,9 +9,10 @@ import styled from 'styled-components';
|
||||
import { useAccountInfo, useApi, useRegistrars, useToggle } from '@polkadot/react-hooks';
|
||||
import { classes } from '@polkadot/react-components/util';
|
||||
import { colorLink } from '@polkadot/react-components/styles/theme';
|
||||
import { AccountName, AddressMini, AvatarItem, Button, Icon, IconLink, IdentityIcon, Input, InputTags, LinkExternal, Tag, Transfer } from '@polkadot/react-components';
|
||||
import { AccountName, AddressMini, AvatarItem, Button, Icon, IconLink, IdentityIcon, Input, InputTags, LinkExternal, Tag } from '@polkadot/react-components';
|
||||
import { isHex } from '@polkadot/util';
|
||||
|
||||
import Transfer from '../Accounts/modals/Transfer';
|
||||
import { useTranslation } from '../translate';
|
||||
import Flags from './Flags';
|
||||
import RegistrarJudgement from './RegistrarJudgement';
|
||||
|
||||
@ -6,44 +6,56 @@ import { Hash, Proposal, ProposalIndex } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Button, InputAddress, Modal, ProposedAction, TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts, useToggle } from '@polkadot/react-hooks';
|
||||
import { useToggle } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
hash: Hash;
|
||||
idNumber: ProposalIndex;
|
||||
isDisabled: boolean;
|
||||
members: string[];
|
||||
proposal: Proposal;
|
||||
}
|
||||
|
||||
function Close ({ hash, idNumber, proposal }: Props): React.ReactElement<Props> | null {
|
||||
function Close ({ hash, idNumber, isDisabled, members, proposal }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { hasAccounts } = useAccounts();
|
||||
const [isOpen, toggleOpen] = useToggle();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
|
||||
if (!hasAccounts) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isOpen && (
|
||||
<Modal
|
||||
header={t('Close proposal')}
|
||||
size='small'
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
<ProposedAction
|
||||
idNumber={idNumber}
|
||||
proposal={proposal}
|
||||
/>
|
||||
<InputAddress
|
||||
help={t('Select the account you wish close the proposal with.')}
|
||||
label={t('sending account')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
/>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<ProposedAction
|
||||
idNumber={idNumber}
|
||||
proposal={proposal}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('The proposal that will be affected. Once closed for the current voting round, it would need to be re-submitted to council for a subsequent voting round.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputAddress
|
||||
filter={members}
|
||||
help={t('Select the account you wish close the proposal with.')}
|
||||
label={t('sending account')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('The council account that will apply the close for the current round.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<Modal.Actions onCancel={toggleOpen}>
|
||||
<TxButton
|
||||
@ -57,6 +69,7 @@ function Close ({ hash, idNumber, proposal }: Props): React.ReactElement<Props>
|
||||
)}
|
||||
<Button
|
||||
icon='cancel'
|
||||
isDisabled={isDisabled}
|
||||
label={t('Close')}
|
||||
onClick={toggleOpen}
|
||||
/>
|
||||
|
||||
@ -71,6 +71,8 @@ function Motion ({ className, isMember, members, motion: { hash, proposal, votes
|
||||
<Close
|
||||
hash={hash}
|
||||
idNumber={index}
|
||||
isDisabled={!isMember}
|
||||
members={members}
|
||||
proposal={proposal}
|
||||
/>
|
||||
)
|
||||
|
||||
@ -73,10 +73,17 @@ function Voting ({ proposal, referendumId }: Props): React.ReactElement<Props> |
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
<ProposedAction
|
||||
idNumber={referendumId}
|
||||
proposal={proposal}
|
||||
/>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<ProposedAction
|
||||
idNumber={referendumId}
|
||||
proposal={proposal}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('The referendum info that is voted upon. If passed, the changed will be applied via dispatch and the deposit returned.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<VoteAccount onChange={setAccountId} />
|
||||
|
||||
@ -15,12 +15,13 @@ import Voting from './Voting';
|
||||
interface Props {
|
||||
className?: string;
|
||||
isMember: boolean;
|
||||
proposal: DeriveTreasuryProposal;
|
||||
members: string[];
|
||||
onRespond: () => void;
|
||||
proposal: DeriveTreasuryProposal;
|
||||
withSend: boolean;
|
||||
}
|
||||
|
||||
function ProposalDisplay ({ className, isMember, proposal: { council, id, proposal }, withSend }: Props): React.ReactElement<Props> | null {
|
||||
function ProposalDisplay ({ className, isMember, members, proposal: { council, id, proposal }, withSend }: Props): React.ReactElement<Props> | null {
|
||||
return (
|
||||
<tr className={className}>
|
||||
<td className='number'>
|
||||
@ -45,10 +46,12 @@ function ProposalDisplay ({ className, isMember, proposal: { council, id, propos
|
||||
councilProposals={council}
|
||||
id={id}
|
||||
isDisabled={!isMember}
|
||||
members={members}
|
||||
/>
|
||||
<Voting
|
||||
councilProposals={council}
|
||||
isDisabled={!isMember}
|
||||
members={members}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -15,10 +15,11 @@ interface Props {
|
||||
className?: string;
|
||||
isApprovals?: boolean;
|
||||
isMember: boolean;
|
||||
members: string[];
|
||||
proposals?: DeriveTreasuryProposal[];
|
||||
}
|
||||
|
||||
function ProposalsBase ({ className, isApprovals, isMember, proposals }: Props): React.ReactElement<Props> {
|
||||
function ProposalsBase ({ className, isApprovals, isMember, members, proposals }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
|
||||
@ -47,6 +48,7 @@ function ProposalsBase ({ className, isApprovals, isMember, proposals }: Props):
|
||||
<Proposal
|
||||
isMember={isMember}
|
||||
key={proposal.id.toString()}
|
||||
members={members}
|
||||
onRespond={_onRespond}
|
||||
proposal={proposal}
|
||||
withSend={!isApprovals}
|
||||
|
||||
@ -15,9 +15,10 @@ interface Props {
|
||||
councilProposals: DeriveCollectiveProposal[];
|
||||
id: ProposalIndex;
|
||||
isDisabled: boolean;
|
||||
members: string[];
|
||||
}
|
||||
|
||||
function Submission ({ councilProposals, id, isDisabled }: Props): React.ReactElement<Props> | null {
|
||||
function Submission ({ councilProposals, id, isDisabled, members }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const councilThreshold = useCall<number>((api.query.electionsPhragmen || api.query.elections).members, [], {
|
||||
@ -50,24 +51,39 @@ function Submission ({ councilProposals, id, isDisabled }: Props): React.ReactEl
|
||||
<>
|
||||
{isOpen && (
|
||||
<Modal
|
||||
header={t('To council')}
|
||||
size='small'
|
||||
header={t('Send to council')}
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
<InputAddress
|
||||
help={t('Select the council account you wish to use to make the proposal.')}
|
||||
label={t('submit with council account')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
withLabel
|
||||
/>
|
||||
<Dropdown
|
||||
help={t('The type of council proposal to submit.')}
|
||||
label={t('council proposal type')}
|
||||
onChange={setCouncilType}
|
||||
options={councilTypeOpt}
|
||||
value={councilType}
|
||||
/>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputAddress
|
||||
filter={members}
|
||||
help={t('Select the council account you wish to use to make the proposal.')}
|
||||
label={t('submit with council account')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
withLabel
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('The council member that is proposing this, submission equates to an "aye" vote.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<Dropdown
|
||||
help={t('The type of council proposal to submit.')}
|
||||
label={t('council proposal type')}
|
||||
onChange={setCouncilType}
|
||||
options={councilTypeOpt}
|
||||
value={councilType}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('Proposal can either be to approve or reject this spend. One approved, the change is applied by either removing the proposal or scheduling payout.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<Modal.Actions onCancel={toggleOpen}>
|
||||
<TxButton
|
||||
@ -89,9 +105,9 @@ function Submission ({ councilProposals, id, isDisabled }: Props): React.ReactEl
|
||||
</Modal>
|
||||
)}
|
||||
<Button
|
||||
icon='check'
|
||||
icon='sort'
|
||||
isDisabled={isDisabled}
|
||||
label={t('Send to council')}
|
||||
label={t('To council')}
|
||||
onClick={toggleOpen}
|
||||
/>
|
||||
</>
|
||||
|
||||
@ -33,23 +33,37 @@ function TipEndorse ({ hash, isMember, members }: Props): React.ReactElement<Pro
|
||||
{isOpen && (
|
||||
<Modal
|
||||
header={t('Submit tip endorsement')}
|
||||
size='small'
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
<InputAddress
|
||||
filter={members}
|
||||
help={t('Select the account you wish to submit the tip from.')}
|
||||
label={t('submit with account')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
withLabel
|
||||
/>
|
||||
<InputBalance
|
||||
help={t('The tip amount that should be allocated')}
|
||||
isError={!hasValue}
|
||||
label={t('value')}
|
||||
onChange={setValue}
|
||||
/>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputAddress
|
||||
filter={members}
|
||||
help={t('Select the account you wish to submit the tip from.')}
|
||||
label={t('submit with account')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
withLabel
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('Your endorsement will be applied for this account.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputBalance
|
||||
help={t('The tip amount that should be allocated')}
|
||||
isError={!hasValue}
|
||||
label={t('value')}
|
||||
onChange={setValue}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('Allocate a suggested tip amount. With enough endorsements, the suggested values are averaged and sent to the beneficiary.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<Modal.Actions onCancel={toggleOpen}>
|
||||
<TxButton
|
||||
|
||||
@ -15,6 +15,7 @@ import { useTranslation } from '../translate';
|
||||
interface Props {
|
||||
councilProposals: DeriveCollectiveProposal[];
|
||||
isDisabled?: boolean;
|
||||
members: string[];
|
||||
}
|
||||
|
||||
interface Option {
|
||||
@ -22,7 +23,7 @@ interface Option {
|
||||
value: number;
|
||||
}
|
||||
|
||||
function Voting ({ councilProposals, isDisabled }: Props): React.ReactElement<Props> | null {
|
||||
function Voting ({ councilProposals, isDisabled, members }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { hasAccounts } = useAccounts();
|
||||
const { api } = useApi();
|
||||
@ -82,24 +83,42 @@ function Voting ({ councilProposals, isDisabled }: Props): React.ReactElement<Pr
|
||||
size='small'
|
||||
>
|
||||
<Modal.Content>
|
||||
<VoteAccount onChange={setAccountId} />
|
||||
<Dropdown
|
||||
help={t('The council proposal to make the vote on')}
|
||||
label={t('council proposal')}
|
||||
onChange={_onChangeProposal}
|
||||
options={councilOpts}
|
||||
value={councilOptId}
|
||||
/>
|
||||
<Input
|
||||
help={t('The hash for the proposal this vote applies to')}
|
||||
isDisabled
|
||||
label={t('proposal hash')}
|
||||
value={councilHash}
|
||||
/>
|
||||
<VoteToggle
|
||||
onChange={_onChangeVote}
|
||||
value={voteValue}
|
||||
/>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<VoteAccount
|
||||
filter={members}
|
||||
onChange={setAccountId}
|
||||
/>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<Dropdown
|
||||
help={t('The council proposal to make the vote on')}
|
||||
label={t('council proposal')}
|
||||
onChange={_onChangeProposal}
|
||||
options={councilOpts}
|
||||
value={councilOptId}
|
||||
/>
|
||||
<Input
|
||||
help={t('The hash for the proposal this vote applies to')}
|
||||
isDisabled
|
||||
label={t('proposal hash')}
|
||||
value={councilHash}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t('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}
|
||||
|
||||
@ -49,11 +49,13 @@ function Overview ({ className }: Props): React.ReactElement<Props> {
|
||||
</Button.Group>
|
||||
<Proposals
|
||||
isMember={isMember}
|
||||
members={members}
|
||||
proposals={info?.proposals}
|
||||
/>
|
||||
<Proposals
|
||||
isApprovals
|
||||
isMember={isMember}
|
||||
members={members}
|
||||
proposals={info?.approvals}
|
||||
/>
|
||||
<Tips
|
||||
|
||||
@ -27,7 +27,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export const styles = `
|
||||
margin-bottom: 1rem;
|
||||
margin-left: 2rem;
|
||||
|
||||
.ui--ProposedAction-extrinsic {
|
||||
.ui--Params-Content {
|
||||
|
||||
@ -1,128 +0,0 @@
|
||||
// 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 { SubmittableExtrinsic } from '@polkadot/api/promise/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
import { Available } from '@polkadot/react-query';
|
||||
|
||||
import InputAddress from './InputAddress';
|
||||
import InputBalance from './InputBalance';
|
||||
import Modal from './Modal';
|
||||
import TxButton from './TxButton';
|
||||
|
||||
import { useTranslation } from './translate';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
onClose: () => void;
|
||||
recipientId?: string;
|
||||
senderId?: string;
|
||||
}
|
||||
|
||||
const ZERO = new BN(0);
|
||||
|
||||
function Transfer ({ className, onClose, recipientId: propRecipientId, senderId: propSenderId }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [amount, setAmount] = useState<BN | undefined>(new BN(0));
|
||||
const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic | null>(null);
|
||||
const [hasAvailable] = useState(true);
|
||||
const [maxBalance] = useState(new BN(0));
|
||||
const [recipientId, setRecipientId] = useState<string | null>(propRecipientId || null);
|
||||
const [senderId, setSenderId] = useState<string | null>(propSenderId || null);
|
||||
|
||||
useEffect((): void => {
|
||||
senderId && recipientId && setExtrinsic(
|
||||
() => api.tx.balances.transfer(recipientId, amount || ZERO)
|
||||
);
|
||||
}, [api, amount, recipientId, senderId]);
|
||||
|
||||
const transferrable = <span className='label'>{t('transferrable')}</span>;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className='app--accounts-Modal'
|
||||
header={t('Send funds')}
|
||||
>
|
||||
<Modal.Content>
|
||||
<div className={className}>
|
||||
<InputAddress
|
||||
defaultValue={propSenderId}
|
||||
help={t('The account you will send funds from.')}
|
||||
isDisabled={!!propSenderId}
|
||||
label={t('send from account')}
|
||||
labelExtra={
|
||||
<Available
|
||||
label={transferrable}
|
||||
params={senderId}
|
||||
/>
|
||||
}
|
||||
onChange={setSenderId}
|
||||
type='account'
|
||||
/>
|
||||
<InputAddress
|
||||
defaultValue={propRecipientId}
|
||||
help={t('Select a contact or paste the address you want to send funds to.')}
|
||||
isDisabled={!!propRecipientId}
|
||||
label={t('send to address')}
|
||||
labelExtra={
|
||||
<Available
|
||||
label={transferrable}
|
||||
params={recipientId}
|
||||
/>
|
||||
}
|
||||
onChange={setRecipientId}
|
||||
type='allPlus'
|
||||
/>
|
||||
<InputBalance
|
||||
autoFocus
|
||||
help={t('Type the amount you want to transfer. Note that you can select the unit on the right e.g sending 1 milli is equivalent to sending 0.001.')}
|
||||
isError={!hasAvailable}
|
||||
isZeroable
|
||||
label={t('amount')}
|
||||
maxValue={maxBalance}
|
||||
onChange={setAmount}
|
||||
withMax
|
||||
/>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
<Modal.Actions onCancel={onClose}>
|
||||
<TxButton
|
||||
accountId={senderId}
|
||||
extrinsic={extrinsic}
|
||||
icon='send'
|
||||
isDisabled={!hasAvailable}
|
||||
isPrimary
|
||||
label={t('Make Transfer')}
|
||||
onStart={onClose}
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(styled(Transfer)`
|
||||
article.padded {
|
||||
box-shadow: none;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.balance {
|
||||
margin-bottom: 0.5rem;
|
||||
text-align: right;
|
||||
padding-right: 1rem;
|
||||
|
||||
.label {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
label.with-help {
|
||||
flex-basis: 10rem;
|
||||
}
|
||||
`);
|
||||
@ -84,7 +84,6 @@ export { default as Tabs } from './Tabs';
|
||||
export { default as Tag } from './Tag';
|
||||
export { default as Toggle } from './Toggle';
|
||||
export { default as Tooltip } from './Tooltip';
|
||||
export { default as Transfer } from './Transfer';
|
||||
export { default as TxButton } from './TxButton';
|
||||
export { default as TxComponent } from './TxComponent';
|
||||
export { default as TxModal } from './TxModal';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user