diff --git a/common/app/entities/index.js b/common/app/entities/index.js index bb8aeda1c1..d0367de9b5 100644 --- a/common/app/entities/index.js +++ b/common/app/entities/index.js @@ -196,13 +196,12 @@ export default composeReducers( app.fetchChallenges.complete, map.fetchMapUi.complete ) - ]: (state, { payload }) => { - const {entities: { block } } = payload; - return { - ...merge(state, payload.entities), - fullBlocks: union(state.fullBlocks, [ Object.keys(block)[0] ]) - }; - }, + ]: (state, { payload: { entities } }) => merge({}, state, entities), + [app.fetchChallenges.complete]: + (state, { payload: { entities: { block }}}) => ({ + ...state, + fullBlocks: union(state.fullBlocks, [ Object.keys(block)[0] ]) + }), [ challenges.submitChallenge.complete ]: (state, { payload: { username, points, challengeInfo } }) => ({ diff --git a/common/app/helperComponents/OverlayLoader.jsx b/common/app/helperComponents/OverlayLoader.jsx index 6ca095a494..880ed41ece 100644 --- a/common/app/helperComponents/OverlayLoader.jsx +++ b/common/app/helperComponents/OverlayLoader.jsx @@ -27,20 +27,20 @@ LoaderCircle.displayName = 'LoaderCircle'; const animationProps = [ { - delay: '-1.5s', - origin: '1% 1%' + delay: '0.24s', + origin: '0% 0%' }, { - delay: '-1s', - origin: '1% 99%' + delay: '0.95s', + origin: '0% 100%' }, { - delay: '-0.5s', - origin: '99% 1%' + delay: '0.67s', + origin: '100% 0%' }, { - delay: '0s', - origin: '99% 99%' + delay: '1.33s', + origin: '100% 100%' } ]; diff --git a/common/app/helperComponents/overlayLoader-styles.js b/common/app/helperComponents/overlayLoader-styles.js index 11ce0f43cc..c710ed37ea 100644 --- a/common/app/helperComponents/overlayLoader-styles.js +++ b/common/app/helperComponents/overlayLoader-styles.js @@ -28,13 +28,18 @@ export default ` transform: scale(0.1); opacity: 0; } + 50% { + -webkit-transform: scale(0.8); + transform: scale(0.8); + opacity: 0.8; + } 70% { opacity: 1; } 100% { - opacity: 0.0; - -webkit-transform: scale(1); - transform: scale(1); + opacity: 0; + -webkit-transform: scale(1.2); + transform: scale(1.2); } } @@ -55,14 +60,15 @@ export default ` } .innerCircle { - -webkit-animation-duration: 2s; - animation-duration: 2s; - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; - -webkit-animation-name: overlay-loader; - animation-name: overlay-loader; - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; + -webkit-animation-duration: 2s; + animation-duration: 2s; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-name: overlay-loader; + animation-name: overlay-loader; + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + opacity: 0; } `; diff --git a/common/app/routes/Challenges/Show.jsx b/common/app/routes/Challenges/Show.jsx index f8a4ac62ab..7f4931d8a6 100644 --- a/common/app/routes/Challenges/Show.jsx +++ b/common/app/routes/Challenges/Show.jsx @@ -45,7 +45,7 @@ const mapStateToProps = createSelector( paramsSelector, fullBlocksSelector, ( - { dashedName, isTranslated }, + { dashedName, isTranslated, description }, { viewType, title }, params, blocks @@ -54,6 +54,7 @@ const mapStateToProps = createSelector( challenge: dashedName, isTranslated, params, + showLoading: !description || description.length === 0, title, viewType }) @@ -71,6 +72,7 @@ const propTypes = { dashedName: PropTypes.string, lang: PropTypes.string.isRequired }), + showLoading: PropTypes.bool, title: PropTypes.string, updateSuccessMessage: PropTypes.func.isRequired, updateTitle: PropTypes.func.isRequired, @@ -113,9 +115,9 @@ export class Show extends PureComponent { } render() { - const { viewType } = this.props; + const { viewType, showLoading } = this.props; const View = views[viewType] || Classic; - return ; + return ; } } diff --git a/common/app/routes/Challenges/Side-Panel.jsx b/common/app/routes/Challenges/Side-Panel.jsx index b69e48ba09..79de055b07 100644 --- a/common/app/routes/Challenges/Side-Panel.jsx +++ b/common/app/routes/Challenges/Side-Panel.jsx @@ -30,13 +30,6 @@ import { descriptionRegex } from './utils'; import { challengeSelector } from '../../redux'; import { makeToast } from '../../Toasts/redux'; -const mapDispatchToProps = { - makeToast, - executeChallenge, - updateHint, - openHelpModal, - unlockUntrustedCode -}; const mapStateToProps = createSelector( challengeSelector, challengeMetaSelector, @@ -62,6 +55,15 @@ const mapStateToProps = createSelector( isCodeLocked }) ); + +const mapDispatchToProps = { + makeToast, + executeChallenge, + updateHint, + openHelpModal, + unlockUntrustedCode +}; + const propTypes = { description: PropTypes.arrayOf(PropTypes.string), executeChallenge: PropTypes.func, @@ -95,7 +97,8 @@ export class SidePanel extends PureComponent { this.descriptionTop = node; } - renderDescription(description = [ 'Happy Coding!' ]) { + renderDescription() { + const { description = [ 'Happy Coding!' ] } = this.props; return description.map((line, index) => { if (descriptionRegex.test(line)) { return ( @@ -118,7 +121,6 @@ export class SidePanel extends PureComponent { render() { const { title, - description, tests = [], output, hint, @@ -142,7 +144,7 @@ export class SidePanel extends PureComponent { { title } - { this.renderDescription(description) } + { this.renderDescription() } const getFirstFileKey = _.flow(_.values, _.first, _.property('key')); const propTypes = { - nameToFileKey: PropTypes.object + nameToFileKey: PropTypes.object, + showLoading: PropTypes.bool }; const mapStateToProps = createSelector( @@ -83,9 +85,12 @@ const nameToComponent = { Preview: Preview }; -export function ShowModern({ nameToFileKey }) { +export function ShowModern({ nameToFileKey, showLoading }) { return ( + { + showLoading ? : null + } { const Comp = nameToComponent[name]; diff --git a/common/app/routes/Challenges/views/backend/Show.jsx b/common/app/routes/Challenges/views/backend/Show.jsx index e69702c750..c94ddca3cf 100644 --- a/common/app/routes/Challenges/views/backend/Show.jsx +++ b/common/app/routes/Challenges/views/backend/Show.jsx @@ -1,13 +1,17 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { addNS } from 'berkeleys-redux-utils'; +import { OverlayLoader } from '../../../../helperComponents'; import ChildContainer from '../../Child-Container.jsx'; import BackEnd from './Back-End.jsx'; import { types } from '../../redux'; import Panes from '../../../../Panes'; import _Map from '../../../../Map'; -const propTypes = {}; +const propTypes = { + showLoading: PropTypes.bool +}; export const mapStateToPanes = addNS( 'backend', @@ -27,9 +31,12 @@ const renderPane = name => { return Comp ? : Pane { name } not found; }; -export default function ShowBackEnd() { +export default function ShowBackEnd({ showLoading }) { return ( + { + showLoading ? : null + } ); diff --git a/common/app/routes/Challenges/views/classic/Show.jsx b/common/app/routes/Challenges/views/classic/Show.jsx index b82d361c6d..5d841bc0c4 100644 --- a/common/app/routes/Challenges/views/classic/Show.jsx +++ b/common/app/routes/Challenges/views/classic/Show.jsx @@ -1,15 +1,19 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { addNS } from 'berkeleys-redux-utils'; import Editor from './Editor.jsx'; import ChildContainer from '../../Child-Container.jsx'; +import { OverlayLoader } from '../../../../helperComponents'; import { types, showPreviewSelector } from '../../redux'; import Preview from '../../Preview.jsx'; import SidePanel from '../../Side-Panel.jsx'; import Panes from '../../../../Panes'; import _Map from '../../../../Map'; -const propTypes = {}; +const propTypes = { + showLoading: PropTypes.bool +}; export const mapStateToPanes = addNS( 'classic', @@ -39,9 +43,12 @@ const renderPane = name => { return Comp ? : Pane for { name } not found; }; -export default function ShowClassic() { +export default function ShowClassic({ showLoading }) { return ( + { + showLoading ? : null + } ); diff --git a/common/app/routes/Challenges/views/project/Show.jsx b/common/app/routes/Challenges/views/project/Show.jsx index 9f7de7e7e0..8e021fd481 100644 --- a/common/app/routes/Challenges/views/project/Show.jsx +++ b/common/app/routes/Challenges/views/project/Show.jsx @@ -1,14 +1,18 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { addNS } from 'berkeleys-redux-utils'; import ns from './ns.json'; import Main from './Project.jsx'; +import { OverlayLoader } from '../../../../helperComponents'; import ChildContainer from '../../Child-Container.jsx'; import { types } from '../../redux'; import Panes from '../../../../Panes'; import _Map from '../../../../Map'; -const propTypes = {}; +const propTypes = { + showLoading: PropTypes.bool +}; export const mapStateToPanes = addNS( ns, () => ({ @@ -27,9 +31,12 @@ const renderPane = name => { return Comp ? : Pane { name } not found; }; -export default function ShowProject() { +export default function ShowProject({ showLoading }) { return ( + { + showLoading ? : null + } ); diff --git a/common/app/routes/Challenges/views/quiz/Show.jsx b/common/app/routes/Challenges/views/quiz/Show.jsx index 7937804521..302ac4ccfc 100644 --- a/common/app/routes/Challenges/views/quiz/Show.jsx +++ b/common/app/routes/Challenges/views/quiz/Show.jsx @@ -1,14 +1,18 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { addNS } from 'berkeleys-redux-utils'; import ns from './ns.json'; import Main from './Quiz.jsx'; +import { OverlayLoader } from '../../../../helperComponents'; import ChildContainer from '../../Child-Container.jsx'; import { types } from '../../redux'; import Panes from '../../../../Panes'; import _Map from '../../../../Map'; -const propTypes = {}; +const propTypes = { + showLoading: PropTypes.bool +}; export const mapStateToPanes = addNS( ns, () => ({ @@ -27,9 +31,12 @@ const renderPane = name => { return Comp ? : Pane { name } not found; }; -export default function ShowQuiz() { +export default function ShowQuiz({ showLoading }) { return ( + { + showLoading ? : null + } ); diff --git a/common/app/routes/Challenges/views/step/Show.jsx b/common/app/routes/Challenges/views/step/Show.jsx index 31c4370454..4a7d25e107 100644 --- a/common/app/routes/Challenges/views/step/Show.jsx +++ b/common/app/routes/Challenges/views/step/Show.jsx @@ -1,14 +1,18 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { addNS } from 'berkeleys-redux-utils'; import ns from './ns.json'; import Step from './Step.jsx'; +import { OverlayLoader } from '../../../../helperComponents'; import ChildContainer from '../../Child-Container.jsx'; import { types } from '../../redux'; import Panes from '../../../../Panes'; import _Map from '../../../../Map'; -const propTypes = {}; +const propTypes = { + showLoading: PropTypes.bool +}; export const mapStateToPanes = addNS( ns, () => ({ @@ -27,9 +31,12 @@ const renderPane = name => { return Comp ? : Pane { name } not found; }; -export default function ShowStep() { +export default function ShowStep({ showLoading }) { return ( + { + showLoading ? : null + } ); diff --git a/common/app/routes/Challenges/views/step/Step.jsx b/common/app/routes/Challenges/views/step/Step.jsx index 921af0b797..b1da72ca7d 100644 --- a/common/app/routes/Challenges/views/step/Step.jsx +++ b/common/app/routes/Challenges/views/step/Step.jsx @@ -31,7 +31,7 @@ const mapStateToProps = createSelector( actionCompletedSelector, lightBoxSelector, ( - { description = [] }, + { description = [['', '', 'Happy Coding!', '']] }, currentIndex, previousIndex, isActionCompleted, diff --git a/server/services/mapUi.js b/server/services/mapUi.js index 9360deac3e..adb313b006 100644 --- a/server/services/mapUi.js +++ b/server/services/mapUi.js @@ -58,7 +58,8 @@ export default function mapUiService(app) { block, isLocked, isComingSoon, - isBeta + isBeta, + challengeType } = challenge; map[dashedName] = { dashedName, @@ -68,7 +69,8 @@ export default function mapUiService(app) { block, isLocked, isComingSoon, - isBeta + isBeta, + challengeType }; return map; }, {});