mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-02 06:07:06 +01:00
1304ec7af5
We want to convert NetworkController to TypeScript in order to be able to compare differences in the controller between in this repo and the core repo. To do this, however, we need to convert the dependencies of the controller to TypeScript. As a part of this effort, this commit converts `shared/constants/metametrics` to TypeScript. Note that simple objects have been largely replaced with enums. There are some cases where I even split up some of these objects into multiple enums. Co-authored-by: Mark Stacey <markjstacey@gmail.com>
177 lines
6.2 KiB
JavaScript
177 lines
6.2 KiB
JavaScript
import EventEmitter from 'events';
|
|
import React, { useState, useEffect, useRef, useContext } from 'react';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import PropTypes from 'prop-types';
|
|
import { shuffle } from 'lodash';
|
|
import { useHistory } from 'react-router-dom';
|
|
import isEqual from 'lodash/isEqual';
|
|
import {
|
|
navigateBackToBuildQuote,
|
|
getFetchParams,
|
|
getQuotesFetchStartTime,
|
|
getSmartTransactionsOptInStatus,
|
|
getSmartTransactionsEnabled,
|
|
getCurrentSmartTransactionsEnabled,
|
|
} from '../../../ducks/swaps/swaps';
|
|
import {
|
|
isHardwareWallet,
|
|
getHardwareWalletType,
|
|
} from '../../../selectors/selectors';
|
|
import { I18nContext } from '../../../contexts/i18n';
|
|
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
|
import Mascot from '../../../components/ui/mascot';
|
|
import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics';
|
|
import SwapsFooter from '../swaps-footer';
|
|
import BackgroundAnimation from './background-animation';
|
|
|
|
export default function LoadingSwapsQuotes({
|
|
aggregatorMetadata,
|
|
loadingComplete,
|
|
onDone,
|
|
}) {
|
|
const t = useContext(I18nContext);
|
|
const trackEvent = useContext(MetaMetricsContext);
|
|
const dispatch = useDispatch();
|
|
const history = useHistory();
|
|
const animationEventEmitter = useRef(new EventEmitter());
|
|
|
|
const fetchParams = useSelector(getFetchParams, isEqual);
|
|
const quotesFetchStartTime = useSelector(getQuotesFetchStartTime);
|
|
const hardwareWalletUsed = useSelector(isHardwareWallet);
|
|
const hardwareWalletType = useSelector(getHardwareWalletType);
|
|
const smartTransactionsOptInStatus = useSelector(
|
|
getSmartTransactionsOptInStatus,
|
|
);
|
|
const smartTransactionsEnabled = useSelector(getSmartTransactionsEnabled);
|
|
const currentSmartTransactionsEnabled = useSelector(
|
|
getCurrentSmartTransactionsEnabled,
|
|
);
|
|
const quotesRequestCancelledEventConfig = {
|
|
event: 'Quotes Request Cancelled',
|
|
category: MetaMetricsEventCategory.Swaps,
|
|
sensitiveProperties: {
|
|
token_from: fetchParams?.sourceTokenInfo?.symbol,
|
|
token_from_amount: fetchParams?.value,
|
|
request_type: fetchParams?.balanceError,
|
|
token_to: fetchParams?.destinationTokenInfo?.symbol,
|
|
slippage: fetchParams?.slippage,
|
|
custom_slippage: fetchParams?.slippage !== 2,
|
|
response_time: Date.now() - quotesFetchStartTime,
|
|
is_hardware_wallet: hardwareWalletUsed,
|
|
hardware_wallet_type: hardwareWalletType,
|
|
stx_enabled: smartTransactionsEnabled,
|
|
current_stx_enabled: currentSmartTransactionsEnabled,
|
|
stx_user_opt_in: smartTransactionsOptInStatus,
|
|
},
|
|
};
|
|
|
|
const [aggregatorNames] = useState(() =>
|
|
shuffle(Object.keys(aggregatorMetadata)),
|
|
);
|
|
const numberOfQuotes = aggregatorNames.length;
|
|
const mascotContainer = useRef();
|
|
const currentMascotContainer = mascotContainer.current;
|
|
|
|
const [quoteCount, updateQuoteCount] = useState(0);
|
|
const [midPointTarget, setMidpointTarget] = useState(null);
|
|
|
|
useEffect(() => {
|
|
let timeoutLength;
|
|
|
|
// The below logic simulates a sequential loading of the aggregator quotes, even though we are fetching them all with a single call.
|
|
// This is to give the user a sense of progress. The callback passed to `setTimeout` updates the quoteCount and therefore causes
|
|
// a new logo to be shown, the fox to look at that logo, the logo bar and aggregator name to update.
|
|
|
|
if (loadingComplete) {
|
|
// If loading is complete, but the quoteCount is not, we quickly display the remaining logos/names/fox looks. 0.2s each
|
|
timeoutLength = 20;
|
|
} else {
|
|
// If loading is not complete, we display remaining logos/names/fox looks at random intervals between 0.5s and 2s, to simulate the
|
|
// sort of loading a user would experience in most async scenarios
|
|
timeoutLength = 500 + Math.floor(Math.random() * 1500);
|
|
}
|
|
const quoteCountTimeout = setTimeout(() => {
|
|
if (quoteCount < numberOfQuotes) {
|
|
updateQuoteCount(quoteCount + 1);
|
|
} else if (quoteCount === numberOfQuotes && loadingComplete) {
|
|
onDone();
|
|
}
|
|
}, timeoutLength);
|
|
|
|
return function cleanup() {
|
|
clearTimeout(quoteCountTimeout);
|
|
};
|
|
}, [quoteCount, loadingComplete, onDone, numberOfQuotes]);
|
|
|
|
useEffect(() => {
|
|
if (currentMascotContainer) {
|
|
const { top, left, width, height } =
|
|
currentMascotContainer.getBoundingClientRect();
|
|
const center = { x: left + width / 2, y: top + height / 2 };
|
|
setMidpointTarget(center);
|
|
}
|
|
}, [currentMascotContainer]);
|
|
|
|
return (
|
|
<div className="loading-swaps-quotes">
|
|
<div className="loading-swaps-quotes__content">
|
|
<>
|
|
<div className="loading-swaps-quotes__quote-counter">
|
|
<span>
|
|
{t('swapFetchingQuoteNofN', [
|
|
Math.min(quoteCount + 1, numberOfQuotes),
|
|
numberOfQuotes,
|
|
])}
|
|
</span>
|
|
</div>
|
|
<div className="loading-swaps-quotes__quote-name-check">
|
|
<span>{t('swapFetchingQuotes')}</span>
|
|
</div>
|
|
<div className="loading-swaps-quotes__loading-bar-container">
|
|
<div
|
|
className="loading-swaps-quotes__loading-bar"
|
|
style={{
|
|
width: `${(100 / numberOfQuotes) * quoteCount}%`,
|
|
}}
|
|
/>
|
|
</div>
|
|
</>
|
|
<div className="loading-swaps-quotes__animation">
|
|
<BackgroundAnimation />
|
|
<div
|
|
className="loading-swaps-quotes__mascot-container"
|
|
ref={mascotContainer}
|
|
>
|
|
<Mascot
|
|
animationEventEmitter={animationEventEmitter.current}
|
|
width="90"
|
|
height="90"
|
|
lookAtTarget={midPointTarget}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<SwapsFooter
|
|
submitText={t('back')}
|
|
onSubmit={async () => {
|
|
trackEvent(quotesRequestCancelledEventConfig);
|
|
await dispatch(navigateBackToBuildQuote(history));
|
|
}}
|
|
hideCancel
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
LoadingSwapsQuotes.propTypes = {
|
|
loadingComplete: PropTypes.bool.isRequired,
|
|
onDone: PropTypes.func.isRequired,
|
|
aggregatorMetadata: PropTypes.objectOf(
|
|
PropTypes.shape({
|
|
title: PropTypes.string,
|
|
color: PropTypes.string,
|
|
icon: PropTypes.string,
|
|
}),
|
|
),
|
|
};
|