diff --git a/packages/page-bounties/src/Bounties.spec.ts b/packages/page-bounties/src/Bounties.spec.ts index 511c77da7c..a206a5dc65 100644 --- a/packages/page-bounties/src/Bounties.spec.ts +++ b/packages/page-bounties/src/Bounties.spec.ts @@ -402,7 +402,7 @@ describe('Bounties', () => { }); }); - describe('slash curator modal', () => { + describe('give up curator modal', () => { it('gives up on the Curator role of an Active bounty', async () => { const bounty = aBounty({ status: bountyStatusWith({ curator: alice }) }); @@ -410,12 +410,14 @@ describe('Bounties', () => { await bountiesPage.openGiveUpCuratorsRole(); bountiesPage.enterProposingAccount(alice); - await bountiesPage.clickButton('Approve'); + await bountiesPage.clickButton('Give Up'); bountiesPage.expectExtrinsicQueued({ accountId: alice, extrinsic: 'mockUnassignExtrinsic' }); expect(mockBountyHooks.bountyApi.unassignCurator).toHaveBeenCalledWith(aBountyIndex(0)); }); + }); + describe('slash curator modal', () => { it('creates a motion when slashing a PendingPayout bounty', async () => { bountiesPage.renderOne(bountyWith({ status: 'PendingPayout' })); diff --git a/packages/page-bounties/src/Bounty.tsx b/packages/page-bounties/src/Bounty.tsx index a86744ec18..11eed43361 100644 --- a/packages/page-bounties/src/Bounty.tsx +++ b/packages/page-bounties/src/Bounty.tsx @@ -14,7 +14,7 @@ import { BlockToTime, FormatBalance } from '@polkadot/react-query'; import { formatNumber } from '@polkadot/util'; import { getProposalToDisplay } from './helpers/extendedStatuses'; -import VotingResultsColumn from './Voting/VotersColumn'; +import VotersColumn from './Voting/VotersColumn'; import { BountyActions } from './BountyActions'; import BountyExtraActions from './BountyExtraActions'; import BountyInfos from './BountyInfos'; @@ -190,12 +190,12 @@ function Bounty ({ bestNumber, bounty, className = '', description, index, propo {proposals && (
- - void; +} + +function BountyGiveUpCurator ({ curatorId, index, toggleOpen }: Props) { + const { t } = useTranslation(); + const { unassignCurator } = useBounties(); + + return ( + ("Give up curator's role")} + size='large' + > + + +

{t('This action will unassign you from the curator role.')}

+
+ + + ('The Curator account that will give up on it\'s role.')} + isDisabled + label={t('curator account')} + type='account' + value={curatorId.toString()} + withLabel + /> + + +

{t('You are giving up your curator role, the bounty will return to the Funded state. You will get your deposit back.')}

+
+
+
+ + ('Give Up')} + onStart={toggleOpen} + params={[index]} + tx={unassignCurator} + /> + +
+ ); +} + +export default React.memo(BountyGiveUpCurator); diff --git a/packages/page-bounties/src/BountyActions/SlashCurator.tsx b/packages/page-bounties/src/BountyExtraActions/SlashCurator.tsx similarity index 89% rename from packages/page-bounties/src/BountyActions/SlashCurator.tsx rename to packages/page-bounties/src/BountyExtraActions/SlashCurator.tsx index 4b2de36a7f..397797cacf 100644 --- a/packages/page-bounties/src/BountyActions/SlashCurator.tsx +++ b/packages/page-bounties/src/BountyExtraActions/SlashCurator.tsx @@ -53,16 +53,6 @@ function SlashCurator ({ action, curatorId, description, index, toggleOpen }: Pr const unassignCuratorProposal = useMemo(() => unassignCurator(index), [index, unassignCurator]); const actionProperties = useMemo>(() => ({ - GiveUp: { - filter: [curatorId.toString()], - header: t('This action will unassign you from a curator role.'), - helpMessage: t("The Curator account that will give up on it's role"), - params: [index], - proposingAccountTip: t('The account that will create the transaction.'), - tip: t('You are giving up your curator role, the bounty will return to the Funded state. You will get your deposit back.'), - title: t("Give up curator's role"), - tx: unassignCurator - }, SlashCuratorAction: { filter: allAccounts, header: t('This action will Slash the Curator.'), @@ -93,7 +83,7 @@ function SlashCurator ({ action, curatorId, description, index, toggleOpen }: Pr title: t('Unassign curator'), tx: api.tx.council.propose } - }), [t, curatorId, index, unassignCurator, api.tx.council.propose, allAccounts, members, threshold, unassignCuratorProposal]); + }), [t, index, unassignCurator, api.tx.council.propose, allAccounts, members, threshold, unassignCuratorProposal]); const { filter, header, helpMessage, params, proposingAccountTip, tip, title, tx } = actionProperties[action]; diff --git a/packages/page-bounties/src/BountyExtraActions.tsx b/packages/page-bounties/src/BountyExtraActions/index.tsx similarity index 81% rename from packages/page-bounties/src/BountyExtraActions.tsx rename to packages/page-bounties/src/BountyExtraActions/index.tsx index a355d0ba9d..44184a5041 100644 --- a/packages/page-bounties/src/BountyExtraActions.tsx +++ b/packages/page-bounties/src/BountyExtraActions/index.tsx @@ -10,15 +10,16 @@ import { ThemeProps } from '@polkadot/react-components/types'; import { useMembers, useToggle } from '@polkadot/react-hooks'; import { BlockNumber, BountyIndex, BountyStatus } from '@polkadot/types/interfaces'; -import CloseBounty from './BountyActions/CloseBounty'; -import ExtendBountyExpiryAction from './BountyActions/ExtendBountyExpiryAction'; -import SlashCurator from './BountyActions/SlashCurator'; +import { determineUnassignCuratorAction } from '../helpers'; +import { useBountyStatus, useUserRole } from '../hooks'; +import { bountySvgColor } from '../theme'; +import { useTranslation } from '../translate'; +import { ValidUnassignCuratorAction } from '../types'; import BountyRejectCurator from './BountyRejectCurator'; -import { determineUnassignCuratorAction } from './helpers'; -import { useBountyStatus, useUserRole } from './hooks'; -import { bountySvgColor } from './theme'; -import { useTranslation } from './translate'; -import { ValidUnassignCuratorAction } from './types'; +import CloseBounty from './CloseBounty'; +import ExtendBountyExpiryAction from './ExtendBountyExpiryAction'; +import GiveUp from './GiveUp'; +import SlashCurator from './SlashCurator'; interface Props { bestNumber: BlockNumber; @@ -29,12 +30,13 @@ interface Props { status: BountyStatus; } -function BountyExtraActions ({ bestNumber, className, description, index, proposals, status }: Props): React.ReactElement | null { +function Index ({ bestNumber, className, description, index, proposals, status }: Props): React.ReactElement | null { const [isPopupOpen, togglePopupOpen] = useToggle(); const [isCloseBountyOpen, toggleCloseBounty] = useToggle(); const [isRejectCuratorOpen, toggleRejectCurator] = useToggle(); const [isSlashCuratorOpen, toggleSlashCurator] = useToggle(); const [isExtendExpiryOpen, toggleExtendExpiry] = useToggle(); + const [isGiveUpCuratorOpen, toggleGiveUpCurator] = useToggle(); const [selectedAction, setSlashAction] = useState(); const { t } = useTranslation(); const { isMember } = useMembers(); @@ -46,7 +48,6 @@ function BountyExtraActions ({ bestNumber, className, description, index, propos const availableSlashActions = determineUnassignCuratorAction(roles, status, blocksUntilUpdate); const slashCuratorActionNames = useRef>({ - GiveUp: t('Give Up'), SlashCuratorAction: t('Slash Curator'), SlashCuratorMotion: t('Slash Curator (Council)'), UnassignCurator: t('Unassign Curator') @@ -57,10 +58,11 @@ function BountyExtraActions ({ bestNumber, className, description, index, propos const showCloseBounty = (status.isFunded || status.isActive || status.isCuratorProposed) && isMember && !existingCloseBountyProposal; const showRejectCurator = status.isCuratorProposed && isCurator; + const showGiveUpCurator = status.isActive && isCurator; const showExtendExpiry = status.isActive && isCurator; const showSlashCurator = (status.isCuratorProposed || status.isActive || status.isPendingPayout) && !existingUnassignCuratorProposal && availableSlashActions.length !== 0; - const hasNoItems = !(showCloseBounty || showRejectCurator || showExtendExpiry || showSlashCurator); + const hasNoItems = !(showCloseBounty || showRejectCurator || showExtendExpiry || showSlashCurator || showGiveUpCurator); function slashCuratorClicked (action: ValidUnassignCuratorAction) { setSlashAction(action); @@ -91,6 +93,13 @@ function BountyExtraActions ({ bestNumber, className, description, index, propos toggleOpen={toggleExtendExpiry} /> } + {isGiveUpCuratorOpen && curator && + + } {isSlashCuratorOpen && curator && selectedAction && ('Extend Expiry')} } + {showGiveUpCurator && + + {t('Give Up')} + + } {showSlashCurator && availableSlashActions.map((actionName) => ` +export default React.memo(styled(Index)(({ theme }: ThemeProps) => ` && .ui--Button:not(.isDisabled):not(.isIcon).settings-button { width: 24px; height: 24px; diff --git a/packages/page-bounties/src/BountyInfo.tsx b/packages/page-bounties/src/BountyInfos/BountyInfo.tsx similarity index 95% rename from packages/page-bounties/src/BountyInfo.tsx rename to packages/page-bounties/src/BountyInfos/BountyInfo.tsx index 9695c36584..6f5427c4c8 100644 --- a/packages/page-bounties/src/BountyInfo.tsx +++ b/packages/page-bounties/src/BountyInfos/BountyInfo.tsx @@ -7,8 +7,8 @@ import styled from 'styled-components'; import { Icon } from '@polkadot/react-components'; import { ThemeProps } from '@polkadot/react-components/types'; -import { bountyColor, bountyLabelColor, bountySvgColor } from './theme'; -import { useTranslation } from './translate'; +import { bountyColor, bountyLabelColor, bountySvgColor } from '../theme'; +import { useTranslation } from '../translate'; interface Props { className: ''; diff --git a/packages/page-bounties/src/Voting/VotingSummary.tsx b/packages/page-bounties/src/BountyInfos/VotingSummary.tsx similarity index 100% rename from packages/page-bounties/src/Voting/VotingSummary.tsx rename to packages/page-bounties/src/BountyInfos/VotingSummary.tsx diff --git a/packages/page-bounties/src/BountyInfos.tsx b/packages/page-bounties/src/BountyInfos/index.tsx similarity index 91% rename from packages/page-bounties/src/BountyInfos.tsx rename to packages/page-bounties/src/BountyInfos/index.tsx index 56b7664784..0cb7820f9b 100644 --- a/packages/page-bounties/src/BountyInfos.tsx +++ b/packages/page-bounties/src/BountyInfos/index.tsx @@ -10,11 +10,11 @@ import React from 'react'; import { AddressSmall } from '@polkadot/react-components'; import { BN_HUNDRED } from '@polkadot/util'; -import VotingSummary from './Voting/VotingSummary'; +import Description from '../Description'; +import { useBounties } from '../hooks'; +import { useTranslation } from '../translate'; import BountyInfo from './BountyInfo'; -import Description from './Description'; -import { useBounties } from './hooks'; -import { useTranslation } from './translate'; +import VotingSummary from './VotingSummary'; interface Props { beneficiary?: AccountId; diff --git a/packages/page-bounties/src/helpers/determineUnassignCuratorAction.spec.ts b/packages/page-bounties/src/helpers/determineUnassignCuratorAction.spec.ts index f6fc8f4b0a..c5024767d6 100644 --- a/packages/page-bounties/src/helpers/determineUnassignCuratorAction.spec.ts +++ b/packages/page-bounties/src/helpers/determineUnassignCuratorAction.spec.ts @@ -29,12 +29,6 @@ describe('adjust slash curator component for', () => { expect(displayAs).toEqual(['SlashCuratorMotion']); }); - it('Curator in Active state', () => { - const displayAs = determineUnassignCuratorAction(['Curator'], aBountyStatus('Active')); - - expect(displayAs).toEqual(['GiveUp']); - }); - it('User in Active state with update due blocks remaining', () => { const displayAs = determineUnassignCuratorAction(['User'], aBountyStatus('Active'), new BN('1')); diff --git a/packages/page-bounties/src/helpers/determineUnassignCuratorAction.ts b/packages/page-bounties/src/helpers/determineUnassignCuratorAction.ts index 3d7ba78dee..151b8f0919 100644 --- a/packages/page-bounties/src/helpers/determineUnassignCuratorAction.ts +++ b/packages/page-bounties/src/helpers/determineUnassignCuratorAction.ts @@ -17,10 +17,6 @@ export function determineUnassignCuratorAction (roles: UserRole[], status: Bount } if (status.isActive) { - if (roles.includes('Curator')) { - actions.push('GiveUp'); - } - if (roles.includes('Member')) { actions.push('SlashCuratorMotion'); } diff --git a/packages/page-bounties/src/helpers/extendedStatuses.ts b/packages/page-bounties/src/helpers/extendedStatuses.ts index 442d108353..c20cd90c5d 100644 --- a/packages/page-bounties/src/helpers/extendedStatuses.ts +++ b/packages/page-bounties/src/helpers/extendedStatuses.ts @@ -9,7 +9,7 @@ import { BountyVotingStatuses, StatusName } from '../types'; const validProposalNames: BountyVotingStatuses = { Active: ['closeBounty', 'unassignCurator'], Approved: [], - CuratorProposed: ['unassignCurator', 'closeBounty'], + CuratorProposed: ['closeBounty', 'unassignCurator'], Funded: ['proposeCurator', 'closeBounty'], PendingPayout: ['unassignCurator'], Proposed: ['approveBounty', 'closeBounty'] diff --git a/packages/page-bounties/src/types.ts b/packages/page-bounties/src/types.ts index c3a56c2fd2..cb9fff7876 100644 --- a/packages/page-bounties/src/types.ts +++ b/packages/page-bounties/src/types.ts @@ -15,6 +15,6 @@ export type HelpMessages = Record; export type StatusName = 'Active' | 'Approved' | 'CuratorProposed' | 'Funded' | 'PendingPayout' | 'Proposed'; export type BountyVotingStatuses = { [status in StatusName]: string[] }; -export type ValidUnassignCuratorAction = 'GiveUp' | 'UnassignCurator' | 'SlashCuratorMotion' | 'SlashCuratorAction'; +export type ValidUnassignCuratorAction = 'UnassignCurator' | 'SlashCuratorMotion' | 'SlashCuratorAction'; export type UnassignCuratorAction = ValidUnassignCuratorAction | 'None'; export type UserRole = 'User' | 'Member' | 'Curator' | 'None'; diff --git a/packages/page-bounties/test/pages/bountiesPage.tsx b/packages/page-bounties/test/pages/bountiesPage.tsx index e3f8247323..ed68db4ff0 100644 --- a/packages/page-bounties/test/pages/bountiesPage.tsx +++ b/packages/page-bounties/test/pages/bountiesPage.tsx @@ -281,7 +281,7 @@ export class BountiesPage { async openGiveUpCuratorsRole (): Promise { await this.openExtraActions(); await this.clickButtonByText('Give Up'); - await this.expectText('This action will unassign you from a curator role.'); + await this.expectText('This action will unassign you from the curator role.'); } async openSlashCuratorByCouncil (): Promise {