parent
2f4e0fbafd
commit
ea63c8eb53
@ -149,7 +149,7 @@ function Validator ({ allSlashes, canSelect, filterName, info, isNominated, isSe
|
||||
<td className='number together'>{!bondOwn.isZero() && <FormatBalance value={bondOwn} />}</td>
|
||||
<td className='number together media--1600'>{!bondOther.isZero() && <FormatBalance value={bondOther} />}</td>
|
||||
<td className='number together'>{!rewardPayout.isZero() && <FormatBalance value={rewardPayout} />}</td>
|
||||
<td>
|
||||
<td className='badge'>
|
||||
{(canSelect || isSelected) && (
|
||||
<Checkbox
|
||||
onChange={_toggleSelected}
|
||||
|
||||
@ -140,6 +140,7 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
1,
|
||||
(): void => _sort(header as 'rankComm')
|
||||
]),
|
||||
[undefined, 'badge'],
|
||||
[]
|
||||
], [_sort, labels, sortBy, sorted, sortFromMax, t]);
|
||||
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
import { AccountId, Balance, BlockNumber, OpenTip, OpenTipTo225 } from '@polkadot/types/interfaces';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { AddressSmall, AddressMini, Expander, Icon, LinkExternal, TxButton } from '@polkadot/react-components';
|
||||
import { AddressSmall, AddressMini, Checkbox, Expander, Icon, LinkExternal, TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts } from '@polkadot/react-hooks';
|
||||
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
|
||||
import { BN_ZERO, formatNumber } from '@polkadot/util';
|
||||
@ -20,9 +20,11 @@ import TipReason from './TipReason';
|
||||
interface Props {
|
||||
bestNumber?: BlockNumber;
|
||||
className?: string;
|
||||
defaultId: string | null;
|
||||
hash: string;
|
||||
isMember: boolean;
|
||||
members: string[];
|
||||
onSelect: (hash: string, isSelected: boolean, value: BN) => void,
|
||||
tip: OpenTip | OpenTipTo225;
|
||||
}
|
||||
|
||||
@ -74,7 +76,7 @@ function extractTipState (tip: OpenTip | OpenTipTo225, hash: string, allAccounts
|
||||
};
|
||||
}
|
||||
|
||||
function Tip ({ bestNumber, className = '', hash, isMember, members, tip }: Props): React.ReactElement<Props> | null {
|
||||
function Tip ({ bestNumber, className = '', defaultId, hash, isMember, members, onSelect, tip }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { allAccounts } = useAccounts();
|
||||
|
||||
@ -83,6 +85,16 @@ function Tip ({ bestNumber, className = '', hash, isMember, members, tip }: Prop
|
||||
[allAccounts, hash, tip]
|
||||
);
|
||||
|
||||
const [isMedianSelected, setMedianTip] = useState(false);
|
||||
|
||||
useEffect((): void => {
|
||||
onSelect(hash, isMedianSelected, median);
|
||||
}, [hash, isMedianSelected, median, onSelect]);
|
||||
|
||||
useEffect((): void => {
|
||||
setMedianTip(isMember && !isTipper);
|
||||
}, [isMember, isTipper]);
|
||||
|
||||
const { reason, tips, who } = tip;
|
||||
|
||||
return (
|
||||
@ -135,6 +147,7 @@ function Tip ({ bestNumber, className = '', hash, isMember, members, tip }: Prop
|
||||
{(!closesAt || !bestNumber || closesAt.gt(bestNumber))
|
||||
? (
|
||||
<TipEndorse
|
||||
defaultId={defaultId}
|
||||
hash={hash}
|
||||
isMember={isMember}
|
||||
isTipped={isTipped}
|
||||
@ -159,6 +172,13 @@ function Tip ({ bestNumber, className = '', hash, isMember, members, tip }: Prop
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
<td className='badge'>
|
||||
<Checkbox
|
||||
isDisabled={!isMember}
|
||||
onChange={setMedianTip}
|
||||
value={isMedianSelected}
|
||||
/>
|
||||
</td>
|
||||
<td className='mini media--1700'>
|
||||
<LinkExternal
|
||||
data={hash}
|
||||
|
||||
@ -3,13 +3,14 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Button, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts, useToggle } from '@polkadot/react-hooks';
|
||||
import { useToggle } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
defaultId: string | null;
|
||||
hash: string;
|
||||
isMember: boolean;
|
||||
isTipped: boolean;
|
||||
@ -17,20 +18,12 @@ interface Props {
|
||||
members: string[];
|
||||
}
|
||||
|
||||
function TipEndorse ({ hash, isMember, isTipped, median, members }: Props): React.ReactElement<Props> {
|
||||
function TipEndorse ({ defaultId, hash, isMember, isTipped, median, members }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const [isOpen, toggleOpen] = useToggle();
|
||||
const { allAccounts } = useAccounts();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [defaultId, setDefaultId] = useState<string | null>(null);
|
||||
const [accountId, setAccountId] = useState<string | null>(defaultId);
|
||||
const [value, setValue] = useState<BN | undefined>();
|
||||
|
||||
useEffect((): void => {
|
||||
setDefaultId(
|
||||
members.find((memberId) => allAccounts.includes(memberId)) || null
|
||||
);
|
||||
}, [allAccounts, members]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import { BlockNumber, OpenTip, OpenTipTo225 } from '@polkadot/types/interfaces';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useMemo, useRef } from 'react';
|
||||
import { Table } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
@ -14,9 +15,11 @@ import Tip from './Tip';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
defaultId: string | null;
|
||||
hashes?: string[] | null;
|
||||
isMember: boolean;
|
||||
members: string[];
|
||||
onSelectTip: (hash: string, isSelected: boolean, value: BN) => void,
|
||||
}
|
||||
|
||||
type Tip = [string, OpenTip | OpenTipTo225];
|
||||
@ -40,7 +43,7 @@ function extractTips (optTips?: Option<OpenTip>[], hashes?: string[] | null): Ti
|
||||
);
|
||||
}
|
||||
|
||||
function Tips ({ className = '', hashes, isMember, members }: Props): React.ReactElement<Props> {
|
||||
function Tips ({ className = '', defaultId, hashes, isMember, members, onSelectTip }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const bestNumber = useCall<BlockNumber>(api.derive.chain.bestNumber);
|
||||
@ -58,6 +61,7 @@ function Tips ({ className = '', hashes, isMember, members }: Props): React.Reac
|
||||
[],
|
||||
[],
|
||||
[undefined, 'badge media--1700'],
|
||||
[undefined, 'badge'],
|
||||
[undefined, 'mini media--1700']
|
||||
]);
|
||||
|
||||
@ -70,10 +74,12 @@ function Tips ({ className = '', hashes, isMember, members }: Props): React.Reac
|
||||
{tips?.map(([hash, tip]): React.ReactNode => (
|
||||
<Tip
|
||||
bestNumber={bestNumber}
|
||||
defaultId={defaultId}
|
||||
hash={hash}
|
||||
isMember={isMember}
|
||||
key={hash}
|
||||
members={members}
|
||||
onSelect={onSelectTip}
|
||||
tip={tip}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -2,9 +2,14 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import React from 'react';
|
||||
import { Button } from '@polkadot/react-components';
|
||||
import { SubmittableExtrinsic } from '@polkadot/api/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { Button, TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import TipCreate from './TipCreate';
|
||||
import Tips from './Tips';
|
||||
|
||||
@ -16,7 +21,43 @@ interface Props {
|
||||
trigger: () => void;
|
||||
}
|
||||
|
||||
interface QuickTipsState {
|
||||
quickTips: Record<string, BN | null>;
|
||||
quickTx: SubmittableExtrinsic<'promise'> | null;
|
||||
}
|
||||
|
||||
function TipsEntry ({ className, hashes, isMember, members, trigger }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { allAccounts } = useAccounts();
|
||||
const { api } = useApi();
|
||||
const [{ quickTx }, setQuickTips] = useState<QuickTipsState>({ quickTips: {}, quickTx: null });
|
||||
|
||||
const defaultId = useMemo(
|
||||
() => members.find((memberId) => allAccounts.includes(memberId)) || null,
|
||||
[allAccounts, members]
|
||||
);
|
||||
|
||||
const _selectTip = useCallback(
|
||||
(hash: string, isSelected: boolean, value: BN) => setQuickTips(({ quickTips }): QuickTipsState => {
|
||||
quickTips[hash] = isSelected ? value : null;
|
||||
|
||||
const available = Object
|
||||
.entries(quickTips)
|
||||
.map(([hash, value]) => value ? api.tx.treasury.tip(hash, value) : null)
|
||||
.filter((value): value is SubmittableExtrinsic<'promise'> => !!value);
|
||||
|
||||
return {
|
||||
quickTips,
|
||||
quickTx: available.length
|
||||
? available.length === 1
|
||||
? available[0]
|
||||
: api.tx.utility.batch(available)
|
||||
: null
|
||||
};
|
||||
}),
|
||||
[api]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Button.Group>
|
||||
@ -24,11 +65,20 @@ function TipsEntry ({ className, hashes, isMember, members, trigger }: Props): R
|
||||
members={members}
|
||||
refresh={trigger}
|
||||
/>
|
||||
<TxButton
|
||||
accountId={defaultId}
|
||||
extrinsic={quickTx}
|
||||
icon='fighter-jet'
|
||||
isDisabled={!isMember || !quickTx}
|
||||
label={t<string>('Median tip selected')}
|
||||
/>
|
||||
</Button.Group>
|
||||
<Tips
|
||||
defaultId={defaultId}
|
||||
hashes={hashes}
|
||||
isMember={isMember}
|
||||
members={members}
|
||||
onSelectTip={_selectTip}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user