Retrieve outstanding at once via multi (#3120)
This commit is contained in:
parent
90cbd1cd19
commit
01dcd74a5e
@ -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;
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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}
|
||||
/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user