import EventEmitter from 'events'
import React, { useContext, useRef, useState, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { useHistory } from 'react-router-dom'
import { I18nContext } from '../../../contexts/i18n'
import { useNewMetricEvent } from '../../../hooks/useMetricEvent'
import { MetaMetricsContext } from '../../../contexts/metametrics.new'
import { getCurrentCurrency, conversionRateSelector } from '../../../selectors'
import {
getUsedQuote,
getFetchParams,
getApproveTxParams,
getUsedSwapsGasPrice,
fetchQuotesAndSetQuoteState,
navigateBackToBuildQuote,
prepareForRetryGetQuotes,
prepareToLeaveSwaps,
} from '../../../ducks/swaps/swaps'
import { useTransactionTimeRemaining } from '../../../hooks/useTransactionTimeRemaining'
import { usePrevious } from '../../../hooks/usePrevious'
import Mascot from '../../../components/ui/mascot'
import PulseLoader from '../../../components/ui/pulse-loader'
import {
getBlockExplorerUrlForTx,
getStatusKey,
} from '../../../helpers/utils/transactions.util'
import CountdownTimer from '../countdown-timer'
import {
QUOTES_EXPIRED_ERROR,
SWAP_FAILED_ERROR,
ERROR_FETCHING_QUOTES,
QUOTES_NOT_AVAILABLE_ERROR,
OFFLINE_FOR_MAINTENANCE,
} from '../../../helpers/constants/swaps'
import { ASSET_ROUTE, DEFAULT_ROUTE } from '../../../helpers/constants/routes'
import { getRenderableNetworkFeesForQuote } from '../swaps.util'
import SwapsFooter from '../swaps-footer'
import { TRANSACTION_STATUSES } from '../../../../../shared/constants/transaction'
import SwapFailureIcon from './swap-failure-icon'
import SwapSuccessIcon from './swap-success-icon'
import QuotesTimeoutIcon from './quotes-timeout-icon'
import ViewOnEtherScanLink from './view-on-ether-scan-link'
export default function AwaitingSwap({
swapComplete,
errorKey,
txHash,
networkId,
tokensReceived,
rpcPrefs,
submittingSwap,
tradeTxData,
usedGasPrice,
inputValue,
maxSlippage,
}) {
const t = useContext(I18nContext)
const metaMetricsEvent = useContext(MetaMetricsContext)
const history = useHistory()
const dispatch = useDispatch()
const animationEventEmitter = useRef(new EventEmitter())
const fetchParams = useSelector(getFetchParams)
const { destinationTokenInfo, sourceTokenInfo } = fetchParams?.metaData || {}
const usedQuote = useSelector(getUsedQuote)
const approveTxParams = useSelector(getApproveTxParams)
const swapsGasPrice = useSelector(getUsedSwapsGasPrice)
const currentCurrency = useSelector(getCurrentCurrency)
const conversionRate = useSelector(conversionRateSelector)
const [timeRemainingExpired, setTimeRemainingExpired] = useState(false)
const [trackedQuotesExpiredEvent, setTrackedQuotesExpiredEvent] = useState(
false,
)
let feeinFiat
if (usedQuote && swapsGasPrice) {
const renderableNetworkFees = getRenderableNetworkFeesForQuote(
usedQuote.gasEstimateWithRefund || usedQuote.averageGas,
approveTxParams?.gas || '0x0',
swapsGasPrice,
currentCurrency,
conversionRate,
usedQuote?.trade?.value,
sourceTokenInfo?.symbol,
usedQuote.sourceAmount,
)
feeinFiat = renderableNetworkFees.feeinFiat?.slice(1)
}
const quotesExpiredEvent = useNewMetricEvent({
event: 'Quotes Timed Out',
excludeMetaMetricsId: true,
properties: {
token_from: sourceTokenInfo?.symbol,
token_from_amount: fetchParams?.value,
token_to: destinationTokenInfo?.symbol,
request_type: fetchParams?.balanceError ? 'Quote' : 'Order',
slippage: fetchParams?.slippage,
custom_slippage: fetchParams?.slippage === 2,
gas_fees: feeinFiat,
},
category: 'swaps',
})
const anonymousQuotesExpiredEvent = useNewMetricEvent({
event: 'Quotes Timed Out',
category: 'swaps',
})
const blockExplorerUrl =
txHash && getBlockExplorerUrlForTx(networkId, txHash, rpcPrefs)
const statusKey = tradeTxData && getStatusKey(tradeTxData)
const timeRemaining = useTransactionTimeRemaining(
statusKey === TRANSACTION_STATUSES.SUBMITTED,
true,
tradeTxData?.submittedTime,
usedGasPrice,
true,
true,
)
const previousTimeRemaining = usePrevious(timeRemaining)
const timeRemainingIsNumber =
typeof timeRemaining === 'number' && !isNaN(timeRemaining)
const previousTimeRemainingIsNumber =
typeof previousTimeRemaining === 'number' && !isNaN(previousTimeRemaining)
const estimatedTransactionWaitTime = timeRemaining * 1000 * 60
useEffect(() => {
if (
!timeRemainingIsNumber &&
previousTimeRemainingIsNumber &&
!timeRemainingExpired
) {
setTimeRemainingExpired(true)
}
}, [
timeRemainingIsNumber,
previousTimeRemainingIsNumber,
timeRemainingExpired,
])
let countdownText
if (
timeRemainingIsNumber &&
!timeRemainingExpired &&
tradeTxData?.submittedTime
) {
countdownText = (