diff --git a/client/index.js b/client/index.js
index 3d59d7c821..a6939e186b 100644
--- a/client/index.js
+++ b/client/index.js
@@ -49,7 +49,11 @@ const primaryLang = getLangFromPath(location.pathname);
defaultState.app.csrfToken = csrfToken;
-const serviceOptions = { xhrPath: '/services', context: { _csrf: csrfToken } };
+const serviceOptions = {
+ context: { _csrf: csrfToken },
+ xhrPath: '/services',
+ xhrTimeout: 15000
+};
const history = useLangRoutes(createHistory, primaryLang)();
sendPageAnalytics(history, ga);
diff --git a/common/app/entities/index.js b/common/app/entities/index.js
index d0367de9b5..e7dd2943ce 100644
--- a/common/app/entities/index.js
+++ b/common/app/entities/index.js
@@ -167,9 +167,7 @@ export default composeReducers(
}
};
}
- return {
- ...merge(state, action.meta.entities)
- };
+ return merge({}, state, action.meta.entities);
}
return state;
},
diff --git a/common/app/routes/Challenges/Child-Container.jsx b/common/app/routes/Challenges/Child-Container.jsx
index d13a0b6428..e21b4192b9 100644
--- a/common/app/routes/Challenges/Child-Container.jsx
+++ b/common/app/routes/Challenges/Child-Container.jsx
@@ -1,20 +1,56 @@
-import React from 'react';
+import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { createSelector } from 'reselect';
+
+import { challengeSelector } from '../../redux';
+import { challengeUpdated } from './redux';
import CompletionModal from './Completion-Modal.jsx';
import AppChildContainer from '../../Child-Container.jsx';
+import { OverlayLoader } from '../../helperComponents';
+
+const mapStateToProps = createSelector(
+ challengeSelector,
+ challenge => {
+ const { description } = challenge;
+ return {
+ challenge,
+ showLoading: !description || description.length === 0
+ };
+ }
+);
+
+const mapDispatchToProps = { challengeUpdated };
const propTypes = {
- children: PropTypes.node
+ challenge: PropTypes.object,
+ challengeUpdated: PropTypes.func.isRequired,
+ children: PropTypes.node,
+ showLoading: PropTypes.bool
};
-export default function ChildContainer({ children, ...props }) {
- return (
-
- { children }
-
-
- );
+class ChildContainer extends PureComponent {
+ componentDidUpdate(prevProps) {
+ const { challenge = {}, challengeUpdated } = this.props;
+ if (prevProps.showLoading && !this.props.showLoading) {
+ challengeUpdated(challenge);
+ }
+ }
+ render() {
+ const { children, showLoading, ...props } = this.props;
+ return (
+
+ {
+ showLoading ? : null
+ }
+ { children }
+
+
+ );
+ }
}
ChildContainer.propTypes = propTypes;
+
+export default connect(mapStateToProps, mapDispatchToProps)(ChildContainer);
diff --git a/common/app/routes/Challenges/Show.jsx b/common/app/routes/Challenges/Show.jsx
index 7f4931d8a6..91557aa1e5 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, description },
+ { dashedName, isTranslated },
{ viewType, title },
params,
blocks
@@ -54,7 +54,6 @@ const mapStateToProps = createSelector(
challenge: dashedName,
isTranslated,
params,
- showLoading: !description || description.length === 0,
title,
viewType
})
@@ -115,9 +114,9 @@ export class Show extends PureComponent {
}
render() {
- const { viewType, showLoading } = this.props;
+ const { viewType } = this.props;
const View = views[viewType] || Classic;
- return ;
+ return ;
}
}
diff --git a/common/app/routes/Challenges/views/Modern/Show.jsx b/common/app/routes/Challenges/views/Modern/Show.jsx
index 70a83f41f8..b0f6d99b99 100644
--- a/common/app/routes/Challenges/views/Modern/Show.jsx
+++ b/common/app/routes/Challenges/views/Modern/Show.jsx
@@ -7,7 +7,6 @@ import { addNS } from 'berkeleys-redux-utils';
import ns from './ns.json';
import Editor from './Editor.jsx';
-import { OverlayLoader } from '../../../../helperComponents';
import ChildContainer from '../../Child-Container.jsx';
import { showPreviewSelector, types } from '../../redux';
import SidePanel from '../../Side-Panel.jsx';
@@ -22,8 +21,7 @@ const createModernEditorToggleType = fileKey =>
const getFirstFileKey = _.flow(_.values, _.first, _.property('key'));
const propTypes = {
- nameToFileKey: PropTypes.object,
- showLoading: PropTypes.bool
+ nameToFileKey: PropTypes.object
};
const mapStateToProps = createSelector(
@@ -85,12 +83,9 @@ const nameToComponent = {
Preview: Preview
};
-export function ShowModern({ nameToFileKey, showLoading }) {
+export function ShowModern({ nameToFileKey }) {
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 c94ddca3cf..e69702c750 100644
--- a/common/app/routes/Challenges/views/backend/Show.jsx
+++ b/common/app/routes/Challenges/views/backend/Show.jsx
@@ -1,17 +1,13 @@
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 = {
- showLoading: PropTypes.bool
-};
+const propTypes = {};
export const mapStateToPanes = addNS(
'backend',
@@ -31,12 +27,9 @@ const renderPane = name => {
return Comp ? : Pane { name } not found;
};
-export default function ShowBackEnd({ showLoading }) {
+export default function ShowBackEnd() {
return (
- {
- showLoading ? : null
- }
);
diff --git a/common/app/routes/Challenges/views/classic/Show.jsx b/common/app/routes/Challenges/views/classic/Show.jsx
index 5d841bc0c4..b82d361c6d 100644
--- a/common/app/routes/Challenges/views/classic/Show.jsx
+++ b/common/app/routes/Challenges/views/classic/Show.jsx
@@ -1,19 +1,15 @@
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 = {
- showLoading: PropTypes.bool
-};
+const propTypes = {};
export const mapStateToPanes = addNS(
'classic',
@@ -43,12 +39,9 @@ const renderPane = name => {
return Comp ? : Pane for { name } not found;
};
-export default function ShowClassic({ showLoading }) {
+export default function ShowClassic() {
return (
- {
- showLoading ? : null
- }
);
diff --git a/common/app/routes/Challenges/views/project/Show.jsx b/common/app/routes/Challenges/views/project/Show.jsx
index 8e021fd481..9f7de7e7e0 100644
--- a/common/app/routes/Challenges/views/project/Show.jsx
+++ b/common/app/routes/Challenges/views/project/Show.jsx
@@ -1,18 +1,14 @@
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 = {
- showLoading: PropTypes.bool
-};
+const propTypes = {};
export const mapStateToPanes = addNS(
ns,
() => ({
@@ -31,12 +27,9 @@ const renderPane = name => {
return Comp ? : Pane { name } not found;
};
-export default function ShowProject({ showLoading }) {
+export default function ShowProject() {
return (
- {
- showLoading ? : null
- }
);
diff --git a/common/app/routes/Challenges/views/quiz/Show.jsx b/common/app/routes/Challenges/views/quiz/Show.jsx
index 302ac4ccfc..7937804521 100644
--- a/common/app/routes/Challenges/views/quiz/Show.jsx
+++ b/common/app/routes/Challenges/views/quiz/Show.jsx
@@ -1,18 +1,14 @@
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 = {
- showLoading: PropTypes.bool
-};
+const propTypes = {};
export const mapStateToPanes = addNS(
ns,
() => ({
@@ -31,12 +27,9 @@ const renderPane = name => {
return Comp ? : Pane { name } not found;
};
-export default function ShowQuiz({ showLoading }) {
+export default function ShowQuiz() {
return (
- {
- showLoading ? : null
- }
);
diff --git a/common/app/routes/Challenges/views/step/Show.jsx b/common/app/routes/Challenges/views/step/Show.jsx
index 4a7d25e107..31c4370454 100644
--- a/common/app/routes/Challenges/views/step/Show.jsx
+++ b/common/app/routes/Challenges/views/step/Show.jsx
@@ -1,18 +1,14 @@
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 = {
- showLoading: PropTypes.bool
-};
+const propTypes = {};
export const mapStateToPanes = addNS(
ns,
() => ({
@@ -31,12 +27,9 @@ const renderPane = name => {
return Comp ? : Pane { name } not found;
};
-export default function ShowStep({ showLoading }) {
+export default function ShowStep() {
return (
- {
- showLoading ? : null
- }
);