diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 311e2dfda..017103ecd 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -2810,6 +2810,9 @@ "openSeaNew": { "message": "OpenSea" }, + "operationFailed": { + "message": "Operation Failed" + }, "optional": { "message": "Optional" }, @@ -4478,6 +4481,10 @@ "transactionErrored": { "message": "Transaction encountered an error." }, + "transactionFailed": { + "message": "Transaction Failed" + }, + "transactionFee": { "message": "Transaction fee" }, diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index 0fb69b866..b646641ba 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -104,3 +104,6 @@ @import 'network-account-balance-header/index'; @import 'approve-content-card/index'; @import 'transaction-alerts/transaction-alerts'; +///: BEGIN:ONLY_INCLUDE_IN(mmi) +@import '../institutional/transaction-failed-modal/index'; +///: END:ONLY_INCLUDE_IN diff --git a/ui/components/institutional/transaction-failed-modal/index.js b/ui/components/institutional/transaction-failed-modal/index.js new file mode 100644 index 000000000..2f120e825 --- /dev/null +++ b/ui/components/institutional/transaction-failed-modal/index.js @@ -0,0 +1 @@ +export { default } from './transaction-failed'; diff --git a/ui/components/institutional/transaction-failed-modal/index.scss b/ui/components/institutional/transaction-failed-modal/index.scss new file mode 100644 index 000000000..c36a45fed --- /dev/null +++ b/ui/components/institutional/transaction-failed-modal/index.scss @@ -0,0 +1,7 @@ +.transaction-failed { + &__description { + border: 1px solid var(--color-border-muted); + max-width: 100%; + overflow-wrap: anywhere; + } +} diff --git a/ui/components/institutional/transaction-failed-modal/transaction-failed.js b/ui/components/institutional/transaction-failed-modal/transaction-failed.js new file mode 100644 index 000000000..24f566fed --- /dev/null +++ b/ui/components/institutional/transaction-failed-modal/transaction-failed.js @@ -0,0 +1,79 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import withModalProps from '../../../helpers/higher-order-components/with-modal-props'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import Modal from '../../app/modal'; +import Box from '../../ui/box/box'; +import { + AlignItems, + BorderRadius, + DISPLAY, + FLEX_DIRECTION, + FONT_WEIGHT, + TEXT_ALIGN, + TextVariant, +} from '../../../helpers/constants/design-system'; +import { Text, Icon, IconName, IconSize } from '../../component-library'; + +const TransactionFailedModal = ({ + hideModal, + closeNotification, + operationFailed, + errorMessage, +}) => { + const t = useI18nContext(); + const handleSubmit = () => { + if (closeNotification) { + global.platform.closeCurrentWindow(); + } + hideModal(); + }; + + return ( + + + + + {operationFailed + ? `${t('operationFailed')}!` + : `${t('transactionFailed')}!`} + + + {errorMessage} + + + + ); +}; + +TransactionFailedModal.propTypes = { + hideModal: PropTypes.func, + errorMessage: PropTypes.string, + closeNotification: PropTypes.bool, + operationFailed: PropTypes.bool, +}; + +export default withModalProps(TransactionFailedModal); diff --git a/ui/components/institutional/transaction-failed-modal/transaction-failed.stories.js b/ui/components/institutional/transaction-failed-modal/transaction-failed.stories.js new file mode 100644 index 000000000..256b1c59e --- /dev/null +++ b/ui/components/institutional/transaction-failed-modal/transaction-failed.stories.js @@ -0,0 +1,17 @@ +import React from 'react'; +import TransactionFailedModal from '.'; + +export default { + title: 'Components/Institutional/TransactionFailedModal', + argTypes: {}, + args: { + errorMessage: 'test', + operationFailed: false, + }, +}; + +export const DefaultStory = (args) => { + return ; +}; + +DefaultStory.storyName = 'TransactionFailedModal'; diff --git a/ui/components/institutional/transaction-failed-modal/transaction-failed.test.js b/ui/components/institutional/transaction-failed-modal/transaction-failed.test.js new file mode 100644 index 000000000..ccff04111 --- /dev/null +++ b/ui/components/institutional/transaction-failed-modal/transaction-failed.test.js @@ -0,0 +1,63 @@ +import React from 'react'; +import { screen, fireEvent } from '@testing-library/react'; +import configureMockStore from 'redux-mock-store'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import testData from '../../../../.storybook/test-data'; +import TransactionFailed from '.'; + +const mockErrorMessage = 'Something went wrong'; + +describe('Transaction Failed', () => { + const mockStore = { + ...testData, + }; + + const store = configureMockStore()(mockStore); + + it('renders the error message', () => { + renderWithProvider( + , + store, + ); + const errorMessageElement = screen.getByText(mockErrorMessage); + expect(errorMessageElement).toBeInTheDocument(); + }); + + it('renders the correct title when operation fails', () => { + const operationFailed = true; + const title = 'Operation Failed!'; + renderWithProvider( + , + store, + ); + const titleElement = screen.getByText(title); + expect(titleElement).toBeInTheDocument(); + }); + + it('renders the correct title when transaction fails', () => { + const operationFailed = false; + const title = 'Transaction Failed!'; + renderWithProvider( + , + store, + ); + const titleElement = screen.getByText(title); + expect(titleElement).toBeInTheDocument(); + }); + + it('closes window when closeNotification is true', () => { + global.platform = { + closeCurrentWindow: jest.fn(), + }; + renderWithProvider(, store); + const okButton = screen.getByText('Ok'); + fireEvent.click(okButton); + expect(global.platform.closeCurrentWindow).toHaveBeenCalledTimes(1); + }); +});