diff --git a/packages/learn/src/templates/Challenges/redux/completion-epic.js b/packages/learn/src/templates/Challenges/redux/completion-epic.js index d7eda54b50..dd6f11073b 100644 --- a/packages/learn/src/templates/Challenges/redux/completion-epic.js +++ b/packages/learn/src/templates/Challenges/redux/completion-epic.js @@ -1,5 +1,4 @@ import { of } from 'rxjs/observable/of'; -import { _if } from 'rxjs/observable/if'; import { empty } from 'rxjs/observable/empty'; import { switchMap, @@ -29,8 +28,7 @@ import { openDonationModal, shouldShowDonationSelector, updateComplete, - updateFailed, - isOnlineSelector + updateFailed } from '../../../redux/app'; import postUpdate$ from '../utils/postUpdate$'; @@ -49,13 +47,7 @@ function postChallenge(update, username) { updateComplete() ) ), - catchError(({ _body, _endpoint }) => { - let payload = _body; - if (typeof _body === 'string') { - payload = JSON.parse(_body); - } - return of(updateFailed({ endpoint: _endpoint, payload })); - }) + catchError(() => of(updateFailed(update))) ); return saveChallenge; } @@ -79,11 +71,7 @@ function submitModern(type, state) { endpoint: '/external/modern-challenge-completed', payload: challengeInfo }; - return _if( - () => isOnlineSelector(state), - postChallenge(update, username), - of(updateFailed(update)) - ); + return postChallenge(update, username); } } return empty(); @@ -106,12 +94,8 @@ function submitProject(type, state) { endpoint: '/external/project-completed', payload: challengeInfo }; - return _if( - () => isOnlineSelector(state), - postChallenge(update, username).pipe( - concat(of(updateProjectFormValues({}))) - ), - of(updateFailed(update)) + return postChallenge(update, username).pipe( + concat(of(updateProjectFormValues({}))) ); } @@ -130,11 +114,7 @@ function submitBackendChallenge(type, state) { endpoint: '/external/backend-challenge-completed', payload: challengeInfo }; - return _if( - () => isOnlineSelector(state), - postChallenge(update, username), - of(updateFailed(update)) - ); + return postChallenge(update, username); } } return empty(); diff --git a/packages/learn/src/templates/Challenges/redux/current-challenge-epic.js b/packages/learn/src/templates/Challenges/redux/current-challenge-epic.js index 24e15c1a6e..a1f523ab07 100644 --- a/packages/learn/src/templates/Challenges/redux/current-challenge-epic.js +++ b/packages/learn/src/templates/Challenges/redux/current-challenge-epic.js @@ -1,4 +1,3 @@ -import { _if } from 'rxjs/observable/if'; import { of } from 'rxjs/observable/of'; import { ofType } from 'redux-observable'; @@ -8,8 +7,7 @@ import { isSignedInSelector, currentChallengeIdSelector, updateComplete, - updateFailed, - isOnlineSelector + updateFailed } from '../../../redux/app'; import postUpdate$ from '../utils/postUpdate$'; @@ -25,18 +23,10 @@ function currentChallengeEpic(action$, { getState }) { currentChallengeId: payload } }; - return _if( - () => isOnlineSelector(getState()), - postUpdate$(update).pipe(mapTo(updateComplete())), - of(updateFailed(update)) - ); - }), - catchError(({ _body, _endpoint }) => { - let payload = _body; - if (typeof _body === 'string') { - payload = JSON.parse(_body); - } - return of(updateFailed({ endpoint: _endpoint, payload })); + return postUpdate$(update).pipe( + mapTo(updateComplete()), + catchError(() => of(updateFailed(update))) + ); }) ); } diff --git a/packages/learn/src/templates/Challenges/utils/ajax-stream.js b/packages/learn/src/templates/Challenges/utils/ajax-stream.js index df08952913..d72f0114ae 100644 --- a/packages/learn/src/templates/Challenges/utils/ajax-stream.js +++ b/packages/learn/src/templates/Challenges/utils/ajax-stream.js @@ -20,6 +20,8 @@ import debugFactory from 'debug'; import { Observable, noop } from 'rxjs'; import { map } from 'rxjs/operators'; +import { isGoodXHRStatus } from './'; + const debug = debugFactory('fcc:ajax$'); const root = typeof window !== 'undefined' ? window : {}; @@ -67,14 +69,19 @@ function getCORSRequest() { function parseXhrResponse(responseType, xhr) { switch (responseType) { - case 'json': - if ('response' in xhr) { - return xhr.responseType - ? xhr.response - : JSON.parse(xhr.response || xhr.responseText || 'null'); + case 'json': { + if (isGoodXHRStatus(xhr.status)) { + if ('response' in xhr) { + return xhr.responseType + ? xhr.response + : JSON.parse(xhr.response || xhr.responseText || 'null'); + } else { + return JSON.parse(xhr.responseText || 'null'); + } } else { - return JSON.parse(xhr.responseText || 'null'); + return null; } + } case 'xml': return xhr.responseXML; case 'text': @@ -293,7 +300,7 @@ export function postJSON$(url, body) { Accept: 'application/json' }, normalizeError: (e, xhr) => parseXhrResponse('json', xhr) - }).pipe(map(({ response }) => response)); + }); } // Creates an observable sequence from an Ajax GET Request with the body. @@ -318,5 +325,5 @@ export function getJSON$(url) { Accept: 'application/json' }, normalizeError: (e, xhr) => parseXhrResponse('json', xhr) - }).map(({ response }) => response); + }).pipe(map(({ response }) => response)); } diff --git a/packages/learn/src/templates/Challenges/utils/index.js b/packages/learn/src/templates/Challenges/utils/index.js index 9be91ac3a3..45e0e8002c 100644 --- a/packages/learn/src/templates/Challenges/utils/index.js +++ b/packages/learn/src/templates/Challenges/utils/index.js @@ -3,3 +3,8 @@ const guideBase = 'https://guide.freecodecamp.org/certifications'; export function createGuideUrl(slug = '') { return guideBase + slug; } + +export function isGoodXHRStatus(status) { + const statusInt = parseInt(status, 10); + return statusInt >= 200 && statusInt < 400; +}