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 <jacogr@gmail.com>
This commit is contained in:
parent
5ce8c40916
commit
75023bb4f3
@ -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",
|
||||
|
||||
@ -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 (
|
||||
<>
|
||||
<Summary activeBounties={deriveBounties?.length}/>
|
||||
<Button.Group>
|
||||
<BountyCreate />
|
||||
</Button.Group>
|
||||
|
||||
91
packages/page-bounties/src/Summary.tsx
Normal file
91
packages/page-bounties/src/Summary.tsx
Normal file
@ -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<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
|
||||
const bountyIndex = useCall<BountyIndex>((api.query.bounties || api.query.treasury).bountyCount);
|
||||
const bestNumber = useCall<Balance>(api.derive.chain.bestNumber);
|
||||
|
||||
const { burn, spendPeriod, value } = useTreasury();
|
||||
|
||||
return (
|
||||
<SummaryBox className={`ui--BountySummary ${className}`}>
|
||||
<section>
|
||||
<CardSummary label={t<string>('active')}>
|
||||
{activeBounties}
|
||||
</CardSummary>
|
||||
{activeBounties !== undefined && (
|
||||
<CardSummary label={t<string>('past')}>
|
||||
{bountyIndex?.subn(activeBounties).toString()}
|
||||
</CardSummary>
|
||||
)}
|
||||
{bestNumber && spendPeriod.gtn(0) && (
|
||||
<CardSummary label={t<string>('next bounty funding in')}>
|
||||
<BlockToTime
|
||||
blocks={spendPeriod.sub(bestNumber.mod(spendPeriod))}
|
||||
className='timer'
|
||||
/>
|
||||
</CardSummary>
|
||||
)}
|
||||
</section>
|
||||
<section>
|
||||
{value && (
|
||||
<CardSummary label={t<string>('treasury')}>
|
||||
<FormatBalance
|
||||
value={value}
|
||||
withSi
|
||||
/>
|
||||
</CardSummary>
|
||||
)}
|
||||
{burn && (
|
||||
<CardSummary
|
||||
label={t<string>('next burn')}
|
||||
>
|
||||
<FormatBalance
|
||||
value={burn}
|
||||
withSi
|
||||
/>
|
||||
</CardSummary>
|
||||
)}
|
||||
{spendPeriod.gtn(0) && (
|
||||
<CardSummary
|
||||
label={t<string>('spend period')}
|
||||
>
|
||||
<BlockToTime
|
||||
blocks={spendPeriod}
|
||||
className='timer'
|
||||
/>
|
||||
</CardSummary>
|
||||
)}
|
||||
{bestNumber && spendPeriod.gtn(0) && (
|
||||
<Progress
|
||||
className='media--1000'
|
||||
total={spendPeriod}
|
||||
value={bestNumber.mod(spendPeriod)}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
</SummaryBox>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Summary);
|
||||
@ -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<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const bestNumber = useCall<Balance>(api.derive.chain.bestNumber);
|
||||
const totalProposals = useCall<BN>(api.query.treasury.proposalCount);
|
||||
const treasuryBalance = useCall<DeriveBalancesAccount>(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 (
|
||||
<SummaryBox>
|
||||
|
||||
46
packages/react-hooks/src/useTreasury.ts
Normal file
46
packages/react-hooks/src/useTreasury.ts
Normal file
@ -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<Balance>();
|
||||
const [burn, setBurn] = useState<BN>();
|
||||
|
||||
const treasuryBalance = useCall<DeriveBalancesAccount>(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
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user