// Copyright 2017-2025 @pezkuwi/app-staking-async authors & contributors // SPDX-License-Identifier: Apache-2.0 import type { ApiPromise } from '@pezkuwi/api'; import type { NominatedBy as NominatedByType } from '@pezkuwi/app-staking/types'; import type { SlashingSpans } from '@pezkuwi/types/interfaces'; import React, { useMemo } from 'react'; import { AddressMini, ExpanderScroll } from '@pezkuwi/react-components'; import { useApi } from '@pezkuwi/react-hooks'; import { formatNumber } from '@pezkuwi/util'; import { useTranslation } from '../../translate.js'; interface Props { nominators?: NominatedByType[]; slashingSpans?: SlashingSpans | null; } interface Chilled { active: null | [number, () => React.ReactNode[]]; chilled: null | [number, () => React.ReactNode[]]; } function extractFunction (all: string[]): null | [number, () => React.ReactNode[]] { return all.length ? [ all.length, () => all.map((value): React.ReactNode => ) ] : null; } function extractChilled (api: ApiPromise, nominators: NominatedByType[] = [], slashingSpans?: SlashingSpans | null): Chilled { // NOTE With the introduction of the SlashReported event, // nominators are not auto-chilled on validator slash const chilled = slashingSpans && !api.events.staking.SlashReported ? nominators .filter(({ submittedIn }) => slashingSpans.lastNonzeroSlash.gt(submittedIn) ) .map(({ nominatorId }) => nominatorId) : []; return { active: extractFunction( nominators .filter(({ nominatorId }) => !chilled.includes(nominatorId)) .map(({ nominatorId }) => nominatorId) ), chilled: extractFunction(chilled) }; } function NominatedBy ({ nominators, slashingSpans }: Props): React.ReactElement { const { t } = useTranslation(); const { api } = useApi(); const { active, chilled } = useMemo( () => extractChilled(api, nominators, slashingSpans), [api, nominators, slashingSpans] ); return ( {active && ( )} {chilled && ( )} ); } export default React.memo(NominatedBy);