diff --git a/app/actions/alert/index.js b/app/actions/alert/index.js
deleted file mode 100644
index 42afeee9c5f..00000000000
--- a/app/actions/alert/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export function dismissAlert() {
- return {
- type: 'HIDE_ALERT',
- };
-}
-
-export function showAlert({ isVisible, autodismiss, content, data }) {
- return {
- type: 'SHOW_ALERT',
- isVisible,
- autodismiss,
- content,
- data,
- };
-}
diff --git a/app/components/Nav/Main/index.js b/app/components/Nav/Main/index.js
index 49a02bef5d9..4282296f6c3 100644
--- a/app/components/Nav/Main/index.js
+++ b/app/components/Nav/Main/index.js
@@ -16,7 +16,6 @@ import {
import NetInfo from '@react-native-community/netinfo';
import PropTypes from 'prop-types';
import { connect, useSelector } from 'react-redux';
-import GlobalAlert from '../../UI/GlobalAlert';
import NotificationManager from '../../../core/NotificationManager';
import Engine from '../../../core/Engine';
import AppConstants from '../../../core/AppConstants';
@@ -401,7 +400,6 @@ const Main = (props) => {
) : (
renderLoader()
)}
-
diff --git a/app/components/Nav/Main/index.test.tsx b/app/components/Nav/Main/index.test.tsx
index e2f71a48558..a5f622cfff2 100644
--- a/app/components/Nav/Main/index.test.tsx
+++ b/app/components/Nav/Main/index.test.tsx
@@ -32,11 +32,6 @@ jest.mock('./MainNavigator', () => {
};
});
-jest.mock(
- '../../UI/GlobalAlert',
- () => () => mockReact.createElement('GlobalAlertMock'),
-);
-
jest.mock(
'../../UI/FadeOutOverlay',
() => () => mockReact.createElement('FadeOutOverlayMock'),
diff --git a/app/components/UI/AccountOverview/index.js b/app/components/UI/AccountOverview/index.js
index 7262f48ec29..351ac4c9c13 100644
--- a/app/components/UI/AccountOverview/index.js
+++ b/app/components/UI/AccountOverview/index.js
@@ -12,8 +12,8 @@ import { connect } from 'react-redux';
import { strings } from '../../../../locales/i18n';
import { AccountOverviewSelectorsIDs } from './AccountOverview.testIds';
import { WalletViewSelectorsIDs } from '../../Views/Wallet/WalletView.testIds';
-import { showAlert } from '../../../actions/alert';
import { protectWalletModalVisible } from '../../../actions/user';
+import { toast, ToastSeverity } from '@metamask/design-system-react-native';
import Routes from '../../../constants/navigation/Routes';
import ClipboardManager from '../../../core/ClipboardManager';
import { fontStyles } from '../../../styles/common';
@@ -162,10 +162,6 @@ class AccountOverview extends PureComponent {
* Object that represents the selected account
*/
account: PropTypes.object,
- /**
- /* Triggers global alert
- */
- showAlert: PropTypes.func,
/**
* Used to get child ref
*/
@@ -278,11 +274,9 @@ class AccountOverview extends PureComponent {
copyAccountToClipboard = async () => {
const { selectedAddress } = this.props;
await ClipboardManager.setString(selectedAddress);
- this.props.showAlert({
- isVisible: true,
- autodismiss: 1500,
- content: 'clipboard-alert',
- data: { msg: strings('account_details.account_copied_to_clipboard') },
+ toast({
+ description: strings('account_details.account_copied_to_clipboard'),
+ severity: ToastSeverity.Success,
});
setTimeout(() => this.props.protectWalletModalVisible(), 2000);
@@ -458,7 +452,6 @@ const mapStateToProps = (state) => ({
});
const mapDispatchToProps = (dispatch) => ({
- showAlert: (config) => dispatch(showAlert(config)),
protectWalletModalVisible: () => dispatch(protectWalletModalVisible()),
});
diff --git a/app/components/UI/GlobalAlert/index.js b/app/components/UI/GlobalAlert/index.js
deleted file mode 100644
index 0541552bdda..00000000000
--- a/app/components/UI/GlobalAlert/index.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import React, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-import Modal from 'react-native-modal';
-import { StyleSheet, View, Text } from 'react-native';
-import { dismissAlert } from '../../../actions/alert';
-import { connect } from 'react-redux';
-import { fontStyles } from '../../../styles/common';
-import Icon from 'react-native-vector-icons/FontAwesome';
-import ElevatedView from 'react-native-elevated-view';
-import { ThemeContext, mockTheme } from '../../../util/theme';
-
-const createStyles = (colors) =>
- StyleSheet.create({
- modal: {
- margin: 0,
- width: '100%',
- },
- copyAlert: (width) => ({
- width: width || 180,
- backgroundColor: colors.overlay.alternative,
- padding: 20,
- paddingTop: 30,
- alignSelf: 'center',
- alignItems: 'center',
- justifyContent: 'center',
- borderRadius: 8,
- }),
- copyAlertIcon: {
- marginBottom: 20,
- },
- copyAlertText: {
- textAlign: 'center',
- color: colors.overlay.inverse,
- fontSize: 16,
- ...fontStyles.normal,
- },
- });
-
-/**
- * Wrapper component for a global alert
- * connected to redux
- */
-class GlobalAlert extends PureComponent {
- static propTypes = {
- /**
- * Boolean that determines if the modal should be shown
- */
- isVisible: PropTypes.bool.isRequired,
- /**
- * Number that determines when it should be autodismissed (in miliseconds)
- */
- autodismiss: PropTypes.number,
- /**
- * Children component(s)
- */
- content: PropTypes.any,
- /**
- * Object with data required to render the content
- */
- data: PropTypes.object,
- /**
- * function that dismisses de modal
- */
- dismissAlert: PropTypes.func,
- };
-
- onClose = () => {
- this.props.dismissAlert();
- };
-
- componentDidUpdate(prevProps) {
- if (
- this.props.autodismiss &&
- !isNaN(this.props.autodismiss) &&
- !prevProps.isVisible &&
- this.props.isVisible
- ) {
- setTimeout(() => {
- this.props.dismissAlert();
- }, this.props.autodismiss);
- }
- }
-
- getComponent(content) {
- switch (content) {
- case 'clipboard-alert':
- return this.renderClipboardAlert();
- default:
- return ;
- }
- }
-
- getStyles = () => {
- const colors = this.context.colors || mockTheme.colors;
- return createStyles(colors);
- };
-
- renderClipboardAlert = () => {
- const colors = this.context.colors || mockTheme.colors;
- const styles = this.getStyles(colors);
-
- return (
-
-
-
-
-
- {this.props.data && this.props.data.msg}
-
-
- );
- };
-
- render = () => {
- const { content, isVisible } = this.props;
- const colors = this.context.colors || mockTheme.colors;
- const styles = this.getStyles(colors);
-
- return (
-
- {this.getComponent(content)}
-
- );
- };
-}
-
-const mapStateToProps = (state) => ({
- isVisible: state.alert.isVisible,
- autodismiss: state.alert.autodismiss,
- content: state.alert.content,
- data: state.alert.data,
-});
-
-const mapDispatchToProps = (dispatch) => ({
- dismissAlert: () => dispatch(dismissAlert()),
-});
-
-GlobalAlert.contextType = ThemeContext;
-
-export default connect(mapStateToProps, mapDispatchToProps)(GlobalAlert);
diff --git a/app/components/UI/Transactions/index.js b/app/components/UI/Transactions/index.js
index fa0e03f60b9..67b2cceddc2 100644
--- a/app/components/UI/Transactions/index.js
+++ b/app/components/UI/Transactions/index.js
@@ -14,7 +14,6 @@ import {
import { connect } from 'react-redux';
import { ActivitiesViewSelectorsIDs } from '../../Views/ActivityView/ActivitiesView.testIds';
import { strings } from '../../../../locales/i18n';
-import { showAlert } from '../../../actions/alert';
import ExtendedKeyringTypes from '../../../constants/keyringTypes';
import { NO_RPC_BLOCK_EXPLORER, RPC } from '../../../constants/network';
import Engine from '../../../core/Engine';
@@ -1053,10 +1052,6 @@ const mapStateToProps = (state) => ({
Transactions.contextType = ThemeContext;
-const mapDispatchToProps = (dispatch) => ({
- showAlert: (config) => dispatch(showAlert(config)),
-});
-
export { Transactions as UnconnectedTransactions };
const TransactionsWithHardwareWallet = (props) => {
@@ -1065,7 +1060,6 @@ const TransactionsWithHardwareWallet = (props) => {
return ;
};
-export default connect(
- mapStateToProps,
- mapDispatchToProps,
-)(withQRHardwareAwareness(TransactionsWithHardwareWallet));
+export default connect(mapStateToProps)(
+ withQRHardwareAwareness(TransactionsWithHardwareWallet),
+);
diff --git a/app/components/UI/Transactions/index.test.tsx b/app/components/UI/Transactions/index.test.tsx
index 74bdd2ec3c2..9b6d73d5053 100644
--- a/app/components/UI/Transactions/index.test.tsx
+++ b/app/components/UI/Transactions/index.test.tsx
@@ -290,7 +290,6 @@ const defaultTestProps = {
collectibleContracts: [],
tokens: {},
navigation: mockNavigation,
- showAlert: jest.fn(),
gasFeeEstimates: {
medium: { suggestedMaxFeePerGas: '20' },
},
diff --git a/app/components/Views/MultichainAccounts/AddressList/AddressList.tsx b/app/components/Views/MultichainAccounts/AddressList/AddressList.tsx
index 9436cf97bc0..b0f78074af0 100644
--- a/app/components/Views/MultichainAccounts/AddressList/AddressList.tsx
+++ b/app/components/Views/MultichainAccounts/AddressList/AddressList.tsx
@@ -10,7 +10,7 @@ import {
selectInternalAccountListSpreadByScopesByGroupId,
selectInternalAccountsByGroupId,
} from '../../../../selectors/multichainAccounts/accounts';
-import { IconName, Toaster, toast } from '@metamask/design-system-react-native';
+import { IconName, toast } from '@metamask/design-system-react-native';
import MultichainAddressRow, {
MULTICHAIN_ADDRESS_ROW_QR_BUTTON_TEST_ID,
} from '../../../../component-library/components-temp/MultichainAccounts/MultichainAddressRow';
@@ -156,7 +156,6 @@ export const AddressList = () => {
renderItem={renderAddressItem}
onLoad={onLoad}
/>
-
);
};
diff --git a/app/components/Views/MultichainAccounts/MultichainAccountConnect/MultichainAccountConnect.tsx b/app/components/Views/MultichainAccounts/MultichainAccountConnect/MultichainAccountConnect.tsx
index 809a8c11548..136f46f4ddc 100644
--- a/app/components/Views/MultichainAccounts/MultichainAccountConnect/MultichainAccountConnect.tsx
+++ b/app/components/Views/MultichainAccounts/MultichainAccountConnect/MultichainAccountConnect.tsx
@@ -17,7 +17,6 @@ import {
AvatarFavicon,
AvatarFaviconSize,
Box,
- Toaster,
toast,
} from '@metamask/design-system-react-native';
import { USER_INTENT } from '../../../../constants/permissions.ts';
@@ -1002,7 +1001,6 @@ const MultichainAccountConnect = (props: AccountConnectProps) => {
)}
{renderPhishingModal()}
-
);
};
diff --git a/app/components/Views/MultichainAccounts/PrivateKeyList/PrivateKeyList.tsx b/app/components/Views/MultichainAccounts/PrivateKeyList/PrivateKeyList.tsx
index 1a262cd4c6e..4c8a0579d8d 100644
--- a/app/components/Views/MultichainAccounts/PrivateKeyList/PrivateKeyList.tsx
+++ b/app/components/Views/MultichainAccounts/PrivateKeyList/PrivateKeyList.tsx
@@ -25,7 +25,6 @@ import {
Button,
ButtonVariant,
ButtonSize,
- Toaster,
toast,
} from '@metamask/design-system-react-native';
import Engine from '../../../../core/Engine';
@@ -326,7 +325,6 @@ export const PrivateKeyList = () => {
/>
{reveal ? renderPrivateKeyList() : renderPassword()}
-
);
};
diff --git a/app/components/Views/NftDetails/NftDetails.tsx b/app/components/Views/NftDetails/NftDetails.tsx
index b14eedf8553..d54b8876bb0 100644
--- a/app/components/Views/NftDetails/NftDetails.tsx
+++ b/app/components/Views/NftDetails/NftDetails.tsx
@@ -19,6 +19,8 @@ import {
ButtonVariant,
HeaderStandard,
IconName as DSIconName,
+ toast,
+ ToastSeverity,
} from '@metamask/design-system-react-native';
import NftDetailsBox from './NftDetailsBox';
import NftDetailsInformationRow from './NftDetailsInformationRow';
@@ -28,8 +30,7 @@ import Icon, {
IconSize,
} from '../../../component-library/components/Icons/Icon';
import ClipboardManager from '../../../core/ClipboardManager';
-import { useDispatch, useSelector } from 'react-redux';
-import { showAlert } from '../../../actions/alert';
+import { useSelector } from 'react-redux';
import { strings } from '../../../../locales/i18n';
import {
selectChainId,
@@ -61,7 +62,6 @@ const NftDetails = () => {
const navigation = useNavigation();
const { collectible, source } = useParams();
const chainId = useSelector(selectChainId);
- const dispatch = useDispatch();
const currentCurrency = useSelector(selectCurrentCurrency);
const ticker = useSelector(selectEvmTicker);
const { trackEvent, createEventBuilder } = useAnalytics();
@@ -135,14 +135,10 @@ const NftDetails = () => {
return;
}
await ClipboardManager.setString(address);
- dispatch(
- showAlert({
- isVisible: true,
- autodismiss: 1500,
- content: 'clipboard-alert',
- data: { msg: strings('detected_tokens.address_copied_to_clipboard') },
- }),
- );
+ toast({
+ description: strings('detected_tokens.address_copied_to_clipboard'),
+ severity: ToastSeverity.Success,
+ });
};
const blockExplorerTokenLink = () =>
diff --git a/app/components/Views/Notifications/Details/index.test.tsx b/app/components/Views/Notifications/Details/index.test.tsx
index 9c06705918a..200468f4f18 100644
--- a/app/components/Views/Notifications/Details/index.test.tsx
+++ b/app/components/Views/Notifications/Details/index.test.tsx
@@ -34,10 +34,6 @@ const mockInitialState = {
},
};
-jest.mock('../../../../actions/alert', () => ({
- showAlert: jest.fn(),
-}));
-
jest.mock('@react-navigation/native');
describe('NotificationsDetails', () => {
const mockStore = configureMockStore();
diff --git a/app/components/Views/Root/index.tsx b/app/components/Views/Root/index.tsx
index 0f087ffac6a..023a8548070 100644
--- a/app/components/Views/Root/index.tsx
+++ b/app/components/Views/Root/index.tsx
@@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from 'react';
-import { StyleSheet } from 'react-native';
+import { StyleSheet, View } from 'react-native';
import { Provider as ReduxProvider } from 'react-redux';
import { PersistGate } from 'redux-persist/lib/integration/react';
import { store, persistor } from '../../../store';
@@ -28,6 +28,7 @@ import { QueryClientProvider } from '@tanstack/react-query';
import reactQueryService from '../../../core/ReactQueryService';
import { HardwareWalletProvider } from '../../../core/HardwareWallet';
import { UIMessengerProvider } from '../../../contexts/ui-messenger';
+import { Toaster } from '@metamask/design-system-react-native';
import {
createUIMessenger,
UIMessenger,
@@ -37,6 +38,12 @@ const styles = StyleSheet.create({
gestureRoot: {
flex: 1,
},
+ appRoot: {
+ flex: 1,
+ },
+ toasterOverlay: {
+ ...StyleSheet.absoluteFillObject,
+ },
});
/**
@@ -111,20 +118,28 @@ const Root = ({ foxCode }: RootProps) => {
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/Views/TransactionsView/index.js b/app/components/Views/TransactionsView/index.js
index 01321865c94..4a87b756e3a 100644
--- a/app/components/Views/TransactionsView/index.js
+++ b/app/components/Views/TransactionsView/index.js
@@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import { connect, useSelector } from 'react-redux';
import { KnownCaipNamespace } from '@metamask/utils';
import { useNavigation } from '@react-navigation/native';
-import { showAlert } from '../../../actions/alert';
import Transactions from '../../UI/Transactions';
import {
TX_UNAPPROVED,
@@ -305,8 +304,4 @@ const mapStateToProps = (state) => {
};
};
-const mapDispatchToProps = (dispatch) => ({
- showAlert: (config) => dispatch(showAlert(config)),
-});
-
-export default connect(mapStateToProps, mapDispatchToProps)(TransactionsView);
+export default connect(mapStateToProps)(TransactionsView);
diff --git a/app/reducers/alert/index.js b/app/reducers/alert/index.js
deleted file mode 100644
index 7afc3d3f142..00000000000
--- a/app/reducers/alert/index.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const initialState = {
- isVisible: false,
- autodismiss: null,
- content: null,
- data: null,
-};
-
-const alertReducer = (state = initialState, action) => {
- switch (action.type) {
- case 'SHOW_ALERT':
- return {
- ...state,
- isVisible: true,
- autodismiss: action.autodismiss,
- content: action.content,
- data: action.data,
- };
- case 'HIDE_ALERT':
- return {
- ...state,
- isVisible: false,
- autodismiss: null,
- };
- default:
- return state;
- }
-};
-export default alertReducer;
diff --git a/app/reducers/index.ts b/app/reducers/index.ts
index 31a76f3145c..cf6dee0aa12 100644
--- a/app/reducers/index.ts
+++ b/app/reducers/index.ts
@@ -4,7 +4,6 @@ import engineReducer from '../core/redux/slices/engine';
import privacyReducer from './privacy';
import modalsReducer from './modals';
import settingsReducer from './settings';
-import alertReducer from './alert';
import securityAlertsReducer, { SecurityAlertsState } from './security-alerts';
import legalNoticesReducer, { LegalNoticesState } from './legalNotices';
import userReducer, { UserState } from './user';
@@ -86,9 +85,6 @@ export interface RootState {
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
settings: any;
- // TODO: Replace "any" with type
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- alert: any;
securityAlerts: SecurityAlertsState;
user: UserState;
// TODO: Replace "any" with type
@@ -149,7 +145,6 @@ const baseReducers = {
browser: browserReducer,
modals: modalsReducer,
settings: settingsReducer,
- alert: alertReducer,
securityAlerts: securityAlertsReducer,
user: userReducer,
onboarding: onboardingReducer,
diff --git a/app/store/persistConfig/index.ts b/app/store/persistConfig/index.ts
index ad816519c68..0bb4824f5d2 100644
--- a/app/store/persistConfig/index.ts
+++ b/app/store/persistConfig/index.ts
@@ -208,7 +208,6 @@ const persistConfig = {
'rpcEvents',
'accounts',
'confirmationMetrics',
- 'alert',
'engine',
'qrKeyringScanner',
'securityAlerts',
diff --git a/app/store/persistConfig/persistConfig.test.ts b/app/store/persistConfig/persistConfig.test.ts
index a35b4914083..aa119e7c2f9 100644
--- a/app/store/persistConfig/persistConfig.test.ts
+++ b/app/store/persistConfig/persistConfig.test.ts
@@ -135,7 +135,6 @@ describe('persistConfig', () => {
'rpcEvents',
'accounts',
'confirmationMetrics',
- 'alert',
'engine',
'qrKeyringScanner',
'securityAlerts',
diff --git a/app/util/networks/switchNetwork.test.ts b/app/util/networks/switchNetwork.test.ts
index 865d256645c..f2209844464 100644
--- a/app/util/networks/switchNetwork.test.ts
+++ b/app/util/networks/switchNetwork.test.ts
@@ -1,9 +1,18 @@
import switchNetwork from './switchNetwork';
-import { showAlert } from '../../actions/alert';
+import { toast, ToastSeverity } from '@metamask/design-system-react-native';
import { strings } from '../../../locales/i18n';
import { handleNetworkSwitch } from './handleNetworkSwitch';
import { store } from '../../store';
+jest.mock('@metamask/design-system-react-native', () => {
+ const actual = jest.requireActual('@metamask/design-system-react-native');
+
+ return {
+ ...actual,
+ toast: Object.assign(jest.fn(), { dismiss: jest.fn() }),
+ };
+});
+
jest.mock('../../store', () => ({
store: {
dispatch: jest.fn(),
@@ -15,10 +24,6 @@ jest.mock('./handleNetworkSwitch', () => ({
handleNetworkSwitch: jest.fn(),
}));
-jest.mock('../../actions/alert', () => ({
- showAlert: jest.fn(),
-}));
-
describe('switchNetwork', () => {
const mockHandleNetworkSwitch = handleNetworkSwitch as jest.MockedFunction<
typeof handleNetworkSwitch
@@ -31,19 +36,15 @@ describe('switchNetwork', () => {
mockHandleNetworkSwitch.mockReturnValue('Ethereum Mainnet');
});
- it('should dispatch an alert for a valid switchToChainId', () => {
+ it('should show a warning toast for a valid switchToChainId', () => {
const switchToChainId = '1'; // Assuming '1' is a valid chain ID
switchNetwork({ switchToChainId });
- expect(store.dispatch).toHaveBeenCalledWith(
- showAlert({
- isVisible: true,
- autodismiss: 5000,
- content: 'clipboard-alert',
- data: { msg: strings('send.warn_network_change') + 'Ethereum Mainnet' },
- }),
- );
+ expect(toast).toHaveBeenCalledWith({
+ description: strings('send.warn_network_change') + 'Ethereum Mainnet',
+ severity: ToastSeverity.Warning,
+ });
});
it('should throw an error for an invalid switchToChainId', () => {
@@ -55,12 +56,12 @@ describe('switchNetwork', () => {
);
});
- it('should not dispatch an alert when switchNetwork returns undefined', () => {
+ it('should not show a toast when switchNetwork returns undefined', () => {
const switchToChainId = '1'; // Assuming '1' is a valid chain ID
mockHandleNetworkSwitch.mockReturnValue(undefined);
switchNetwork({ switchToChainId });
- expect(store.dispatch).not.toHaveBeenCalled();
+ expect(toast).not.toHaveBeenCalled();
});
});
diff --git a/app/util/networks/switchNetwork.ts b/app/util/networks/switchNetwork.ts
index 95019e250aa..cfc0483c31b 100644
--- a/app/util/networks/switchNetwork.ts
+++ b/app/util/networks/switchNetwork.ts
@@ -1,5 +1,5 @@
+import { toast, ToastSeverity } from '@metamask/design-system-react-native';
import { strings } from '../../../locales/i18n';
-import { showAlert } from '../../actions/alert';
import { handleNetworkSwitch } from './handleNetworkSwitch';
import DevLogger from '../../core/SDKConnect/utils/DevLogger';
@@ -27,14 +27,10 @@ function switchNetwork({
throw new Error(`Unable to find network with chain id ${newChainId}`);
}
- store.dispatch(
- showAlert({
- isVisible: true,
- autodismiss: 5000,
- content: 'clipboard-alert',
- data: { msg: strings('send.warn_network_change') + networkName },
- }),
- );
+ toast({
+ description: strings('send.warn_network_change') + networkName,
+ severity: ToastSeverity.Warning,
+ });
} else {
DevLogger.log(
'Invalid Type: switchToChainId must be a string or number but was ' +
diff --git a/app/util/test/initial-root-state.ts b/app/util/test/initial-root-state.ts
index 0cd9067a1b8..9e2c8c03d7e 100644
--- a/app/util/test/initial-root-state.ts
+++ b/app/util/test/initial-root-state.ts
@@ -39,7 +39,6 @@ const initialRootState: RootState = {
browser: undefined,
modals: undefined,
settings: undefined,
- alert: undefined,
securityAlerts: {
alerts: {},
},