import React, { useMemo, useState, useCallback, useContext } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useHistory } from 'react-router-dom'; import { useSelector } from 'react-redux'; import ListItem from '../../ui/list-item'; import { useTransactionDisplayData } from '../../../hooks/useTransactionDisplayData'; import { useI18nContext } from '../../../hooks/useI18nContext'; import TransactionListItemDetails from '../transaction-list-item-details'; import { CONFIRM_TRANSACTION_ROUTE } from '../../../helpers/constants/routes'; import { useShouldShowSpeedUp } from '../../../hooks/useShouldShowSpeedUp'; import TransactionStatus from '../transaction-status/transaction-status.component'; import TransactionIcon from '../transaction-icon'; import { EVENT } from '../../../../shared/constants/metametrics'; import { TRANSACTION_GROUP_CATEGORIES, TRANSACTION_STATUSES, } from '../../../../shared/constants/transaction'; import { EDIT_GAS_MODES } from '../../../../shared/constants/gas'; import { GasFeeContextProvider, useGasFeeContext, } from '../../../contexts/gasFee'; import { TransactionModalContextProvider, useTransactionModalContext, } from '../../../contexts/transaction-modal'; import { checkNetworkAndAccountSupports1559, getEIP1559V2Enabled, } from '../../../selectors'; import { isLegacyTransaction } from '../../../helpers/utils/transactions.util'; import Button from '../../ui/button'; import AdvancedGasFeePopover from '../advanced-gas-fee-popover'; import CancelButton from '../cancel-button'; import CancelSpeedupPopover from '../cancel-speedup-popover'; import EditGasFeePopover from '../edit-gas-fee-popover'; import EditGasPopover from '../edit-gas-popover'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import SiteOrigin from '../../ui/site-origin'; function TransactionListItemInner({ transactionGroup, setEditGasMode, isEarliestNonce = false, }) { const t = useI18nContext(); const history = useHistory(); const { hasCancelled } = transactionGroup; const [showDetails, setShowDetails] = useState(false); const [showCancelEditGasPopover, setShowCancelEditGasPopover] = useState(false); const [showRetryEditGasPopover, setShowRetryEditGasPopover] = useState(false); const { supportsEIP1559V2 } = useGasFeeContext(); const { openModal } = useTransactionModalContext(); const { initialTransaction: { id }, primaryTransaction: { err, status }, } = transactionGroup; const trackEvent = useContext(MetaMetricsContext); const retryTransaction = useCallback( async (event) => { event.stopPropagation(); trackEvent({ event: 'Clicked "Speed Up"', category: EVENT.CATEGORIES.NAVIGATION, properties: { action: 'Activity Log', legacy_event: true, }, }); if (supportsEIP1559V2) { setEditGasMode(EDIT_GAS_MODES.SPEED_UP); openModal('cancelSpeedUpTransaction'); } else { setShowRetryEditGasPopover(true); } }, [openModal, setEditGasMode, trackEvent, supportsEIP1559V2], ); const cancelTransaction = useCallback( (event) => { event.stopPropagation(); trackEvent({ event: 'Clicked "Cancel"', category: EVENT.CATEGORIES.NAVIGATION, properties: { action: 'Activity Log', legacy_event: true, }, }); if (supportsEIP1559V2) { setEditGasMode(EDIT_GAS_MODES.CANCEL); openModal('cancelSpeedUpTransaction'); } else { setShowCancelEditGasPopover(true); } }, [trackEvent, openModal, setEditGasMode, supportsEIP1559V2], ); const shouldShowSpeedUp = useShouldShowSpeedUp( transactionGroup, isEarliestNonce, ); const { title, subtitle, subtitleContainsOrigin, date, category, primaryCurrency, recipientAddress, secondaryCurrency, displayedStatusKey, isPending, senderAddress, } = useTransactionDisplayData(transactionGroup); const isSignatureReq = category === TRANSACTION_GROUP_CATEGORIES.SIGNATURE_REQUEST; const isApproval = category === TRANSACTION_GROUP_CATEGORIES.APPROVAL; const isUnapproved = status === TRANSACTION_STATUSES.UNAPPROVED; const isSwap = category === TRANSACTION_GROUP_CATEGORIES.SWAP; const className = classnames('transaction-list-item', { 'transaction-list-item--unconfirmed': isPending || [ TRANSACTION_STATUSES.FAILED, TRANSACTION_STATUSES.DROPPED, TRANSACTION_STATUSES.REJECTED, ].includes(displayedStatusKey), }); const toggleShowDetails = useCallback(() => { if (isUnapproved) { history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`); return; } setShowDetails((prev) => !prev); }, [isUnapproved, history, id]); const speedUpButton = useMemo(() => { if (!shouldShowSpeedUp || !isPending || isUnapproved) { return null; } return ( ); }, [ shouldShowSpeedUp, isUnapproved, t, isPending, hasCancelled, retryTransaction, cancelTransaction, ]); const showCancelButton = !hasCancelled && isPending && !isUnapproved; return ( <> } subtitle={

{subtitleContainsOrigin ? ( ) : ( {subtitle} )}

} rightContent={ !isSignatureReq && !isApproval && ( <>

{primaryCurrency}

{secondaryCurrency}

) } >
{speedUpButton} {showCancelButton && ( )}
{showDetails && ( ( )} /> )} {!supportsEIP1559V2 && showRetryEditGasPopover && ( setShowRetryEditGasPopover(false)} mode={EDIT_GAS_MODES.SPEED_UP} transaction={transactionGroup.primaryTransaction} /> )} {!supportsEIP1559V2 && showCancelEditGasPopover && ( setShowCancelEditGasPopover(false)} mode={EDIT_GAS_MODES.CANCEL} transaction={transactionGroup.primaryTransaction} /> )} ); } TransactionListItemInner.propTypes = { transactionGroup: PropTypes.object.isRequired, isEarliestNonce: PropTypes.bool, setEditGasMode: PropTypes.func, }; const TransactionListItem = (props) => { const { transactionGroup } = props; const [editGasMode, setEditGasMode] = useState(); const transaction = transactionGroup.primaryTransaction; const eip1559V2Enabled = useSelector(getEIP1559V2Enabled); const supportsEIP1559 = useSelector(checkNetworkAndAccountSupports1559) && !isLegacyTransaction(transaction?.txParams); const supportsEIP1559V2 = eip1559V2Enabled && supportsEIP1559; return ( {supportsEIP1559V2 && ( <> )} ); }; TransactionListItem.propTypes = { transactionGroup: PropTypes.object.isRequired, }; export default TransactionListItem;