From 5689ae60a6dc2cb258ca2fe1d28cc2439f8d0a67 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Thu, 7 Mar 2024 12:00:08 -0600 Subject: [PATCH] feat: UX: Multichain: Close other popups when new popup is opened --- app/scripts/controllers/app-state.js | 5 +++++ app/scripts/metamask-controller.js | 2 ++ ui/index.js | 13 +++++++++++++ ui/pages/routes/routes.component.js | 17 +++++++++++++++++ ui/pages/routes/routes.container.js | 4 ++++ ui/store/actions.ts | 10 ++++++++++ 6 files changed, 51 insertions(+) diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 02bcf916939e..af9f410cd985 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -53,6 +53,7 @@ export default class AppStateController extends EventEmitter { showAccountBanner: true, trezorModel: null, currentPopupId: undefined, + currentExtensionPopupId: undefined, // This key is only used for checking if the user had set advancedGasFee // prior to Migration 92.3 where we split out the setting to support // multiple networks. @@ -523,6 +524,10 @@ export default class AppStateController extends EventEmitter { }); } + setCurrentExtensionPopupId(currentExtensionPopupId) { + this.store.updateState({ currentExtensionPopupId }); + } + /** * A getter to retrieve currentPopupId saved in the appState */ diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 84c20573479e..d47b49ba7d90 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3105,6 +3105,8 @@ export default class MetamaskController extends EventEmitter { // AppStateController setLastActiveTime: appStateController.setLastActiveTime.bind(appStateController), + setCurrentExtensionPopupId: + appStateController.setCurrentExtensionPopupId.bind(appStateController), setDefaultHomeActiveTabName: appStateController.setDefaultHomeActiveTabName.bind(appStateController), setConnectedStatusPopoverHasBeenShown: diff --git a/ui/index.js b/ui/index.js index e1c01714ceab..99ba9980b9aa 100644 --- a/ui/index.js +++ b/ui/index.js @@ -23,6 +23,7 @@ import { getSelectedInternalAccount, getUnapprovedTransactions, getAutomaticSwitchNetwork, + getUseRequestQueue, } from './selectors'; import { ALERT_STATE } from './ducks/alerts'; import { @@ -211,6 +212,18 @@ async function startApp(metamaskState, backgroundConnection, opts) { }, }; + // Register this window as the current popup + // and set in background state + if ( + process.env.MULTICHAIN && + getUseRequestQueue(state) && + getEnvironmentType() === ENVIRONMENT_TYPE_POPUP + ) { + const thisPopupId = Date.now(); + global.metamask.id = thisPopupId; + actions.setCurrentExtensionPopupId(thisPopupId); + } + // start app render(, opts.container); diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js index 6b9137b15d4d..7d3c51350fd1 100644 --- a/ui/pages/routes/routes.component.js +++ b/ui/pages/routes/routes.component.js @@ -198,6 +198,8 @@ export default class Routes extends Component { neverShowSwitchedNetworkMessage: PropTypes.bool.isRequired, autoSwitchNetwork: PropTypes.func.isRequired, unapprovedTransactions: PropTypes.number.isRequired, + currentExtensionPopupId: PropTypes.number, + useRequestQueue: PropTypes.bool, ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) isShowKeyringSnapRemovalResultModal: PropTypes.bool.isRequired, hideShowKeyringSnapRemovalResultModal: PropTypes.func.isRequired, @@ -254,9 +256,12 @@ export default class Routes extends Component { networkToAutomaticallySwitchTo, activeTabOrigin, unapprovedTransactions, + useRequestQueue, + currentExtensionPopupId, allNetworks, isUnlocked, } = this.props; + if (theme !== prevProps.theme) { this.setTheme(); } @@ -283,6 +288,18 @@ export default class Routes extends Component { ); } } + + // Terminate the popup when another popup is opened + // if the user is using RPC queueing + if ( + useRequestQueue && + process.env.MULTICHAIN && + currentExtensionPopupId !== undefined && + global.metamask.id !== undefined && + currentExtensionPopupId !== global.metamask.id + ) { + window.close(); + } } UNSAFE_componentWillMount() { diff --git a/ui/pages/routes/routes.container.js b/ui/pages/routes/routes.container.js index 225b9e57a22f..2c3862b10a04 100644 --- a/ui/pages/routes/routes.container.js +++ b/ui/pages/routes/routes.container.js @@ -23,6 +23,7 @@ import { getNeverShowSwitchedNetworkMessage, getAutomaticSwitchNetwork, getNumberOfAllUnapprovedTransactions, + getUseRequestQueue, } from '../../selectors'; import { lockMetamask, @@ -114,6 +115,9 @@ function mapStateToProps(state) { unapprovedTransactions: getNumberOfAllUnapprovedTransactions(state), allNetworks: getAllNetworks(state), neverShowSwitchedNetworkMessage: getNeverShowSwitchedNetworkMessage(state), + currentExtensionPopupId: state.metamask.currentExtensionPopupId, + useRequestQueue: getUseRequestQueue(state), + ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) isShowKeyringSnapRemovalResultModal: state.appState.showKeyringRemovalSnapModal, diff --git a/ui/store/actions.ts b/ui/store/actions.ts index c0d0799ad161..2fa356a68d99 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -4950,6 +4950,16 @@ export function updateInterfaceState( }) as any; } +/** + * Update the currentPopupid generated when the user opened the popup + * + * @param id - The Snap interface ID. + * @returns Promise Resolved on successfully submitted background request. + */ +export async function setCurrentExtensionPopupId(id: number) { + await submitRequestToBackground('setCurrentExtensionPopupId', [id]); +} + /** * Delete the Snap interface from state. *