Skip to content

Commit

Permalink
Add reject all option to personal sign header (#22942)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpuri authored Mar 19, 2024
1 parent 59e9948 commit 29cf827
Show file tree
Hide file tree
Showing 14 changed files with 469 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { useContext } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory, useParams } from 'react-router-dom';
import {
unconfirmedTransactionsHashSelector,
unapprovedDecryptMsgsSelector,
unapprovedEncryptionPublicKeyMsgsSelector,
unconfirmedTransactionsListSelector,
} from '../../../../../selectors';
import { I18nContext } from '../../../../../contexts/i18n';
import {
Expand All @@ -23,9 +23,8 @@ const ConfirmPageContainerNavigation = () => {
const unapprovedEncryptionPublicKeyMsgs = useSelector(
unapprovedEncryptionPublicKeyMsgsSelector,
);
const unconfirmedTransactions = useSelector(
unconfirmedTransactionsHashSelector,
);
const unconfirmedTransactions =
useSelector(unconfirmedTransactionsListSelector) ?? [];

const enumUnapprovedDecryptMsgsKey = Object.keys(unapprovedDecryptMsgs || {});
const enumUnapprovedEncryptMsgsKey = Object.keys(
Expand All @@ -36,9 +35,9 @@ const ConfirmPageContainerNavigation = () => {
...enumUnapprovedEncryptMsgsKey,
];

const enumUnapprovedTxs = Object.keys(unconfirmedTransactions).filter(
(key) => enumDecryptAndEncryptMsgs.includes(key) === false,
);
const enumUnapprovedTxs = unconfirmedTransactions
.map((tx) => tx.id)
.filter((key) => enumDecryptAndEncryptMsgs.includes(key) === false);

const currentPosition = enumUnapprovedTxs.indexOf(id);

Expand All @@ -54,7 +53,7 @@ const ConfirmPageContainerNavigation = () => {
if (txId) {
dispatch(clearConfirmTransaction());
history.push(
unconfirmedTransactions[txId]?.msgParams
unconfirmedTransactions[currentPosition]?.msgParams
? `${CONFIRM_TRANSACTION_ROUTE}/${txId}${SIGNATURE_REQUEST_PATH}`
: `${CONFIRM_TRANSACTION_ROUTE}/${txId}`,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Footer } from '.';
import Footer from './footer';

const Story = {
title: 'Confirmations/Components/Confirm/Footer',
Expand Down
10 changes: 7 additions & 3 deletions ui/pages/confirmations/components/confirm/footer/footer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import { fireEvent, renderWithProvider } from '../../../../../../test/jest';
import * as Actions from '../../../../../store/actions';
import configureStore from '../../../../../store/store';

import { Footer } from '.';
import Footer from './footer';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => jest.fn(),
}));

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
Expand Down Expand Up @@ -38,8 +43,7 @@ describe('ConfirmFooter', () => {
it('renders the "Cancel" and "Confirm" Buttons', () => {
const { getAllByRole, getByText } = render();
const buttons = getAllByRole('button');
expect(buttons[0]).toBeInTheDocument();
expect(buttons[1]).toBeInTheDocument();
expect(buttons).toHaveLength(2);
expect(getByText('Confirm')).toBeInTheDocument();
expect(getByText('Cancel')).toBeInTheDocument();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ConfirmNav should match snapshot 1`] = `
<div>
<div
class="mm-box mm-box--padding-3 mm-box--display-flex mm-box--flex-direction-row mm-box--justify-content-space-between mm-box--align-items-center mm-box--background-color-background-default"
>
<div
class="mm-box mm-box--display-flex mm-box--align-items-center"
>
<button
aria-label="Previous Confirmation"
class="mm-box mm-button-icon mm-button-icon--size-sm confirm_nav__left_btn mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-alternative mm-box--background-color-background-alternative mm-box--rounded-full"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/arrow-left.svg');"
/>
</button>
<p
class="mm-box mm-text mm-text--body-sm mm-box--margin-inline-2 mm-box--color-text-alternative"
>
2
of
3
</p>
<button
aria-label="Next Confirmation"
class="mm-box mm-button-icon mm-button-icon--size-sm confirm_nav__right_btn mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-alternative mm-box--background-color-background-alternative mm-box--rounded-full"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/arrow-right.svg');"
/>
</button>
</div>
<button
class="mm-box mm-text mm-button-base mm-button-base--size-md confirm_nav__reject_all mm-button-primary mm-text--body-md-medium mm-text--font-weight-normal mm-box--padding-0 mm-box--padding-right-3 mm-box--padding-left-3 mm-box--display-inline-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-xl"
type="secondary"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--margin-inline-end-1 mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/close.svg');"
/>
Reject all
</button>
</div>
</div>
`;
1 change: 1 addition & 0 deletions ui/pages/confirmations/components/confirm/nav/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Nav } from './nav';
31 changes: 31 additions & 0 deletions ui/pages/confirmations/components/confirm/nav/nav.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.confirm_nav {
&__reject_all {
background-color: var(--color-error-muted);
color: #d73847;
font-size: 12px;
height: 20px;
padding-left: 8px !important;
padding-right: 8px !important;

&:hover {
background-color: var(--color-error-muted) !important;
box-shadow: none !important;
color: #d73847 !important;
}

> span {
font-size: 10px;
}
}

&__left_btn,
&__right_btn {
height: 20px;
width: 20px;
min-width: 20px;

& > span {
font-size: 12px;
}
}
}
71 changes: 71 additions & 0 deletions ui/pages/confirmations/components/confirm/nav/nav.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { Provider } from 'react-redux';

import mockState from '../../../../../../test/data/mock-state.json';
import configureStore from '../../../../../store/store';

import Nav from './nav';

const store = configureStore({
metamask: {
...mockState.metamask,
pendingApprovals: {
testApprovalId: {
id: 'testApprovalId',
time: 1528133319641,
origin: 'metamask',
type: 'personal_sign',
requestData: {
txId: 'testTransactionId',
},
requestState: {
test: 'value',
},
},
testApprovalId2: {
id: 'testApprovalId2',
time: 1528133319641,
origin: 'metamask',
type: 'personal_sign',
requestData: {
txId: 'testTransactionId',
},
requestState: {
test: 'value',
},
},
testApprovalId3: {
id: 'testApprovalId3',
time: 1528133319649,
origin: 'metamask',
type: 'personal_sign',
requestData: {
txId: 'testTransactionId',
},
requestState: {
test: 'value',
},
},
},
},
confirm: {
currentConfirmation: {
id: 'testApprovalId2',
msgParams: {
from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
},
},
},
});

const Story = {
title: 'Components/App/Confirm/Nav',
component: Nav,
decorators: [(story: any) => <Provider store={store}>{story()}</Provider>],
};

export default Story;

export const DefaultStory = () => <Nav />;

DefaultStory.storyName = 'Default';
119 changes: 119 additions & 0 deletions ui/pages/confirmations/components/confirm/nav/nav.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React from 'react';

import mockState from '../../../../../../test/data/mock-state.json';
import { fireEvent, renderWithProvider } from '../../../../../../test/jest';
import * as Actions from '../../../../../store/actions';
import configureStore from '../../../../../store/store';

import Nav from './nav';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => jest.fn(),
}));

const mockHistoryReplace = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
replace: mockHistoryReplace,
}),
}));

const render = () => {
const store = configureStore({
metamask: {
...mockState.metamask,
pendingApprovals: {
testApprovalId: {
id: 'testApprovalId',
time: 1528133319641,
origin: 'metamask',
type: 'personal_sign',
requestData: {
txId: 'testTransactionId',
},
requestState: {
test: 'value',
},
},
testApprovalId2: {
id: 'testApprovalId2',
time: 1528133319641,
origin: 'metamask',
type: 'personal_sign',
requestData: {
txId: 'testTransactionId',
},
requestState: {
test: 'value',
},
},
testApprovalId3: {
id: 'testApprovalId3',
time: 1528133319649,
origin: 'metamask',
type: 'personal_sign',
requestData: {
txId: 'testTransactionId',
},
requestState: {
test: 'value',
},
},
},
},
confirm: {
currentConfirmation: {
id: 'testApprovalId2',
msgParams: {
from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
},
},
},
});

return renderWithProvider(<Nav />, store);
};

describe('ConfirmNav', () => {
it('should match snapshot', () => {
const { container } = render();
expect(container).toMatchSnapshot();
});

it('renders the "Reject all" Button', () => {
const { getAllByRole, getByText } = render();
const buttons = getAllByRole('button');
expect(buttons).toHaveLength(3);
expect(getByText('Reject all')).toBeInTheDocument();
});

it('renders button to navigate to previous or next confirmation', () => {
const { getAllByRole, getByLabelText } = render();
const buttons = getAllByRole('button');
expect(buttons).toHaveLength(3);
expect(getByLabelText('Previous Confirmation')).toBeInTheDocument();
expect(getByLabelText('Next Confirmation')).toBeInTheDocument();
});

it('invoke history replace method when previous or next buttons are clicked', () => {
const { getByLabelText } = render();
const prevButton = getByLabelText('Previous Confirmation');
fireEvent.click(prevButton);
expect(mockHistoryReplace).toHaveBeenCalledTimes(1);
const nextButton = getByLabelText('Next Confirmation');
fireEvent.click(nextButton);
expect(mockHistoryReplace).toHaveBeenCalledTimes(2);
});

it('invoke action rejectPendingApproval for all pending approvals when "Reject all" button is clicked', () => {
const { getByRole } = render();
const rejectAllButton = getByRole('button', { name: /Reject all/iu });
const rejectSpy = jest
.spyOn(Actions, 'rejectPendingApproval')
.mockImplementation(() => ({} as any));
fireEvent.click(rejectAllButton);
expect(rejectSpy).toHaveBeenCalledTimes(3);
});
});
Loading

0 comments on commit 29cf827

Please sign in to comment.