From fec1abfb46f395af5dc5925bc2f64a8d22cae586 Mon Sep 17 00:00:00 2001 From: Stuart Taylor Date: Fri, 23 Feb 2018 18:34:46 +0000 Subject: [PATCH] feat(challenge): Add pre-fetching logic --- common/app/redux/fetch-challenges-epic.js | 62 ++++++++++++++++++- .../routes/Challenges/Completion-Modal.jsx | 11 +++- common/app/routes/Challenges/redux/index.js | 2 + 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/common/app/redux/fetch-challenges-epic.js b/common/app/redux/fetch-challenges-epic.js index 66e5b5c5b0..faecb7711a 100644 --- a/common/app/redux/fetch-challenges-epic.js +++ b/common/app/redux/fetch-challenges-epic.js @@ -10,12 +10,24 @@ import { fetchChallengeCompleted, fetchChallengesCompleted, - challengeSelector + fetchNewBlock, + challengeSelector, + superBlocksSelector, + currentChallengeSelector } from './'; -import { isChallengeLoaded, fullBlocksSelector } from '../entities/index.js'; +import { + isChallengeLoaded, + fullBlocksSelector, + entitiesSelector +} from '../entities'; import { shapeChallenges } from './utils'; import { types as challenge } from '../routes/Challenges/redux'; +import { + getFirstChallengeOfNextBlock, + getFirstChallengeOfNextSuperBlock, + getNextChallenge +} from '../routes/Challenges/utils'; import { langSelector } from '../Router/redux'; const isDev = debug.enabled('fcc:*'); @@ -86,4 +98,48 @@ export function fetchChallengesForBlockEpic( }); } -export default combineEpics(fetchChallengeEpic, fetchChallengesForBlockEpic); +function fetchChallengesForNextBlockEpic(action$, { getState }) { + return action$::ofType(challenge.checkForNextBlock) + .map(() => { + let nextChallenge = {}; + let isNewBlock = false; + let isNewSuperBlock = false; + const state = getState(); + const challenge = currentChallengeSelector(state); + const superBlocks = superBlocksSelector(state); + const entities = entitiesSelector(state); + nextChallenge = getNextChallenge(challenge, entities, { isDev }); + // block completed. + if (!nextChallenge) { + isNewBlock = true; + nextChallenge = getFirstChallengeOfNextBlock( + challenge, + entities, + { isDev } + ); + } + // superBlock completed + if (!nextChallenge) { + isNewSuperBlock = true; + nextChallenge = getFirstChallengeOfNextSuperBlock( + challenge, + entities, + superBlocks, + { isDev } + ); + } + const isNewBlockRequired = ( + (isNewBlock || isNewSuperBlock) && + !nextChallenge.description + ); + return isNewBlockRequired ? + fetchNewBlock(nextChallenge.block) : + { type: 'NULL' }; + }); +} + +export default combineEpics( + fetchChallengeEpic, + fetchChallengesForBlockEpic, + fetchChallengesForNextBlockEpic +); diff --git a/common/app/routes/Challenges/Completion-Modal.jsx b/common/app/routes/Challenges/Completion-Modal.jsx index 49c986f0db..6ef24ea35d 100644 --- a/common/app/routes/Challenges/Completion-Modal.jsx +++ b/common/app/routes/Challenges/Completion-Modal.jsx @@ -11,6 +11,8 @@ import { closeChallengeModal, submitChallenge, + checkForNextBlock, + challengeModalSelector, successMessageSelector } from './redux'; @@ -34,12 +36,14 @@ const mapDispatchToProps = function(dispatch) { }, submitChallenge: () => { dispatch(submitChallenge()); - } + }, + checkForNextBlock: () => dispatch(checkForNextBlock()) }; return () => dispatchers; }; const propTypes = { + checkForNextBlock: PropTypes.func.isRequired, close: PropTypes.func.isRequired, handleKeypress: PropTypes.func.isRequired, isOpen: PropTypes.bool, @@ -48,6 +52,11 @@ const propTypes = { }; export class CompletionModal extends PureComponent { + componentDidUpdate() { + if (this.props.isOpen) { + this.props.checkForNextBlock(); + } + } render() { const { close, diff --git a/common/app/routes/Challenges/redux/index.js b/common/app/routes/Challenges/redux/index.js index 090de13004..7d92931a69 100644 --- a/common/app/routes/Challenges/redux/index.js +++ b/common/app/routes/Challenges/redux/index.js @@ -77,6 +77,7 @@ export const types = createTypes([ 'checkChallenge', createAsyncTypes('submitChallenge'), 'moveToNextChallenge', + 'checkForNextBlock', // help 'openHelpModal', @@ -150,6 +151,7 @@ export const submitChallengeComplete = createAction( ); export const moveToNextChallenge = createAction(types.moveToNextChallenge); +export const checkForNextBlock = createAction(types.checkForNextBlock); // help export const openHelpModal = createAction(types.openHelpModal);