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 TransactionStatusLabel from '../transaction-status-label/transaction-status-label'; import TransactionIcon from '../transaction-icon'; import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics'; import { TransactionGroupCategory, TransactionStatus, } from '../../../../shared/constants/transaction'; import { EditGasModes } from '../../../../shared/constants/gas'; import { GasFeeContextProvider, useGasFeeContext, } from '../../../contexts/gasFee'; import { TransactionModalContextProvider, useTransactionModalContext, } from '../../../contexts/transaction-modal'; import { checkNetworkAndAccountSupports1559 } 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 { supportsEIP1559 } = 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: MetaMetricsEventCategory.Navigation, properties: { action: 'Activity Log', legacy_event: true, }, }); if (supportsEIP1559) { setEditGasMode(EditGasModes.speedUp); openModal('cancelSpeedUpTransaction'); } else { setShowRetryEditGasPopover(true); } }, [openModal, setEditGasMode, trackEvent, supportsEIP1559], ); const cancelTransaction = useCallback( (event) => { event.stopPropagation(); trackEvent({ event: 'Clicked "Cancel"', category: MetaMetricsEventCategory.Navigation, properties: { action: 'Activity Log', legacy_event: true, }, }); if (supportsEIP1559) { setEditGasMode(EditGasModes.cancel); openModal('cancelSpeedUpTransaction'); } else { setShowCancelEditGasPopover(true); } }, [trackEvent, openModal, setEditGasMode, supportsEIP1559], ); const shouldShowSpeedUp = useShouldShowSpeedUp( transactionGroup, isEarliestNonce, ); const { title, subtitle, subtitleContainsOrigin, date, category, primaryCurrency, recipientAddress, secondaryCurrency, displayedStatusKey, isPending, senderAddress, } = useTransactionDisplayData(transactionGroup); const isSignatureReq = category === TransactionGroupCategory.signatureRequest; const isApproval = category === TransactionGroupCategory.approval; const isUnapproved = status === TransactionStatus.unapproved; const isSwap = category === TransactionGroupCategory.swap; const className = classnames('transaction-list-item', { 'transaction-list-item--unconfirmed': isPending || [ TransactionStatus.failed, TransactionStatus.dropped, TransactionStatus.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 && ( ( )} /> )} {!supportsEIP1559 && showRetryEditGasPopover && ( setShowRetryEditGasPopover(false)} mode={EditGasModes.speedUp} transaction={transactionGroup.primaryTransaction} /> )} {!supportsEIP1559 && showCancelEditGasPopover && ( setShowCancelEditGasPopover(false)} mode={EditGasModes.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 supportsEIP1559 = useSelector(checkNetworkAndAccountSupports1559) && !isLegacyTransaction(transaction?.txParams); return ( {supportsEIP1559 && ( <> )} ); }; TransactionListItem.propTypes = { transactionGroup: PropTypes.object.isRequired, }; export default TransactionListItem;