Accept and reject curator from bounty list (#4295)
* Add Accept Curator functionality to bounty list * Extract Bounties Action Button * Add unassign curator functionality * Change curator reject icon and button labels * Apply review suggestions * Revert "Apply review suggestions" This reverts commit 93d637bb3d4593555ce4cc6d5a0654263eb7b4d2. * Apply review suggestions * Apply requested changes
This commit is contained in:
parent
8e1ae30016
commit
8490d76bc0
@ -1,4 +1,5 @@
|
||||
{
|
||||
"Accept": "Accept",
|
||||
"Account does not have enough funds.": "Account does not have enough funds.",
|
||||
"Add Bounty": "Add Bounty",
|
||||
"Allocation value is smaller than the minimum bounty value.": "Allocation value is smaller than the minimum bounty value.",
|
||||
@ -6,7 +7,7 @@
|
||||
"Bond is estimated based on bountyDepositBase and dataDepositPerByte constants.": "Bond is estimated based on bountyDepositBase and dataDepositPerByte constants.",
|
||||
"Bounties": "Bounties",
|
||||
"Calculated bond for bounty": "Calculated bond for bounty",
|
||||
"Claim Bounty": "Claim Bounty",
|
||||
"Claim": "Claim",
|
||||
"Claimable": "Claimable",
|
||||
"Curators deposit": "Curators deposit",
|
||||
"Curators fee": "Curators fee",
|
||||
@ -15,6 +16,7 @@
|
||||
"No open bounties": "No open bounties",
|
||||
"Proposer": "Proposer",
|
||||
"Proposer bond depends on bounty title length.": "Proposer bond depends on bounty title length.",
|
||||
"Reject": "Reject",
|
||||
"Select the account you wish to propose the bounty from.": "Select the account you wish to propose the bounty from.",
|
||||
"The description of this bounty": "The description of this bounty",
|
||||
"The total payment amount of this bounty, curators fee included.": "The total payment amount of this bounty, curators fee included.",
|
||||
|
||||
@ -11,7 +11,7 @@ import { AddressSmall, Icon, LinkExternal } from '@polkadot/react-components';
|
||||
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
|
||||
import BountyClaim from './BountyClaim';
|
||||
import { BountyActions } from './BountyActions';
|
||||
import { getBountyStatus } from './helpers';
|
||||
import { useTranslation } from './translate';
|
||||
|
||||
@ -58,13 +58,11 @@ function Bounty ({ bestNumber, bounty, className = '', description, index }: Pro
|
||||
<td>{beneficiary ? <AddressSmall value={beneficiary} /> : EMPTY_CELL}</td>
|
||||
<td><DueBlocks dueBlocks={blocksUntilPayout} /></td>
|
||||
<td>
|
||||
{beneficiary && blocksUntilPayout && (
|
||||
<BountyClaim
|
||||
beneficiaryId={beneficiary}
|
||||
index={index}
|
||||
payoutDue={blocksUntilPayout}
|
||||
/>
|
||||
)}
|
||||
<BountyActions
|
||||
bestNumber={bestNumber}
|
||||
index={index}
|
||||
status={status}
|
||||
/>
|
||||
</td>
|
||||
<td className='table-column-icon'>
|
||||
<LinkExternal
|
||||
|
||||
40
packages/page-bounties/src/BountyActions.tsx
Normal file
40
packages/page-bounties/src/BountyActions.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2017-2020 @polkadot/app-bounties authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { BlockNumber, BountyStatus } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import BountyClaimAction from './BountyClaimAction';
|
||||
import BountyCuratorProposedActions from './BountyCuratorProposedActions';
|
||||
import { getBountyStatus } from './helpers';
|
||||
|
||||
interface Props {
|
||||
bestNumber: BlockNumber;
|
||||
index: number;
|
||||
status: BountyStatus;
|
||||
}
|
||||
|
||||
export function BountyActions ({ bestNumber, index, status }: Props): JSX.Element {
|
||||
const updateStatus = useCallback(() => getBountyStatus(status), [status]);
|
||||
|
||||
const { beneficiary, curator, unlockAt } = updateStatus();
|
||||
|
||||
const blocksUntilPayout = useMemo(() => unlockAt?.sub(bestNumber), [bestNumber, unlockAt]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{status.isCuratorProposed && curator &&
|
||||
<BountyCuratorProposedActions
|
||||
curatorId={curator}
|
||||
index={index}
|
||||
/>}
|
||||
{status.isPendingPayout && beneficiary && blocksUntilPayout &&
|
||||
<BountyClaimAction
|
||||
beneficiaryId={beneficiary}
|
||||
index={index}
|
||||
payoutDue={blocksUntilPayout}
|
||||
/>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -18,22 +18,22 @@ interface Props {
|
||||
payoutDue: BN;
|
||||
}
|
||||
|
||||
function BountyClaim ({ beneficiaryId, index, payoutDue }: Props) {
|
||||
function BountyClaimAction ({ beneficiaryId, index, payoutDue }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { allAccounts, hasAccounts } = useAccounts();
|
||||
const { allAccounts } = useAccounts();
|
||||
|
||||
const isBountyClaimable = useMemo(
|
||||
() => isClaimable(allAccounts, beneficiaryId, payoutDue),
|
||||
[allAccounts, beneficiaryId, payoutDue]
|
||||
);
|
||||
|
||||
return hasAccounts && isBountyClaimable
|
||||
return isBountyClaimable
|
||||
? (
|
||||
<TxButton
|
||||
accountId={beneficiaryId}
|
||||
icon='plus'
|
||||
label={t<string>('Claim Bounty')}
|
||||
label={t<string>('Claim')}
|
||||
params={[index]}
|
||||
tx={(api.tx.bounties || api.tx.treasury).claimBounty}
|
||||
/>
|
||||
@ -41,4 +41,4 @@ function BountyClaim ({ beneficiaryId, index, payoutDue }: Props) {
|
||||
: null;
|
||||
}
|
||||
|
||||
export default React.memo(BountyClaim);
|
||||
export default React.memo(BountyClaimAction);
|
||||
47
packages/page-bounties/src/BountyCuratorProposedActions.tsx
Normal file
47
packages/page-bounties/src/BountyCuratorProposedActions.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2017-2020 @polkadot/app-bounties authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { AccountId } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from './translate';
|
||||
|
||||
interface Props {
|
||||
curatorId: AccountId;
|
||||
index: number;
|
||||
}
|
||||
|
||||
function BountyCuratorProposedActions ({ curatorId, index }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { allAccounts } = useAccounts();
|
||||
|
||||
const isCurator = useMemo(() => allAccounts.includes(curatorId.toString()), [allAccounts, curatorId]);
|
||||
|
||||
return isCurator
|
||||
? (
|
||||
<>
|
||||
<TxButton
|
||||
accountId={curatorId}
|
||||
icon='check'
|
||||
label={t<string>('Accept')}
|
||||
params={[index]}
|
||||
tx={(api.tx.bounties || api.tx.treasury).acceptCurator}
|
||||
/>
|
||||
<TxButton
|
||||
accountId={curatorId}
|
||||
icon='times'
|
||||
label={t<string>('Reject')}
|
||||
params={[index]}
|
||||
tx={(api.tx.bounties || api.tx.treasury).unassignCurator}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
export default React.memo(BountyCuratorProposedActions);
|
||||
Loading…
Reference in New Issue
Block a user