mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-06-15 11:31:08 +00:00
137 lines
4.2 KiB
TypeScript
137 lines
4.2 KiB
TypeScript
// Copyright 2017-2026 @pezkuwi/app-staking authors & contributors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import type { ApiPromise } from '@pezkuwi/api';
|
|
import type { ContractPromise } from '@pezkuwi/api-contract';
|
|
import type { ContractCallOutcome } from '@pezkuwi/api-contract/types';
|
|
import type { SignedBlockExtended } from '@pezkuwi/api-derive/types';
|
|
import type { ContractLink } from './types.js';
|
|
|
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
import { Table } from '@pezkuwi/react-components';
|
|
import { useApi, useCall } from '@pezkuwi/react-hooks';
|
|
import { formatNumber } from '@pezkuwi/util';
|
|
|
|
import { useTranslation } from '../translate.js';
|
|
import Call from './Call.js';
|
|
import Contract from './Contract.js';
|
|
import { getContractForAddress } from './util.js';
|
|
|
|
export interface Props {
|
|
contracts: string[];
|
|
updated: number;
|
|
}
|
|
|
|
interface Indexes {
|
|
contractIndex: number;
|
|
messageIndex: number;
|
|
onCallResult?: (messageIndex: number, result?: ContractCallOutcome) => void;
|
|
}
|
|
|
|
function filterContracts (api: ApiPromise, keyringContracts: string[] = []): ContractPromise[] {
|
|
return keyringContracts
|
|
.map((address) => getContractForAddress(api, address.toString()))
|
|
.filter((contract): contract is ContractPromise => !!contract);
|
|
}
|
|
|
|
function ContractsTable ({ contracts: keyringContracts }: Props): React.ReactElement<Props> {
|
|
const { t } = useTranslation();
|
|
const { api } = useApi();
|
|
const newBlock = useCall<SignedBlockExtended>(api.derive.chain.subscribeNewBlocks);
|
|
const [{ contractIndex, messageIndex, onCallResult }, setIndexes] = useState<Indexes>({ contractIndex: 0, messageIndex: 0 });
|
|
const [isCallOpen, setIsCallOpen] = useState(false);
|
|
const [contractLinks, setContractLinks] = useState<Record<string, ContractLink[]>>({});
|
|
|
|
const headerRef = useRef<[string?, string?, number?][]>([
|
|
[t('contracts'), 'start'],
|
|
[undefined, undefined, 3],
|
|
[t('status'), 'start'],
|
|
[]
|
|
]);
|
|
|
|
useEffect((): void => {
|
|
if (newBlock) {
|
|
const exts = newBlock.block.extrinsics
|
|
.filter(({ method }) => api.tx.contracts.call.is(method))
|
|
.map(({ args }): ContractLink | null => {
|
|
const contractId = keyringContracts.find((a) => args[0].eq(a));
|
|
|
|
if (!contractId) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
blockHash: newBlock.block.header.hash.toHex(),
|
|
blockNumber: formatNumber(newBlock.block.header.number),
|
|
contractId
|
|
};
|
|
})
|
|
.filter((value): value is ContractLink => !!value);
|
|
|
|
exts.length && setContractLinks((links): Record<string, ContractLink[]> => {
|
|
exts.forEach((value): void => {
|
|
links[value.contractId] = [value].concat(links[value.contractId] || []).slice(0, 3);
|
|
});
|
|
|
|
return { ...links };
|
|
});
|
|
}
|
|
}, [api, keyringContracts, newBlock]);
|
|
|
|
const contracts = useMemo(
|
|
() => filterContracts(api, keyringContracts),
|
|
[api, keyringContracts]
|
|
);
|
|
|
|
const _toggleCall = useCallback(
|
|
() => setIsCallOpen((isCallOpen) => !isCallOpen),
|
|
[]
|
|
);
|
|
|
|
const _onCall = useCallback(
|
|
(contractIndex: number, messageIndex: number, onCallResult: (messageIndex: number, result?: ContractCallOutcome) => void): void => {
|
|
setIndexes({ contractIndex, messageIndex, onCallResult });
|
|
setIsCallOpen(true);
|
|
},
|
|
[]
|
|
);
|
|
|
|
const _setMessageIndex = useCallback(
|
|
(messageIndex: number) => setIndexes((state) => ({ ...state, messageIndex })),
|
|
[]
|
|
);
|
|
|
|
const contract = contracts[contractIndex] || null;
|
|
|
|
return (
|
|
<>
|
|
<Table
|
|
empty={t('No contracts available')}
|
|
header={headerRef.current}
|
|
>
|
|
{contracts.map((contract, index): React.ReactNode => (
|
|
<Contract
|
|
contract={contract}
|
|
index={index}
|
|
key={contract.address.toString()}
|
|
links={contractLinks[contract.address.toString()]}
|
|
onCall={_onCall}
|
|
/>
|
|
))}
|
|
</Table>
|
|
{isCallOpen && contract && (
|
|
<Call
|
|
contract={contract}
|
|
messageIndex={messageIndex}
|
|
onCallResult={onCallResult}
|
|
onChangeMessage={_setMessageIndex}
|
|
onClose={_toggleCall}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default React.memo(ContractsTable);
|