1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

EIP-1559 - Show gas estimate updating animation in transaction detail (#11566)

This commit is contained in:
David Walsh 2021-07-26 10:24:44 -05:00 committed by GitHub
parent 6986e76adc
commit a2be02dfeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 138 additions and 42 deletions

View File

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useGasFeeInputs } from '../../../hooks/useGasFeeInputs';
import { useShouldAnimateGasEstimations } from '../../../hooks/useShouldAnimateGasEstimations';
import {
GAS_ESTIMATE_TYPES,
@ -27,6 +28,7 @@ import {
hideSidebar,
updateTransaction,
} from '../../../store/actions';
import LoadingHeartBeat from '../../ui/loading-heartbeat';
export default function EditGasPopover({
popoverTitle = '',
@ -41,6 +43,8 @@ export default function EditGasPopover({
const dispatch = useDispatch();
const showSidebar = useSelector((state) => state.appState.sidebar.isOpen);
const shouldAnimate = useShouldAnimateGasEstimations();
const showEducationButton =
mode === EDIT_GAS_MODES.MODIFY_IN_PLACE && process.env.SHOW_EIP_1559_UI;
const [showEducationContent, setShowEducationContent] = useState(false);
@ -181,10 +185,12 @@ export default function EditGasPopover({
)
}
>
<div style={{ padding: '0 20px 20px 20px' }}>
<div style={{ padding: '0 20px 20px 20px', position: 'relative' }}>
{showEducationContent ? (
<EditGasDisplayEducation />
) : (
<>
<LoadingHeartBeat active={shouldAnimate} />
<EditGasDisplay
showEducationButton={showEducationButton}
warning={warning}
@ -212,14 +218,15 @@ export default function EditGasPopover({
setEstimateToUse={setEstimateToUse}
estimatedMinimumFiat={estimatedMinimumFiat}
estimatedMaximumFiat={estimatedMaximumFiat}
hasGasErrors={hasGasErrors}
onEducationClick={() => setShowEducationContent(true)}
mode={mode}
transaction={transaction}
hasGasErrors={hasGasErrors}
gasErrors={gasErrors}
onManualChange={onManualChange}
{...editGasDisplayProps}
/>
</>
)}
</div>
</Popover>

View File

@ -1,4 +1,6 @@
.transaction-detail {
position: relative;
.transaction-detail-edit {
text-align: end;
padding-top: 20px;

View File

@ -1,20 +1,19 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { I18nContext } from '../../../contexts/i18n';
import { useShouldAnimateGasEstimations } from '../../../hooks/useShouldAnimateGasEstimations';
import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component';
import LoadingHeartBeat from '../../ui/loading-heartbeat';
export default function TransactionDetail({ rows = [], onEdit }) {
const t = useContext(I18nContext);
const shouldAnimate = useShouldAnimateGasEstimations();
return (
<div
className={classNames('transaction-detail', {
'transaction-detail--editable': Boolean(onEdit),
})}
>
<div className="transaction-detail">
<LoadingHeartBeat active={shouldAnimate} />
{onEdit && (
<div className="transaction-detail-edit">
<button onClick={onEdit}>{t('edit')}</button>

View File

@ -0,0 +1,36 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { useEffect, useRef } from 'react';
export default function LoadingHeartBeat({ active }) {
const heartNode = useRef(null);
const LOADING_CLASS = 'loading-heartbeat--active';
// When the loading animation completes, remove the className to disappear again
useEffect(() => {
const eventName = 'animationend';
const node = heartNode?.current;
const eventHandler = () => {
node?.classList.remove(LOADING_CLASS);
};
node?.addEventListener(eventName, eventHandler);
return () => {
node?.removeEventListener(eventName, eventHandler);
};
}, [heartNode]);
return (
<div
className={classNames('loading-heartbeat', {
[LOADING_CLASS]: active,
})}
ref={heartNode}
></div>
);
}
LoadingHeartBeat.propTypes = {
active: PropTypes.bool,
};

View File

@ -0,0 +1,23 @@
.loading-heartbeat {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
opacity: 0;
background: #fff;
display: none;
&--active {
display: block;
animation: heartbeat 2s ease-in-out;
}
}
@keyframes heartbeat {
0% { opacity: 0; }
25% { opacity: 1; }
50% { opacity: 0.5; }
75% { opacity: 1; }
100% { opacity: 0; }
}

View File

@ -31,6 +31,7 @@
@import 'identicon/index';
@import 'info-tooltip/index';
@import 'list-item/index';
@import 'loading-heartbeat/index';
@import 'loading-indicator/loading-indicator';
@import 'loading-screen/index';
@import 'menu/menu';

View File

@ -0,0 +1,28 @@
import { useRef } from 'react';
import { isEqual } from 'lodash';
import { useGasFeeEstimates } from './useGasFeeEstimates';
export function useShouldAnimateGasEstimations() {
const { isGasEstimatesLoading, gasFeeEstimates } = useGasFeeEstimates();
// Do the animation only when gas prices have changed...
const lastGasEstimates = useRef(gasFeeEstimates);
const gasEstimatesChanged = !isEqual(
lastGasEstimates.current,
gasFeeEstimates,
);
// ... and only if gas didn't just load
// Removing this line will cause the initial loading screen to stay empty
const gasJustLoaded = isEqual(lastGasEstimates.current, {});
if (gasEstimatesChanged) {
lastGasEstimates.current = gasFeeEstimates;
}
const showLoadingAnimation =
isGasEstimatesLoading || (gasEstimatesChanged && !gasJustLoaded);
return showLoadingAnimation;
}