From b9813773044353fe31ffdf95f0fe4ecd9de2aed2 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Mon, 8 May 2023 12:32:39 -0500 Subject: [PATCH] UX: Multichain: Disable network and account picker when necessary (#18909) --- .../account-picker/account-picker.js | 7 ++- .../multichain/app-header/app-header.js | 52 ++++++++++++++----- .../app-header/app-header.stories.js | 7 ++- .../multichain/app-header/app-header.test.js | 9 +++- ui/pages/routes/routes.component.js | 3 +- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/ui/components/multichain/account-picker/account-picker.js b/ui/components/multichain/account-picker/account-picker.js index c0a6ba190..56c704d2e 100644 --- a/ui/components/multichain/account-picker/account-picker.js +++ b/ui/components/multichain/account-picker/account-picker.js @@ -19,7 +19,7 @@ import { Size, } from '../../../helpers/constants/design-system'; -export const AccountPicker = ({ address, name, onClick }) => { +export const AccountPicker = ({ address, name, onClick, disabled }) => { const useBlockie = useSelector((state) => state.metamask.useBlockie); return ( @@ -34,6 +34,7 @@ export const AccountPicker = ({ address, name, onClick }) => { gap: 2, alignItems: AlignItems.center, }} + disabled={disabled} > { +export const AppHeader = ({ location }) => { const trackEvent = useContext(MetaMetricsContext); const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false); const [multichainProductTourStep, setMultichainProductTourStep] = useState(1); @@ -87,6 +91,33 @@ export const AppHeader = ({ onClick }) => { .querySelector('[dir]') ?.getAttribute('dir'); + // Disable the network and account pickers if the user is in + // a critical flow + const sendStage = useSelector(getSendStage); + const isConfirmationPage = Boolean( + matchPath(location.pathname, { + path: CONFIRM_TRANSACTION_ROUTE, + exact: false, + }), + ); + const isTransactionEditPage = [ + SEND_STAGES.EDIT, + SEND_STAGES.DRAFT, + SEND_STAGES.ADD_RECIPIENT, + ].includes(sendStage); + const isSwapsPage = Boolean( + matchPath(location.pathname, { path: SWAPS_ROUTE, exact: false }), + ); + const isSwapsBuildQuotePage = Boolean( + matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }), + ); + + const disablePickers = + isConfirmationPage || + isTransactionEditPage || + (isSwapsPage && !isSwapsBuildQuotePage); + const disableNetworkPicker = isSwapsPage || disablePickers; + // Callback for network dropdown const networkOpenCallback = useCallback(() => { dispatch(toggleNetworkMenu()); @@ -113,12 +144,7 @@ export const AppHeader = ({ onClick }) => { > { - if (onClick) { - await onClick(); - } - history.push(DEFAULT_ROUTE); - }} + onClick={async () => history.push(DEFAULT_ROUTE)} /> ) : null} @@ -160,6 +186,7 @@ export const AppHeader = ({ onClick }) => { size={Size.SM} onClick={networkOpenCallback} display={[DISPLAY.FLEX, DISPLAY.NONE]} // show on popover hide on desktop + disabled={disableNetworkPicker} /> {popupStatus ? null : (
@@ -170,6 +197,7 @@ export const AppHeader = ({ onClick }) => { onClick={networkOpenCallback} display={[DISPLAY.NONE, DISPLAY.FLEX]} // show on desktop hide on popover className="multichain-app-header__contents__network-picker" + disabled={disableNetworkPicker} />
)} @@ -205,6 +233,7 @@ export const AppHeader = ({ onClick }) => { }, }); }} + disabled={disablePickers} /> { { - if (onClick) { - await onClick(); - } history.push(DEFAULT_ROUTE); }} /> @@ -350,7 +376,7 @@ export const AppHeader = ({ onClick }) => { AppHeader.propTypes = { /** - * The onClick handler to be passed to the MetaMask Logo in the App Header + * The location object for the application */ - onClick: PropTypes.func, + location: PropTypes.object, }; diff --git a/ui/components/multichain/app-header/app-header.stories.js b/ui/components/multichain/app-header/app-header.stories.js index c8ae6a810..ea2da2019 100644 --- a/ui/components/multichain/app-header/app-header.stories.js +++ b/ui/components/multichain/app-header/app-header.stories.js @@ -11,10 +11,13 @@ export default { decorators: [(story) => {story()}], component: AppHeader, argTypes: { - onClick: { - action: 'onClick', + location: { + control: 'object', }, }, + args: { + location: { pathname: '' }, + }, }; const customNetworkUnlockedData = { ...testData, diff --git a/ui/components/multichain/app-header/app-header.test.js b/ui/components/multichain/app-header/app-header.test.js index d2885587e..cca6bfe2d 100644 --- a/ui/components/multichain/app-header/app-header.test.js +++ b/ui/components/multichain/app-header/app-header.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import { CHAIN_IDS } from '../../../../shared/constants/network'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import { SEND_STAGES } from '../../../ducks/send'; import { AppHeader } from '.'; describe('App Header', () => { @@ -100,11 +101,17 @@ describe('App Header', () => { appState: { onboardedInThisUISession: false, }, + send: { + stage: SEND_STAGES.INACTIVE, + }, }; const mockStore = configureStore(); const store = mockStore(mockState); - const { container } = renderWithProvider(, store); + const { container } = renderWithProvider( + , + store, + ); expect(container).toMatchSnapshot(); }); }); diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js index 0b5620949..7ae47b961 100644 --- a/ui/pages/routes/routes.component.js +++ b/ui/pages/routes/routes.component.js @@ -498,6 +498,7 @@ export default class Routes extends Component { isNetworkMenuOpen, toggleNetworkMenu, accountDetailsAddress, + location, } = this.props; const loadMessage = loadingMessage || isNetworkLoading @@ -542,7 +543,7 @@ export default class Routes extends Component { {!this.hideAppHeader() && (process.env.MULTICHAIN ? ( - + ) : (