diff --git a/packages/learn/package.json b/packages/learn/package.json
index f99d3eb3b6..5b625c7056 100644
--- a/packages/learn/package.json
+++ b/packages/learn/package.json
@@ -46,6 +46,7 @@
"redux-observable": "^0.18.0",
"reselect": "^3.0.1",
"rxjs": "^5.5.7",
+ "store": "^2.0.12",
"uglifyjs-webpack-plugin": "^1.2.4",
"validator": "^9.4.1"
},
diff --git a/packages/learn/src/auth/index.js b/packages/learn/src/auth/index.js
index d82ee473d4..8139940652 100644
--- a/packages/learn/src/auth/index.js
+++ b/packages/learn/src/auth/index.js
@@ -8,16 +8,16 @@ const clientID = AUTH0_CLIENT_ID;
class Auth {
constructor() {
- this.auth0 = new auth0.WebAuth({
- domain,
- clientID,
- redirectUri: `${
- typeof window !== 'undefined' ? window.location.origin : ''
- }/auth-callback`,
- audience: `https://${domain}/api/v2/`,
- responseType: 'token id_token',
- scope: `openid profile email ${namespace + 'accountLinkId'}`
- });
+ this.auth0 = new auth0.WebAuth({
+ domain,
+ clientID,
+ redirectUri: `${
+ typeof window !== 'undefined' ? window.location.origin : ''
+ }/auth-callback`,
+ audience: `https://${domain}/api/v2/`,
+ responseType: 'token id_token',
+ scope: `openid profile email ${namespace + 'accountLinkId'}`
+ });
this.getUser = this.getUser.bind(this);
this.getToken = this.getToken.bind(this);
diff --git a/packages/learn/src/templates/Challenges/classic/Editor.js b/packages/learn/src/templates/Challenges/classic/Editor.js
index 38f335a30a..13f4989f00 100644
--- a/packages/learn/src/templates/Challenges/classic/Editor.js
+++ b/packages/learn/src/templates/Challenges/classic/Editor.js
@@ -82,7 +82,6 @@ class Editor extends PureComponent {
render() {
const { contents, ext } = this.props;
-
return (
diff --git a/packages/learn/src/templates/Challenges/classic/Show.js b/packages/learn/src/templates/Challenges/classic/Show.js
index badaaf5317..195fb68bf6 100644
--- a/packages/learn/src/templates/Challenges/classic/Show.js
+++ b/packages/learn/src/templates/Challenges/classic/Show.js
@@ -12,6 +12,7 @@ import Preview from '../components/Preview';
import SidePanel from '../components/Side-Panel';
import CompletionModal from '../components/CompletionModal';
import HelpModal from '../components/HelpModal';
+import ResetModal from '../components/ResetModal';
import { challengeTypes } from '../../../../utils/challengeTypes';
import { ChallengeNode } from '../../../redux/propTypes';
@@ -19,7 +20,8 @@ import {
createFiles,
challengeFilesSelector,
initTests,
- updateChallengeMeta
+ updateChallengeMeta,
+ challengeMounted
} from '../redux';
import './classic.css';
@@ -29,9 +31,13 @@ const mapStateToProps = createSelector(challengeFilesSelector, files => ({
}));
const mapDispatchToProps = dispatch =>
- bindActionCreators({ createFiles, initTests, updateChallengeMeta }, dispatch);
+ bindActionCreators(
+ { createFiles, initTests, updateChallengeMeta, challengeMounted },
+ dispatch
+ );
const propTypes = {
+ challengeMounted: PropTypes.func.isRequired,
createFiles: PropTypes.func.isRequired,
data: PropTypes.shape({
challengeNode: ChallengeNode
@@ -51,6 +57,7 @@ const propTypes = {
class ShowClassic extends PureComponent {
componentDidMount() {
const {
+ challengeMounted,
createFiles,
initTests,
updateChallengeMeta,
@@ -60,11 +67,13 @@ class ShowClassic extends PureComponent {
createFiles(files);
initTests(tests);
updateChallengeMeta({ ...challengeMeta, title });
+ challengeMounted(challengeMeta.id);
}
componentDidUpdate(prevProps) {
const { data: { challengeNode: { title: prevTitle } } } = prevProps;
const {
+ challengeMounted,
createFiles,
initTests,
updateChallengeMeta,
@@ -77,6 +86,7 @@ class ShowClassic extends PureComponent {
createFiles(files);
initTests(tests);
updateChallengeMeta({ ...challengeMeta, title: currentTitle });
+ challengeMounted(challengeMeta.id);
}
}
@@ -135,6 +145,7 @@ class ShowClassic extends PureComponent {
+
);
}
diff --git a/packages/learn/src/templates/Challenges/components/CompletionModal.js b/packages/learn/src/templates/Challenges/components/CompletionModal.js
index 55ffb0a7a6..031daf7a7a 100644
--- a/packages/learn/src/templates/Challenges/components/CompletionModal.js
+++ b/packages/learn/src/templates/Challenges/components/CompletionModal.js
@@ -28,12 +28,10 @@ const mapDispatchToProps = function(dispatch) {
close: () => dispatch(closeModal('completion')),
handleKeypress: e => {
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
- console.log('dispatching');
dispatch(submitChallenge());
}
},
submitChallenge: () => {
- console.log('dispatching');
dispatch(submitChallenge());
}
};
diff --git a/packages/learn/src/templates/Challenges/components/ResetModal.js b/packages/learn/src/templates/Challenges/components/ResetModal.js
new file mode 100644
index 0000000000..791a1942a9
--- /dev/null
+++ b/packages/learn/src/templates/Challenges/components/ResetModal.js
@@ -0,0 +1,70 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import { createSelector } from 'reselect';
+import { Button, Modal } from 'react-bootstrap';
+
+import { isResetModalOpenSelector, closeModal, resetChallenge } from '../redux';
+
+const propTypes = {
+ close: PropTypes.func.isRequired,
+ isOpen: PropTypes.bool.isRequired,
+ reset: PropTypes.func.isRequired
+};
+
+const mapStateToProps = createSelector(isResetModalOpenSelector, isOpen => ({
+ isOpen
+}));
+
+const mapDispatchToProps = dispatch =>
+ bindActionCreators(
+ { close: () => closeModal('reset'), reset: () => resetChallenge() },
+ dispatch
+ );
+
+function withActions(...fns) {
+ return () => fns.forEach(fn => fn());
+}
+
+function ResetModal({ reset, close, isOpen }) {
+ return (
+
+
+ Reset this lesson?
+
+
+
+
+ Are you sure you wish to reset this lesson? The editors and tests
+ will be reset.
+
+
+ This cannot be undone.
+
+
+
+
+
+
+
+ );
+}
+
+ResetModal.displayName = 'ResetModal';
+ResetModal.propTypes = propTypes;
+
+export default connect(mapStateToProps, mapDispatchToProps)(ResetModal);
diff --git a/packages/learn/src/templates/Challenges/components/Side-Panel.js b/packages/learn/src/templates/Challenges/components/Side-Panel.js
index 336461a57d..1756c4ecf5 100644
--- a/packages/learn/src/templates/Challenges/components/Side-Panel.js
+++ b/packages/learn/src/templates/Challenges/components/Side-Panel.js
@@ -17,7 +17,6 @@ import {
consoleOutputSelector,
challengeTestsSelector,
executeChallenge,
- resetChallenge,
initConsole,
openModal
} from '../redux';
@@ -32,9 +31,9 @@ const mapDispatchToProps = dispatch =>
bindActionCreators(
{
executeChallenge,
- resetChallenge,
initConsole,
- openHelpModal: () => openModal('help')
+ openHelpModal: () => openModal('help'),
+ openResetModal: () => openModal('reset')
},
dispatch
);
@@ -45,8 +44,8 @@ const propTypes = {
guideUrl: PropTypes.string,
initConsole: PropTypes.func.isRequired,
openHelpModal: PropTypes.func.isRequired,
+ openResetModal: PropTypes.func.isRequired,
output: PropTypes.string,
- resetChallenge: PropTypes.func.isRequired,
tests: PropTypes.arrayOf(
PropTypes.shape({
text: PropTypes.string,
@@ -89,7 +88,7 @@ export class SidePanel extends PureComponent {
output = '',
guideUrl,
executeChallenge,
- resetChallenge,
+ openResetModal,
openHelpModal
} = this.props;
return (
@@ -103,7 +102,7 @@ export class SidePanel extends PureComponent {
executeChallenge={executeChallenge}
guideUrl={guideUrl}
openHelpModal={openHelpModal}
- reset={resetChallenge}
+ openResetModal={openResetModal}
/>