Skip to content

Commit

Permalink
fix(payment): CHECKOUT-5161 Re-initialise credit card form after dele…
Browse files Browse the repository at this point in the history
…ting last stored card
  • Loading branch information
davidchin committed Sep 14, 2020
1 parent 8c0d274 commit 306ae2a
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
33 changes: 31 additions & 2 deletions src/app/payment/paymentMethod/CreditCardPaymentMethod.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createCheckoutService, CheckoutSelectors, CheckoutService } from '@bigcommerce/checkout-sdk';
import { mount, ReactWrapper } from 'enzyme';
import { EventEmitter } from 'events';
import { Formik } from 'formik';
import { noop } from 'lodash';
import { merge, noop } from 'lodash';
import React, { FunctionComponent } from 'react';
import { object, string, Schema } from 'yup';

Expand Down Expand Up @@ -36,6 +37,7 @@ describe('CreditCardPaymentMethod', () => {
let initialValues: CreditCardPaymentMethodValues;
let localeContext: LocaleContextType;
let paymentContext: PaymentContextProps;
let subscribeEventEmitter: EventEmitter;
let CreditCardPaymentMethodTest: FunctionComponent<CreditCardPaymentMethodProps>;

beforeEach(() => {
Expand Down Expand Up @@ -66,13 +68,15 @@ describe('CreditCardPaymentMethod', () => {
isSubmitted: false,
setSubmitted: jest.fn(),
};
subscribeEventEmitter = new EventEmitter();

jest.spyOn(checkoutService, 'getState')
.mockReturnValue(checkoutState);

jest.spyOn(checkoutService, 'subscribe')
.mockImplementation(subscriber => {
subscriber(checkoutState);
subscribeEventEmitter.on('change', () => subscriber(checkoutState));
subscribeEventEmitter.emit('change');

return noop;
});
Expand Down Expand Up @@ -324,5 +328,30 @@ describe('CreditCardPaymentMethod', () => {
expect(component.find(CreditCardFieldset))
.toHaveLength(1);
});

it('switches to "use new card" view if all instruments are deleted', () => {
const component = mount(<CreditCardPaymentMethodTest { ...defaultProps } />);

expect(component.find(CreditCardFieldset))
.toHaveLength(0);

// Update state
checkoutState = merge({}, checkoutState, {
data: {
getInstruments: jest.fn(() => []),
},
});

subscribeEventEmitter.emit('change');

component.find(CardInstrumentFieldset)
// tslint:disable-next-line:no-non-null-assertion
.prop('onDeleteInstrument')!(getInstruments()[0].bigpayToken);

component.update();

expect(component.find(CreditCardFieldset))
.toHaveLength(1);
});
});
});
21 changes: 21 additions & 0 deletions src/app/payment/paymentMethod/CreditCardPaymentMethod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class CreditCardPaymentMethod extends Component<
<div className="paymentMethod paymentMethod--creditCard">
{ shouldShowInstrumentFieldset && <CardInstrumentFieldset
instruments={ instruments }
onDeleteInstrument={ this.handleDeleteInstrument }
onSelectInstrument={ this.handleSelectInstrument }
onUseNewInstrument={ this.handleUseNewCard }
selectedInstrumentId={ selectedInstrument && selectedInstrument.bigpayToken }
Expand Down Expand Up @@ -271,6 +272,26 @@ class CreditCardPaymentMethod extends Component<
selectedInstrumentId: id,
});
};

private handleDeleteInstrument: (id: string) => void = id => {
const { instruments, formik: { setFieldValue } } = this.props;
const { selectedInstrumentId } = this.state;

if (instruments.length === 0) {
this.setState({
isAddingNewCard: true,
selectedInstrumentId: undefined,
});

setFieldValue('instrumentId', '');
} else if (selectedInstrumentId === id) {
this.setState({
selectedInstrumentId: this.getDefaultInstrumentId(),
});

setFieldValue('instrumentId', this.getDefaultInstrumentId());
}
};
}

const mapFromCheckoutProps: MapToPropsFactory<
Expand Down
8 changes: 7 additions & 1 deletion src/app/payment/storedInstrument/CardInstrumentFieldset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface CardInstrumentFieldsetProps {
selectedInstrumentId?: string;
shouldHideExpiryDate?: boolean;
validateInstrument?: React.ReactNode;
onDeleteInstrument?(instrumentId: string): void;
onSelectInstrument(id: string): void;
onUseNewInstrument(): void;
}
Expand All @@ -26,6 +27,7 @@ export type CardInstrumentFieldsetValues = {

const CardInstrumentFieldset: FunctionComponent<CardInstrumentFieldsetProps> = ({
instruments,
onDeleteInstrument,
onSelectInstrument,
onUseNewInstrument,
selectedInstrumentId,
Expand All @@ -52,9 +54,13 @@ const CardInstrumentFieldset: FunctionComponent<CardInstrumentFieldsetProps> = (
const renderModal = useCallback((props: ModalTriggerModalProps) => (
<ManageInstrumentsModal
instruments={ instruments }
onDeleteInstrument={ onDeleteInstrument }
{ ...props }
/>
), [instruments]);
), [
instruments,
onDeleteInstrument,
]);

return <Fieldset
additionalClassName="instrumentFieldset"
Expand Down
4 changes: 3 additions & 1 deletion src/app/payment/storedInstrument/ManageInstrumentsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface ManageInstrumentsModalProps {
isOpen: boolean;
instruments: PaymentInstrument[];
onAfterOpen?(): void;
onDeleteInstrument?(instrumentId: string): void;
onDeleteInstrumentError?(error: Error): void;
onRequestClose?(): void;
}
Expand Down Expand Up @@ -165,7 +166,7 @@ class ManageInstrumentsModal extends Component<ManageInstrumentsModalProps & Wit
};

private handleConfirmDelete: () => void = async () => {
const { deleteInstrument, onDeleteInstrumentError = noop, onRequestClose = noop } = this.props;
const { deleteInstrument, onDeleteInstrument = noop, onDeleteInstrumentError = noop, onRequestClose = noop } = this.props;
const { selectedInstrumentId } = this.state;

if (!selectedInstrumentId) {
Expand All @@ -174,6 +175,7 @@ class ManageInstrumentsModal extends Component<ManageInstrumentsModalProps & Wit

try {
await deleteInstrument(selectedInstrumentId);
onDeleteInstrument(selectedInstrumentId);
onRequestClose();
} catch (error) {
onDeleteInstrumentError(error);
Expand Down

0 comments on commit 306ae2a

Please sign in to comment.