From efc34b94203934d7f4ba87048fcc6d5c1f8f65a6 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Wed, 29 Mar 2023 11:14:38 -0500 Subject: [PATCH 1/2] UX: Multichain: Address Copy Button (#18153) --- .../address-copy-button.js | 64 +++++++++++++++++++ .../address-copy-button.stories.js | 36 +++++++++++ .../address-copy-button.test.js | 31 +++++++++ .../multichain/address-copy-button/index.js | 1 + .../multichain/address-copy-button/index.scss | 7 ++ ui/components/multichain/index.js | 1 + .../multichain/multichain-components.scss | 1 + ui/components/ui/qr-code/qr-code.js | 44 +++++++------ 8 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 ui/components/multichain/address-copy-button/address-copy-button.js create mode 100644 ui/components/multichain/address-copy-button/address-copy-button.stories.js create mode 100644 ui/components/multichain/address-copy-button/address-copy-button.test.js create mode 100644 ui/components/multichain/address-copy-button/index.js create mode 100644 ui/components/multichain/address-copy-button/index.scss diff --git a/ui/components/multichain/address-copy-button/address-copy-button.js b/ui/components/multichain/address-copy-button/address-copy-button.js new file mode 100644 index 000000000..f88fabdd8 --- /dev/null +++ b/ui/components/multichain/address-copy-button/address-copy-button.js @@ -0,0 +1,64 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import { ICON_NAMES, ButtonBase } from '../../component-library'; +import { + BackgroundColor, + TextVariant, + TextColor, + Size, + BorderRadius, + AlignItems, +} from '../../../helpers/constants/design-system'; +import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard'; +import { shortenAddress } from '../../../helpers/utils/util'; +import Tooltip from '../../ui/tooltip/tooltip'; +import { useI18nContext } from '../../../hooks/useI18nContext'; + +export const AddressCopyButton = ({ + address, + shorten = false, + wrap = false, +}) => { + const displayAddress = shorten ? shortenAddress(address) : address; + const [copied, handleCopy] = useCopyToClipboard(); + const t = useI18nContext(); + + return ( + + handleCopy(address)} + paddingRight={4} + paddingLeft={4} + size={Size.SM} + variant={TextVariant.bodyXs} + color={TextColor.primaryDefault} + endIconName={copied ? ICON_NAMES.COPY_SUCCESS : ICON_NAMES.COPY} + className={classnames('multichain-address-copy-button', { + 'multichain-address-copy-button__address--wrap': wrap, + })} + borderRadius={BorderRadius.pill} + alignItems={AlignItems.center} + data-testid="address-copy-button-text" + > + {displayAddress} + + + ); +}; + +AddressCopyButton.propTypes = { + /** + * Address to be copied + */ + address: PropTypes.string.isRequired, + /** + * Represents if the address should be shortened + */ + shorten: PropTypes.bool, + /** + * Represents if the element should wrap to multiple lines + */ + wrap: PropTypes.bool, +}; diff --git a/ui/components/multichain/address-copy-button/address-copy-button.stories.js b/ui/components/multichain/address-copy-button/address-copy-button.stories.js new file mode 100644 index 000000000..869bfec25 --- /dev/null +++ b/ui/components/multichain/address-copy-button/address-copy-button.stories.js @@ -0,0 +1,36 @@ +import React from 'react'; +import { AddressCopyButton } from '.'; + +export default { + title: 'Components/Multichain/AddressCopyButton', + component: AddressCopyButton, + argTypes: { + address: { + control: 'text', + }, + shorten: { + control: 'boolean', + }, + wrap: { + control: 'boolean', + }, + }, + args: { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + }, +}; + +export const DefaultStory = (args) => ; +DefaultStory.storyName = 'Default'; + +export const ShortenedStory = (args) => ; +ShortenedStory.storyName = 'Shortened'; +ShortenedStory.args = { shorten: true }; + +export const WrappedStory = (args) => ( +
+ +
+); +WrappedStory.storyName = 'Wrapped'; +WrappedStory.args = { wrap: true }; diff --git a/ui/components/multichain/address-copy-button/address-copy-button.test.js b/ui/components/multichain/address-copy-button/address-copy-button.test.js new file mode 100644 index 000000000..a885fe45d --- /dev/null +++ b/ui/components/multichain/address-copy-button/address-copy-button.test.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import { AddressCopyButton } from '.'; + +const SAMPLE_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; + +describe('AccountListItem', () => { + it('renders the full address by default', () => { + render(); + expect( + document.querySelector('[data-testid="address-copy-button-text"]') + .textContent, + ).toStrictEqual(SAMPLE_ADDRESS); + }); + + it('renders a shortened address when it should', () => { + render(); + expect( + document.querySelector('[data-testid="address-copy-button-text"]') + .textContent, + ).toStrictEqual('0x0dc...e7bc'); + }); + + it('changes icon when clicked', () => { + render(); + fireEvent.click(document.querySelector('button')); + expect(document.querySelector('.mm-icon').style.maskImage).toContain( + 'copy-success.svg', + ); + }); +}); diff --git a/ui/components/multichain/address-copy-button/index.js b/ui/components/multichain/address-copy-button/index.js new file mode 100644 index 000000000..8b93ba9b9 --- /dev/null +++ b/ui/components/multichain/address-copy-button/index.js @@ -0,0 +1 @@ +export { AddressCopyButton } from './address-copy-button'; diff --git a/ui/components/multichain/address-copy-button/index.scss b/ui/components/multichain/address-copy-button/index.scss new file mode 100644 index 000000000..12226fec1 --- /dev/null +++ b/ui/components/multichain/address-copy-button/index.scss @@ -0,0 +1,7 @@ +.multichain-address-copy-button { + &__address--wrap { + word-break: break-word; + min-height: 32px; + height: auto; + } +} diff --git a/ui/components/multichain/index.js b/ui/components/multichain/index.js index 29562dc83..edf6785b9 100644 --- a/ui/components/multichain/index.js +++ b/ui/components/multichain/index.js @@ -5,3 +5,4 @@ export { DetectedTokensBanner } from './detected-token-banner'; 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'; diff --git a/ui/components/multichain/multichain-components.scss b/ui/components/multichain/multichain-components.scss index e8ee40ffa..8fe555f0b 100644 --- a/ui/components/multichain/multichain-components.scss +++ b/ui/components/multichain/multichain-components.scss @@ -4,6 +4,7 @@ * This will help improve specificity and reduce the chance of * unintended overrides. **/ +@import 'address-copy-button/index'; @import 'account-list-item/index'; @import 'account-list-menu/index'; @import 'multichain-token-list-item/multichain-token-list-item'; diff --git a/ui/components/ui/qr-code/qr-code.js b/ui/components/ui/qr-code/qr-code.js index 758620092..995424c5f 100644 --- a/ui/components/ui/qr-code/qr-code.js +++ b/ui/components/ui/qr-code/qr-code.js @@ -8,6 +8,8 @@ import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils import Tooltip from '../tooltip'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { Icon, ICON_NAMES, ICON_SIZES } from '../../component-library'; +import { AddressCopyButton } from '../../multichain/address-copy-button'; +import Box from '../box/box'; export default connect(mapStateToProps)(QrCodeView); @@ -56,25 +58,31 @@ function QrCodeView(props) { __html: qrImage.createTableTag(4), }} /> - -
{ - handleCopy(toChecksumHexAddress(data)); - }} + {process.env.MULTICHAIN ? ( + + + + ) : ( + -
{toChecksumHexAddress(data)}
- -
-
+
{ + handleCopy(toChecksumHexAddress(data)); + }} + > +
{toChecksumHexAddress(data)}
+ +
+ + )} ); } From 60528413813ea913a7a4805cbb54ed272b57d31c Mon Sep 17 00:00:00 2001 From: David Walsh Date: Wed, 29 Mar 2023 12:44:04 -0500 Subject: [PATCH 2/2] Fix breaking jest test for MMI (#18365) * Fix breaking jest test for MMI * Bump coverage threshold --------- Co-authored-by: Elliot Winkler Co-authored-by: PeterYinusa --- coverage-targets.js | 6 +++--- .../__snapshots__/compliance-settings.test.js.snap | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/coverage-targets.js b/coverage-targets.js index e221e9466..6157a706d 100644 --- a/coverage-targets.js +++ b/coverage-targets.js @@ -6,10 +6,10 @@ // subset of files to check against these targets. module.exports = { global: { - lines: 65, + lines: 65.5, branches: 53.5, - statements: 64, - functions: 57.4, + statements: 64.75, + functions: 58, }, transforms: { branches: 100, diff --git a/ui/components/institutional/compliance-settings/__snapshots__/compliance-settings.test.js.snap b/ui/components/institutional/compliance-settings/__snapshots__/compliance-settings.test.js.snap index bddb1ef05..946a5a7f5 100644 --- a/ui/components/institutional/compliance-settings/__snapshots__/compliance-settings.test.js.snap +++ b/ui/components/institutional/compliance-settings/__snapshots__/compliance-settings.test.js.snap @@ -44,17 +44,17 @@ exports[`Compliance Settings shows start btn when Compliance its not activated 1 class="box institutional-feature__content box--flex-direction-row" >

DeFi raises AML/CFT risk for institutions, given the decentralised pools and pseudonymous counterparties.

Codefi Compliance is the only product capable of running AML/CFT analysis on DeFi pools. This allows you to identify and avoid pools and counterparties that fail your risk setting.

Steps to enable AML/CFT Compliance: