1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Changing cancel button labels in send screen when in editing stage (#12056)

* Changing cancel button labels in send screen when in editing stage

* Re-route user to home page when reject is clicked on edit transaction page
This commit is contained in:
Jyoti Puri 2021-09-17 10:07:50 +05:30 committed by GitHub
parent ae84b0cb6d
commit ade9e4ac4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 157 additions and 22 deletions

View File

@ -305,6 +305,9 @@
"cancel": {
"message": "Cancel"
},
"cancelEdit": {
"message": "Cancel Edit"
},
"cancelPopoverTitle": {
"message": "Cancel transaction"
},

View File

@ -1736,6 +1736,10 @@ export function getSendHexData(state) {
return state[name].draftTransaction.userInputHexData;
}
export function getDraftTransactionID(state) {
return state[name].draftTransaction.id;
}
export function sendAmountIsInError(state) {
return Boolean(state[name].amount.error);
}

View File

@ -51,6 +51,7 @@ import sendReducer, {
getSendAmount,
getIsBalanceInsufficient,
getSendMaxModeState,
getDraftTransactionID,
sendAmountIsInError,
getSendHexData,
getSendTo,
@ -2459,6 +2460,21 @@ describe('Send Slice', () => {
).toBe(true);
});
it('has a selector to get the draft transaction ID', () => {
expect(getDraftTransactionID({ send: initialState })).toBeNull();
expect(
getDraftTransactionID({
send: {
...initialState,
draftTransaction: {
...initialState.draftTransaction,
id: 'ID',
},
},
}),
).toBe('ID');
});
it('has a selector to get the user entered hex data', () => {
expect(getSendHexData({ send: initialState })).toBeNull();
expect(

View File

@ -2,7 +2,11 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { isEqual } from 'lodash';
import PageContainerFooter from '../../../components/ui/page-container/page-container-footer';
import { CONFIRM_TRANSACTION_ROUTE } from '../../../helpers/constants/routes';
import {
CONFIRM_TRANSACTION_ROUTE,
DEFAULT_ROUTE,
} from '../../../helpers/constants/routes';
import { SEND_STAGES } from '../../../ducks/send';
export default class SendFooter extends Component {
static propTypes = {
@ -13,9 +17,12 @@ export default class SendFooter extends Component {
sign: PropTypes.func,
to: PropTypes.string,
toAccounts: PropTypes.array,
sendStage: PropTypes.string,
sendErrors: PropTypes.object,
gasEstimateType: PropTypes.string,
mostRecentOverviewPage: PropTypes.string.isRequired,
cancelTx: PropTypes.func,
draftTransactionID: PropTypes.string,
};
static contextTypes = {
@ -24,9 +31,21 @@ export default class SendFooter extends Component {
};
onCancel() {
const { resetSendState, history, mostRecentOverviewPage } = this.props;
const {
cancelTx,
draftTransactionID,
history,
mostRecentOverviewPage,
resetSendState,
sendStage,
} = this.props;
if (draftTransactionID) cancelTx({ id: draftTransactionID });
resetSendState();
history.push(mostRecentOverviewPage);
const nextRoute =
sendStage === SEND_STAGES.EDIT ? DEFAULT_ROUTE : mostRecentOverviewPage;
history.push(nextRoute);
}
async onSubmit(event) {
@ -85,11 +104,14 @@ export default class SendFooter extends Component {
}
render() {
const { t } = this.context;
const { sendStage } = this.props;
return (
<PageContainerFooter
onCancel={() => this.onCancel()}
onSubmit={(e) => this.onSubmit(e)}
disabled={this.props.disabled}
cancelText={sendStage === SEND_STAGES.EDIT ? t('reject') : t('cancel')}
/>
);
}

View File

@ -1,8 +1,12 @@
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import { CONFIRM_TRANSACTION_ROUTE } from '../../../helpers/constants/routes';
import {
CONFIRM_TRANSACTION_ROUTE,
DEFAULT_ROUTE,
} from '../../../helpers/constants/routes';
import PageContainerFooter from '../../../components/ui/page-container/page-container-footer';
import { renderWithProvider } from '../../../../test/jest';
import SendFooter from './send-footer.component';
describe('SendFooter Component', () => {
@ -10,6 +14,7 @@ describe('SendFooter Component', () => {
const propsMethodSpies = {
addToAddressBookIfNew: sinon.spy(),
cancelTx: sinon.spy(),
resetSendState: sinon.spy(),
sign: sinon.spy(),
update: sinon.spy(),
@ -20,31 +25,40 @@ describe('SendFooter Component', () => {
};
const MOCK_EVENT = { preventDefault: () => undefined };
const renderShallow = (props) => {
return shallow(
<SendFooter
addToAddressBookIfNew={propsMethodSpies.addToAddressBookIfNew}
resetSendState={propsMethodSpies.resetSendState}
cancelTx={propsMethodSpies.cancelTx}
disabled
draftTransactionID="ID"
history={historySpies}
sign={propsMethodSpies.sign}
to="mockTo"
toAccounts={['mockAccount']}
sendErrors={{}}
sendStage="DRAFT"
gasEstimateType="BASIC"
mostRecentOverviewPage="mostRecentOverviewPage"
{...props}
/>,
{ context: { t: (str) => str, metricsEvent: () => ({}) } },
);
};
beforeAll(() => {
sinon.spy(SendFooter.prototype, 'onCancel');
sinon.spy(SendFooter.prototype, 'onSubmit');
});
beforeEach(() => {
wrapper = shallow(
<SendFooter
addToAddressBookIfNew={propsMethodSpies.addToAddressBookIfNew}
resetSendState={propsMethodSpies.resetSendState}
disabled
history={historySpies}
sign={propsMethodSpies.sign}
to="mockTo"
toAccounts={['mockAccount']}
sendErrors={{}}
gasEstimateType="BASIC"
mostRecentOverviewPage="mostRecentOverviewPage"
/>,
{ context: { t: (str) => str, metricsEvent: () => ({}) } },
);
wrapper = renderShallow();
});
afterEach(() => {
propsMethodSpies.resetSendState.resetHistory();
propsMethodSpies.cancelTx.resetHistory();
propsMethodSpies.addToAddressBookIfNew.resetHistory();
propsMethodSpies.resetSendState.resetHistory();
propsMethodSpies.sign.resetHistory();
@ -65,6 +79,15 @@ describe('SendFooter Component', () => {
expect(propsMethodSpies.resetSendState.callCount).toStrictEqual(1);
});
it('should call cancelTx', () => {
expect(propsMethodSpies.cancelTx.callCount).toStrictEqual(0);
wrapper.instance().onCancel();
expect(propsMethodSpies.cancelTx.callCount).toStrictEqual(1);
expect(propsMethodSpies.cancelTx.getCall(0).args[0]?.id).toStrictEqual(
'ID',
);
});
it('should call history.push', () => {
expect(historySpies.push.callCount).toStrictEqual(0);
wrapper.instance().onCancel();
@ -73,6 +96,14 @@ describe('SendFooter Component', () => {
'mostRecentOverviewPage',
);
});
it('should call history.push with DEFAULT_ROUTE in edit stage', () => {
wrapper = renderShallow({ sendStage: 'EDIT' });
expect(historySpies.push.callCount).toStrictEqual(0);
wrapper.instance().onCancel();
expect(historySpies.push.callCount).toStrictEqual(1);
expect(historySpies.push.getCall(0).args[0]).toStrictEqual(DEFAULT_ROUTE);
});
});
describe('onSubmit', () => {
@ -107,7 +138,9 @@ describe('SendFooter Component', () => {
addToAddressBookIfNew={propsMethodSpies.addToAddressBookIfNew}
amount="mockAmount"
resetSendState={propsMethodSpies.resetSendState}
cancelTx={propsMethodSpies.cancelTx}
disabled
draftTransactionID="ID"
editingTransactionId="mockEditingTransactionId"
errors={{}}
from={{ address: 'mockAddress', balance: 'mockBalance' }}
@ -147,4 +180,28 @@ describe('SendFooter Component', () => {
expect(SendFooter.prototype.onCancel.callCount).toStrictEqual(1);
});
});
describe('Cancel Button', () => {
const renderFooter = (props) =>
renderWithProvider(
<SendFooter
disabled
mostRecentOverviewPage="mostRecentOverviewPage"
draftTransactionID="ID"
sendErrors={{}}
sendStage="DRAFT"
{...props}
/>,
);
it('has a cancel button in footer', () => {
const { getByText } = renderFooter();
expect(getByText('Cancel')).toBeTruthy();
});
it('has label changed to Reject in editing stage', () => {
const { getByText } = renderFooter({ sendStage: 'EDIT' });
expect(getByText('Reject')).toBeTruthy();
});
});
});

View File

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { addToAddressBook } from '../../../store/actions';
import { addToAddressBook, cancelTx } from '../../../store/actions';
import {
getRenderableEstimateDataForSmallButtonsFromGWEI,
getDefaultActiveButtonIndex,
@ -7,10 +7,12 @@ import {
import {
resetSendState,
getGasPrice,
getSendStage,
getSendTo,
getSendErrors,
isSendFormInvalid,
signTransaction,
getDraftTransactionID,
} from '../../../ducks/send';
import { getMostRecentOverviewPage } from '../../../ducks/history/history';
import { addHexPrefix } from '../../../../app/scripts/lib/util';
@ -43,7 +45,9 @@ function mapStateToProps(state) {
disabled: isSendFormInvalid(state),
to: getSendTo(state),
toAccounts: getSendToAccounts(state),
sendStage: getSendStage(state),
sendErrors: getSendErrors(state),
draftTransactionID: getDraftTransactionID(state),
gasEstimateType,
mostRecentOverviewPage: getMostRecentOverviewPage(state),
};
@ -52,6 +56,7 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
resetSendState: () => dispatch(resetSendState()),
cancelTx: (t) => dispatch(cancelTx(t)),
sign: () => dispatch(signTransaction()),
addToAddressBookIfNew: (newAddress, toAccounts, nickname = '') => {
const hexPrefixedAddress = addHexPrefix(newAddress);

View File

@ -1,6 +1,6 @@
import sinon from 'sinon';
import { addToAddressBook } from '../../../store/actions';
import { addToAddressBook, cancelTx } from '../../../store/actions';
import { resetSendState, signTransaction } from '../../../ducks/send';
let mapDispatchToProps;
@ -14,6 +14,7 @@ jest.mock('react-redux', () => ({
jest.mock('../../../store/actions.js', () => ({
addToAddressBook: jest.fn(),
cancelTx: jest.fn(),
}));
jest.mock('../../../ducks/metamask/metamask', () => ({
@ -24,6 +25,8 @@ jest.mock('../../../ducks/send', () => ({
getGasPrice: (s) => `mockGasPrice:${s}`,
getSendTo: (s) => `mockTo:${s}`,
getSendErrors: (s) => `mockSendErrors:${s}`,
getSendStage: (s) => `mockStage:${s}`,
getDraftTransaction: (s) => ({ id: `draftTransaction:${s}` }),
resetSendState: jest.fn(),
signTransaction: jest.fn(),
}));
@ -53,6 +56,16 @@ describe('send-footer container', () => {
});
});
describe('cancelTx()', () => {
it('should dispatch an action', () => {
const draftTansaction = { id: 'ID' };
mapDispatchToPropsObject.cancelTx(draftTansaction);
expect(dispatchSpy.calledOnce).toStrictEqual(true);
expect(cancelTx).toHaveBeenCalledTimes(1);
expect(cancelTx).toHaveBeenCalledWith(draftTansaction);
});
});
describe('sign()', () => {
it('should dispatch a signTransaction action', () => {
mapDispatchToPropsObject.sign();

View File

@ -38,7 +38,9 @@ export default function SendHeader() {
className="send__header"
onClose={onClose}
title={title}
headerCloseText={t('cancel')}
headerCloseText={
stage === SEND_STAGES.EDIT ? t('cancelEdit') : t('cancel')
}
/>
);
}

View File

@ -103,6 +103,18 @@ describe('SendHeader Component', () => {
expect(getByText('Cancel')).toBeTruthy();
});
it('has button label changed to Cancel Edit in editing stage', () => {
const { getByText } = renderWithProvider(
<SendHeader />,
configureMockStore(middleware)({
send: { ...initialState, stage: SEND_STAGES.EDIT },
gas: { basicEstimateStatus: 'LOADING' },
history: { mostRecentOverviewPage: 'activity' },
}),
);
expect(getByText('Cancel Edit')).toBeTruthy();
});
it('resets send state when clicked', () => {
const store = configureMockStore(middleware)({
send: initialState,

View File

@ -22,6 +22,7 @@
right: 1rem;
width: min-content;
font-size: 0.75rem;
white-space: nowrap;
}
}