mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
UX Multichain: Added Select an action Modal (#20559)
* added select-action-modal skeleton * added select action modal item * replaced stake link with constant * added route for open and close of modal * updated lint errors * lint fix * updated tests * revert unnecessary changes * fixed lint errors * added suggestions * lint fix * updated test * nit fix * updated select action item to use button * removed unused fragments * moved onClose command to bottom * moved select action modal on footer click * changed isDisabled to disabled * added hover and updated test * nit fix
This commit is contained in:
parent
215430236e
commit
6a17d76efc
27
app/_locales/en/messages.json
generated
27
app/_locales/en/messages.json
generated
@ -596,6 +596,12 @@
|
|||||||
"bridge": {
|
"bridge": {
|
||||||
"message": "Bridge"
|
"message": "Bridge"
|
||||||
},
|
},
|
||||||
|
"bridgeDescription": {
|
||||||
|
"message": "Transfer tokens from different networks"
|
||||||
|
},
|
||||||
|
"bridgeDisabled": {
|
||||||
|
"message": "Bridge is not available in this network"
|
||||||
|
},
|
||||||
"browserNotSupported": {
|
"browserNotSupported": {
|
||||||
"message": "Your browser is not supported..."
|
"message": "Your browser is not supported..."
|
||||||
},
|
},
|
||||||
@ -615,6 +621,12 @@
|
|||||||
"message": "Buy $1",
|
"message": "Buy $1",
|
||||||
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
|
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
|
||||||
},
|
},
|
||||||
|
"buyDescription": {
|
||||||
|
"message": "Hold up your crypto and earn potential profits"
|
||||||
|
},
|
||||||
|
"buyDisabled": {
|
||||||
|
"message": "Buy is not available in this network"
|
||||||
|
},
|
||||||
"buyMoreAsset": {
|
"buyMoreAsset": {
|
||||||
"message": "Buy more $1",
|
"message": "Buy more $1",
|
||||||
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
|
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
|
||||||
@ -3753,6 +3765,9 @@
|
|||||||
"selectAnAccountHelp": {
|
"selectAnAccountHelp": {
|
||||||
"message": "Select the custodian accounts to use in MetaMask Institutional."
|
"message": "Select the custodian accounts to use in MetaMask Institutional."
|
||||||
},
|
},
|
||||||
|
"selectAnAction": {
|
||||||
|
"message": "Select an action"
|
||||||
|
},
|
||||||
"selectHdPath": {
|
"selectHdPath": {
|
||||||
"message": "Select HD path"
|
"message": "Select HD path"
|
||||||
},
|
},
|
||||||
@ -3780,6 +3795,9 @@
|
|||||||
"sendBugReport": {
|
"sendBugReport": {
|
||||||
"message": "Send us a bug report."
|
"message": "Send us a bug report."
|
||||||
},
|
},
|
||||||
|
"sendDescription": {
|
||||||
|
"message": "Send crypto to any account"
|
||||||
|
},
|
||||||
"sendSpecifiedTokens": {
|
"sendSpecifiedTokens": {
|
||||||
"message": "Send $1",
|
"message": "Send $1",
|
||||||
"description": "Symbol of the specified token"
|
"description": "Symbol of the specified token"
|
||||||
@ -4226,6 +4244,9 @@
|
|||||||
"stake": {
|
"stake": {
|
||||||
"message": "Stake"
|
"message": "Stake"
|
||||||
},
|
},
|
||||||
|
"stakeDescription": {
|
||||||
|
"message": "Hold up your crypto and earn potential profits"
|
||||||
|
},
|
||||||
"stateLogError": {
|
"stateLogError": {
|
||||||
"message": "Error in retrieving state logs."
|
"message": "Error in retrieving state logs."
|
||||||
},
|
},
|
||||||
@ -4417,9 +4438,15 @@
|
|||||||
"swapDecentralizedExchange": {
|
"swapDecentralizedExchange": {
|
||||||
"message": "Decentralized exchange"
|
"message": "Decentralized exchange"
|
||||||
},
|
},
|
||||||
|
"swapDescription": {
|
||||||
|
"message": "Swap and trade your tokens"
|
||||||
|
},
|
||||||
"swapDirectContract": {
|
"swapDirectContract": {
|
||||||
"message": "Direct contract"
|
"message": "Direct contract"
|
||||||
},
|
},
|
||||||
|
"swapDisabled": {
|
||||||
|
"message": "Swap is not available in this network"
|
||||||
|
},
|
||||||
"swapEditLimit": {
|
"swapEditLimit": {
|
||||||
"message": "Edit limit"
|
"message": "Edit limit"
|
||||||
},
|
},
|
||||||
|
14
ui/components/multichain/app-footer/app-footer-actions.tsx
Normal file
14
ui/components/multichain/app-footer/app-footer-actions.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Action } from 'redux';
|
||||||
|
import * as actionConstants from '../../../store/actionConstants';
|
||||||
|
|
||||||
|
export function showSelectActionModal(): Action {
|
||||||
|
return {
|
||||||
|
type: actionConstants.SELECT_ACTION_MODAL_OPEN,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hideSelectActionModal(): Action {
|
||||||
|
return {
|
||||||
|
type: actionConstants.SELECT_ACTION_MODAL_CLOSE,
|
||||||
|
};
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
CONNECTED_ROUTE,
|
CONNECTED_ROUTE,
|
||||||
DEFAULT_ROUTE,
|
DEFAULT_ROUTE,
|
||||||
@ -26,10 +27,12 @@ import {
|
|||||||
TextColor,
|
TextColor,
|
||||||
TextVariant,
|
TextVariant,
|
||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
|
import { showSelectActionModal } from './app-footer-actions';
|
||||||
|
|
||||||
export const AppFooter = () => {
|
export const AppFooter = () => {
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const walletRoute = `#${DEFAULT_ROUTE}`;
|
const walletRoute = `#${DEFAULT_ROUTE}`;
|
||||||
const connectedRoute = `#${CONNECTED_ROUTE}`;
|
const connectedRoute = `#${CONNECTED_ROUTE}`;
|
||||||
@ -78,7 +81,7 @@ export const AppFooter = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
as="a"
|
as="button"
|
||||||
width={BlockSize.OneThird}
|
width={BlockSize.OneThird}
|
||||||
padding={2}
|
padding={2}
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
@ -96,6 +99,7 @@ export const AppFooter = () => {
|
|||||||
backgroundColor={BackgroundColor.primaryDefault}
|
backgroundColor={BackgroundColor.primaryDefault}
|
||||||
size={ButtonIconSize.Lg}
|
size={ButtonIconSize.Lg}
|
||||||
borderRadius={BorderRadius.full}
|
borderRadius={BorderRadius.full}
|
||||||
|
onClick={() => dispatch(showSelectActionModal())}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
|
@ -21,3 +21,5 @@ export { ImportAccount } from './import-account';
|
|||||||
export { ImportNftsModal } from './import-nfts-modal';
|
export { ImportNftsModal } from './import-nfts-modal';
|
||||||
export { AccountDetailsMenuItem, ViewExplorerMenuItem } from './menu-items';
|
export { AccountDetailsMenuItem, ViewExplorerMenuItem } from './menu-items';
|
||||||
export { ImportTokensModal } from './import-tokens-modal';
|
export { ImportTokensModal } from './import-tokens-modal';
|
||||||
|
export { SelectActionModal } from './select-action-modal';
|
||||||
|
export { SelectActionModalItem } from './select-action-modal-item';
|
||||||
|
@ -21,4 +21,4 @@
|
|||||||
@import 'product-tour-popover/product-tour-popover';
|
@import 'product-tour-popover/product-tour-popover';
|
||||||
@import 'nft-item/nft-item';
|
@import 'nft-item/nft-item';
|
||||||
@import 'import-tokens-modal/import-tokens-modal';
|
@import 'import-tokens-modal/import-tokens-modal';
|
||||||
|
@import 'select-action-modal-item/select-action-modal-item';
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`SelectActionModalItem should render correctly 1`] = `
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="mm-box select-action-modal-item mm-box--padding-top-4 mm-box--padding-bottom-4 mm-box--display-flex mm-box--gap-4 mm-box--flex-direction-row mm-box--width-full mm-box--background-color-transparent"
|
||||||
|
data-testid="select-action-modal-item"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mm-box"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-icon select-action-modal-item__avatar mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-inverse mm-box--background-color-primary-default mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="mm-box mm-icon mm-icon--size-md mm-box--display-inline-block mm-box--color-inherit"
|
||||||
|
style="mask-image: url('./images/icons/add.svg');"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mm-box mm-box--display-flex mm-box--flex-direction-column"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mm-box mm-box--display-flex mm-box--gap-2 mm-box--flex-direction-row mm-box--align-items-center"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="mm-box mm-text mm-text--body-lg-medium mm-text--text-align-left mm-box--color-text-default"
|
||||||
|
>
|
||||||
|
Buy
|
||||||
|
</p>
|
||||||
|
<span
|
||||||
|
class="mm-box mm-icon mm-icon--size-xs mm-box--display-inline-block mm-box--color-icon-alternative"
|
||||||
|
style="mask-image: url('./images/icons/export.svg');"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="mm-box mm-text mm-text--body-md mm-text--text-align-left mm-box--color-text-default"
|
||||||
|
>
|
||||||
|
Buy crypto with MetaMask
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -0,0 +1 @@
|
|||||||
|
export { SelectActionModalItem } from './select-action-modal-item';
|
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { IconName } from '../../component-library';
|
||||||
|
import { SelectActionModalItem } from '.';
|
||||||
|
|
||||||
|
describe('SelectActionModalItem', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const props = {
|
||||||
|
showIcon: true,
|
||||||
|
primaryText: 'Buy',
|
||||||
|
secondaryText: 'Buy crypto with MetaMask',
|
||||||
|
actionIcon: IconName.Add,
|
||||||
|
};
|
||||||
|
const { container, getByTestId } = render(
|
||||||
|
<SelectActionModalItem {...props} />,
|
||||||
|
);
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
expect(getByTestId('select-action-modal-item')).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,111 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
AlignItems,
|
||||||
|
BackgroundColor,
|
||||||
|
BlockSize,
|
||||||
|
Display,
|
||||||
|
FlexDirection,
|
||||||
|
IconColor,
|
||||||
|
TextAlign,
|
||||||
|
TextVariant,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
import {
|
||||||
|
AvatarIcon,
|
||||||
|
AvatarIconSize,
|
||||||
|
Box,
|
||||||
|
Icon,
|
||||||
|
IconName,
|
||||||
|
IconSize,
|
||||||
|
Text,
|
||||||
|
} from '../../component-library';
|
||||||
|
|
||||||
|
export const SelectActionModalItem = ({
|
||||||
|
actionIcon,
|
||||||
|
onClick,
|
||||||
|
showIcon,
|
||||||
|
primaryText,
|
||||||
|
secondaryText,
|
||||||
|
disabled,
|
||||||
|
}) => {
|
||||||
|
if (disabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
paddingTop={4}
|
||||||
|
paddingBottom={4}
|
||||||
|
gap={4}
|
||||||
|
display={Display.Flex}
|
||||||
|
flexDirection={FlexDirection.Row}
|
||||||
|
as="button"
|
||||||
|
backgroundColor={BackgroundColor.transparent}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
onClick();
|
||||||
|
}}
|
||||||
|
className="select-action-modal-item"
|
||||||
|
data-testid="select-action-modal-item"
|
||||||
|
width={BlockSize.Full}
|
||||||
|
>
|
||||||
|
<Box>
|
||||||
|
<AvatarIcon
|
||||||
|
iconName={actionIcon}
|
||||||
|
color={IconColor.primaryInverse}
|
||||||
|
backgroundColor={BackgroundColor.primaryDefault}
|
||||||
|
size={AvatarIconSize.Md}
|
||||||
|
className="select-action-modal-item__avatar"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box display={Display.Flex} flexDirection={FlexDirection.Column}>
|
||||||
|
<Box
|
||||||
|
display={Display.Flex}
|
||||||
|
flexDirection={FlexDirection.Row}
|
||||||
|
gap={2}
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
>
|
||||||
|
<Text variant={TextVariant.bodyLgMedium} textAlign={TextAlign.Left}>
|
||||||
|
{primaryText}
|
||||||
|
</Text>
|
||||||
|
{showIcon && (
|
||||||
|
<Icon
|
||||||
|
name={IconName.Export}
|
||||||
|
size={IconSize.Xs}
|
||||||
|
color={IconColor.iconAlternative}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
<Text variant={TextVariant.bodyMd} textAlign={TextAlign.Left}>
|
||||||
|
{secondaryText}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectActionModalItem.propTypes = {
|
||||||
|
/**
|
||||||
|
* Show link icon with text
|
||||||
|
*/
|
||||||
|
showIcon: PropTypes.bool,
|
||||||
|
/**
|
||||||
|
* onClick handler for each action
|
||||||
|
*/
|
||||||
|
onClick: PropTypes.func.isRequired,
|
||||||
|
/**
|
||||||
|
* Icon for each action Item
|
||||||
|
*/
|
||||||
|
actionIcon: PropTypes.string.isRequired,
|
||||||
|
/**
|
||||||
|
* Title for each action Item
|
||||||
|
*/
|
||||||
|
primaryText: PropTypes.string.isRequired,
|
||||||
|
/**
|
||||||
|
* Description for each action Item
|
||||||
|
*/
|
||||||
|
secondaryText: PropTypes.string.isRequired,
|
||||||
|
/**
|
||||||
|
* Disable bridge and swap for selected networks
|
||||||
|
*/
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
};
|
@ -0,0 +1,6 @@
|
|||||||
|
.select-action-modal-item {
|
||||||
|
&:hover,
|
||||||
|
&:focus-within {
|
||||||
|
background-color: var(--color-background-default-hover);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { IconName } from '../../component-library';
|
||||||
|
import { SelectActionModalItem } from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/Multichain/SelectActionModalItem',
|
||||||
|
component: SelectActionModalItem,
|
||||||
|
argTypes: {
|
||||||
|
showIcon: {
|
||||||
|
control: 'boolean',
|
||||||
|
},
|
||||||
|
primaryText: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
actionIcon: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
secondaryText: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
onClick: {
|
||||||
|
action: 'onClick',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
showIcon: true,
|
||||||
|
primaryText: 'Buy',
|
||||||
|
secondaryText: 'Buy crypto with MetaMask',
|
||||||
|
actionIcon: IconName.Add,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultStory = (args) => <SelectActionModalItem {...args} />;
|
||||||
|
|
||||||
|
DefaultStory.storyName = 'Default';
|
1
ui/components/multichain/select-action-modal/index.js
Normal file
1
ui/components/multichain/select-action-modal/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { SelectActionModal } from './select-action-modal';
|
@ -0,0 +1,249 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import {
|
||||||
|
useHistory,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
useLocation,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
IconName,
|
||||||
|
Modal,
|
||||||
|
ModalContent,
|
||||||
|
ModalHeader,
|
||||||
|
ModalOverlay,
|
||||||
|
} from '../../component-library';
|
||||||
|
import { SelectActionModalItem } from '../select-action-modal-item';
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
import useRamps from '../../../hooks/experiences/useRamps';
|
||||||
|
import { getPortfolioUrl } from '../../../helpers/utils/portfolio';
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||||
|
import {
|
||||||
|
MetaMetricsEventCategory,
|
||||||
|
MetaMetricsEventName,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
MetaMetricsSwapsEventSource,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../../../shared/constants/metametrics';
|
||||||
|
import {
|
||||||
|
getCurrentChainId,
|
||||||
|
getIsSwapsChain,
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
getSwapsDefaultToken,
|
||||||
|
getCurrentKeyring,
|
||||||
|
getIsBridgeChain,
|
||||||
|
getIsBuyableChain,
|
||||||
|
getMetaMetricsId,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
} from '../../../selectors';
|
||||||
|
import {
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
BUILD_QUOTE_ROUTE,
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
SEND_ROUTE,
|
||||||
|
} from '../../../helpers/constants/routes';
|
||||||
|
import { startNewDraftTransaction } from '../../../ducks/send';
|
||||||
|
import { I18nContext } from '../../../contexts/i18n';
|
||||||
|
import { AssetType } from '../../../../shared/constants/transaction';
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
import { MMI_SWAPS_URL } from '../../../../shared/constants/swaps';
|
||||||
|
import { MMI_STAKE_WEBSITE } from '../../../helpers/constants/common';
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
import { setSwapsFromToken } from '../../../ducks/swaps/swaps';
|
||||||
|
import { isHardwareKeyring } from '../../../helpers/utils/hardware';
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
export const SelectActionModal = ({ onClose }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const t = useContext(I18nContext);
|
||||||
|
const trackEvent = useContext(MetaMetricsContext);
|
||||||
|
const history = useHistory();
|
||||||
|
const chainId = useSelector(getCurrentChainId);
|
||||||
|
const isSwapsChain = useSelector(getIsSwapsChain);
|
||||||
|
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
const location = useLocation();
|
||||||
|
const { openBuyCryptoInPdapp } = useRamps();
|
||||||
|
const defaultSwapsToken = useSelector(getSwapsDefaultToken);
|
||||||
|
const keyring = useSelector(getCurrentKeyring);
|
||||||
|
const usingHardwareWallet = isHardwareKeyring(keyring?.type);
|
||||||
|
const isBridgeChain = useSelector(getIsBridgeChain);
|
||||||
|
const metaMetricsId = useSelector(getMetaMetricsId);
|
||||||
|
const isBuyableChain = useSelector(getIsBuyableChain);
|
||||||
|
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
const stakingEvent = () => {
|
||||||
|
trackEvent({
|
||||||
|
category: MetaMetricsEventCategory.Navigation,
|
||||||
|
event: MetaMetricsEventName.MMIPortfolioButtonClicked,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen
|
||||||
|
onClose={onClose}
|
||||||
|
className="select-action-modal"
|
||||||
|
data-testid="select-action-modal"
|
||||||
|
>
|
||||||
|
<ModalOverlay />
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader onClose={onClose}>{t('selectAnAction')}</ModalHeader>
|
||||||
|
<Box className="select-action-modal__container" marginTop={6}>
|
||||||
|
{
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
<SelectActionModalItem
|
||||||
|
actionIcon={IconName.Add}
|
||||||
|
showIcon
|
||||||
|
primaryText={t('buy')}
|
||||||
|
secondaryText={t('buyDescription')}
|
||||||
|
disabled={!isBuyableChain}
|
||||||
|
tooltipTitle={t('buyDisabled')}
|
||||||
|
onClick={() => {
|
||||||
|
openBuyCryptoInPdapp();
|
||||||
|
trackEvent({
|
||||||
|
event: MetaMetricsEventName.NavBuyButtonClicked,
|
||||||
|
category: MetaMetricsEventCategory.Navigation,
|
||||||
|
properties: {
|
||||||
|
location: 'Home',
|
||||||
|
text: 'Buy',
|
||||||
|
chain_id: chainId,
|
||||||
|
token_symbol: defaultSwapsToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
}
|
||||||
|
{
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
<SelectActionModalItem
|
||||||
|
actionIcon={IconName.Stake}
|
||||||
|
showIcon
|
||||||
|
primaryText={t('stake')}
|
||||||
|
secondaryText={t('stakeDescription')}
|
||||||
|
onClick={() => {
|
||||||
|
stakingEvent();
|
||||||
|
global.platform.openTab({
|
||||||
|
url: MMI_STAKE_WEBSITE,
|
||||||
|
});
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
}
|
||||||
|
<SelectActionModalItem
|
||||||
|
actionIcon={IconName.SwapHorizontal}
|
||||||
|
primaryText={t('swap')}
|
||||||
|
secondaryText={t('swapDescription')}
|
||||||
|
disabled={!isSwapsChain}
|
||||||
|
tooltipTitle={t('swapDisabled')}
|
||||||
|
onClick={() => {
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
|
global.platform.openTab({
|
||||||
|
url: MMI_SWAPS_URL,
|
||||||
|
});
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
if (isSwapsChain) {
|
||||||
|
trackEvent({
|
||||||
|
event: MetaMetricsEventName.NavSwapButtonClicked,
|
||||||
|
category: MetaMetricsEventCategory.Swaps,
|
||||||
|
properties: {
|
||||||
|
token_symbol: 'ETH',
|
||||||
|
location: MetaMetricsSwapsEventSource.MainView,
|
||||||
|
text: 'Swap',
|
||||||
|
chain_id: chainId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dispatch(setSwapsFromToken(defaultSwapsToken));
|
||||||
|
if (usingHardwareWallet) {
|
||||||
|
global.platform.openExtensionInBrowser(BUILD_QUOTE_ROUTE);
|
||||||
|
} else {
|
||||||
|
history.push(BUILD_QUOTE_ROUTE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SelectActionModalItem
|
||||||
|
actionIcon={IconName.Arrow2UpRight}
|
||||||
|
primaryText={t('send')}
|
||||||
|
secondaryText={t('sendDescription')}
|
||||||
|
onClick={async () => {
|
||||||
|
trackEvent({
|
||||||
|
event: MetaMetricsEventName.NavSendButtonClicked,
|
||||||
|
category: MetaMetricsEventCategory.Navigation,
|
||||||
|
properties: {
|
||||||
|
token_symbol: 'ETH',
|
||||||
|
location: 'Home',
|
||||||
|
text: 'Send',
|
||||||
|
chain_id: chainId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await dispatch(
|
||||||
|
startNewDraftTransaction({ type: AssetType.native }),
|
||||||
|
);
|
||||||
|
history.push(SEND_ROUTE);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
||||||
|
<SelectActionModalItem
|
||||||
|
actionIcon={IconName.Arrow2UpRight}
|
||||||
|
showIcon
|
||||||
|
primaryText={t('bridge')}
|
||||||
|
secondaryText={t('bridgeDescription')}
|
||||||
|
disabled={!isBridgeChain}
|
||||||
|
tooltipTitle={t('bridgeDisabled')}
|
||||||
|
onClick={() => {
|
||||||
|
if (isBridgeChain) {
|
||||||
|
const portfolioUrl = getPortfolioUrl(
|
||||||
|
'bridge',
|
||||||
|
'ext_bridge_button',
|
||||||
|
metaMetricsId,
|
||||||
|
);
|
||||||
|
global.platform.openTab({
|
||||||
|
url: `${portfolioUrl}${
|
||||||
|
location.pathname.includes('asset') ? '&token=native' : ''
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
trackEvent({
|
||||||
|
category: MetaMetricsEventCategory.Navigation,
|
||||||
|
event: MetaMetricsEventName.BridgeLinkClicked,
|
||||||
|
properties: {
|
||||||
|
location: 'Home',
|
||||||
|
text: 'Bridge',
|
||||||
|
chain_id: chainId,
|
||||||
|
token_symbol: 'ETH',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectActionModal.propTypes = {
|
||||||
|
/**
|
||||||
|
* onClose handler for Modal
|
||||||
|
*/
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
};
|
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SelectActionModal } from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/Multichain/SelectActionModal',
|
||||||
|
component: SelectActionModal,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultStory = () => <SelectActionModal />;
|
||||||
|
|
||||||
|
DefaultStory.storyName = 'Default';
|
@ -0,0 +1,265 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import configureMockStore from 'redux-mock-store';
|
||||||
|
import thunk from 'redux-thunk';
|
||||||
|
import { fireEvent, waitFor } from '@testing-library/react';
|
||||||
|
import mockState from '../../../../test/data/mock-state.json';
|
||||||
|
|
||||||
|
import { renderWithProvider } from '../../../../test/jest/rendering';
|
||||||
|
|
||||||
|
import { KeyringType } from '../../../../shared/constants/keyring';
|
||||||
|
import { CHAIN_IDS } from '../../../../shared/constants/network';
|
||||||
|
import { SelectActionModal } from '.';
|
||||||
|
|
||||||
|
// Mock BUYABLE_CHAINS_MAP
|
||||||
|
jest.mock('../../../../shared/constants/network', () => ({
|
||||||
|
...jest.requireActual('../../../../shared/constants/network'),
|
||||||
|
BUYABLE_CHAINS_MAP: {
|
||||||
|
// MAINNET
|
||||||
|
'0x1': {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
|
network: 'ethereum',
|
||||||
|
},
|
||||||
|
// POLYGON
|
||||||
|
'0x89': {
|
||||||
|
nativeCurrency: 'MATIC',
|
||||||
|
network: 'polygon',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
let openTabSpy;
|
||||||
|
|
||||||
|
describe('Select Action Modal', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
Object.defineProperty(global, 'platform', {
|
||||||
|
value: {
|
||||||
|
openTab: jest.fn(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
openTabSpy = jest.spyOn(global.platform, 'openTab');
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
openTabSpy.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockStore = {
|
||||||
|
metamask: {
|
||||||
|
providerConfig: {
|
||||||
|
type: 'test',
|
||||||
|
chainId: CHAIN_IDS.MAINNET,
|
||||||
|
},
|
||||||
|
cachedBalances: {
|
||||||
|
'0x1': {
|
||||||
|
'0x1': '0x1F4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
useNativeCurrencyAsPrimaryCurrency: true,
|
||||||
|
},
|
||||||
|
useCurrencyRateCheck: true,
|
||||||
|
conversionRate: 2,
|
||||||
|
identities: {
|
||||||
|
'0x1': {
|
||||||
|
address: '0x1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
accounts: {
|
||||||
|
'0x1': {
|
||||||
|
address: '0x1',
|
||||||
|
balance: '0x1F4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selectedAddress: '0x1',
|
||||||
|
keyrings: [
|
||||||
|
{
|
||||||
|
type: KeyringType.imported,
|
||||||
|
accounts: ['0x1', '0x2'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: KeyringType.ledger,
|
||||||
|
accounts: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
contractExchangeRates: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const store = configureMockStore([thunk])(mockState);
|
||||||
|
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const { getByTestId } = renderWithProvider(<SelectActionModal />, store);
|
||||||
|
|
||||||
|
expect(getByTestId('select-action-modal')).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the Buy native token enabled if chain id is part of supported buyable chains', () => {
|
||||||
|
const mockedStoreWithBuyableChainId = {
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: { type: 'test', chainId: CHAIN_IDS.POLYGON },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(
|
||||||
|
mockedStoreWithBuyableChainId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
expect(queryByText('Buy')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open the Buy native token URI when clicking on Buy button for a buyable chain ID', async () => {
|
||||||
|
const mockedStoreWithBuyableChainId = {
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: { type: 'test', chainId: CHAIN_IDS.POLYGON },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(
|
||||||
|
mockedStoreWithBuyableChainId,
|
||||||
|
);
|
||||||
|
const onClose = jest.fn();
|
||||||
|
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal onClose={onClose} />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
const buyButton = queryByText('Buy');
|
||||||
|
expect(buyButton).toBeInTheDocument();
|
||||||
|
expect(buyButton).not.toBeDisabled();
|
||||||
|
|
||||||
|
fireEvent.click(buyButton);
|
||||||
|
expect(onClose).toHaveBeenCalledTimes(1);
|
||||||
|
expect(openTabSpy).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(openTabSpy).toHaveBeenCalledWith({
|
||||||
|
url: expect.stringContaining(`/buy?metamaskEntry=ext_buy_button`),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not have the Buy native token button if chain id is not part of supported buyable chains', () => {
|
||||||
|
const mockedStoreWithUnbuyableChainId = {
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: { type: 'test', chainId: CHAIN_IDS.FANTOM },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(
|
||||||
|
mockedStoreWithUnbuyableChainId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
const buyButton = queryByText('Buy');
|
||||||
|
expect(buyButton).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it('should have the Bridge button if chain id is a part of supported chains', () => {
|
||||||
|
const mockedAvalancheStore = {
|
||||||
|
...mockStore,
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: {
|
||||||
|
...mockStore.metamask.providerConfig,
|
||||||
|
chainId: '0xa86a',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(mockedAvalancheStore);
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
const bridgeButton = queryByText('Bridge');
|
||||||
|
expect(bridgeButton).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it('should open the Bridge URI when clicking on Bridge button on supported network', async () => {
|
||||||
|
const onClose = jest.fn();
|
||||||
|
const mockedAvalancheStore = {
|
||||||
|
...mockStore,
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: {
|
||||||
|
...mockStore.metamask.providerConfig,
|
||||||
|
chainId: '0xa86a',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(mockedAvalancheStore);
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal onClose={onClose} />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
|
||||||
|
const bridgeButton = queryByText('Bridge');
|
||||||
|
expect(bridgeButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(bridgeButton);
|
||||||
|
expect(onClose).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
expect(openTabSpy).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(openTabSpy).toHaveBeenCalledWith({
|
||||||
|
url: expect.stringContaining('/bridge?metamaskEntry=ext_bridge_button'),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should not have the Bridge button if chain id is not part of supported chains', () => {
|
||||||
|
const mockedFantomStore = {
|
||||||
|
...mockStore,
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: {
|
||||||
|
...mockStore.metamask.providerConfig,
|
||||||
|
chainId: '0xfa',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(mockedFantomStore);
|
||||||
|
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
const buyButton = queryByText('Bridge');
|
||||||
|
expect(buyButton).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it('should have the Swap button if chain id is part of supported buyable chains', () => {
|
||||||
|
const mockedStoreWithSwapableChainId = {
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: { type: 'test', chainId: CHAIN_IDS.POLYGON },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(
|
||||||
|
mockedStoreWithSwapableChainId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
expect(queryByText('Swap')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it('should have the Send button if chain id is part of supported buyable chains', () => {
|
||||||
|
const mockedStoreWithSendChainId = {
|
||||||
|
metamask: {
|
||||||
|
...mockStore.metamask,
|
||||||
|
providerConfig: { type: 'test', chainId: CHAIN_IDS.POLYGON },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockedStore = configureMockStore([thunk])(mockedStoreWithSendChainId);
|
||||||
|
|
||||||
|
const { queryByText } = renderWithProvider(
|
||||||
|
<SelectActionModal />,
|
||||||
|
mockedStore,
|
||||||
|
);
|
||||||
|
expect(queryByText('Send')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -29,6 +29,7 @@ interface AppState {
|
|||||||
importNftsModalOpen: boolean;
|
importNftsModalOpen: boolean;
|
||||||
showIpfsModalOpen: boolean;
|
showIpfsModalOpen: boolean;
|
||||||
importTokensModalOpen: boolean;
|
importTokensModalOpen: boolean;
|
||||||
|
showSelectActionModal: boolean;
|
||||||
accountDetail: {
|
accountDetail: {
|
||||||
subview?: string;
|
subview?: string;
|
||||||
accountExport?: string;
|
accountExport?: string;
|
||||||
@ -100,6 +101,7 @@ const initialState: AppState = {
|
|||||||
importNftsModalOpen: false,
|
importNftsModalOpen: false,
|
||||||
showIpfsModalOpen: false,
|
showIpfsModalOpen: false,
|
||||||
importTokensModalOpen: false,
|
importTokensModalOpen: false,
|
||||||
|
showSelectActionModal: false,
|
||||||
accountDetail: {
|
accountDetail: {
|
||||||
privateKey: '',
|
privateKey: '',
|
||||||
},
|
},
|
||||||
@ -205,6 +207,18 @@ export default function reduceApp(
|
|||||||
importTokensModalOpen: false,
|
importTokensModalOpen: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case actionConstants.SELECT_ACTION_MODAL_OPEN:
|
||||||
|
return {
|
||||||
|
...appState,
|
||||||
|
showSelectActionModal: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
case actionConstants.SELECT_ACTION_MODAL_CLOSE:
|
||||||
|
return {
|
||||||
|
...appState,
|
||||||
|
showSelectActionModal: false,
|
||||||
|
};
|
||||||
|
|
||||||
// alert methods
|
// alert methods
|
||||||
case actionConstants.ALERT_OPEN:
|
case actionConstants.ALERT_OPEN:
|
||||||
return {
|
return {
|
||||||
|
@ -7,6 +7,7 @@ const _contractAddressLink =
|
|||||||
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
||||||
const _mmiWebSite = 'https://metamask.io/institutions/';
|
const _mmiWebSite = 'https://metamask.io/institutions/';
|
||||||
export const MMI_WEB_SITE = _mmiWebSite;
|
export const MMI_WEB_SITE = _mmiWebSite;
|
||||||
|
export const MMI_STAKE_WEBSITE = 'https://metamask-institutional.io/stake';
|
||||||
///: END:ONLY_INCLUDE_IN
|
///: END:ONLY_INCLUDE_IN
|
||||||
|
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
AccountDetails,
|
AccountDetails,
|
||||||
ImportNftsModal,
|
ImportNftsModal,
|
||||||
ImportTokensModal,
|
ImportTokensModal,
|
||||||
|
SelectActionModal,
|
||||||
} from '../../components/multichain';
|
} from '../../components/multichain';
|
||||||
import UnlockPage from '../unlock-page';
|
import UnlockPage from '../unlock-page';
|
||||||
import Alerts from '../../components/app/alerts';
|
import Alerts from '../../components/app/alerts';
|
||||||
@ -164,6 +165,8 @@ export default class Routes extends Component {
|
|||||||
hideIpfsModal: PropTypes.func.isRequired,
|
hideIpfsModal: PropTypes.func.isRequired,
|
||||||
isImportTokensModalOpen: PropTypes.bool.isRequired,
|
isImportTokensModalOpen: PropTypes.bool.isRequired,
|
||||||
hideImportTokensModal: PropTypes.func.isRequired,
|
hideImportTokensModal: PropTypes.func.isRequired,
|
||||||
|
isSelectActionModalOpen: PropTypes.bool.isRequired,
|
||||||
|
hideSelectActionModal: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
@ -511,12 +514,14 @@ export default class Routes extends Component {
|
|||||||
toggleNetworkMenu,
|
toggleNetworkMenu,
|
||||||
accountDetailsAddress,
|
accountDetailsAddress,
|
||||||
isImportTokensModalOpen,
|
isImportTokensModalOpen,
|
||||||
|
isSelectActionModalOpen,
|
||||||
location,
|
location,
|
||||||
isImportNftsModalOpen,
|
isImportNftsModalOpen,
|
||||||
hideImportNftsModal,
|
hideImportNftsModal,
|
||||||
isIpfsModalOpen,
|
isIpfsModalOpen,
|
||||||
hideIpfsModal,
|
hideIpfsModal,
|
||||||
hideImportTokensModal,
|
hideImportTokensModal,
|
||||||
|
hideSelectActionModal,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const loadMessage =
|
const loadMessage =
|
||||||
@ -585,6 +590,9 @@ export default class Routes extends Component {
|
|||||||
{isImportTokensModalOpen ? (
|
{isImportTokensModalOpen ? (
|
||||||
<ImportTokensModal onClose={() => hideImportTokensModal()} />
|
<ImportTokensModal onClose={() => hideImportTokensModal()} />
|
||||||
) : null}
|
) : null}
|
||||||
|
{isSelectActionModalOpen ? (
|
||||||
|
<SelectActionModal onClose={() => hideSelectActionModal()} />
|
||||||
|
) : null}
|
||||||
<Box className="main-container-wrapper">
|
<Box className="main-container-wrapper">
|
||||||
{isLoading ? <Loading loadingMessage={loadMessage} /> : null}
|
{isLoading ? <Loading loadingMessage={loadMessage} /> : null}
|
||||||
{!isLoading && isNetworkLoading ? <LoadingNetwork /> : null}
|
{!isLoading && isNetworkLoading ? <LoadingNetwork /> : null}
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
isCurrentProviderCustom,
|
isCurrentProviderCustom,
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import {
|
import {
|
||||||
hideImportTokensModal,
|
|
||||||
lockMetamask,
|
lockMetamask,
|
||||||
hideImportNftsModal,
|
hideImportNftsModal,
|
||||||
hideIpfsModal,
|
hideIpfsModal,
|
||||||
@ -23,7 +22,9 @@ import {
|
|||||||
setMouseUserState,
|
setMouseUserState,
|
||||||
toggleAccountMenu,
|
toggleAccountMenu,
|
||||||
toggleNetworkMenu,
|
toggleNetworkMenu,
|
||||||
|
hideImportTokensModal,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions';
|
||||||
|
import { hideSelectActionModal } from '../../components/multichain/app-footer/app-footer-actions';
|
||||||
import { pageChanged } from '../../ducks/history/history';
|
import { pageChanged } from '../../ducks/history/history';
|
||||||
import { prepareToLeaveSwaps } from '../../ducks/swaps/swaps';
|
import { prepareToLeaveSwaps } from '../../ducks/swaps/swaps';
|
||||||
import { getSendStage } from '../../ducks/send';
|
import { getSendStage } from '../../ducks/send';
|
||||||
@ -69,6 +70,7 @@ function mapStateToProps(state) {
|
|||||||
accountDetailsAddress: state.appState.accountDetailsAddress,
|
accountDetailsAddress: state.appState.accountDetailsAddress,
|
||||||
isImportNftsModalOpen: state.appState.importNftsModalOpen,
|
isImportNftsModalOpen: state.appState.importNftsModalOpen,
|
||||||
isIpfsModalOpen: state.appState.showIpfsModalOpen,
|
isIpfsModalOpen: state.appState.showIpfsModalOpen,
|
||||||
|
isSelectActionModalOpen: state.appState.showSelectActionModal,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +88,7 @@ function mapDispatchToProps(dispatch) {
|
|||||||
hideImportNftsModal: () => dispatch(hideImportNftsModal()),
|
hideImportNftsModal: () => dispatch(hideImportNftsModal()),
|
||||||
hideIpfsModal: () => dispatch(hideIpfsModal()),
|
hideIpfsModal: () => dispatch(hideIpfsModal()),
|
||||||
hideImportTokensModal: () => dispatch(hideImportTokensModal()),
|
hideImportTokensModal: () => dispatch(hideImportTokensModal()),
|
||||||
|
hideSelectActionModal: () => dispatch(hideSelectActionModal()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ export const SHOW_IPFS_MODAL_OPEN = 'UI_IPFS_MODAL_OPEN';
|
|||||||
export const SHOW_IPFS_MODAL_CLOSE = 'UI_IPFS_MODAL_CLOSE';
|
export const SHOW_IPFS_MODAL_CLOSE = 'UI_IPFS_MODAL_CLOSE';
|
||||||
export const IMPORT_TOKENS_POPOVER_OPEN = 'UI_IMPORT_TOKENS_POPOVER_OPEN';
|
export const IMPORT_TOKENS_POPOVER_OPEN = 'UI_IMPORT_TOKENS_POPOVER_OPEN';
|
||||||
export const IMPORT_TOKENS_POPOVER_CLOSE = 'UI_IMPORT_TOKENS_POPOVER_CLOSE';
|
export const IMPORT_TOKENS_POPOVER_CLOSE = 'UI_IMPORT_TOKENS_POPOVER_CLOSE';
|
||||||
|
export const SELECT_ACTION_MODAL_OPEN = 'UI_SELECT_ACTION_MODAL_OPEN';
|
||||||
|
export const SELECT_ACTION_MODAL_CLOSE = 'UI_SELECT_ACTION_MODAL_CLOSE';
|
||||||
|
|
||||||
// remote state
|
// remote state
|
||||||
export const UPDATE_METAMASK_STATE = 'UPDATE_METAMASK_STATE';
|
export const UPDATE_METAMASK_STATE = 'UPDATE_METAMASK_STATE';
|
||||||
export const SELECTED_ADDRESS_CHANGED = 'SELECTED_ADDRESS_CHANGED';
|
export const SELECTED_ADDRESS_CHANGED = 'SELECTED_ADDRESS_CHANGED';
|
||||||
|
Loading…
Reference in New Issue
Block a user