Skip to content

Commit

Permalink
PON-281: SDN error handling (#759)
Browse files Browse the repository at this point in the history
* feat: fixed the program_tile italic and subscribe checkout state

* feat: added SDN error check with feedback saga

* test: fixed borken tests

* test: removed the screen.debug call

* feat: do not display any error alert on the checkout page for sdn

* fix: fixed the config name for feedback saga alert
  • Loading branch information
mrazadar authored Jun 12, 2023
1 parent 75104bc commit 1eb1793
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 15 deletions.
44 changes: 35 additions & 9 deletions src/feedback/data/sagas.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { put } from 'redux-saga/effects';
import { getConfig, ensureConfig } from '@edx/frontend-platform';

import { logError, logInfo } from '@edx/frontend-platform/logging';
import { addMessage, clearMessages } from './actions';
import { MESSAGE_TYPES } from './constants';

ensureConfig(['ECOMMERCE_BASE_URL'], 'Alert saga');

export function* handleErrors(e, clearExistingMessages) {
if (clearExistingMessages) {
yield put(clearMessages());
Expand Down Expand Up @@ -56,6 +59,25 @@ export function* handleMessages(messages, clearExistingMessages, url) {
return null;
}

/**
* handleSDNCheckFailure
* log the SDN check failure error message
* and redirect user to SDN failure page
*/
const handleSDNCheckFailure = (error) => {
const setLocation = href => { global.location.href = href; };
logError(error, {
messagePrefix: 'SDN Check Error',
paymentMethod: 'Stripe',
paymentErrorType: 'SDN Check Submit Api',
program_uuid: error?.data?.program_uuid,
});
if (getConfig().ENVIRONMENT !== 'test') {
// SDN failure: redirect to Ecommerce SDN error page.
setLocation(`${getConfig().ECOMMERCE_BASE_URL}/payment/sdn/failure/`);
}
};

/**
* Handle Subscription Errors
*/
Expand All @@ -70,15 +92,19 @@ export function* handleSubscriptionErrors(e, clearExistingMessages) {
if (e.errors !== undefined) {
for (let i = 0; i < e.errors.length; i++) { // eslint-disable-line no-plusplus
const error = e.errors[i];
const customErrors = [
'empty_subscription',
'embargo_error',
'basket_changed_error',
'program_unavailable',
'ineligible_program',
'payment_attachment_error',
];
if (error.code !== 'empty_subscription') {
if (error.code === 'sdn_check_failure') {
handleSDNCheckFailure(error);
} else if (error.code === 'empty_subscription') {
// do nothing as empty placeholder message will be rendered by Subscription Page
} else {
const customErrors = [
'embargo_error',
'basket_changed_error',
'program_unavailable',
'ineligible_program',
'payment_attachment_error',
];

if (customErrors.includes(error.code)) {
if (error.code !== 'create-paymentMethod') { // already logged error
logInfo('API Error', error.code);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ const SubscriptionSubmitButton = ({
if (disabled) { submitButtonState = 'disabled'; }
if (isProcessing) { submitButtonState = 'processing'; }
// handle submitted state
if (status === 'trialing' || status === 'succeeded') { submitButtonState = 'success'; }
if (status === 'trialing' || status === 'succeeded') {
submitButtonState = 'success';
}

return (
<div className="col-lg-7 col-xl-6 form-group float-right">
Expand All @@ -27,7 +29,7 @@ const SubscriptionSubmitButton = ({
<StatefulButton
type="submit"
id="placeOrderButton"
variant={(status === 'success' || status === 'trialing') ? 'success' : 'brand'}
variant={(status === 'succeeded' || status === 'trialing') ? 'success' : 'brand'}
size="md"
block
state={submitButtonState}
Expand Down
2 changes: 1 addition & 1 deletion src/subscription/confirmation-modal/ConfirmationModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const ConfirmationModal = () => {
<ModalDialog.Title as="h3">
{
intl.formatMessage(messages[`subscription.confirmation.modal.${subscriptionState}.heading`], {
programTitle,
programTitle: <i>{programTitle}</i>,
})
}
</ModalDialog.Title>
Expand Down
16 changes: 14 additions & 2 deletions src/subscription/confirmation-modal/ConfirmationModal.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ import { subscriptionStatusReceived } from '../data/status/actions';

import { camelCaseObject } from '../../payment/data/utils';

function getCustomTextContent(content, node) {
// eslint-disable-next-line no-shadow
// The textContent property sets or returns the text content of the specified node, and all its descendants.
const hasText = (elem) => elem.textContent === this.searchFor;
const nodeHasText = hasText(node);
const childrenDontHaveText = Array.from(node.children).every(
(child) => !hasText(child),
);

return nodeHasText && childrenDontHaveText;
}

/**
* ConfirmationModal Test
*/
Expand Down Expand Up @@ -43,7 +55,7 @@ describe('<ConfirmationModal />', () => {
);
store.dispatch(fetchSubscriptionDetails.fulfill());
});
const heading = getByText(`Congratulations! Your subscription to ${subscriptionDetails.programTitle} has started.`);
const heading = getByText(getCustomTextContent.bind({ searchFor: `Congratulations! Your subscription to ${subscriptionDetails.programTitle} has started.` }));
expect(heading).toBeInTheDocument();
});

Expand All @@ -62,7 +74,7 @@ describe('<ConfirmationModal />', () => {
store.dispatch(fetchSubscriptionDetails.fulfill());
});

const heading = getByText(`Congratulations! Your 7-day free trial of ${subscriptionDetails.programTitle} has started.`);
const heading = getByText(getCustomTextContent.bind({ searchFor: `Congratulations! Your 7-day free trial of ${subscriptionDetails.programTitle} has started.` }));
expect(heading).toBeInTheDocument();

const gotoDashboardLink = getByRole('link', { name: 'Go to dashboard' });
Expand Down
3 changes: 2 additions & 1 deletion src/subscription/data/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function handleDetailsApiError(requestError) {
errors.push({
code: error_code,
userMessage: user_message,
data: this?.payload,
});
}
const apiError = new Error();
Expand All @@ -50,6 +51,6 @@ export async function postDetails(postData) {
`${getConfig().SUBSCRIPTIONS_BASE_URL}/api/v1/stripe-checkout/`,
postData,
)
.catch(handleDetailsApiError);
.catch(handleDetailsApiError.bind({ payload: postData }));
return transformSubscriptionDetails(data);
}

0 comments on commit 1eb1793

Please sign in to comment.