Retrieve outstanding at once via multi (#3120)

This commit is contained in:
Jaco Greeff 2020-07-03 14:29:17 +02:00 committed by GitHub
parent 90cbd1cd19
commit 01dcd74a5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 59 deletions

View File

@ -7,9 +7,8 @@ import { AccountId, Balance, BlockNumber, OpenTip, OpenTipTo225 } from '@polkado
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { AddressSmall, AddressMini, Expander, Icon, TxButton } from '@polkadot/react-components';
import { useAccounts, useApi, useCall } from '@polkadot/react-hooks';
import { useAccounts } from '@polkadot/react-hooks';
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
import { Option } from '@polkadot/types';
import { formatNumber, isBoolean } from '@polkadot/util';
import { useTranslation } from '../translate';
@ -23,7 +22,7 @@ interface Props {
hash: string;
isMember: boolean;
members: string[];
setClosed: (hash: string, blockNumber: BlockNumber) => void;
tip: OpenTip | OpenTipTo225;
}
interface TipState {
@ -38,45 +37,34 @@ function isCurrentTip (tip: OpenTip | OpenTipTo225): tip is OpenTip {
return isBoolean((tip as OpenTip).findersFee);
}
function Tip ({ bestNumber, className = '', hash, isMember, members, setClosed }: Props): React.ReactElement<Props> | null {
function Tip ({ bestNumber, className = '', hash, isMember, members, tip }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const { allAccounts } = useAccounts();
const [{ closesAt, deposit, finder, isFinder, isTipper }, setTipState] = useState<TipState>({ closesAt: null, deposit: null, finder: null, isFinder: false, isTipper: false });
const tip = useCall<OpenTip | OpenTipTo225 | null>(api.query.treasury.tips, [hash], {
transform: (optTip: Option<OpenTip>) => optTip.unwrapOr(null)
});
useEffect((): void => {
if (tip) {
const closesAt = tip.closes.unwrapOr(null);
let finder: AccountId | null = null;
let deposit: Balance | null = null;
const closesAt = tip.closes.unwrapOr(null);
let finder: AccountId | null = null;
let deposit: Balance | null = null;
if (isCurrentTip(tip)) {
finder = tip.finder;
deposit = tip.deposit;
} else if (tip.finder.isSome) {
const finderInfo = tip.finder.unwrap();
if (isCurrentTip(tip)) {
finder = tip.finder;
deposit = tip.deposit;
} else if (tip.finder.isSome) {
const finderInfo = tip.finder.unwrap();
finder = finderInfo[0];
deposit = finderInfo[1];
}
closesAt && setClosed(hash, closesAt);
setTipState({
closesAt,
deposit,
finder,
isFinder: !!finder && allAccounts.includes(finder.toString()),
isTipper: tip.tips.some(([address]) => allAccounts.includes(address.toString()))
});
finder = finderInfo[0];
deposit = finderInfo[1];
}
}, [allAccounts, hash, setClosed, tip]);
if (!tip) {
return null;
}
setTipState({
closesAt,
deposit,
finder,
isFinder: !!finder && allAccounts.includes(finder.toString()),
isTipper: tip.tips.some(([address]) => allAccounts.includes(address.toString()))
});
}, [allAccounts, hash, tip]);
const { reason, tips, who } = tip;

View File

@ -2,11 +2,12 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { BlockNumber } from '@polkadot/types/interfaces';
import { BlockNumber, OpenTip, OpenTipTo225 } from '@polkadot/types/interfaces';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { Table } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
import { Option } from '@polkadot/types';
import { BN_ZERO } from '@polkadot/util';
import { useTranslation } from '../translate';
@ -19,27 +20,23 @@ interface Props {
members: string[];
}
type Tip = [string, OpenTip | OpenTipTo225];
function Tips ({ className = '', hashes, isMember, members }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber, []);
const [closed, setClosed] = useState<Record<string, BlockNumber>>({});
const [sorted, setSorted] = useState<string[]>([]);
const [tips, setTips] = useState<Tip[] | undefined>();
const optTips = useCall<Option<OpenTip>[]>(hashes && api.query.treasury.tips.multi, [hashes]);
useEffect((): void => {
hashes && setSorted(
hashes.sort((a, b) => (closed[a] || BN_ZERO).cmp(closed[b] || BN_ZERO))
hashes && optTips && setTips(
optTips
.map((opt, index): [string, OpenTip | null] => [hashes[index], opt.unwrapOr(null)])
.filter((val): val is [string, OpenTip] => !!val[1])
.sort((a, b) => a[1].closes.unwrapOr(BN_ZERO).cmp(b[1].closes.unwrapOr(BN_ZERO)))
);
}, [closed, hashes]);
const _setClosed = useCallback(
(hash: string, blockNumber: BlockNumber) =>
setClosed((closed) => ({
...closed,
[hash]: blockNumber
})),
[]
);
}, [hashes, optTips]);
const header = useMemo(() => [
[t('tips'), 'start'],
@ -54,17 +51,17 @@ function Tips ({ className = '', hashes, isMember, members }: Props): React.Reac
return (
<Table
className={className}
empty={!sorted.length && t<string>('No open tips')}
empty={tips && t<string>('No open tips')}
header={header}
>
{sorted.length !== 0 && sorted.map((hash): React.ReactNode => (
{tips?.map(([hash, tip]): React.ReactNode => (
<Tip
bestNumber={bestNumber}
hash={hash}
isMember={isMember}
key={hash}
members={members}
setClosed={_setClosed}
tip={tip}
/>
))}
</Table>

View File

@ -21,18 +21,18 @@ function Overview ({ className }: Props): React.ReactElement<Props> {
const { isMember, members } = useMembers();
const mountedRef = useIsMountedRef();
const [hashTrigger, triggerHashes] = useIncrement();
const [hashes, setHashes] = useState<string[] | null>(null);
const [tipHashTrigger, triggerTipHashes] = useIncrement();
const [tipHashes, setTipHashes] = useState<string[] | null>(null);
useEffect((): void => {
if (hashTrigger && mountedRef.current) {
if (tipHashTrigger && mountedRef.current) {
api.query.treasury.tips.keys().then((keys) =>
mountedRef.current && setHashes(
mountedRef.current && setTipHashes(
keys.map((key) => key.args[0].toHex())
)
).catch(console.error);
}
}, [api, hashTrigger, mountedRef]);
}, [api, tipHashTrigger, mountedRef]);
return (
<div className={className}>
@ -44,7 +44,7 @@ function Overview ({ className }: Props): React.ReactElement<Props> {
<ProposalCreate />
<TipCreate
members={members}
refresh={triggerHashes}
refresh={triggerTipHashes}
/>
</Button.Group>
<Proposals
@ -59,7 +59,7 @@ function Overview ({ className }: Props): React.ReactElement<Props> {
proposals={info?.approvals}
/>
<Tips
hashes={hashes}
hashes={tipHashes}
isMember={isMember}
members={members}
/>