1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-22 17:33:23 +01:00

Adding network status section on edit gas fee modal (#12704)

This commit is contained in:
Jyoti Puri 2021-11-23 22:22:50 +05:30 committed by GitHub
parent bf06025615
commit fbc6f4e603
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 378 additions and 6 deletions

View File

@ -323,6 +323,9 @@
"builtAroundTheWorld": {
"message": "MetaMask is designed and built around the world."
},
"busy": {
"message": "Busy"
},
"buy": {
"message": "Buy"
},
@ -1318,8 +1321,11 @@
"layer1Fees": {
"message": "Layer 1 fees"
},
"learmMoreAboutGas": {
"message": "Want to $1 about gas?"
},
"learnMore": {
"message": "Learn more"
"message": "learn more"
},
"learnScamRisk": {
"message": "scams and security risks."
@ -1585,6 +1591,9 @@
"networkSettingsDescription": {
"message": "Add and edit custom RPC networks"
},
"networkStatus": {
"message": "Network status"
},
"networkURL": {
"message": "Network URL"
},
@ -1689,6 +1698,9 @@
"nonceFieldHeading": {
"message": "Custom Nonce"
},
"notBusy": {
"message": "Not busy"
},
"notCurrentAccount": {
"message": "Is this the correct account? It's different from the currently selected account in your wallet"
},
@ -2381,6 +2393,9 @@
"spendLimitTooLarge": {
"message": "Spend limit too large"
},
"stable": {
"message": "Stable"
},
"stateLogError": {
"message": "Error in retrieving state logs."
},

View File

@ -15,6 +15,8 @@
@import 'edit-gas-display-education/index';
@import 'edit-gas-fee-popover/index';
@import 'edit-gas-fee-popover/edit-gas-item/index';
@import 'edit-gas-fee-popover/network-status/index';
@import 'edit-gas-fee-popover/network-status/status-slider/index';
@import 'gas-customization/gas-modal-page-container/index';
@import 'gas-customization/gas-price-button-group/index';
@import 'gas-customization/index';

View File

@ -3,11 +3,14 @@ import PropTypes from 'prop-types';
import { PRIORITY_LEVELS } from '../../../../shared/constants/gas';
import { useI18nContext } from '../../../hooks/useI18nContext';
import Popover from '../../ui/popover';
import I18nValue from '../../ui/i18n-value';
import LoadingHeartBeat from '../../ui/loading-heartbeat';
import Popover from '../../ui/popover';
import Typography from '../../ui/typography/typography';
import { COLORS } from '../../../helpers/constants/design-system';
import EditGasItem from './edit-gas-item';
import NetworkStatus from './network-status';
const EditGasFeePopover = ({ onClose }) => {
const t = useI18nContext();
@ -54,6 +57,27 @@ const EditGasFeePopover = ({ onClose }) => {
priorityLevel={PRIORITY_LEVELS.CUSTOM}
onClose={onClose}
/>
<NetworkStatus />
<Typography
className="edit-gas-fee-popover__know-more"
align="center"
color={COLORS.UI4}
fontSize="12px"
>
<I18nValue
messageKey="learmMoreAboutGas"
options={[
<a
key="learnMoreLink"
target="_blank"
rel="noopener noreferrer"
href="https://metamask.zendesk.com/hc/en-us/articles/4404600179227-User-Guide-Gas"
>
<I18nValue messageKey="learnMore" />
</a>,
]}
/>
</Typography>
</div>
</div>
</>

View File

@ -1,7 +1,5 @@
.edit-gas-fee-popover {
@media screen and (min-width: $break-large) {
max-height: 84vh;
}
height: 500px;
&__wrapper {
border-top: 1px solid $ui-grey;
@ -37,4 +35,12 @@
margin: 8px 12px;
}
}
&__network-status {
margin-top: 36px;
}
&__know-more a {
color: $primary-1;
}
}

View File

@ -0,0 +1 @@
export { default } from './network-status';

View File

@ -0,0 +1,41 @@
.network-status {
margin: 24px 0 12px;
&__info {
border-top: 1px solid $ui-2;
border-bottom: 1px solid $ui-2;
height: 56px;
display: flex;
align-items: center;
&__separator {
border-left: 1px solid $ui-2;
height: 65%;
}
&__field {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 30%;
&--priority-fee {
width: 40%;
}
&-data {
color: $ui-4;
font-size: 12px;
text-align: center;
}
&-label {
color: $Black-100;
font-size: 10px;
font-weight: bold;
margin-top: 4px;
}
}
}
}

View File

@ -0,0 +1,59 @@
import React from 'react';
import { toBigNumber } from '../../../../../shared/modules/conversion.utils';
import { COLORS } from '../../../../helpers/constants/design-system';
import { useGasFeeContext } from '../../../../contexts/gasFee';
import I18nValue from '../../../ui/i18n-value';
import Typography from '../../../ui/typography/typography';
import StatusSlider from './status-slider';
const NetworkStatus = () => {
const { gasFeeEstimates } = useGasFeeContext();
let estBaseFee = null;
if (gasFeeEstimates?.estimatedBaseFee) {
// estimatedBaseFee is not likely to be below 1, value .01 is used as test networks sometimes
// show have small values for it and more decimal places may cause UI to look broken.
estBaseFee = toBigNumber.dec(gasFeeEstimates?.estimatedBaseFee);
estBaseFee = estBaseFee.lessThan(0.01) ? 0.01 : estBaseFee.toFixed(2);
}
return (
<div className="network-status">
<Typography
color={COLORS.UI4}
fontSize="10px"
fontWeight="bold"
margin={[3, 0]}
variant="h6"
>
<I18nValue messageKey="networkStatus" />
</Typography>
<div className="network-status__info">
<div className="network-status__info__field">
<span className="network-status__info__field-data">
{estBaseFee !== null && `${estBaseFee} GWEI`}
</span>
<span className="network-status__info__field-label">Base fee</span>
</div>
<div className="network-status__info__separator" />
<div className="network-status__info__field network-status__info__field--priority-fee">
<span className="network-status__info__field-data">
0.5 - 22 GWEI
</span>
<span className="network-status__info__field-label">
Priority fee
</span>
</div>
<div className="network-status__info__separator" />
<div className="network-status__info__field">
<StatusSlider />
</div>
</div>
</div>
);
};
NetworkStatus.propTypes = {};
export default NetworkStatus;

View File

@ -0,0 +1,77 @@
import React from 'react';
import { screen } from '@testing-library/react';
import { renderWithProvider } from '../../../../../test/jest';
import { ETH } from '../../../../helpers/constants/common';
import { GasFeeContextProvider } from '../../../../contexts/gasFee';
import configureStore from '../../../../store/store';
import NetworkStatus from './network-status';
jest.mock('../../../../store/actions', () => ({
disconnectGasFeeEstimatePoller: jest.fn(),
getGasFeeEstimatesAndStartPolling: jest
.fn()
.mockImplementation(() => Promise.resolve()),
addPollingTokenToAppState: jest.fn(),
getGasFeeTimeEstimate: jest
.fn()
.mockImplementation(() => Promise.resolve('unknown')),
}));
const MOCK_FEE_ESTIMATE = {
estimatedBaseFee: '50.0112',
};
const renderComponent = (props) => {
const store = configureStore({
metamask: {
nativeCurrency: ETH,
provider: {},
cachedBalances: {},
accounts: {
'0xAddress': {
address: '0xAddress',
balance: '0x176e5b6f173ebe66',
},
},
selectedAddress: '0xAddress',
featureFlags: { advancedInlineGas: true },
gasFeeEstimates: MOCK_FEE_ESTIMATE,
...props,
},
});
return renderWithProvider(
<GasFeeContextProvider>
<NetworkStatus />
</GasFeeContextProvider>,
store,
);
};
describe('NetworkStatus', () => {
it('should renders labels', () => {
renderComponent();
expect(screen.queryByText('Base fee')).toBeInTheDocument();
expect(screen.queryByText('Priority fee')).toBeInTheDocument();
});
it('should renders current base fee value rounded to 2 decimal places', () => {
renderComponent();
expect(
screen.queryByText(
`${parseFloat(MOCK_FEE_ESTIMATE.estimatedBaseFee).toFixed(2)} GWEI`,
),
).toBeInTheDocument();
});
it('should .01 as estimates base fee if estimated base fee is < .01', () => {
renderComponent({
gasFeeEstimates: {
estimatedBaseFee: '0.0012',
},
});
expect(screen.queryByText('0.01 GWEI')).toBeInTheDocument();
});
});

View File

@ -0,0 +1 @@
export { default } from './status-slider';

View File

@ -0,0 +1,42 @@
.status-slider {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 65%;
&__line {
background-image: linear-gradient(to right, #037dd6, #d73a49);
height: 4px;
width: 100%;
border-radius: 100px;
display: block;
}
&__label {
font-size: 10px;
font-weight: bold;
margin-top: 4px;
}
&__arrow-border {
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid white;
position: relative;
margin-bottom: -2px;
}
&__arrow {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid black;
position: absolute;
bottom: 3px;
left: -5px;
}
}

View File

@ -0,0 +1,53 @@
import React from 'react';
import I18nValue from '../../../../ui/i18n-value';
const GRADIENT_COLORS = [
'#037DD6',
'#1876C8',
'#2D70BA',
'#4369AB',
'#57629E',
'#6A5D92',
'#805683',
'#9A4D71',
'#B44561',
'#C54055',
];
const StatusSlider = () => {
// todo: value below to be replaced with dynamic values from api once it is available
// corresponding test cases also to be added
const statusValue = 0.5;
const sliderValueNumeric = Math.round(statusValue * 10);
let statusLabel = 'stable';
if (statusValue <= 0.33) {
statusLabel = 'notBusy';
} else if (statusValue > 0.66) {
statusLabel = 'busy';
}
return (
<div className="status-slider">
<div className="status-slider__arrow-border">
<div
className="status-slider__arrow"
style={{
borderTopColor: GRADIENT_COLORS[sliderValueNumeric],
marginLeft: `${sliderValueNumeric * 10}%`,
}}
/>
</div>
<div className="status-slider__line" />
<div
className="status-slider__label"
style={{ color: GRADIENT_COLORS[sliderValueNumeric] }}
>
<I18nValue messageKey={statusLabel} />
</div>
</div>
);
};
export default StatusSlider;

View File

@ -0,0 +1,51 @@
import React from 'react';
import { screen } from '@testing-library/react';
import { renderWithProvider } from '../../../../../../test/jest';
import { ETH } from '../../../../../helpers/constants/common';
import { GasFeeContextProvider } from '../../../../../contexts/gasFee';
import configureStore from '../../../../../store/store';
import StatusSlider from './status-slider';
jest.mock('../../../../../store/actions', () => ({
disconnectGasFeeEstimatePoller: jest.fn(),
getGasFeeEstimatesAndStartPolling: jest
.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 />
</GasFeeContextProvider>,
store,
);
};
describe('NetworkStatus', () => {
it('should renders stable for statusValue > 0.33 and <= 0.66', () => {
renderComponent();
expect(screen.queryByText('Stable')).toBeInTheDocument();
});
});

View File

@ -82,4 +82,4 @@ $display: block, grid, flex, inline-block, inline-grid, inline-flex, list-item;
$text-align: left, right, center, justify, end;
$font-weight: bold, normal, 100, 200, 300, 400, 500, 600, 700, 800, 900;
$font-style: normal, italic, oblique;
$font-size: 12px;
$font-size: 10px, 12px;