From 0bbfd38cc6b50386bd9b30d6336db18455d2796e Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Fri, 31 Mar 2023 22:53:27 +0530 Subject: [PATCH] UX Multichain: Menu for Site connections and permissions (#18167) * added site connection menu component * reverted change for unlock page * updated snapshot * updated state with useSelector * updated state for connected * updated icons * updated test * updated snapshot * moved component to multichain folder * updated color * added multichain connection to menu bar * updated default color * updated css * updated multichain site with connected site info * updated ui for not connected state * removed scripts * updated lint errors * updated lint errors * updated stories * updated story for not connected to current state * updated story for not connected to current state * updated badge to 16px * updated badge position * updated snapshot * fixed lint errors * updated not connected state icon * updated constants for status and added new locale string --- app/_locales/en/messages.json | 9 ++ .../connected-status-indicator.js | 30 ++++- ui/components/app/menu-bar/menu-bar.js | 2 +- ui/components/multichain/index.js | 1 + .../multichain/multichain-components.scss | 1 + ...ultichain-connected-site-menu.test.js.snap | 112 ++++++++++++++++++ .../multichain-connected-site-menu/index.js | 1 + .../multichain-connected-site-menu/index.scss | 23 ++++ .../multichain-connected-site-menu.js | 98 +++++++++++++++ .../multichain-connected-site-menu.stories.js | 51 ++++++++ .../multichain-connected-site-menu.test.js | 87 ++++++++++++++ 11 files changed, 409 insertions(+), 6 deletions(-) create mode 100644 ui/components/multichain/multichain-connected-site-menu/__snapshots__/multichain-connected-site-menu.test.js.snap create mode 100644 ui/components/multichain/multichain-connected-site-menu/index.js create mode 100644 ui/components/multichain/multichain-connected-site-menu/index.scss create mode 100644 ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.js create mode 100644 ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.stories.js create mode 100644 ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.test.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index c9669541e..a14cbc3e1 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3753,6 +3753,9 @@ "statusNotConnected": { "message": "Not connected" }, + "statusNotConnectedAccount": { + "message": "No accounts connected" + }, "step1LatticeWallet": { "message": "Connect your Lattice1" }, @@ -4351,6 +4354,12 @@ "tooltipApproveButton": { "message": "I understand" }, + "tooltipSatusConnected": { + "message": "connected" + }, + "tooltipSatusNotConnected": { + "message": "not connected" + }, "total": { "message": "Total" }, diff --git a/ui/components/app/connected-status-indicator/connected-status-indicator.js b/ui/components/app/connected-status-indicator/connected-status-indicator.js index 1abca94f3..55a268510 100644 --- a/ui/components/app/connected-status-indicator/connected-status-indicator.js +++ b/ui/components/app/connected-status-indicator/connected-status-indicator.js @@ -8,13 +8,17 @@ import { STATUS_NOT_CONNECTED, } from '../../../helpers/constants/connected-sites'; import ColorIndicator from '../../ui/color-indicator'; -import { Color } from '../../../helpers/constants/design-system'; +import { + BackgroundColor, + Color, +} from '../../../helpers/constants/design-system'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { getAddressConnectedSubjectMap, getOriginOfCurrentTab, getSelectedAddress, } from '../../../selectors'; +import { MultichainConnectedSiteMenu } from '../../multichain'; export default function ConnectedStatusIndicator({ onClick }) { const t = useI18nContext(); @@ -38,23 +42,39 @@ export default function ConnectedStatusIndicator({ onClick }) { let indicatorType = ColorIndicator.TYPES.OUTLINE; let indicatorColor = Color.iconDefault; + let globalMenuColor = Color.iconAlternative; if (status === STATUS_CONNECTED) { indicatorColor = Color.successDefault; indicatorType = ColorIndicator.TYPES.PARTIAL; + globalMenuColor = Color.successDefault; } else if (status === STATUS_CONNECTED_TO_ANOTHER_ACCOUNT) { indicatorColor = Color.errorDefault; + globalMenuColor = BackgroundColor.backgroundDefault; } const text = status === STATUS_CONNECTED ? t('statusConnected') - : t('statusNotConnected'); - + : t('statusNotConnected'); // TODO: Remove text since we only need the tooltip text for new permission icon + const tooltipText = + status === STATUS_CONNECTED + ? t('tooltipSatusConnected') + : t('tooltipSatusNotConnected'); return ( ); } diff --git a/ui/components/app/menu-bar/menu-bar.js b/ui/components/app/menu-bar/menu-bar.js index bf80cad5d..3ddc301af 100644 --- a/ui/components/app/menu-bar/menu-bar.js +++ b/ui/components/app/menu-bar/menu-bar.js @@ -30,7 +30,7 @@ export default function MenuBar() { return (
- {showStatus ? ( + {showStatus ? ( // TODO: Move the connection status menu icon to the correct position in header once we implement the new header history.push(CONNECTED_ACCOUNTS_ROUTE)} /> diff --git a/ui/components/multichain/index.js b/ui/components/multichain/index.js index b686c0948..debaef289 100644 --- a/ui/components/multichain/index.js +++ b/ui/components/multichain/index.js @@ -7,3 +7,4 @@ export { GlobalMenu } from './global-menu'; export { MultichainImportTokenLink } from './multichain-import-token-link'; export { MultichainTokenListItem } from './multichain-token-list-item'; export { AddressCopyButton } from './address-copy-button'; +export { MultichainConnectedSiteMenu } from './multichain-connected-site-menu'; diff --git a/ui/components/multichain/multichain-components.scss b/ui/components/multichain/multichain-components.scss index a2a2dbd20..ea41f990e 100644 --- a/ui/components/multichain/multichain-components.scss +++ b/ui/components/multichain/multichain-components.scss @@ -8,4 +8,5 @@ @import 'account-list-item/index'; @import 'account-list-menu/index'; @import 'account-picker/index'; +@import 'multichain-connected-site-menu/index'; @import 'multichain-token-list-item/multichain-token-list-item'; diff --git a/ui/components/multichain/multichain-connected-site-menu/__snapshots__/multichain-connected-site-menu.test.js.snap b/ui/components/multichain/multichain-connected-site-menu/__snapshots__/multichain-connected-site-menu.test.js.snap new file mode 100644 index 000000000..876d9d2c3 --- /dev/null +++ b/ui/components/multichain/multichain-connected-site-menu/__snapshots__/multichain-connected-site-menu.test.js.snap @@ -0,0 +1,112 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Multichain Connected Site Menu should render the site menu in connected state 1`] = ` +
+
+
+
+
+ +
+
+
+
+
+
+
+
+`; + +exports[`Multichain Connected Site Menu should render the site menu in not connected state 1`] = ` +
+
+
+
+
+ +
+
+
+
+
+
+
+
+`; + +exports[`Multichain Connected Site Menu should render the site menu in not connected to current account state 1`] = ` +
+
+
+
+
+ +
+
+
+
+
+
+
+
+`; diff --git a/ui/components/multichain/multichain-connected-site-menu/index.js b/ui/components/multichain/multichain-connected-site-menu/index.js new file mode 100644 index 000000000..a7724dd6b --- /dev/null +++ b/ui/components/multichain/multichain-connected-site-menu/index.js @@ -0,0 +1 @@ +export { MultichainConnectedSiteMenu } from './multichain-connected-site-menu'; diff --git a/ui/components/multichain/multichain-connected-site-menu/index.scss b/ui/components/multichain/multichain-connected-site-menu/index.scss new file mode 100644 index 000000000..3b7c363c4 --- /dev/null +++ b/ui/components/multichain/multichain-connected-site-menu/index.scss @@ -0,0 +1,23 @@ +.multichain-connected-site-menu { + &__badge { + height: 16px; + width: 16px; + } + + &__badge.not-connected { + height: 10px; + width: 10px; + } + + &__badge.not-connected::after { + content: ''; + position: absolute; + top: -3px; + left: -3px; + right: -3px; + bottom: -3px; + background: var(--color-background-default); + z-index: -1; + border-radius: 50%; + } +} diff --git a/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.js b/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.js new file mode 100644 index 000000000..23f8076ec --- /dev/null +++ b/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.js @@ -0,0 +1,98 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { useSelector } from 'react-redux'; +import { + STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, + STATUS_NOT_CONNECTED, +} from '../../../helpers/constants/connected-sites'; +import { + BackgroundColor, + BorderColor, + BorderRadius, + IconColor, + Size, +} from '../../../helpers/constants/design-system'; +import { BadgeWrapper, Icon, ICON_NAMES } from '../../component-library'; +import Box from '../../ui/box'; +import { getSelectedIdentity } from '../../../selectors'; +import Tooltip from '../../ui/tooltip'; +import { useI18nContext } from '../../../hooks/useI18nContext'; + +export const MultichainConnectedSiteMenu = ({ + className, + globalMenuColor, + status, + text, +}) => { + const t = useI18nContext(); + const selectedAccount = useSelector(getSelectedIdentity); + return ( + + + + } + > + + + + + ); +}; + +MultichainConnectedSiteMenu.propTypes = { + /** + * Additional classNames to be added to the MultichainConnectedSiteMenu + */ + className: PropTypes.string, + /** + * Background color based on the connection status + */ + globalMenuColor: PropTypes.string.isRequired, + /** + * Connection status string + */ + status: PropTypes.string.isRequired, + /** + * Connection status message + */ + text: PropTypes.string, +}; diff --git a/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.stories.js b/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.stories.js new file mode 100644 index 000000000..d959caa3a --- /dev/null +++ b/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.stories.js @@ -0,0 +1,51 @@ +import React from 'react'; +import { + STATUS_CONNECTED, + STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, + STATUS_NOT_CONNECTED, +} from '../../../helpers/constants/connected-sites'; +import { + BackgroundColor, + Color, +} from '../../../helpers/constants/design-system'; +import { MultichainConnectedSiteMenu } from './multichain-connected-site-menu'; + +export default { + title: 'Components/Multichain/MultichainConnectedSiteMenu', + component: MultichainConnectedSiteMenu, + argTypes: { + globalMenuColor: { + control: 'text', + }, + text: { + control: 'text', + }, + status: { + control: 'text', + }, + }, + args: { + globalMenuColor: Color.iconAlternative, + status: STATUS_NOT_CONNECTED, + }, +}; + +const Template = (args) => { + return ; +}; + +export const DefaultStory = Template.bind({}); + +export const ConnectedStory = Template.bind({}); +ConnectedStory.args = { + globalMenuColor: Color.successDefault, + text: 'connected', + status: STATUS_CONNECTED, +}; + +export const ConnectedtoAnotherAccountStory = Template.bind({}); +ConnectedtoAnotherAccountStory.args = { + globalMenuColor: BackgroundColor.backgroundDefault, + text: 'not connected', + status: STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, +}; diff --git a/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.test.js b/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.test.js new file mode 100644 index 000000000..6f2a711e3 --- /dev/null +++ b/ui/components/multichain/multichain-connected-site-menu/multichain-connected-site-menu.test.js @@ -0,0 +1,87 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; +import { renderWithProvider } from '../../../../test/jest'; +import { + STATUS_CONNECTED, + STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, + STATUS_NOT_CONNECTED, +} from '../../../helpers/constants/connected-sites'; +import { + BackgroundColor, + Color, +} from '../../../helpers/constants/design-system'; +import { MultichainConnectedSiteMenu } from './multichain-connected-site-menu'; + +describe('Multichain Connected Site Menu', () => { + const selectedAddress = '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b'; + + const identities = { + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + name: 'Account 1', + }, + '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + name: 'Account 2', + }, + }; + + const accounts = { + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + balance: '0x0', + }, + '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + balance: '0x0', + }, + }; + const mockStore = { + metamask: { + selectedAddress, + identities, + accounts, + }, + }; + it('should render the site menu in connected state', () => { + const props = { + globalMenuColor: Color.successDefault, + text: 'connected', + status: STATUS_CONNECTED, + }; + const store = configureMockStore()(mockStore); + const { getByTestId, container } = renderWithProvider( + , + store, + ); + expect(getByTestId('connection-menu')).toBeDefined(); + expect(container).toMatchSnapshot(); + }); + it('should render the site menu in not connected state', () => { + const props = { + globalMenuColor: Color.iconAlternative, + status: STATUS_NOT_CONNECTED, + }; + const store = configureMockStore()(mockStore); + const { getByTestId, container } = renderWithProvider( + , + store, + ); + expect(getByTestId('connection-menu')).toBeDefined(); + expect(container).toMatchSnapshot(); + }); + it('should render the site menu in not connected to current account state', () => { + const props = { + globalMenuColor: BackgroundColor.backgroundDefault, + text: 'not connected', + status: STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, + }; + const store = configureMockStore()(mockStore); + const { getByTestId, container } = renderWithProvider( + , + store, + ); + expect(getByTestId('connection-menu')).toBeDefined(); + expect(container).toMatchSnapshot(); + }); +});