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

Wire up network stability slider in new gas modal (#13029)

Use the new `networkCongestion` property available when we fetch gas fee
estimates.
This commit is contained in:
Elliot Winkler 2021-12-09 14:34:38 -07:00 committed by GitHub
parent ba54a3d83b
commit a820bce99a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 135 additions and 77 deletions

View File

@ -1,7 +1,6 @@
.status-slider { .status-slider {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
justify-content: center; justify-content: center;
width: 56px; width: 56px;
@ -17,6 +16,12 @@
font-size: 10px; font-size: 10px;
font-weight: bold; font-weight: bold;
margin-top: 4px; margin-top: 4px;
text-align: center;
}
&__arrow-container {
margin-left: -10px;
width: 100%;
} }
&__arrow-border { &__arrow-border {

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { useGasFeeContext } from '../../../../../contexts/gasFee';
import I18nValue from '../../../../ui/i18n-value'; import I18nValue from '../../../../ui/i18n-value';
import { NetworkStabilityTooltip } from '../tooltips'; import { NetworkStabilityTooltip } from '../tooltips';
@ -14,57 +15,70 @@ const GRADIENT_COLORS = [
'#9A4D71', '#9A4D71',
'#B44561', '#B44561',
'#C54055', '#C54055',
'#D73A49',
]; ];
const STATUS_INFO = { const determineStatusInfo = (givenNetworkCongestion) => {
low: { const networkCongestion = givenNetworkCongestion ?? 0.5;
statusLabel: 'notBusy', const colorIndex = Math.round(networkCongestion * 10);
tooltipLabel: 'lowLowercase', const color = GRADIENT_COLORS[colorIndex];
color: GRADIENT_COLORS[0], const sliderTickValue = colorIndex * 10;
},
stable: { if (networkCongestion <= 0.33) {
return {
statusLabel: 'notBusy',
tooltipLabel: 'lowLowercase',
color,
sliderTickValue,
};
} else if (networkCongestion > 0.66) {
return {
statusLabel: 'busy',
tooltipLabel: 'highLowercase',
color,
sliderTickValue,
};
}
return {
statusLabel: 'stable', statusLabel: 'stable',
tooltipLabel: 'stableLowercase', tooltipLabel: 'stableLowercase',
color: GRADIENT_COLORS[4], color,
}, sliderTickValue,
high: { };
statusLabel: 'busy',
tooltipLabel: 'highLowercase',
color: GRADIENT_COLORS[9],
},
};
const getStatusInfo = (status) => {
if (status <= 0.33) {
return STATUS_INFO.low;
} else if (status > 0.66) {
return STATUS_INFO.high;
}
return STATUS_INFO.stable;
}; };
const StatusSlider = () => { const StatusSlider = () => {
const statusValue = 0.5; const { gasFeeEstimates } = useGasFeeContext();
const sliderValueNumeric = Math.round(statusValue * 10); const statusInfo = determineStatusInfo(gasFeeEstimates.networkCongestion);
const statusInfo = getStatusInfo(statusValue);
return ( return (
<NetworkStabilityTooltip statusInfo={statusInfo}> <NetworkStabilityTooltip
color={statusInfo.color}
tooltipLabel={statusInfo.tooltipLabel}
>
<div className="status-slider"> <div className="status-slider">
<div className="status-slider__arrow-border"> <div className="status-slider__arrow-container">
<div <div
className="status-slider__arrow" className="status-slider__arrow-border"
style={{ style={{
borderTopColor: GRADIENT_COLORS[sliderValueNumeric], marginLeft: `${statusInfo.sliderTickValue}%`,
marginLeft: `${sliderValueNumeric * 10}%`,
}} }}
/> data-testid="status-slider-arrow-border"
>
<div
className="status-slider__arrow"
style={{
borderTopColor: statusInfo.color,
}}
data-testid="status-slider-arrow"
/>
</div>
</div> </div>
<div className="status-slider__line" /> <div className="status-slider__line" />
<div <div
className="status-slider__label" className="status-slider__label"
style={{ color: GRADIENT_COLORS[sliderValueNumeric] }} style={{ color: statusInfo.color }}
data-testid="status-slider-label"
> >
<I18nValue messageKey={statusInfo.statusLabel} /> <I18nValue messageKey={statusInfo.statusLabel} />
</div> </div>

View File

@ -1,51 +1,89 @@
import React from 'react'; import React from 'react';
import { screen } from '@testing-library/react';
import { renderWithProvider } from '../../../../../../test/jest'; import { renderWithProvider } from '../../../../../../test/jest';
import { ETH } from '../../../../../helpers/constants/common'; import { GasFeeContext } from '../../../../../contexts/gasFee';
import { GasFeeContextProvider } from '../../../../../contexts/gasFee';
import configureStore from '../../../../../store/store'; import configureStore from '../../../../../store/store';
import StatusSlider from './status-slider'; import StatusSlider from './status-slider';
jest.mock('../../../../../store/actions', () => ({ const renderComponent = ({ networkCongestion }) => {
disconnectGasFeeEstimatePoller: jest.fn(), const component = (
getGasFeeEstimatesAndStartPolling: jest <GasFeeContext.Provider value={{ gasFeeEstimates: { networkCongestion } }}>
.fn()
.mockImplementation(() => Promise.resolve()),
addPollingTokenToAppState: jest.fn(),
getGasFeeTimeEstimate: jest
.fn()
.mockImplementation(() => Promise.resolve('unknown')),
}));
const renderComponent = () => {
const store = configureStore({
metamask: {
nativeCurrency: ETH,
provider: {},
cachedBalances: {},
accounts: {
'0xAddress': {
address: '0xAddress',
balance: '0x176e5b6f173ebe66',
},
},
selectedAddress: '0xAddress',
},
});
return renderWithProvider(
<GasFeeContextProvider>
<StatusSlider /> <StatusSlider />
</GasFeeContextProvider>, </GasFeeContext.Provider>
store,
); );
const store = configureStore();
return renderWithProvider(component, store);
}; };
describe('NetworkStatus', () => { describe('StatusSlider', () => {
it('should renders stable for statusValue > 0.33 and <= 0.66', () => { it('should show "Not busy" when networkCongestion is less than 0.33', () => {
renderComponent(); const { queryByText } = renderComponent({ networkCongestion: 0.32 });
expect(screen.queryByText('Stable')).toBeInTheDocument(); expect(queryByText('Not busy')).toBeInTheDocument();
});
it('should show "Not busy" when networkCongestion is 0.33', () => {
const { queryByText } = renderComponent({ networkCongestion: 0.33 });
expect(queryByText('Not busy')).toBeInTheDocument();
});
it('should show "Stable" when networkCongestion is between 0.33 and 0.66', () => {
const { queryByText } = renderComponent({ networkCongestion: 0.5 });
expect(queryByText('Stable')).toBeInTheDocument();
});
it('should show "Stable" when networkCongestion is 0.66', () => {
const { queryByText } = renderComponent({ networkCongestion: 0.66 });
expect(queryByText('Stable')).toBeInTheDocument();
});
it('should show "Busy" when networkCongestion is greater than 0.66', () => {
const { queryByText } = renderComponent({ networkCongestion: 0.67 });
expect(queryByText('Busy')).toBeInTheDocument();
});
it('should show "Stable" if networkCongestion has not been set yet', () => {
const { getByText } = renderComponent({});
expect(getByText('Stable')).toBeInTheDocument();
});
it('should position the arrow based on converting networkCongestion to a percentage rounded to the nearest 10', () => {
const { getByTestId } = renderComponent({ networkCongestion: 0.23 });
expect(getByTestId('status-slider-arrow-border')).toHaveStyle(
'margin-left: 20%',
);
});
it('should position the arrow in the middle if networkCongestion has not been set yet', () => {
const { getByTestId } = renderComponent({});
expect(getByTestId('status-slider-arrow-border')).toHaveStyle(
'margin-left: 50%',
);
});
it('should color the arrow and label based on converting networkCongestion to a percentage rounded to the nearest 10', () => {
const { getByTestId } = renderComponent({ networkCongestion: 0.23 });
expect(getByTestId('status-slider-arrow')).toHaveStyle(
'border-top-color: #2D70BA',
);
expect(getByTestId('status-slider-label')).toHaveStyle('color: #2D70BA');
});
it('should color the arrow and label for the end position if networkCongestion rounds to 100%', () => {
const { getByTestId } = renderComponent({ networkCongestion: 0.95 });
expect(getByTestId('status-slider-arrow')).toHaveStyle(
'border-top-color: #D73A49',
);
expect(getByTestId('status-slider-label')).toHaveStyle('color: #D73A49');
});
it('should color the arrow and label for the middle position if networkCongestion has not been set yet', () => {
const { getByTestId } = renderComponent({});
expect(getByTestId('status-slider-arrow')).toHaveStyle(
'border-top-color: #6A5D92',
);
expect(getByTestId('status-slider-label')).toHaveStyle('color: #6A5D92');
}); });
}); });

View File

@ -57,7 +57,7 @@ PriorityFeeTooltip.propTypes = {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
}; };
export const NetworkStabilityTooltip = ({ children, statusInfo }) => { export const NetworkStabilityTooltip = ({ children, color, tooltipLabel }) => {
const t = useI18nContext(); const t = useI18nContext();
return ( return (
@ -66,9 +66,9 @@ export const NetworkStabilityTooltip = ({ children, statusInfo }) => {
<strong <strong
key="network-status__tooltip" key="network-status__tooltip"
className="network-status__tooltip-label" className="network-status__tooltip-label"
style={{ color: statusInfo.color }} style={{ color }}
> >
{t(statusInfo.tooltipLabel)} {t(tooltipLabel)}
</strong>, </strong>,
])} ])}
> >
@ -79,5 +79,6 @@ export const NetworkStabilityTooltip = ({ children, statusInfo }) => {
NetworkStabilityTooltip.propTypes = { NetworkStabilityTooltip.propTypes = {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
statusInfo: PropTypes.object, color: PropTypes.string.isRequired,
tooltipLabel: PropTypes.string.isRequired,
}; };