mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-07-26 07:25:41 +00:00
971df8edba
- Remove all 3rd party parachain configurations from endpoints: - productionRelayPolkadot.ts: Keep only system parachains - productionRelayDicle.ts: Keep only system parachains - testingRelayZagros.ts: Keep only system parachains - testingRelayTeyrChain.ts: Keep only system parachains - Update domain references: - polkadot.js.org → pezkuwichain.app - wiki.polkadot.network → wiki.pezkuwichain.io - dotapps.io → pezkuwichain.app - statement.polkadot.network → docs.pezkuwichain.io/statement - support.polkadot.network → docs.pezkuwichain.io - Update repository references: - github.com/pezkuwi-js/apps → github.com/pezkuwichain/pwap - Rename system parachains to Pezkuwi ecosystem: - PolkadotAssetHub → PezkuwiAssetHub - polkadotBridgeHub → pezkuwiBridgeHub - polkadotCollectives → pezkuwiCollectives - polkadotCoretime → pezkuwiCoretime - polkadotPeople → pezkuwiPeople - Update network name in claims utility: - Polkadot → Pezkuwi
151 lines
4.8 KiB
TypeScript
151 lines
4.8 KiB
TypeScript
// Copyright 2017-2026 @pezkuwi/react-components authors & contributors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import type { DeriveSessionProgress, DeriveStakingAccount } from '@pezkuwi/api-derive/types';
|
|
|
|
import React, { useMemo } from 'react';
|
|
|
|
import { useApi, useCall, useStakingAsyncApis } from '@pezkuwi/react-hooks';
|
|
import { BlockToTime, FormatBalance } from '@pezkuwi/react-query';
|
|
import { BN, BN_ONE, BN_ZERO, formatBalance, formatNumber } from '@pezkuwi/util';
|
|
|
|
import Icon from './Icon.js';
|
|
import { styled } from './styled.js';
|
|
import Tooltip from './Tooltip.js';
|
|
import { useTranslation } from './translate.js';
|
|
|
|
interface Unlocking {
|
|
remainingEras: BN;
|
|
value: BN;
|
|
}
|
|
|
|
interface DeriveStakingAccountPartial {
|
|
accountId: DeriveStakingAccount['accountId'] | string;
|
|
unlocking?: Unlocking[];
|
|
}
|
|
|
|
interface Props {
|
|
iconPosition?: 'left' | 'right';
|
|
className?: string;
|
|
stakingInfo?: DeriveStakingAccountPartial;
|
|
}
|
|
|
|
function extractTotals (stakingInfo?: DeriveStakingAccountPartial, progress?: DeriveSessionProgress): [[Unlocking, BN, BN][], BN, boolean] {
|
|
if (!stakingInfo?.unlocking || !progress) {
|
|
return [[], BN_ZERO, false];
|
|
}
|
|
|
|
const isStalled = progress.eraProgress.gt(BN_ZERO) && progress.eraProgress.gt(progress.eraLength);
|
|
const mapped = stakingInfo.unlocking
|
|
.filter(({ remainingEras, value }) => value.gt(BN_ZERO) && remainingEras.gt(BN_ZERO))
|
|
.map((unlock): [Unlocking, BN, BN] => [
|
|
unlock,
|
|
unlock.remainingEras,
|
|
unlock.remainingEras
|
|
.sub(BN_ONE)
|
|
.imul(progress.eraLength)
|
|
.iadd(progress.eraLength)
|
|
.isub(
|
|
// in the case of a stalled era, this would not be accurate. We apply the mod here
|
|
// otherwise we would enter into negative values (which is "accurate" since we are
|
|
// overdue, but confusing since it implied it needed to be done already).
|
|
//
|
|
// This does mean that in cases of era stalls we would have an jiggling time, i.e.
|
|
// would be down and then when a session completes, would be higher again, just to
|
|
// repeat the cycle again
|
|
//
|
|
// See https://github.com/pezkuwi-js/apps/issues/9397#issuecomment-1532465939
|
|
isStalled
|
|
? progress.eraProgress.mod(progress.eraLength)
|
|
: progress.eraProgress
|
|
)
|
|
]);
|
|
const total = mapped.reduce((total, [{ value }]) => total.iadd(value), new BN(0));
|
|
|
|
return [mapped, total, isStalled];
|
|
}
|
|
|
|
function StakingUnbonding ({ className = '', iconPosition = 'left', stakingInfo }: Props): React.ReactElement<Props> | null {
|
|
const { api: connectedApi } = useApi();
|
|
const { isStakingAsync, rcApi } = useStakingAsyncApis();
|
|
const api = useMemo(() => (isStakingAsync ? rcApi : connectedApi), [connectedApi, isStakingAsync, rcApi]);
|
|
const progress = useCall<DeriveSessionProgress>(api?.derive.session.progress);
|
|
const { t } = useTranslation();
|
|
|
|
const [mapped, total, isStalled] = useMemo(
|
|
() => extractTotals(stakingInfo, progress),
|
|
[progress, stakingInfo]
|
|
);
|
|
|
|
if (!stakingInfo || !mapped.length) {
|
|
return null;
|
|
}
|
|
|
|
const trigger = `${stakingInfo.accountId.toString()}-unlocking-trigger`;
|
|
|
|
return (
|
|
<StyledDiv className={className}>
|
|
{iconPosition === 'left' && (
|
|
<Icon
|
|
className='left'
|
|
icon='clock'
|
|
tooltip={trigger}
|
|
/>
|
|
)}
|
|
<FormatBalance value={total} />
|
|
<Tooltip trigger={trigger}>
|
|
{mapped.map(([{ value }, eras, blocks], index): React.ReactNode => (
|
|
<div
|
|
className='row'
|
|
key={index}
|
|
>
|
|
<div>{t('Unbonding {{value}}', { replace: { value: formatBalance(value, { forceUnit: '-' }) } })}</div>
|
|
<div className='faded'>
|
|
{api?.consts.babe?.epochDuration
|
|
? (
|
|
<BlockToTime
|
|
api={api}
|
|
label={`${t('{{blocks}} blocks', { replace: { blocks: formatNumber(blocks) } })}, `}
|
|
value={blocks}
|
|
/>
|
|
)
|
|
: t('{{eras}} eras remaining', { replace: { eras: formatNumber(eras) } })
|
|
}
|
|
</div>
|
|
{isStalled && (
|
|
<div className='faded'>{t('Era is overdue for completion due to current network operating conditions')}</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</Tooltip>
|
|
{iconPosition === 'right' && (
|
|
<Icon
|
|
className='right'
|
|
icon='clock'
|
|
tooltip={trigger}
|
|
/>
|
|
)}
|
|
</StyledDiv>
|
|
);
|
|
}
|
|
|
|
const StyledDiv = styled.div`
|
|
white-space: nowrap;
|
|
|
|
.ui--Icon.left {
|
|
margin-left: 0;
|
|
margin-right: 0.25rem;
|
|
}
|
|
|
|
.ui--Icon.right {
|
|
margin-left: 0.25rem;
|
|
margin-right: 0;
|
|
}
|
|
|
|
.ui--FormatBalance {
|
|
display: inline-block;
|
|
}
|
|
`;
|
|
|
|
export default React.memo(StakingUnbonding);
|