Files
pezkuwi-apps/packages/page-contracts/src/Contracts/Contract.tsx
T

129 lines
3.8 KiB
TypeScript

// Copyright 2017-2026 @pezkuwi/app-staking authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ContractPromise } from '@pezkuwi/api-contract';
import type { ContractCallOutcome } from '@pezkuwi/api-contract/types';
import type { ActionStatus } from '@pezkuwi/react-components/Status/types';
import type { Option } from '@pezkuwi/types';
import type { ContractInfo } from '@pezkuwi/types/interfaces';
import type { ContractLink } from './types.js';
import React, { useCallback } from 'react';
import { AddressInfo, AddressMini, Button, Forget, styled } from '@pezkuwi/react-components';
import { useApi, useCall, useToggle } from '@pezkuwi/react-hooks';
import { keyring } from '@pezkuwi/ui-keyring';
import { isUndefined } from '@pezkuwi/util';
import Messages from '../shared/Messages.js';
import { useTranslation } from '../translate.js';
interface Props {
className?: string;
contract: ContractPromise;
index: number;
links?: ContractLink[];
onCall: (contractIndex: number, messaeIndex: number, resultCb: (messageIndex: number, result?: ContractCallOutcome) => void) => void;
}
function transformInfo (optInfo: Option<ContractInfo>): ContractInfo | null {
return optInfo.unwrapOr(null);
}
function Contract ({ className, contract, index, links, onCall }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const info = useCall<ContractInfo | null>(api.query.contracts.contractInfoOf, [contract.address], { transform: transformInfo });
const [isForgetOpen, toggleIsForgetOpen] = useToggle();
const _onCall = useCallback(
(messageIndex: number, resultCb: (messageIndex: number, result?: ContractCallOutcome) => void) =>
onCall(index, messageIndex, resultCb),
[index, onCall]
);
const _onForget = useCallback(
(): void => {
const status: Partial<ActionStatus> = {
account: contract.address,
action: 'forget'
};
try {
keyring.forgetContract(contract.address.toString());
status.status = 'success';
status.message = t('address forgotten');
} catch (error) {
status.status = 'error';
status.message = (error as Error).message;
}
toggleIsForgetOpen();
},
[contract.address, t, toggleIsForgetOpen]
);
return (
<StyledTr className={className}>
<td className='address top'>
{isForgetOpen && (
<Forget
address={contract.address.toString()}
key='modal-forget-contract'
mode='contract'
onClose={toggleIsForgetOpen}
onForget={_onForget}
/>
)}
<AddressMini value={contract.address} />
</td>
<td className='all top'>
<Messages
contract={contract}
contractAbi={contract.abi}
isWatching
onSelect={_onCall}
trigger={links?.length}
withMessages
/>
</td>
<td className='top'>
{links?.map(({ blockHash, blockNumber }, index): React.ReactNode => (
<a
href={`#/explorer/query/${blockHash}`}
key={`${index}-${blockNumber}`}
>#{blockNumber}</a>
))}
</td>
<td className='number'>
<AddressInfo
address={contract.address}
withBalance
withBalanceToggle
/>
</td>
<td className='start together'>
{!isUndefined(info) && (
info
? info.type
: t('Not on-chain')
)}
</td>
<td className='button'>
<Button
icon='trash'
onClick={toggleIsForgetOpen}
/>
</td>
</StyledTr>
);
}
const StyledTr = styled.tr`
td.top a+a {
margin-left: 0.75rem;
}
`;
export default React.memo(Contract);