1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

[MMI] Added confirm-remove-jwt component (#18186)

* Added confirm-remove-jwt component

* changing folder directory

* Fixed lint issues

* Added story

* Fixed confirm remove jwt imports

* Fixed import

* Finished implementing component

* Fixed capitalize eslint problem

* Fixed PR suggestions

* Changed CustodyAccountList import

* updated snapshot

* Fixed typo

* Moved folder to confirm-remove-jwt-modal

* added index

* Adding filter first
This commit is contained in:
Albert Olivé 2023-04-28 11:01:40 +02:00 committed by GitHub
parent 9d794e97b3
commit 49f01406c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 404 additions and 5 deletions

View File

@ -103,9 +103,6 @@
"SIWEWarningTitle": {
"message": "Are you sure?"
},
"ShowMore": {
"message": "Show more"
},
"about": {
"message": "About"
},
@ -3278,6 +3275,12 @@
"removeAccountDescription": {
"message": "This account will be removed from your wallet. Please make sure you have the original Secret Recovery Phrase or private key for this imported account before continuing. You can import or create accounts again from the account drop-down. "
},
"removeJWT": {
"message": "Remove custodian token"
},
"removeJWTDescription": {
"message": "Are you sure you want to remove this token? All accounts assigned to this token will be removed from extension as well: "
},
"removeNFT": {
"message": "Remove NFT"
},
@ -3661,6 +3664,9 @@
"message": "This relies on $1 which will have access to your Ethereum address and your IP address. $2",
"description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs"
},
"showMore": {
"message": "Show more"
},
"showPermissions": {
"message": "Show permissions"
},

View File

@ -106,6 +106,7 @@
@import 'approve-content-card/index';
@import 'transaction-alerts/transaction-alerts';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
@import '../institutional/confirm-remove-jwt-modal/index';
@import '../institutional/custody-confirm-link-modal/index';
@import '../institutional/transaction-failed-modal/index';
///: END:ONLY_INCLUDE_IN

View File

@ -0,0 +1,151 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Confirm Remove JWT should render correctly 1`] = `
<div>
<div
class="modal-container"
>
<div
class="modal-container__header"
>
<div
class="modal-container__header-text"
>
Remove custodian token?
</div>
<div
class="modal-container__header-close"
data-testid="modal-header-close"
/>
</div>
<div
class="modal-container__content"
>
<div
class="box confirm-action-jwt__jwt box--padding-2 box--display-flex box--flex-direction-row box--rounded-sm"
>
...Dce07538D
</div>
<p
class="box mm-text confirm-action-jwt__show-more mm-text--body-md box--margin-left-2 box--flex-direction-row box--color-goerli"
>
<a
rel="noopener noreferrer"
>
Show more
</a>
</p>
<h6
class="box mm-text mm-text--body-sm mm-text--text-align-center box--margin-top-2 box--flex-direction-row box--color-text-default"
>
Are you sure you want to remove this token? All accounts assigned to this token will be removed from extension as well:
</h6>
<div
class="box confirm-action-jwt__accounts-list box--flex-direction-row"
>
<div
class="box box--padding-top-4 box--padding-right-7 box--padding-bottom-7 box--padding-left-7 box--flex-direction-row"
>
<div
class="box custody-account-list box--display-flex box--flex-direction-column box--width-full"
data-testid="custody-account-list"
>
<div
class="box custody-account-list__item box--display-flex box--flex-direction-row"
>
<div
class="box box--display-flex box--flex-direction-row box--align-items-flex-start"
data-testid="custody-account-list-item-radio-button"
/>
<div
class="box box--margin-left-2 box--display-flex box--flex-direction-column box--width-full"
>
<label
class="box mm-text mm-label mm-label--html-for custody-account-list__item__title mm-text--body-md mm-text--font-weight-bold box--margin-top-2 box--margin-left-2 box--display-flex box--flex-direction-row box--align-items-center box--color-text-default"
for="address-0"
>
<span
class="box mm-text custody-account-list__item__name mm-text--inherit box--padding-right-1 box--flex-direction-row box--color-text-default"
>
Test name account
</span>
</label>
<label
class="box mm-text mm-label mm-label--html-for mm-text--body-md mm-text--font-weight-bold box--margin-top-2 box--margin-right-3 box--margin-left-2 box--display-flex box--flex-direction-row box--align-items-center box--color-text-default"
for="address-0"
>
<span
class="box mm-text custody-account-list__item mm-text--body-md box--display-flex box--flex-direction-row box--color-text-default"
>
<a
class="box mm-text mm-button-base mm-button-link mm-button-link--size-auto mm-text--body-md box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-default box--background-color-transparent"
href="https://etherscan.io/address/0xaD6D458402F60fD3Bd25163575031ACDce07538D"
rel="noopener noreferrer"
target="_blank"
>
<span
class="box mm-text mm-text--inherit box--flex-direction-row box--color-primary-default"
>
0xaD6...538D
<span
class="box mm-icon mm-icon--size-md box--margin-left-1 box--display-inline-block box--flex-direction-row box--color-primary-default"
style="mask-image: url('./images/icons/undefined.svg');"
/>
</span>
</a>
<div>
<div
aria-describedby="tippy-tooltip-1"
class=""
data-original-title="Copy to clipboard"
data-tooltipped=""
style="display: inline; background-color: transparent;"
tabindex="0"
>
<button
class="custody-account-list__item__clipboard"
>
<span
class="box mm-icon mm-icon--size-md box--display-inline-block box--flex-direction-row box--color-icon-muted"
style="mask-image: url('./images/icons/undefined.svg');"
/>
</button>
</div>
</div>
</span>
</label>
<div
class="box box--display-flex box--flex-direction-row box--justify-content-space-between"
>
<label
class="box mm-text mm-label mm-label--html-for mm-text--body-md mm-text--font-weight-bold box--display-flex box--flex-direction-row box--align-items-center box--color-text-default"
for="address-0"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="modal-container__footer"
>
<button
class="button btn--rounded btn-secondary modal-container__footer-button"
role="button"
tabindex="0"
>
Nevermind
</button>
<button
class="button btn--rounded btn-primary modal-container__footer-button"
role="button"
tabindex="0"
>
Remove
</button>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,125 @@
import React, { memo, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch } from 'react-redux';
import Modal from '../../app/modal';
import CustodyAccountList from '../../../pages/institutional/connect-custody/account-list';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { removeAccount } from '../../../store/actions';
import withModalProps from '../../../helpers/higher-order-components/with-modal-props';
import { Text } from '../../component-library';
import Box from '../../ui/box';
import {
BorderRadius,
DISPLAY,
TEXT_ALIGN,
TextColor,
TextVariant,
} from '../../../helpers/constants/design-system';
const ConfirmRemoveJWT = ({
custodyAccountDetails,
accounts,
token,
hideModal,
}) => {
const t = useI18nContext();
const dispatch = useDispatch();
const [showMore, setShowMore] = useState(false);
const [tokenAccounts, setTokenAccounts] = useState([]);
useEffect(() => {
const lowercasedTokenAddress = token.address.toLowerCase();
const filteredAccounts = custodyAccountDetails.filter((item) => {
const addressLower = item.address.toLowerCase();
return accounts.find((acc) => acc.address.toLowerCase() === addressLower);
});
const tokens = filteredAccounts
.filter(({ authDetails }) => {
const getToken =
authDetails?.token ?? authDetails?.jwt ?? authDetails?.refreshToken;
return getToken?.toLowerCase() === lowercasedTokenAddress;
})
.map(({ address, name, labels, authDetails }) => {
const lowercasedAddress = address.toLowerCase();
const account = accounts.find(
({ address: adressAcc }) =>
adressAcc.toLowerCase() === lowercasedAddress,
);
const balance = account?.balance;
const getToken =
authDetails?.token ?? authDetails?.jwt ?? authDetails?.refreshToken;
return { address, name, labels, balance, token: getToken };
});
setTokenAccounts(tokens);
}, [accounts, custodyAccountDetails, token]);
const handleRemove = async () => {
try {
for (const account of tokenAccounts) {
await dispatch(removeAccount(account.address.toLowerCase()));
}
hideModal();
} catch (error) {
console.error(error);
}
};
const handleShowMore = () => {
setShowMore(true);
};
return (
<Modal
headerText={`${t('removeJWT')}?`}
onClose={hideModal}
onSubmit={handleRemove}
onCancel={hideModal}
submitText={t('remove')}
cancelText={t('nevermind')}
submitType="primary"
>
<Box
display={DISPLAY.FLEX}
padding={2}
borderRadius={BorderRadius.SM}
className="confirm-action-jwt__jwt"
>
{showMore && token ? token.address : `...${token.address.slice(-9)}`}
</Box>
{!showMore && (
<Text
color={TextColor.goerli}
marginLeft={2}
className="confirm-action-jwt__show-more"
>
<a rel="noopener noreferrer" onClick={handleShowMore}>
{t('showMore')}
</a>
</Text>
)}
<Text
as="h6"
textAlign={TEXT_ALIGN.CENTER}
variant={TextVariant.bodySm}
marginTop={2}
>
{t('removeJWTDescription')}
</Text>
<Box className="confirm-action-jwt__accounts-list">
<CustodyAccountList accounts={tokenAccounts} rawList />
</Box>
</Modal>
);
};
ConfirmRemoveJWT.propTypes = {
hideModal: PropTypes.func.isRequired,
token: PropTypes.object.isRequired,
custodyAccountDetails: PropTypes.array.isRequired,
accounts: PropTypes.array.isRequired,
};
export default withModalProps(memo(ConfirmRemoveJWT));

View File

@ -0,0 +1,31 @@
import React from 'react';
import ConfirmRemoveJWT from '.';
export default {
title: 'Components/Institutional/ConfirmRemoveJWT',
component: ConfirmRemoveJWT,
args: {
hideModal: () => {
/**/
},
removeAccount: () => {
/**/
},
token: { address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D' },
custodyAccountDetails: [
{
address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D',
name: 'Test name account',
labels: [],
authDetails: { token: '0xaD6D458402F60fD3Bd25163575031ACDce07538D' },
},
],
accounts: [
{ address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D', balance: '0x0' },
],
},
};
export const DefaultStory = (args) => <ConfirmRemoveJWT {...args} />;
DefaultStory.storyName = 'ConfirmRemoveJWT';

View File

@ -0,0 +1,71 @@
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import testData from '../../../../.storybook/test-data';
import ConfirmRemoveJwt from '.';
const mockedRemoveAccount = jest.fn();
const mockedHideModal = jest.fn();
jest.mock('../../../store/actions', () => ({
removeAccount: () => mockedRemoveAccount,
hideModal: () => mockedHideModal,
}));
const address = '0xaD6D458402F60fD3Bd25163575031ACDce07538D';
const props = {
hideModal: mockedHideModal,
token: { address },
custodyAccountDetails: [
{
address,
name: 'Test name account',
labels: [],
authDetails: { token: address },
},
],
accounts: [{ address, balance: '0x0' }],
};
const mockStore = {
...testData,
metamask: {},
};
const middleware = [thunk];
const store = configureMockStore(middleware)(mockStore);
const render = () => {
return renderWithProvider(<ConfirmRemoveJwt {...props} />, store);
};
describe('Confirm Remove JWT', function () {
it('should render correctly', () => {
const { container } = render();
expect(container).toMatchSnapshot();
});
it('should show full token address when "show more" is clicked', () => {
const { getByText } = render();
const showMoreLink = getByText('Show more');
fireEvent.click(showMoreLink);
const fullTokenAddress = getByText(address);
expect(fullTokenAddress).toBeInTheDocument();
});
it('dispatches removeAccount action when user clicks remove button', async () => {
const { getByText } = render();
const removeButton = getByText('Remove');
fireEvent.click(removeButton);
await waitFor(() => expect(mockedRemoveAccount).toHaveBeenCalled());
expect(mockedHideModal).toHaveBeenCalled();
});
});

View File

@ -0,0 +1 @@
export { default } from './confirm-remove-jwt-modal';

View File

@ -0,0 +1,13 @@
.confirm-action-jwt {
&__jwt {
border: 1px solid var(--color-border-muted);
}
&__show-more {
cursor: pointer;
}
&__accounts-list {
margin-left: -5%;
}
}

View File

@ -79,7 +79,7 @@ const ConfirmAddCustodianToken = () => {
setShowMore(true);
}}
>
{t('ShowMore')}
{t('showMore')}
</ButtonLink>
</Box>
)}

View File

@ -34,7 +34,7 @@ export default function CustodyAccountList({
rawList,
accounts,
onAccountChange,
selectedAccounts,
selectedAccounts = {},
onCancel,
onAddAccounts,
custody,