From 75023bb4f3b6f3d6ca2bf6de989d2da0839b249b Mon Sep 17 00:00:00 2001 From: MiZiet <55240109+MiZiet@users.noreply.github.com> Date: Sat, 9 Jan 2021 12:46:52 +0100 Subject: [PATCH] Add bounties summary (#4336) * Add bounty summary INIT * Add timed displays * WIP * Add locales * Add chain colors and progress display * Extract useTreasury hook * Pull spendPeriod into useTreasury * Apply review suggestions * Apply review suggestion * Add check if activeBounties exists * Add dark theme to bounty summary * Add border-radius to HighlightedSection * Apply review suggestions Co-authored-by: Jaco Greeff --- .../apps/public/locales/en/app-bounties.json | 6 ++ packages/page-bounties/src/Bounties.tsx | 2 + packages/page-bounties/src/Summary.tsx | 91 +++++++++++++++++++ .../page-treasury/src/Overview/Summary.tsx | 17 +--- packages/react-hooks/src/useTreasury.ts | 46 ++++++++++ 5 files changed, 148 insertions(+), 14 deletions(-) create mode 100644 packages/page-bounties/src/Summary.tsx create mode 100644 packages/react-hooks/src/useTreasury.ts diff --git a/packages/apps/public/locales/en/app-bounties.json b/packages/apps/public/locales/en/app-bounties.json index f88147cd93..87b891cf36 100644 --- a/packages/apps/public/locales/en/app-bounties.json +++ b/packages/apps/public/locales/en/app-bounties.json @@ -31,15 +31,21 @@ "Title too long": "Title too long", "Use this account to propose bounty from. This can be a normal or council account.": "Use this account to propose bounty from. This can be a normal or council account.", "Value": "Value", + "active": "active", "beneficiary": "beneficiary", "bounties": "bounties", "bounty bond": "bounty bond", "bounty requested allocation": "bounty requested allocation", "bounty title": "bounty title", "curator": "curator", + "next bounty funding in": "next bounty funding in", + "next burn": "next burn", + "past": "past", "payout due": "payout due", + "spend period": "spend period", "submit with account": "submit with account", "title": "title", + "treasury": "treasury", "update due": "update due", "value": "value", "vote with account": "vote with account", diff --git a/packages/page-bounties/src/Bounties.tsx b/packages/page-bounties/src/Bounties.tsx index 706e99bd79..e0df29c548 100644 --- a/packages/page-bounties/src/Bounties.tsx +++ b/packages/page-bounties/src/Bounties.tsx @@ -6,6 +6,7 @@ import type { BlockNumber } from '@polkadot/types/interfaces'; import React, { useRef } from 'react'; +import Summary from '@polkadot/app-bounties/Summary'; import { Button, Table } from '@polkadot/react-components'; import { useApi, useCall } from '@polkadot/react-hooks'; @@ -34,6 +35,7 @@ function Bounties (): React.ReactElement { return ( <> + diff --git a/packages/page-bounties/src/Summary.tsx b/packages/page-bounties/src/Summary.tsx new file mode 100644 index 0000000000..0b51b14b9e --- /dev/null +++ b/packages/page-bounties/src/Summary.tsx @@ -0,0 +1,91 @@ +// Copyright 2017-2020 @polkadot/app-bounties authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { BountyIndex } from '@polkadot/types/interfaces'; + +import React from 'react'; + +import { useTranslation } from '@polkadot/app-treasury/translate'; +import { CardSummary, SummaryBox } from '@polkadot/react-components'; +import Progress from '@polkadot/react-components/Progress'; +import { useApi, useCall } from '@polkadot/react-hooks'; +import { useTreasury } from '@polkadot/react-hooks/useTreasury'; +import { BlockToTime, FormatBalance } from '@polkadot/react-query'; +import { Balance } from '@polkadot/types/interfaces'; + +interface Props { + activeBounties?: number; + className?: string; +} + +function Summary ({ activeBounties, className = '' }: Props): React.ReactElement { + const { t } = useTranslation(); + const { api } = useApi(); + + const bountyIndex = useCall((api.query.bounties || api.query.treasury).bountyCount); + const bestNumber = useCall(api.derive.chain.bestNumber); + + const { burn, spendPeriod, value } = useTreasury(); + + return ( + +
+ ('active')}> + {activeBounties} + + {activeBounties !== undefined && ( + ('past')}> + {bountyIndex?.subn(activeBounties).toString()} + + )} + {bestNumber && spendPeriod.gtn(0) && ( + ('next bounty funding in')}> + + + )} +
+
+ {value && ( + ('treasury')}> + + + )} + {burn && ( + ('next burn')} + > + + + )} + {spendPeriod.gtn(0) && ( + ('spend period')} + > + + + )} + {bestNumber && spendPeriod.gtn(0) && ( + + )} +
+
+ ); +} + +export default React.memo(Summary); diff --git a/packages/page-treasury/src/Overview/Summary.tsx b/packages/page-treasury/src/Overview/Summary.tsx index 9454c6deb2..cbffdce2af 100644 --- a/packages/page-treasury/src/Overview/Summary.tsx +++ b/packages/page-treasury/src/Overview/Summary.tsx @@ -1,7 +1,6 @@ // Copyright 2017-2021 @polkadot/app-treasury authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { DeriveBalancesAccount } from '@polkadot/api-derive/types'; import type { Balance } from '@polkadot/types/interfaces'; import BN from 'bn.js'; @@ -9,34 +8,24 @@ import React from 'react'; import { CardSummary, SummaryBox } from '@polkadot/react-components'; import { useApi, useCall } from '@polkadot/react-hooks'; +import { useTreasury } from '@polkadot/react-hooks/useTreasury'; import { FormatBalance } from '@polkadot/react-query'; -import { formatNumber, stringToU8a } from '@polkadot/util'; +import { formatNumber } from '@polkadot/util'; import { useTranslation } from '../translate'; -const TREASURY_ACCOUNT = stringToU8a('modlpy/trsry'.padEnd(32, '\0')); - interface Props { approvalCount?: number; proposalCount?: number; } -const PM_DIV = new BN(1000000); - function Summary ({ approvalCount, proposalCount }: Props): React.ReactElement { const { t } = useTranslation(); const { api } = useApi(); const bestNumber = useCall(api.derive.chain.bestNumber); const totalProposals = useCall(api.query.treasury.proposalCount); - const treasuryBalance = useCall(api.derive.balances.account, [TREASURY_ACCOUNT]); - const spendPeriod = api.consts.treasury.spendPeriod; - const value = treasuryBalance?.freeBalance.gtn(0) - ? treasuryBalance.freeBalance - : null; - const burn = treasuryBalance?.freeBalance.gtn(0) && !api.consts.treasury.burn.isZero() - ? api.consts.treasury.burn.mul(treasuryBalance?.freeBalance).div(PM_DIV) - : null; + const { burn, spendPeriod, value } = useTreasury(); return ( diff --git a/packages/react-hooks/src/useTreasury.ts b/packages/react-hooks/src/useTreasury.ts new file mode 100644 index 0000000000..89863ca7b8 --- /dev/null +++ b/packages/react-hooks/src/useTreasury.ts @@ -0,0 +1,46 @@ +// Copyright 2017-2020 @polkadot/react-hooks authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { Balance } from '@polkadot/types/interfaces'; + +import BN from 'bn.js'; +import { useEffect, useState } from 'react'; + +import { DeriveBalancesAccount } from '@polkadot/api-derive/types'; +import { useApi } from '@polkadot/react-hooks/useApi'; +import { useCall } from '@polkadot/react-hooks/useCall'; +import { BN_ZERO, stringToU8a } from '@polkadot/util'; + +const PM_DIV = new BN(1000000); +const TREASURY_ACCOUNT = stringToU8a('modlpy/trsry'.padEnd(32, '\0')); + +interface Treasury { + value?: Balance; + burn?: BN; + spendPeriod: BN; +} + +export function useTreasury (): Treasury { + const { api } = useApi(); + + const [value, setValue] = useState(); + const [burn, setBurn] = useState(); + + const treasuryBalance = useCall(api.derive.balances.account, [TREASURY_ACCOUNT]); + const spendPeriod = api.consts.treasury.spendPeriod; + + useEffect(() => { + setValue(treasuryBalance?.freeBalance.gtn(0) + ? treasuryBalance.freeBalance + : undefined); + setBurn(treasuryBalance?.freeBalance.gtn(0) && !api.consts.treasury.burn.isZero() + ? api.consts.treasury.burn.mul(treasuryBalance?.freeBalance).div(PM_DIV) + : BN_ZERO); + }, [api, treasuryBalance, spendPeriod]); + + return { + burn, + spendPeriod, + value + }; +}