import React, { useCallback, useContext, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { EditGasModes } from '../../../../shared/constants/gas'; import { GasFeeContextProvider } from '../../../contexts/gasFee'; import { TokenStandard, TransactionType, } from '../../../../shared/constants/transaction'; import { NETWORK_TO_NAME_MAP } from '../../../../shared/constants/network'; import { PageContainerFooter } from '../../ui/page-container'; import Button from '../../ui/button'; import ActionableMessage from '../../ui/actionable-message/actionable-message'; import SenderToRecipient from '../../ui/sender-to-recipient'; import AdvancedGasFeePopover from '../advanced-gas-fee-popover'; import EditGasFeePopover from '../edit-gas-fee-popover/edit-gas-fee-popover'; import EditGasPopover from '../edit-gas-popover'; import ErrorMessage from '../../ui/error-message'; import { INSUFFICIENT_FUNDS_ERROR_KEY } from '../../../helpers/constants/error-keys'; import { Text } from '../../component-library'; import { TextVariant, TEXT_ALIGN, } from '../../../helpers/constants/design-system'; import NetworkAccountBalanceHeader from '../network-account-balance-header/network-account-balance-header'; import { fetchTokenBalance } from '../../../../shared/lib/token-util.ts'; import SetApproveForAllWarning from '../set-approval-for-all-warning'; import { useI18nContext } from '../../../hooks/useI18nContext'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import useTransactionInsights from '../../../hooks/useTransactionInsights'; ///: END:ONLY_INCLUDE_IN(flask) import { getAccountName, getAddressBookEntry, getIsBuyableChain, getMetadataContractName, getMetaMaskIdentities, getNetworkIdentifier, getSwapsDefaultToken, } from '../../../selectors'; import useRamps from '../../../hooks/experiences/useRamps'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { MetaMetricsEventCategory, MetaMetricsEventName, } from '../../../../shared/constants/metametrics'; import { ConfirmPageContainerHeader, ConfirmPageContainerContent, ConfirmPageContainerNavigation, } from '.'; const ConfirmPageContainer = (props) => { const { showEdit, onEdit, fromName, fromAddress, toEns, toNickname, toAddress, disabled, errorKey, errorMessage, contentComponent, action, title, image, titleComponent, subtitleComponent, detailsComponent, dataComponent, dataHexComponent, onCancelAll, onCancel, onSubmit, onSetApprovalForAll, showWarningModal, tokenAddress, nonce, unapprovedTxCount, warning, hideSenderToRecipient, showAccountInHeader, origin, ethGasPriceWarning, editingGas, handleCloseEditGas, currentTransaction, supportsEIP1559, nativeCurrency, txData, assetStandard, isApprovalOrRejection, } = props; const t = useI18nContext(); const trackEvent = useContext(MetaMetricsContext); const [collectionBalance, setCollectionBalance] = useState(0); const isBuyableChain = useSelector(getIsBuyableChain); const contact = useSelector((state) => getAddressBookEntry(state, toAddress)); const networkIdentifier = useSelector(getNetworkIdentifier); const defaultToken = useSelector(getSwapsDefaultToken); const accountBalance = defaultToken.string; const identities = useSelector(getMetaMaskIdentities); const ownedAccountName = getAccountName(identities, toAddress); const toName = ownedAccountName || contact?.name; const recipientIsOwnedAccount = Boolean(ownedAccountName); const toMetadataName = useSelector((state) => getMetadataContractName(state, toAddress), ); // TODO: Move useRamps hook to the confirm-transaction-base parent component. // TODO: openBuyCryptoInPdapp should be passed to this component as a custom prop. // We try to keep this component for layout purpose only, we need to move this hook to the confirm-transaction-base parent // component once it is converted to a functional component const { openBuyCryptoInPdapp } = useRamps(); const isSetApproveForAll = currentTransaction.type === TransactionType.tokenMethodSetApprovalForAll; const shouldDisplayWarning = contentComponent && disabled && (errorKey || errorMessage); const networkName = NETWORK_TO_NAME_MAP[currentTransaction.chainId] || networkIdentifier; const fetchCollectionBalance = useCallback(async () => { const tokenBalance = await fetchTokenBalance( tokenAddress, fromAddress, global.ethereumProvider, ); setCollectionBalance(tokenBalance?.balance?.words?.[0] || 0); }, [fromAddress, tokenAddress]); ///: BEGIN:ONLY_INCLUDE_IN(flask) // As confirm-transction-base is converted to functional component // this code can bemoved to it. const insightComponent = useTransactionInsights({ txData, }); ///: END:ONLY_INCLUDE_IN useEffect(() => { if (isSetApproveForAll && assetStandard === TokenStandard.ERC721) { fetchCollectionBalance(); } }, [ currentTransaction, assetStandard, isSetApproveForAll, fetchCollectionBalance, collectionBalance, ]); return (
{assetStandard === TokenStandard.ERC20 || assetStandard === TokenStandard.ERC721 || assetStandard === TokenStandard.ERC1155 ? ( ) : ( onEdit()} showAccountInHeader={showAccountInHeader} accountAddress={fromAddress} > {hideSenderToRecipient ? null : ( )} )} {contentComponent || ( )} {shouldDisplayWarning && errorKey === INSUFFICIENT_FUNDS_ERROR_KEY && (
{t('insufficientCurrencyBuyOrDeposit', [ nativeCurrency, networkName, , ])} ) : ( {t('insufficientCurrencyDeposit', [ nativeCurrency, networkName, ])} ) } useIcon iconFillColor="var(--color-error-default)" type="danger" />
)} {shouldDisplayWarning && errorKey !== INSUFFICIENT_FUNDS_ERROR_KEY && (
)} {showWarningModal && ( )} {contentComponent && ( {unapprovedTxCount > 1 && ( {t('rejectTxsN', [unapprovedTxCount])} )} )} {editingGas && !supportsEIP1559 && ( )} {supportsEIP1559 && ( <> )}
); }; ConfirmPageContainer.propTypes = { // Header action: PropTypes.string, onEdit: PropTypes.func, showEdit: PropTypes.bool, subtitleComponent: PropTypes.node, title: PropTypes.string, image: PropTypes.string, titleComponent: PropTypes.node, hideSenderToRecipient: PropTypes.bool, showAccountInHeader: PropTypes.bool, assetStandard: PropTypes.string, // Sender to Recipient fromAddress: PropTypes.string, fromName: PropTypes.string, toAddress: PropTypes.string, toEns: PropTypes.string, toNickname: PropTypes.string, // Content contentComponent: PropTypes.node, errorKey: PropTypes.string, errorMessage: PropTypes.string, dataComponent: PropTypes.node, dataHexComponent: PropTypes.node, detailsComponent: PropTypes.node, txData: PropTypes.object, tokenAddress: PropTypes.string, nonce: PropTypes.string, warning: PropTypes.string, unapprovedTxCount: PropTypes.number, origin: PropTypes.string.isRequired, ethGasPriceWarning: PropTypes.string, // Footer onCancelAll: PropTypes.func, onCancel: PropTypes.func, onSubmit: PropTypes.func, onSetApprovalForAll: PropTypes.func, showWarningModal: PropTypes.bool, disabled: PropTypes.bool, editingGas: PropTypes.bool, handleCloseEditGas: PropTypes.func, // Gas Popover currentTransaction: PropTypes.object.isRequired, supportsEIP1559: PropTypes.bool, nativeCurrency: PropTypes.string, isApprovalOrRejection: PropTypes.bool, }; export default ConfirmPageContainer;