mirror of
https://github.com/pezkuwichain/pezkuwi-sdk-ui.git
synced 2026-07-17 21:45:46 +00:00
d949863789
Comprehensive web interface for interacting with Pezkuwi blockchain. Features: - Blockchain explorer - Wallet management - Staking interface - Governance participation - Developer tools Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
106 lines
3.2 KiB
TypeScript
106 lines
3.2 KiB
TypeScript
// Copyright 2017-2026 @pezkuwi/app-staking authors & contributors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import type { ValidateInfo } from './types.js';
|
|
|
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
import { Dropdown, InputNumber, MarkError, Modal } from '@pezkuwi/react-components';
|
|
import { useApi } from '@pezkuwi/react-hooks';
|
|
import { BN, BN_HUNDRED as MAX_COMM, BN_ONE, bnMax, isFunction } from '@pezkuwi/util';
|
|
|
|
import { useTranslation } from '../../translate.js';
|
|
import SenderInfo from './SenderInfo.js';
|
|
|
|
interface Props {
|
|
className?: string;
|
|
controllerId: string;
|
|
minCommission?: BN;
|
|
onChange: (info: ValidateInfo) => void;
|
|
stashId: string;
|
|
withFocus?: boolean;
|
|
withSenders?: boolean;
|
|
}
|
|
|
|
const COMM_MUL = new BN(1e7);
|
|
|
|
function Validate ({ className = '', controllerId, minCommission, onChange, stashId, withFocus, withSenders }: Props): React.ReactElement<Props> {
|
|
const { t } = useTranslation();
|
|
const { api } = useApi();
|
|
const [commission, setCommission] = useState(BN_ONE);
|
|
const [allowNoms, setAllowNoms] = useState(true);
|
|
const defaultComm = useMemo(
|
|
() => minCommission
|
|
? bnMax(minCommission.div(COMM_MUL), BN_ONE)
|
|
: BN_ONE,
|
|
[minCommission]
|
|
);
|
|
|
|
const blockedOptions = useRef([
|
|
{ text: t('Yes, allow nominations'), value: true },
|
|
{ text: t('No, block all nominations'), value: false }
|
|
]);
|
|
|
|
useEffect((): void => {
|
|
try {
|
|
onChange({
|
|
validateTx: api.tx.staking.validate({
|
|
blocked: !allowNoms,
|
|
commission
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
} as any)
|
|
});
|
|
} catch {
|
|
onChange({ validateTx: null });
|
|
}
|
|
}, [api, allowNoms, commission, onChange]);
|
|
|
|
const _setCommission = useCallback(
|
|
(value?: BN) => value && setCommission(
|
|
value.isZero()
|
|
? BN_ONE // small non-zero set to avoid isEmpty
|
|
: value.mul(COMM_MUL)
|
|
),
|
|
[]
|
|
);
|
|
|
|
const commErr = !!minCommission && commission.lt(minCommission);
|
|
|
|
return (
|
|
<div className={className}>
|
|
{withSenders && (
|
|
<SenderInfo
|
|
controllerId={controllerId}
|
|
stashId={stashId}
|
|
/>
|
|
)}
|
|
<Modal.Columns hint={t('The commission is deducted from all rewards before the remainder is split with nominators.')}>
|
|
<InputNumber
|
|
autoFocus={withFocus}
|
|
defaultValue={defaultComm}
|
|
isError={commErr}
|
|
isZeroable
|
|
label={t('reward commission percentage')}
|
|
maxValue={MAX_COMM}
|
|
onChange={_setCommission}
|
|
/>
|
|
{commErr && (
|
|
<MarkError content={t('The commission is below the on-chain minimum of {{p}}%', { replace: { p: (minCommission.mul(MAX_COMM).div(COMM_MUL).toNumber() / 100).toFixed(2) } })} />
|
|
)}
|
|
</Modal.Columns>
|
|
{isFunction(api.tx.staking.kick) && (
|
|
<Modal.Columns hint={t('The validator can block any new nominations. By default it is set to allow all nominations.')}>
|
|
<Dropdown
|
|
defaultValue={true}
|
|
label={t('allows new nominations')}
|
|
onChange={setAllowNoms}
|
|
options={blockedOptions.current}
|
|
/>
|
|
</Modal.Columns>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default React.memo(Validate);
|