2023-04-27 16:28:08 +02:00
|
|
|
import React, { useContext, useState, useRef, useCallback } from 'react';
|
2023-04-25 22:39:54 +02:00
|
|
|
import classnames from 'classnames';
|
2023-04-13 18:54:03 +02:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import browser from 'webextension-polyfill';
|
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
2023-05-08 19:32:39 +02:00
|
|
|
import { useHistory, matchPath } from 'react-router-dom';
|
2023-04-13 18:54:03 +02:00
|
|
|
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
|
|
|
import {
|
|
|
|
MetaMetricsEventCategory,
|
|
|
|
MetaMetricsEventName,
|
|
|
|
} from '../../../../shared/constants/metametrics';
|
|
|
|
import {
|
2023-05-08 19:32:39 +02:00
|
|
|
BUILD_QUOTE_ROUTE,
|
|
|
|
CONFIRM_TRANSACTION_ROUTE,
|
2023-04-13 18:54:03 +02:00
|
|
|
CONNECTED_ACCOUNTS_ROUTE,
|
|
|
|
DEFAULT_ROUTE,
|
2023-05-08 19:32:39 +02:00
|
|
|
SWAPS_ROUTE,
|
2023-04-13 18:54:03 +02:00
|
|
|
} from '../../../helpers/constants/routes';
|
|
|
|
|
|
|
|
import {
|
|
|
|
AlignItems,
|
|
|
|
BackgroundColor,
|
|
|
|
BLOCK_SIZES,
|
|
|
|
DISPLAY,
|
|
|
|
JustifyContent,
|
|
|
|
Size,
|
|
|
|
} from '../../../helpers/constants/design-system';
|
2023-04-14 00:24:47 +02:00
|
|
|
import {
|
|
|
|
AvatarNetwork,
|
|
|
|
ButtonIcon,
|
2023-05-05 07:21:10 +02:00
|
|
|
ButtonIconSize,
|
2023-04-14 00:24:47 +02:00
|
|
|
IconName,
|
2023-05-05 07:21:10 +02:00
|
|
|
IconSize,
|
2023-04-14 00:24:47 +02:00
|
|
|
PickerNetwork,
|
|
|
|
} from '../../component-library';
|
|
|
|
|
2023-04-13 18:54:03 +02:00
|
|
|
import {
|
2023-04-27 16:28:08 +02:00
|
|
|
getCurrentChainId,
|
2023-04-13 18:54:03 +02:00
|
|
|
getCurrentNetwork,
|
2023-04-21 17:28:18 +02:00
|
|
|
getOnboardedInThisUISession,
|
2023-04-13 18:54:03 +02:00
|
|
|
getOriginOfCurrentTab,
|
|
|
|
getSelectedIdentity,
|
2023-04-21 17:28:18 +02:00
|
|
|
getShowProductTour,
|
2023-04-13 18:54:03 +02:00
|
|
|
} from '../../../selectors';
|
2023-04-21 17:28:18 +02:00
|
|
|
import { GlobalMenu, ProductTour, AccountPicker } from '..';
|
2023-04-13 18:54:03 +02:00
|
|
|
|
|
|
|
import Box from '../../ui/box/box';
|
2023-04-21 17:28:18 +02:00
|
|
|
import {
|
|
|
|
hideProductTour,
|
|
|
|
toggleAccountMenu,
|
|
|
|
toggleNetworkMenu,
|
|
|
|
} from '../../../store/actions';
|
2023-04-13 18:54:03 +02:00
|
|
|
import MetafoxLogo from '../../ui/metafox-logo';
|
|
|
|
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
|
|
|
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
|
|
|
|
import ConnectedStatusIndicator from '../../app/connected-status-indicator';
|
2023-04-21 17:28:18 +02:00
|
|
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
|
|
|
import { getCompletedOnboarding } from '../../../ducks/metamask/metamask';
|
2023-05-08 19:32:39 +02:00
|
|
|
import { getSendStage, SEND_STAGES } from '../../../ducks/send';
|
2023-04-13 18:54:03 +02:00
|
|
|
|
2023-05-08 19:32:39 +02:00
|
|
|
export const AppHeader = ({ location }) => {
|
2023-04-13 18:54:03 +02:00
|
|
|
const trackEvent = useContext(MetaMetricsContext);
|
|
|
|
const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false);
|
2023-04-21 17:28:18 +02:00
|
|
|
const [multichainProductTourStep, setMultichainProductTourStep] = useState(1);
|
2023-04-13 18:54:03 +02:00
|
|
|
const menuRef = useRef(false);
|
|
|
|
const origin = useSelector(getOriginOfCurrentTab);
|
|
|
|
const history = useHistory();
|
|
|
|
const isUnlocked = useSelector((state) => state.metamask.isUnlocked);
|
2023-04-21 17:28:18 +02:00
|
|
|
const t = useI18nContext();
|
2023-04-27 16:28:08 +02:00
|
|
|
const chainId = useSelector(getCurrentChainId);
|
2023-04-25 22:39:54 +02:00
|
|
|
|
2023-04-13 18:54:03 +02:00
|
|
|
// Used for account picker
|
|
|
|
const identity = useSelector(getSelectedIdentity);
|
|
|
|
const dispatch = useDispatch();
|
2023-04-21 17:28:18 +02:00
|
|
|
const completedOnboarding = useSelector(getCompletedOnboarding);
|
|
|
|
const onboardedInThisUISession = useSelector(getOnboardedInThisUISession);
|
|
|
|
const showProductTourPopup = useSelector(getShowProductTour);
|
2023-04-13 18:54:03 +02:00
|
|
|
|
|
|
|
// Used for network icon / dropdown
|
|
|
|
const currentNetwork = useSelector(getCurrentNetwork);
|
|
|
|
|
2023-04-27 16:28:08 +02:00
|
|
|
// Used to get the environment and connection status
|
2023-04-13 18:54:03 +02:00
|
|
|
const popupStatus = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP;
|
|
|
|
const showStatus =
|
|
|
|
getEnvironmentType() === ENVIRONMENT_TYPE_POPUP &&
|
|
|
|
origin &&
|
|
|
|
origin !== browser.runtime.id;
|
2023-04-21 17:28:18 +02:00
|
|
|
const showProductTour =
|
|
|
|
completedOnboarding && !onboardedInThisUISession && showProductTourPopup;
|
|
|
|
const productTourDirection = document
|
|
|
|
.querySelector('[dir]')
|
|
|
|
?.getAttribute('dir');
|
2023-04-13 18:54:03 +02:00
|
|
|
|
2023-05-08 19:32:39 +02:00
|
|
|
// 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;
|
|
|
|
|
2023-04-27 16:28:08 +02:00
|
|
|
// Callback for network dropdown
|
|
|
|
const networkOpenCallback = useCallback(() => {
|
|
|
|
dispatch(toggleNetworkMenu());
|
|
|
|
trackEvent({
|
|
|
|
event: MetaMetricsEventName.NavNetworkMenuOpened,
|
|
|
|
category: MetaMetricsEventCategory.Navigation,
|
|
|
|
properties: {
|
|
|
|
location: 'App header',
|
|
|
|
chain_id: chainId,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}, [chainId, dispatch, trackEvent]);
|
|
|
|
|
2023-04-13 18:54:03 +02:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{isUnlocked && !popupStatus ? (
|
|
|
|
<Box
|
2023-04-21 17:28:18 +02:00
|
|
|
display={[DISPLAY.NONE, DISPLAY.FLEX]}
|
2023-04-13 18:54:03 +02:00
|
|
|
alignItems={AlignItems.center}
|
|
|
|
margin={2}
|
|
|
|
className="multichain-app-header-logo"
|
|
|
|
data-testid="app-header-logo"
|
|
|
|
justifyContent={JustifyContent.center}
|
|
|
|
>
|
|
|
|
<MetafoxLogo
|
|
|
|
unsetIconHeight
|
2023-05-08 19:32:39 +02:00
|
|
|
onClick={async () => history.push(DEFAULT_ROUTE)}
|
2023-04-13 18:54:03 +02:00
|
|
|
/>
|
|
|
|
</Box>
|
|
|
|
) : null}
|
|
|
|
<Box
|
|
|
|
display={DISPLAY.FLEX}
|
2023-04-25 22:39:54 +02:00
|
|
|
className={classnames('multichain-app-header', {
|
|
|
|
'multichain-app-header-shadow': !isUnlocked || popupStatus,
|
|
|
|
})}
|
2023-04-13 18:54:03 +02:00
|
|
|
alignItems={AlignItems.center}
|
|
|
|
width={BLOCK_SIZES.FULL}
|
|
|
|
backgroundColor={
|
|
|
|
!isUnlocked || popupStatus
|
|
|
|
? BackgroundColor.backgroundDefault
|
|
|
|
: BackgroundColor.backgroundAlternative
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<>
|
|
|
|
{isUnlocked ? (
|
|
|
|
<Box
|
2023-04-25 22:39:54 +02:00
|
|
|
className={classnames('multichain-app-header__contents', {
|
|
|
|
'multichain-app-header-shadow': isUnlocked && !popupStatus,
|
|
|
|
})}
|
2023-04-13 18:54:03 +02:00
|
|
|
alignItems={AlignItems.center}
|
|
|
|
width={BLOCK_SIZES.FULL}
|
|
|
|
backgroundColor={BackgroundColor.backgroundDefault}
|
|
|
|
padding={2}
|
2023-05-05 07:21:10 +02:00
|
|
|
paddingLeft={4}
|
|
|
|
paddingRight={4}
|
2023-04-13 18:54:03 +02:00
|
|
|
gap={2}
|
|
|
|
>
|
2023-04-21 17:28:18 +02:00
|
|
|
<AvatarNetwork
|
|
|
|
className="multichain-app-header__contents--avatar-network"
|
|
|
|
ref={menuRef}
|
|
|
|
as="button"
|
2023-05-02 19:14:48 +02:00
|
|
|
aria-label={t('networkMenu')}
|
2023-04-21 17:28:18 +02:00
|
|
|
padding={0}
|
|
|
|
name={currentNetwork?.nickname}
|
|
|
|
src={currentNetwork?.rpcPrefs?.imageUrl}
|
|
|
|
size={Size.SM}
|
2023-04-27 16:28:08 +02:00
|
|
|
onClick={networkOpenCallback}
|
2023-04-21 17:28:18 +02:00
|
|
|
display={[DISPLAY.FLEX, DISPLAY.NONE]} // show on popover hide on desktop
|
2023-05-08 19:32:39 +02:00
|
|
|
disabled={disableNetworkPicker}
|
2023-04-21 17:28:18 +02:00
|
|
|
/>
|
2023-05-08 16:50:13 +02:00
|
|
|
{popupStatus ? null : (
|
|
|
|
<div>
|
|
|
|
<PickerNetwork
|
|
|
|
margin={2}
|
|
|
|
label={currentNetwork?.nickname}
|
|
|
|
src={currentNetwork?.rpcPrefs?.imageUrl}
|
|
|
|
onClick={networkOpenCallback}
|
|
|
|
display={[DISPLAY.NONE, DISPLAY.FLEX]} // show on desktop hide on popover
|
|
|
|
className="multichain-app-header__contents__network-picker"
|
2023-05-08 19:32:39 +02:00
|
|
|
disabled={disableNetworkPicker}
|
2023-05-08 16:50:13 +02:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
2023-04-21 17:28:18 +02:00
|
|
|
{showProductTour &&
|
|
|
|
popupStatus &&
|
|
|
|
multichainProductTourStep === 1 ? (
|
|
|
|
<ProductTour
|
|
|
|
className="multichain-app-header__product-tour"
|
|
|
|
anchorElement={menuRef.current}
|
|
|
|
title={t('switcherTitle')}
|
|
|
|
description={t('switcherTourDescription')}
|
|
|
|
currentStep="1"
|
|
|
|
totalSteps="3"
|
|
|
|
onClick={() =>
|
|
|
|
setMultichainProductTourStep(multichainProductTourStep + 1)
|
|
|
|
}
|
|
|
|
positionObj={productTourDirection === 'rtl' ? '0%' : '88%'}
|
|
|
|
productTourDirection={productTourDirection}
|
2023-04-13 18:54:03 +02:00
|
|
|
/>
|
2023-04-21 17:28:18 +02:00
|
|
|
) : null}
|
2023-04-13 18:54:03 +02:00
|
|
|
|
|
|
|
<AccountPicker
|
|
|
|
address={identity.address}
|
|
|
|
name={identity.name}
|
2023-04-27 16:28:08 +02:00
|
|
|
onClick={() => {
|
|
|
|
dispatch(toggleAccountMenu());
|
|
|
|
|
|
|
|
trackEvent({
|
|
|
|
event: MetaMetricsEventName.NavAccountMenuOpened,
|
|
|
|
category: MetaMetricsEventCategory.Navigation,
|
|
|
|
properties: {
|
|
|
|
location: 'Home',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}}
|
2023-05-08 19:32:39 +02:00
|
|
|
disabled={disablePickers}
|
2023-04-13 18:54:03 +02:00
|
|
|
/>
|
|
|
|
<Box
|
|
|
|
display={DISPLAY.FLEX}
|
|
|
|
alignItems={AlignItems.center}
|
2023-05-05 07:21:10 +02:00
|
|
|
justifyContent={JustifyContent.flexEnd}
|
2023-04-13 18:54:03 +02:00
|
|
|
>
|
2023-05-05 07:21:10 +02:00
|
|
|
<Box display={DISPLAY.FLEX} gap={4}>
|
|
|
|
{showStatus ? (
|
|
|
|
<Box ref={menuRef}>
|
|
|
|
<ConnectedStatusIndicator
|
|
|
|
onClick={() => {
|
|
|
|
history.push(CONNECTED_ACCOUNTS_ROUTE);
|
|
|
|
trackEvent({
|
|
|
|
event: MetaMetricsEventName.NavConnectedSitesOpened,
|
|
|
|
category: MetaMetricsEventCategory.Navigation,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Box>
|
|
|
|
) : null}{' '}
|
|
|
|
{popupStatus && multichainProductTourStep === 2 ? (
|
|
|
|
<ProductTour
|
|
|
|
className="multichain-app-header__product-tour"
|
|
|
|
anchorElement={menuRef.current}
|
|
|
|
closeMenu={() => setAccountOptionsMenuOpen(false)}
|
|
|
|
prevIcon
|
|
|
|
title={t('permissionsTitle')}
|
|
|
|
description={t('permissionsTourDescription')}
|
|
|
|
currentStep="2"
|
|
|
|
totalSteps="3"
|
|
|
|
prevClick={() =>
|
|
|
|
setMultichainProductTourStep(
|
|
|
|
multichainProductTourStep - 1,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
onClick={() =>
|
|
|
|
setMultichainProductTourStep(
|
|
|
|
multichainProductTourStep + 1,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
positionObj={
|
|
|
|
productTourDirection === 'rtl' ? '76%' : '12%'
|
|
|
|
}
|
|
|
|
productTourDirection={productTourDirection}
|
|
|
|
/>
|
|
|
|
) : null}
|
|
|
|
<Box
|
|
|
|
ref={menuRef}
|
|
|
|
display={DISPLAY.FLEX}
|
|
|
|
justifyContent={JustifyContent.flexEnd}
|
|
|
|
width={BLOCK_SIZES.FULL}
|
|
|
|
>
|
|
|
|
<ButtonIcon
|
|
|
|
iconName={IconName.MoreVertical}
|
|
|
|
data-testid="account-options-menu-button"
|
|
|
|
ariaLabel={t('accountOptions')}
|
2023-04-27 16:28:08 +02:00
|
|
|
onClick={() => {
|
|
|
|
trackEvent({
|
2023-05-05 07:21:10 +02:00
|
|
|
event: MetaMetricsEventName.NavAccountMenuOpened,
|
2023-04-27 16:28:08 +02:00
|
|
|
category: MetaMetricsEventCategory.Navigation,
|
2023-05-05 07:21:10 +02:00
|
|
|
properties: {
|
|
|
|
location: 'Home',
|
|
|
|
},
|
2023-04-27 16:28:08 +02:00
|
|
|
});
|
2023-05-05 07:21:10 +02:00
|
|
|
setAccountOptionsMenuOpen(true);
|
2023-04-27 16:28:08 +02:00
|
|
|
}}
|
2023-05-05 07:21:10 +02:00
|
|
|
size={ButtonIconSize.Sm}
|
|
|
|
iconProps={{ size: IconSize.Sm }}
|
2023-04-21 17:28:18 +02:00
|
|
|
/>
|
|
|
|
</Box>
|
2023-05-05 07:21:10 +02:00
|
|
|
</Box>
|
|
|
|
{accountOptionsMenuOpen ? (
|
|
|
|
<GlobalMenu
|
|
|
|
anchorElement={menuRef.current}
|
|
|
|
closeMenu={() => setAccountOptionsMenuOpen(false)}
|
|
|
|
/>
|
|
|
|
) : null}
|
|
|
|
{showProductTour &&
|
|
|
|
popupStatus &&
|
|
|
|
multichainProductTourStep === 3 ? (
|
2023-04-21 17:28:18 +02:00
|
|
|
<ProductTour
|
|
|
|
className="multichain-app-header__product-tour"
|
|
|
|
anchorElement={menuRef.current}
|
|
|
|
closeMenu={() => setAccountOptionsMenuOpen(false)}
|
|
|
|
prevIcon
|
2023-05-05 07:21:10 +02:00
|
|
|
title={t('globalTitle')}
|
|
|
|
description={t('globalTourDescription')}
|
|
|
|
currentStep="3"
|
2023-04-21 17:28:18 +02:00
|
|
|
totalSteps="3"
|
|
|
|
prevClick={() =>
|
|
|
|
setMultichainProductTourStep(
|
|
|
|
multichainProductTourStep - 1,
|
|
|
|
)
|
|
|
|
}
|
2023-04-13 18:54:03 +02:00
|
|
|
onClick={() => {
|
2023-05-05 07:21:10 +02:00
|
|
|
hideProductTour();
|
2023-04-13 18:54:03 +02:00
|
|
|
}}
|
2023-05-05 07:21:10 +02:00
|
|
|
positionObj={productTourDirection === 'rtl' ? '88%' : '0%'}
|
|
|
|
productTourDirection={productTourDirection}
|
2023-04-13 18:54:03 +02:00
|
|
|
/>
|
2023-05-05 07:21:10 +02:00
|
|
|
) : null}
|
2023-04-13 18:54:03 +02:00
|
|
|
</Box>
|
|
|
|
</Box>
|
|
|
|
) : (
|
|
|
|
<Box
|
|
|
|
display={DISPLAY.FLEX}
|
2023-04-25 22:39:54 +02:00
|
|
|
className={classnames('multichain-app-header__lock-contents', {
|
|
|
|
'multichain-app-header-shadow': isUnlocked && !popupStatus,
|
|
|
|
})}
|
2023-04-13 18:54:03 +02:00
|
|
|
alignItems={AlignItems.center}
|
|
|
|
width={BLOCK_SIZES.FULL}
|
|
|
|
justifyContent={JustifyContent.spaceBetween}
|
|
|
|
backgroundColor={BackgroundColor.backgroundDefault}
|
|
|
|
padding={2}
|
|
|
|
gap={2}
|
|
|
|
>
|
2023-05-09 10:06:54 +02:00
|
|
|
<div>
|
|
|
|
<PickerNetwork
|
|
|
|
label={currentNetwork?.nickname}
|
|
|
|
src={currentNetwork?.rpcPrefs?.imageUrl}
|
|
|
|
onClick={() => dispatch(toggleNetworkMenu())}
|
|
|
|
className="multichain-app-header__contents__network-picker"
|
|
|
|
/>
|
|
|
|
</div>
|
2023-04-13 18:54:03 +02:00
|
|
|
<MetafoxLogo
|
|
|
|
unsetIconHeight
|
|
|
|
onClick={async () => {
|
|
|
|
history.push(DEFAULT_ROUTE);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Box>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
</Box>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
AppHeader.propTypes = {
|
|
|
|
/**
|
2023-05-08 19:32:39 +02:00
|
|
|
* The location object for the application
|
2023-04-13 18:54:03 +02:00
|
|
|
*/
|
2023-05-08 19:32:39 +02:00
|
|
|
location: PropTypes.object,
|
2023-04-13 18:54:03 +02:00
|
|
|
};
|