fix(nextChallenge): Remove some duplication
This commit is contained in:
@@ -26,7 +26,7 @@ export class ShowMap extends PureComponent {
|
||||
const { superBlocks } = this.props;
|
||||
if (!Array.isArray(superBlocks) || !superBlocks.length) {
|
||||
return (
|
||||
<div style={{ hieght: '300px' }}>
|
||||
<div style={{ height: '300px' }}>
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
|
@@ -12,22 +12,15 @@ import {
|
||||
fetchChallengesCompleted,
|
||||
fetchNewBlock,
|
||||
challengeSelector,
|
||||
superBlocksSelector,
|
||||
currentChallengeSelector
|
||||
nextChallengeSelector
|
||||
} from './';
|
||||
import {
|
||||
isChallengeLoaded,
|
||||
fullBlocksSelector,
|
||||
entitiesSelector
|
||||
fullBlocksSelector
|
||||
} 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:*');
|
||||
@@ -81,7 +74,7 @@ export function fetchChallengesForBlockEpic(
|
||||
if (fetchAnotherBlock) {
|
||||
const fullBlocks = fullBlocksSelector(state);
|
||||
if (fullBlocks.includes(payload)) {
|
||||
return Observable.of({ type: 'NULL'});
|
||||
return Observable.of(null);
|
||||
}
|
||||
blockName = payload;
|
||||
}
|
||||
@@ -95,47 +88,28 @@ export function fetchChallengesForBlockEpic(
|
||||
.map(fetchChallengesCompleted)
|
||||
.startWith({ type: types.fetchChallenges.start })
|
||||
.catch(createErrorObservable);
|
||||
});
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
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 {
|
||||
nextChallenge,
|
||||
isNewBlock,
|
||||
isNewSuperBlock
|
||||
} = nextChallengeSelector(getState());
|
||||
const isNewBlockRequired = (
|
||||
(isNewBlock || isNewSuperBlock) &&
|
||||
nextChallenge &&
|
||||
!nextChallenge.description
|
||||
);
|
||||
return isNewBlockRequired ?
|
||||
fetchNewBlock(nextChallenge.block) :
|
||||
{ type: 'NULL' };
|
||||
});
|
||||
null;
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
export default combineEpics(
|
||||
|
@@ -8,6 +8,7 @@ import {
|
||||
handleActions
|
||||
} from 'berkeleys-redux-utils';
|
||||
import { createSelector } from 'reselect';
|
||||
import debug from 'debug';
|
||||
|
||||
import fetchUserEpic from './fetch-user-epic.js';
|
||||
import updateMyCurrentChallengeEpic from './update-my-challenge-epic.js';
|
||||
@@ -20,12 +21,19 @@ import { utils } from '../Flash/redux';
|
||||
import { paramsSelector } from '../Router/redux';
|
||||
import { types as challenges } from '../routes/Challenges/redux';
|
||||
import { types as map } from '../Map/redux';
|
||||
import { challengeToFiles } from '../routes/Challenges/utils';
|
||||
import {
|
||||
challengeToFiles,
|
||||
getFirstChallengeOfNextBlock,
|
||||
getFirstChallengeOfNextSuperBlock,
|
||||
getNextChallenge
|
||||
} from '../routes/Challenges/utils';
|
||||
|
||||
import ns from '../ns.json';
|
||||
|
||||
import { themes, invertTheme } from '../../utils/themes.js';
|
||||
|
||||
const isDev = debug.enabled('fcc:*');
|
||||
|
||||
export const epics = [
|
||||
fetchChallengesEpic,
|
||||
fetchUserEpic,
|
||||
@@ -271,6 +279,40 @@ export const firstChallengeSelector = createSelector(
|
||||
}
|
||||
);
|
||||
|
||||
export const nextChallengeSelector = state => {
|
||||
let nextChallenge = {};
|
||||
let isNewBlock = false;
|
||||
let isNewSuperBlock = false;
|
||||
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 }
|
||||
);
|
||||
}
|
||||
return {
|
||||
nextChallenge,
|
||||
isNewBlock,
|
||||
isNewSuperBlock
|
||||
};
|
||||
};
|
||||
|
||||
export default handleActions(
|
||||
() => ({
|
||||
[types.updateTitle]: (state, { payload = 'Learn To Code' }) => ({
|
||||
@@ -285,12 +327,10 @@ export default handleActions(
|
||||
[combineActions(
|
||||
types.fetchChallenge.complete,
|
||||
map.fetchMapUi.complete
|
||||
)]: (state, { payload }) => {
|
||||
return ({
|
||||
)]: (state, { payload }) => ({
|
||||
...state,
|
||||
superBlocks: payload.result.superBlocks
|
||||
});
|
||||
},
|
||||
}),
|
||||
[challenges.onRouteChallenges]: (state, { payload: { dashedName } }) => ({
|
||||
...state,
|
||||
currentChallenge: dashedName
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import _ from 'lodash';
|
||||
import debug from 'debug';
|
||||
import { Observable } from 'rx';
|
||||
import { combineEpics, ofType } from 'redux-epic';
|
||||
|
||||
@@ -10,23 +9,15 @@ import {
|
||||
onRouteChallenges,
|
||||
onRouteCurrentChallenge
|
||||
} from './';
|
||||
import { getNS as entitiesSelector } from '../../../entities';
|
||||
import {
|
||||
getNextChallenge,
|
||||
getFirstChallengeOfNextBlock,
|
||||
getFirstChallengeOfNextSuperBlock
|
||||
} from '../utils';
|
||||
|
||||
import {
|
||||
createErrorObservable,
|
||||
currentChallengeSelector,
|
||||
challengeSelector,
|
||||
superBlocksSelector
|
||||
nextChallengeSelector
|
||||
} from '../../../redux';
|
||||
import { langSelector } from '../../../Router/redux';
|
||||
import { makeToast } from '../../../Toasts/redux';
|
||||
|
||||
const isDev = debug.enabled('fcc:*');
|
||||
|
||||
// When we change challenge, update the current challenge
|
||||
// UI data.
|
||||
export function challengeUpdatedEpic(actions, { getState }) {
|
||||
@@ -52,73 +43,33 @@ export function resetChallengeEpic(actions, { getState }) {
|
||||
export function nextChallengeEpic(actions, { getState }) {
|
||||
return actions::ofType(types.moveToNextChallenge)
|
||||
.flatMap(() => {
|
||||
let nextChallenge;
|
||||
// let message = '';
|
||||
// let isNewBlock = false;
|
||||
// let isNewSuperBlock = false;
|
||||
try {
|
||||
const state = getState();
|
||||
const superBlocks = superBlocksSelector(state);
|
||||
const challenge = currentChallengeSelector(state);
|
||||
const entities = entitiesSelector(state);
|
||||
const lang = langSelector(state);
|
||||
nextChallenge = getNextChallenge(challenge, entities, { isDev });
|
||||
// block completed.
|
||||
if (!nextChallenge) {
|
||||
// isNewBlock = true;
|
||||
nextChallenge = getFirstChallengeOfNextBlock(
|
||||
challenge,
|
||||
entities,
|
||||
{ isDev }
|
||||
const state = getState();
|
||||
const lang = langSelector(state);
|
||||
const { nextChallenge } = nextChallengeSelector(state);
|
||||
if (!nextChallenge) {
|
||||
return createErrorObservable(
|
||||
new Error('Next Challenge could not be found')
|
||||
);
|
||||
}
|
||||
// superBlock completed
|
||||
if (!nextChallenge) {
|
||||
// isNewSuperBlock = true;
|
||||
nextChallenge = getFirstChallengeOfNextSuperBlock(
|
||||
challenge,
|
||||
entities,
|
||||
superBlocks,
|
||||
{ isDev }
|
||||
);
|
||||
}
|
||||
/* // TODO(berks): get this to work
|
||||
if (isNewSuperBlock || isNewBlock) {
|
||||
const getName = isNewSuperBlock ?
|
||||
getCurrentSuperBlockName :
|
||||
getCurrentBlockName;
|
||||
const blockType = isNewSuperBlock ? 'SuperBlock' : 'Block';
|
||||
message =
|
||||
`You've competed the ${getName(challenge, entities)} ${blockType}!`;
|
||||
}
|
||||
message += ' Your next challenge has arrived.';
|
||||
const toast = {
|
||||
// title: isNewSuperBlock || isNewBlock ? randomVerb() : null,
|
||||
message
|
||||
};
|
||||
*/
|
||||
if (nextChallenge.isLocked) {
|
||||
return Observable.of(
|
||||
makeToast({
|
||||
message: 'The next challenge has not been unlocked. ' +
|
||||
'Please revisit the required (*) challenges ' +
|
||||
'that have not been passed yet. ',
|
||||
timeout: 15000
|
||||
}),
|
||||
onRouteCurrentChallenge()
|
||||
);
|
||||
}
|
||||
return Observable.of(
|
||||
// normally we wouldn't need to add the lang as
|
||||
// addLangToRoutesEnhancer should add langs for us, but the way
|
||||
// enhancers/middlewares and RFR orders things this action will not
|
||||
// see addLangToRoutesEnhancer and cause RFR to render NotFound
|
||||
onRouteChallenges({ lang, ...nextChallenge }),
|
||||
makeToast({ message: 'Your next challenge has arrived.' })
|
||||
);
|
||||
} catch (err) {
|
||||
return createErrorObservable(err);
|
||||
}
|
||||
if (nextChallenge.isLocked) {
|
||||
return Observable.of(
|
||||
makeToast({
|
||||
message: 'The next challenge has not been unlocked. ' +
|
||||
'Please revisit the required (*) challenges ' +
|
||||
'that have not been passed yet. ',
|
||||
timeout: 15000
|
||||
}),
|
||||
onRouteCurrentChallenge()
|
||||
);
|
||||
}
|
||||
return Observable.of(
|
||||
// normally we wouldn't need to add the lang as
|
||||
// addLangToRoutesEnhancer should add langs for us, but the way
|
||||
// enhancers/middlewares and RFR orders things this action will not
|
||||
// see addLangToRoutesEnhancer and cause RFR to render NotFound
|
||||
onRouteChallenges({ lang, ...nextChallenge }),
|
||||
makeToast({ message: 'Your next challenge has arrived.' })
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -28,22 +28,22 @@ export default function getChallengesForBlock(app) {
|
||||
}
|
||||
}) => {
|
||||
log(`sourcing challenges for the ${blockName} block`);
|
||||
const requestedChallenges = pickBy(
|
||||
challengeMap,
|
||||
ch => ch.block === blockName
|
||||
);
|
||||
const entities = {
|
||||
block: {
|
||||
[blockName]: fullBlockMap[blockName]
|
||||
},
|
||||
challenge: requestedChallenges
|
||||
};
|
||||
const { challenge, block } = shapeChallenges(entities, isDev);
|
||||
return Observable.of({
|
||||
result: { superBlocks },
|
||||
entities: { challenge, block }
|
||||
});
|
||||
const requestedChallenges = pickBy(
|
||||
challengeMap,
|
||||
ch => ch.block === blockName
|
||||
);
|
||||
const entities = {
|
||||
block: {
|
||||
[blockName]: fullBlockMap[blockName]
|
||||
},
|
||||
challenge: requestedChallenges
|
||||
};
|
||||
const { challenge, block } = shapeChallenges(entities, isDev);
|
||||
return Observable.of({
|
||||
result: { superBlocks },
|
||||
entities: { challenge, block }
|
||||
});
|
||||
});
|
||||
return Observable.if(
|
||||
() => !!dashedName,
|
||||
getChallenge(dashedName, blockName, challengeMap, lang),
|
||||
|
Reference in New Issue
Block a user