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

17921 Update TransactionAlerts with BannerAlert (#17940)

* use banner alerts

* update selector for banner alert content

* lintage

* update button click for banner alert structure

* bump global branches coverage target

* removed unnecessary Typography usage

* remove Typography usage

* transaction alerts story

* pending transaction alerts

* created separate stories for each alert scenario
This commit is contained in:
flexa-rob 2023-03-14 05:29:10 +10:00 committed by GitHub
parent a2838b0dd1
commit e7527b65ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 219 additions and 91 deletions

View File

@ -53,9 +53,7 @@ describe('Failing contract interaction ', function () {
// display warning when transaction is expected to fail
const warningText =
'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.';
const warning = await driver.findElement(
'.actionable-message__message',
);
const warning = await driver.findElement('.mm-banner-alert .mm-text');
const confirmButton = await driver.findElement(
'[data-testid="page-container-footer-next"]',
);
@ -65,7 +63,7 @@ describe('Failing contract interaction ', function () {
// dismiss warning and confirm the transaction
await driver.clickElement({
text: 'I want to proceed anyway',
tag: 'button',
tag: 'span',
});
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.waitUntilXWindowHandles(2);
@ -141,9 +139,7 @@ describe('Failing contract interaction on non-EIP1559 network', function () {
// display warning when transaction is expected to fail
const warningText =
'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.';
const warning = await driver.findElement(
'.actionable-message__message',
);
const warning = await driver.findElement('.mm-banner-alert .mm-text');
const confirmButton = await driver.findElement(
'[data-testid="page-container-footer-next"]',
);
@ -153,7 +149,7 @@ describe('Failing contract interaction on non-EIP1559 network', function () {
// dismiss warning and confirm the transaction
await driver.clickElement({
text: 'I want to proceed anyway',
tag: 'button',
tag: 'span',
});
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.waitUntilXWindowHandles(2);

View File

@ -6,10 +6,9 @@ import { PriorityLevels } from '../../../../shared/constants/gas';
import { submittedPendingTransactionsSelector } from '../../../selectors';
import { useGasFeeContext } from '../../../contexts/gasFee';
import { useI18nContext } from '../../../hooks/useI18nContext';
import ActionableMessage from '../../ui/actionable-message/actionable-message';
import { BannerAlert, ButtonLink, Text } from '../../component-library';
import SimulationErrorMessage from '../../ui/simulation-error-message';
import Typography from '../../ui/typography';
import { TypographyVariant } from '../../../helpers/constants/design-system';
import { SEVERITIES } from '../../../helpers/constants/design-system';
import ZENDESK_URLS from '../../../helpers/constants/zendesk-url';
const TransactionAlerts = ({
@ -30,74 +29,41 @@ const TransactionAlerts = ({
/>
)}
{supportsEIP1559 && pendingTransactions?.length > 0 && (
<ActionableMessage
message={
<Typography
align="left"
className="transaction-alerts__pending-transactions"
margin={0}
tag={TypographyVariant.paragraph}
variant={TypographyVariant.H7}
>
<strong>
{pendingTransactions?.length === 1
? t('pendingTransactionSingle', [pendingTransactions?.length])
: t('pendingTransactionMultiple', [
pendingTransactions?.length,
])}
</strong>{' '}
{t('pendingTransactionInfo')}
{t('learnCancelSpeeedup', [
<a
key="cancelSpeedUpInfo"
href={ZENDESK_URLS.SPEEDUP_CANCEL}
rel="noopener noreferrer"
target="_blank"
>
{t('cancelSpeedUp')}
</a>,
])}
</Typography>
}
useIcon
iconFillColor="var(--color-warning-default)"
type="warning"
/>
<BannerAlert severity={SEVERITIES.WARNING}>
<Text as="p">
<strong>
{pendingTransactions?.length === 1
? t('pendingTransactionSingle', [pendingTransactions?.length])
: t('pendingTransactionMultiple', [
pendingTransactions?.length,
])}
</strong>{' '}
{t('pendingTransactionInfo')}
{t('learnCancelSpeeedup', [
<ButtonLink
key="cancelSpeedUpInfo"
href={ZENDESK_URLS.SPEEDUP_CANCEL}
rel="noopener noreferrer"
target="_blank"
>
{t('cancelSpeedUp')}
</ButtonLink>,
])}
</Text>
</BannerAlert>
)}
{estimateUsed === PriorityLevels.low && (
<ActionableMessage
dataTestId="low-gas-fee-alert"
message={
<Typography
align="left"
margin={0}
tag={TypographyVariant.paragraph}
variant={TypographyVariant.H7}
>
{t('lowPriorityMessage')}
</Typography>
}
useIcon
iconFillColor="var(--color-warning-default)"
type="warning"
/>
<BannerAlert
data-testid="low-gas-fee-alert"
severity={SEVERITIES.WARNING}
>
{t('lowPriorityMessage')}
</BannerAlert>
)}
{supportsEIP1559 && isNetworkBusy ? (
<ActionableMessage
message={
<Typography
align="left"
margin={0}
tag={TypographyVariant.paragraph}
variant={TypographyVariant.H7}
>
{t('networkIsBusy')}
</Typography>
}
iconFillColor="var(--color-warning-default)"
type="warning"
useIcon
/>
<BannerAlert severity={SEVERITIES.WARNING}>
{t('networkIsBusy')}
</BannerAlert>
) : null}
</div>
);

View File

@ -0,0 +1,167 @@
import React from 'react';
import { Provider } from 'react-redux';
import { keccak } from 'ethereumjs-util';
import { cloneDeep } from 'lodash';
import { GasFeeContextProvider } from '../../../contexts/gasFee';
import configureStore from '../../../store/store';
import testData from '../../../../.storybook/test-data';
import TransactionAlerts from '.';
const customTransaction = ({
estimateUsed,
hasSimulationError,
i = 0,
...props
} = {}) => {
const tx = {
simulationFails: Boolean(hasSimulationError),
userFeeLevel: estimateUsed ? 'low' : 'medium',
blockNumber: `${10902987 + i}`,
id: 4678200543090545 + i,
metamaskNetworkId: testData?.metamask?.network,
chainId: testData?.metamask?.provider?.chainId,
status: 'confirmed',
time: 1600654021000,
txParams: {
from: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4',
gas: '0x5208',
gasPrice: '0x147d357000',
nonce: '0xf',
to: testData?.metamask?.selectedAddress,
value: '0x63eb89da4ed00000',
...props?.txParams,
},
// '0x50be62ab1cabd03ff104c602c11fdef7a50f3d73c55006d5583ba97950ab1144',
transactionCategory: 'incoming',
...props,
};
// just simulate hash if not provided
if (!props?.hash) {
tx.hash = `0x${keccak(Buffer.from(JSON.stringify(tx))).toString('hex')}`;
}
return tx;
};
// simulate gas fee state
const customStore = ({
supportsEIP1559,
isNetworkBusy,
pendingCount = 0,
} = {}) => {
const data = cloneDeep({
...testData,
metamask: {
...testData?.metamask,
// isNetworkBusy
gasFeeEstimates: {
...testData?.metamask?.gasFeeEstimates,
networkCongestion: isNetworkBusy ? 1 : 0.1,
},
// supportsEIP1559
networkDetails: {
...testData?.metamask?.networkDetails,
EIPS: {
...testData?.metamask?.networkDetails?.EIPS,
1159: Boolean(supportsEIP1559),
},
},
// pendingTransactions
featureFlags: {
...testData?.metamask?.featureFlags,
showIncomingTransactions: pendingCount > 0,
},
incomingTransactions: {
...testData?.metamask?.incomingTransactions,
...Object.fromEntries(
Array.from({ length: pendingCount }).map((_, i) => {
const transaction = customTransaction({ i, status: 'submitted' });
return [transaction?.hash, transaction];
}),
),
},
},
});
return configureStore(data);
};
export default {
title: 'Components/App/TransactionAlerts',
argTypes: {
userAcknowledgedGasMissing: {
control: 'boolean',
},
},
args: {
userAcknowledgedGasMissing: false,
},
};
// show everything
export const DefaultStory = (args) => (
<Provider
store={customStore({
isNetworkBusy: true,
supportsEIP1559: true,
pendingCount: 1,
})}
>
<GasFeeContextProvider
transaction={customTransaction({
hasSimulationError: true,
estimateUsed: true,
})}
>
<TransactionAlerts {...args} />
</GasFeeContextProvider>
</Provider>
);
DefaultStory.storyName = 'Default';
export const SimulationError = (args) => (
<Provider store={customStore({ supportsEIP1559: true })}>
<GasFeeContextProvider
transaction={customTransaction({ hasSimulationError: true })}
>
<TransactionAlerts {...args} />
</GasFeeContextProvider>
</Provider>
);
SimulationError.storyName = 'SimulationError';
export const SinglePendingTransaction = (args) => (
<Provider store={customStore({ supportsEIP1559: true, pendingCount: 1 })}>
<GasFeeContextProvider transaction={customTransaction()}>
<TransactionAlerts {...args} />
</GasFeeContextProvider>
</Provider>
);
SinglePendingTransaction.storyName = 'SinglePendingTransaction';
export const MultiplePendingTransactions = (args) => (
<Provider store={customStore({ supportsEIP1559: true, pendingCount: 2 })}>
<GasFeeContextProvider transaction={customTransaction()}>
<TransactionAlerts {...args} />
</GasFeeContextProvider>
</Provider>
);
MultiplePendingTransactions.storyName = 'MultiplePendingTransactions';
export const LowPriority = (args) => (
<Provider store={customStore()}>
<GasFeeContextProvider
transaction={customTransaction({ estimateUsed: true })}
>
<TransactionAlerts {...args} />
</GasFeeContextProvider>
</Provider>
);
LowPriority.storyName = 'LowPriority';
export const BusyNetwork = (args) => (
<Provider store={customStore({ isNetworkBusy: true })}>
<GasFeeContextProvider transaction={customTransaction()}>
<TransactionAlerts {...args} />
</GasFeeContextProvider>
</Provider>
);
BusyNetwork.storyName = 'BusyNetwork';

View File

@ -1,6 +1,8 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import ActionableMessage from '../actionable-message';
import { BannerAlert } from '../../component-library';
import { SEVERITIES } from '../../../helpers/constants/design-system';
import { I18nContext } from '../../../../.storybook/i18n';
export default function SimulationErrorMessage({
@ -9,21 +11,18 @@ export default function SimulationErrorMessage({
}) {
const t = useContext(I18nContext);
return (
<ActionableMessage
message={t('simulationErrorMessageV2')}
useIcon
iconFillColor="var(--color-error-default)"
type="danger"
primaryActionV2={
userAcknowledgedGasMissing === true
? undefined
: {
label: t('proceedWithTransaction'),
onClick: setUserAcknowledgedGasMissing,
}
}
/>
return userAcknowledgedGasMissing === true ? (
<BannerAlert severity={SEVERITIES.DANGER}>
{t('simulationErrorMessageV2')}
</BannerAlert>
) : (
<BannerAlert
severity={SEVERITIES.DANGER}
actionButtonLabel={t('proceedWithTransaction')}
actionButtonOnClick={setUserAcknowledgedGasMissing}
>
{t('simulationErrorMessageV2')}
</BannerAlert>
);
}