Fix next challenge loading logic
This commit is contained in:
@ -53,8 +53,8 @@ function cacheScript({ src } = {}) {
|
||||
|
||||
const frameRunner$ = cacheScript({ src: '/js/frame-runner.js' });
|
||||
|
||||
const htmlCatch = '\n<!-- -->';
|
||||
const jsCatch = '\n;/* */';
|
||||
const htmlCatch = '\n<!--fcc-->';
|
||||
const jsCatch = '\n;/*fcc*/';
|
||||
|
||||
export default function executeChallengeSaga(action$, getState) {
|
||||
return action$
|
||||
|
@ -1,16 +1,8 @@
|
||||
import React from 'react';
|
||||
import React, { PropTypes } from 'react';
|
||||
import PureComponent from 'react-pure-render/component';
|
||||
import NoSSR from 'react-no-ssr';
|
||||
import Codemirror from 'react-codemirror';
|
||||
|
||||
const defaultOutput = `/**
|
||||
* Your output will go here.
|
||||
* Any console.log() -type
|
||||
* statements will appear in
|
||||
* your browser\'s DevTools
|
||||
* JavaScript console.
|
||||
*/`;
|
||||
|
||||
const defaultOptions = {
|
||||
lineNumbers: false,
|
||||
mode: 'javascript',
|
||||
@ -21,11 +13,9 @@ const defaultOptions = {
|
||||
|
||||
export default class extends PureComponent {
|
||||
static displayName = 'Output';
|
||||
|
||||
static defaultProps = {
|
||||
output: defaultOutput
|
||||
static propTypes = {
|
||||
output: PropTypes.string
|
||||
};
|
||||
|
||||
render() {
|
||||
const { output } = this.props;
|
||||
return (
|
||||
@ -33,7 +23,8 @@ export default class extends PureComponent {
|
||||
<NoSSR>
|
||||
<Codemirror
|
||||
options={ defaultOptions }
|
||||
value={ output } />
|
||||
value={ output }
|
||||
/>
|
||||
</NoSSR>
|
||||
</div>
|
||||
);
|
||||
|
@ -22,29 +22,34 @@ export class ToolPanel extends PureComponent {
|
||||
block={ true }
|
||||
bsStyle='primary'
|
||||
className='btn-big'
|
||||
onClick={ executeChallenge }>
|
||||
onClick={ executeChallenge }
|
||||
>
|
||||
Run tests (ctrl + enter)
|
||||
</Button>
|
||||
<div className='button-spacer' />
|
||||
<ButtonGroup
|
||||
className='input-group'
|
||||
justified={ true }>
|
||||
justified={ true }
|
||||
>
|
||||
<Button
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
componentClass='label'>
|
||||
componentClass='label'
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
componentClass='label'>
|
||||
componentClass='label'
|
||||
>
|
||||
Help
|
||||
</Button>
|
||||
<Button
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
componentClass='label'>
|
||||
componentClass='label'
|
||||
>
|
||||
Bug
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
@ -1,24 +1,68 @@
|
||||
import { Observable } from 'rx';
|
||||
import { push } from 'react-router-redux';
|
||||
import { moveToNextChallenge } from './types';
|
||||
import { getNextChallenge } from '../utils';
|
||||
import { resetUi, updateCurrentChallenge } from './actions';
|
||||
// import { createErrorObservable, makeToast } from '../../../redux/actions';
|
||||
import { createErrorObservable, makeToast } from '../../../redux/actions';
|
||||
import {
|
||||
getNextChallenge,
|
||||
getFirstChallengeOfNextBlock,
|
||||
getFirstChallengeOfNextSuperBlock
|
||||
} from '../utils';
|
||||
import { getRandomVerb } from '../../../utils/get-words';
|
||||
|
||||
export default function nextChallengeSaga(actions$, getState) {
|
||||
return actions$
|
||||
.filter(({ type }) => type === moveToNextChallenge)
|
||||
.flatMap(() => {
|
||||
const state = getState();
|
||||
const nextChallenge = getNextChallenge(
|
||||
state.challengesApp.challenge,
|
||||
state.entities,
|
||||
state.challengesApp.superBlocks
|
||||
);
|
||||
return Observable.of(
|
||||
updateCurrentChallenge(nextChallenge),
|
||||
resetUi(),
|
||||
push(`/challenges/${nextChallenge.block}/${nextChallenge.dashedName}`)
|
||||
);
|
||||
let nextChallenge;
|
||||
// let message = '';
|
||||
// let isNewBlock = false;
|
||||
// let isNewSuperBlock = false;
|
||||
try {
|
||||
const state = getState();
|
||||
const { challenge, superBlocks } = state.challengesApp;
|
||||
const { entities } = state;
|
||||
nextChallenge = getNextChallenge(challenge, entities);
|
||||
// block completed.
|
||||
if (!nextChallenge) {
|
||||
// isNewBlock = true;
|
||||
nextChallenge = getFirstChallengeOfNextBlock(challenge, entities);
|
||||
}
|
||||
// superBlock completed
|
||||
if (!nextChallenge) {
|
||||
// isNewSuperBlock = true;
|
||||
nextChallenge = getFirstChallengeOfNextSuperBlock(
|
||||
challenge,
|
||||
entities,
|
||||
superBlocks
|
||||
);
|
||||
}
|
||||
/* this requires user data not available yet
|
||||
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 ? getRandomVerb() : null,
|
||||
message
|
||||
};
|
||||
*/
|
||||
return Observable.of(
|
||||
updateCurrentChallenge(nextChallenge),
|
||||
resetUi(),
|
||||
makeToast({
|
||||
title: getRandomVerb(),
|
||||
message: 'Your next challenge has arrived.'
|
||||
}),
|
||||
push(`/challenges/${nextChallenge.block}/${nextChallenge.dashedName}`)
|
||||
);
|
||||
} catch (err) {
|
||||
return createErrorObservable(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -15,7 +15,12 @@ const initialUiState = {
|
||||
currentIndex: 0,
|
||||
previousIndex: -1,
|
||||
isActionCompleted: false,
|
||||
isSubmitting: true
|
||||
isSubmitting: true,
|
||||
output: `/**
|
||||
* Any console.log()
|
||||
* statements will appear in
|
||||
* here console.
|
||||
*/`
|
||||
};
|
||||
const initialState = {
|
||||
id: '',
|
||||
|
@ -91,20 +91,80 @@ export function getFirstChallenge(
|
||||
];
|
||||
}
|
||||
|
||||
export function getNextChallenge(
|
||||
current,
|
||||
entites,
|
||||
superBlocks
|
||||
) {
|
||||
export function getNextChallenge(current, entites) {
|
||||
const { challenge: challengeMap, block: blockMap } = entites;
|
||||
// find current challenge
|
||||
// find current block
|
||||
// find next challenge in block
|
||||
const currentChallenge = challengeMap[current];
|
||||
if (currentChallenge) {
|
||||
const block = blockMap[currentChallenge.block];
|
||||
const index = block.challenges.indexOf(currentChallenge.dashedName);
|
||||
return challengeMap[block.challenges[index + 1]];
|
||||
if (!currentChallenge) {
|
||||
return null;
|
||||
}
|
||||
return getFirstChallenge(entites, superBlocks);
|
||||
const block = blockMap[currentChallenge.block];
|
||||
const index = block.challenges.indexOf(currentChallenge.dashedName);
|
||||
return challengeMap[block.challenges[index + 1]];
|
||||
}
|
||||
|
||||
export function getFirstChallengeOfNextBlock(current, entites) {
|
||||
const {
|
||||
challenge: challengeMap,
|
||||
block: blockMap,
|
||||
superBlock: SuperBlockMap
|
||||
} = entites;
|
||||
const currentChallenge = challengeMap[current];
|
||||
if (!currentChallenge) {
|
||||
return null;
|
||||
}
|
||||
const block = blockMap[currentChallenge.block];
|
||||
if (!block) {
|
||||
return null;
|
||||
}
|
||||
const superBlock = SuperBlockMap[block.superBlock];
|
||||
const index = superBlock.blocks.indexOf(block.dashedName);
|
||||
const newBlock = superBlock.blocks[ index + 1 ];
|
||||
if (!newBlock) {
|
||||
return null;
|
||||
}
|
||||
return challengeMap[newBlock.challenges[0]];
|
||||
}
|
||||
|
||||
export function getFirstChallengeOfNextSuperBlock(
|
||||
current,
|
||||
entites,
|
||||
superBlocks
|
||||
) {
|
||||
const {
|
||||
challenge: challengeMap,
|
||||
block: blockMap,
|
||||
superBlock: SuperBlockMap
|
||||
} = entites;
|
||||
const currentChallenge = challengeMap[current];
|
||||
if (!currentChallenge) {
|
||||
return null;
|
||||
}
|
||||
const block = blockMap[currentChallenge.block];
|
||||
if (!block) {
|
||||
return null;
|
||||
}
|
||||
const superBlock = SuperBlockMap[block.superBlock];
|
||||
const index = superBlocks.indexOf(superBlock.dashedName);
|
||||
const newSuperBlock = SuperBlockMap[superBlocks[ index + 1]];
|
||||
if (!newSuperBlock) {
|
||||
return null;
|
||||
}
|
||||
const newBlock = blockMap[newSuperBlock.blocks[0]];
|
||||
return challengeMap[newBlock.challenges[0]];
|
||||
}
|
||||
|
||||
export function getCurrentBlockName(current, entities) {
|
||||
const { challenge: challengeMap } = entities;
|
||||
const challenge = challengeMap[current];
|
||||
return challenge.block;
|
||||
}
|
||||
|
||||
export function getCurrentSuperBlockName(current, entities) {
|
||||
const { challenge: challengeMap, block: blockMap } = entities;
|
||||
const challenge = challengeMap[current];
|
||||
const block = blockMap[challenge.block];
|
||||
return block.superBlock;
|
||||
}
|
||||
|
@ -265,7 +265,7 @@
|
||||
"assert($(\"h1\").length > 0, 'message: Make your <code>h1</code> element visible on your page by uncommenting it.');",
|
||||
"assert($(\"h2\").length > 0, 'message: Make your <code>h2</code> element visible on your page by uncommenting it.');",
|
||||
"assert($(\"p\").length > 0, 'message: Make your <code>p</code> element visible on your page by uncommenting it.');",
|
||||
"assert(!/-->/gi.test(code.replace(/ *<!--.*\\n/g,'')), 'message: Be sure to delete all trailing comment tags, i.e. <code>--></code>.');"
|
||||
"assert(!/[^fc]-->/gi.test(code.replace(/ *<!--[^fc]*\\n/g,'')), 'message: Be sure to delete all trailing comment tags, i.e. <code>--></code>.');"
|
||||
],
|
||||
"type": "waypoint",
|
||||
"titleEs": "Quita comentarios HTML",
|
||||
@ -322,7 +322,7 @@
|
||||
"assert(($(\"h1\").length === 0), 'message: Comment out your <code>h1</code> element so that it is not visible on your page.');",
|
||||
"assert(($(\"h2\").length > 0), 'message: Leave your <code>h2</code> element uncommented so that it is visible on your page.');",
|
||||
"assert(($(\"p\").length === 0), 'message: Comment out your <code>p</code> element so that it is not visible on your page.');",
|
||||
"assert(code.match(/-->/g).length > 1, 'message: Be sure to close each of your comments with <code>--></code>.');",
|
||||
"assert(code.match(/[^fc]-->/g).length > 1, 'message: Be sure to close each of your comments with <code>--></code>.');",
|
||||
"assert((code.match(/<([a-z0-9]){1,2}>/g)[0]===\"<h1>\" && code.match(/<([a-z0-9]){1,2}>/g)[1]===\"<h2>\" && code.match(/<([a-z0-9]){1,2}>/g)[2]===\"<p>\") , 'message: Do not change the order of the <code>h1</code> <code>h2</code> or <code>p</code> in the code.');"
|
||||
],
|
||||
"type": "waypoint",
|
||||
@ -1071,8 +1071,8 @@
|
||||
"tests": [
|
||||
"assert($(\"h2\").css(\"font-family\").match(/^\"?lobster/i), 'message: Your h2 element should use the font <code>Lobster</code>.');",
|
||||
"assert($(\"h2\").css(\"font-family\").match(/lobster.*,.*monospace/i), 'message: Your h2 element should degrade to the font <code>Monospace</code> when <code>Lobster</code> is not available.');",
|
||||
"assert(new RegExp(\"<!--\", \"gi\").test(code), 'message: Comment out your call to Google for the <code>Lobster</code> font by putting <code><!--</code> in front of it.');",
|
||||
"assert(new RegExp(\"-->\", \"gi\").test(code), 'message: Be sure to close your comment by adding <code>--></code>.');"
|
||||
"assert(new RegExp(\"<!--[^fc]\", \"gi\").test(code), 'message: Comment out your call to Google for the <code>Lobster</code> font by putting <code><!--</code> in front of it.');",
|
||||
"assert(new RegExp(\"[^fc]-->\", \"gi\").test(code), 'message: Be sure to close your comment by adding <code>--></code>.');"
|
||||
],
|
||||
"type": "waypoint",
|
||||
"titleEs": "Especifica cómo deben degradarse los tipos de letra",
|
||||
|
Reference in New Issue
Block a user