From 4c66ab9173058966aedf6b394f8c7ffe41b58e1d Mon Sep 17 00:00:00 2001
From: Delucse <46593742+Delucse@users.noreply.github.com>
Date: Mon, 7 Sep 2020 15:57:09 +0200
Subject: [PATCH] displaying the status of the tutorial
---
 src/actions/tutorialActions.js               | 24 ++++++
 src/actions/types.js                         |  5 ++
 src/components/Tutorial/SolutionCheck.js     | 10 ++-
 src/components/Tutorial/StepperHorizontal.js | 41 +++++++++-
 src/components/Tutorial/StepperVertical.js   | 85 +++++++++++++-------
 src/components/Tutorial/Tutorial.js          | 12 +--
 src/components/Tutorial/TutorialHome.js      | 77 ++++++++++++++++--
 src/reducers/index.js                        |  4 +-
 src/reducers/tutorialReducer.js              | 25 ++++++
 9 files changed, 229 insertions(+), 54 deletions(-)
 create mode 100644 src/actions/tutorialActions.js
 create mode 100644 src/reducers/tutorialReducer.js
diff --git a/src/actions/tutorialActions.js b/src/actions/tutorialActions.js
new file mode 100644
index 0000000..dd0a5d4
--- /dev/null
+++ b/src/actions/tutorialActions.js
@@ -0,0 +1,24 @@
+import { TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE } from './types';
+
+import { tutorials } from '../components/Tutorial/tutorials';
+
+export const tutorialChange = () => (dispatch) => {
+  dispatch({
+    type: TUTORIAL_CHANGE
+  });
+};
+
+export const tutorialCheck = (id, status) => (dispatch, getState) => {
+  var tutorialsStatus = getState().tutorial.status ?
+                          getState().tutorial.status
+                        : new Array(tutorials.length).fill({});
+  tutorialsStatus[id].status = status;
+  console.log(tutorials);
+  dispatch({
+    type: status === 'success' ? TUTORIAL_SUCCESS : TUTORIAL_ERROR,
+    payload: tutorialsStatus
+  });
+  dispatch(tutorialChange());
+  // update locale storage - sync with redux store
+  window.localStorage.setItem('tutorial', JSON.stringify(tutorialsStatus));
+};
diff --git a/src/actions/types.js b/src/actions/types.js
index c0be6c2..28e5e33 100644
--- a/src/actions/types.js
+++ b/src/actions/types.js
@@ -5,3 +5,8 @@ export const MOVE_BLOCK = 'MOVE_BLOCK';
 export const CHANGE_BLOCK = 'CHANGE_BLOCK';
 export const DELETE_BLOCK = 'DELETE_BLOCK';
 export const CLEAR_STATS = 'CLEAR_STATS';
+
+
+export const TUTORIAL_SUCCESS = 'TUTORIAL_SUCCESS';
+export const TUTORIAL_ERROR = 'TUTORIAL_ERROR';
+export const TUTORIAL_CHANGE = 'TUTORIAL_CHANGE';
diff --git a/src/components/Tutorial/SolutionCheck.js b/src/components/Tutorial/SolutionCheck.js
index 2228570..01a9380 100644
--- a/src/components/Tutorial/SolutionCheck.js
+++ b/src/components/Tutorial/SolutionCheck.js
@@ -1,4 +1,7 @@
 import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { tutorialCheck } from '../../actions/tutorialActions';
 
 import * as Blockly from 'blockly/core';
 
@@ -49,6 +52,7 @@ class SolutionCheck extends Component {
   check = () => {
     const workspace = Blockly.getMainWorkspace();
     var msg = tutorials[this.props.tutorial].test(workspace);
+    this.props.tutorialCheck(this.props.tutorial, msg.type);
     this.setState({ msg, open: true });
   }
 
@@ -95,4 +99,8 @@ class SolutionCheck extends Component {
   };
 }
 
-export default withRouter(withStyles(styles, {withTheme: true})(SolutionCheck));
+SolutionCheck.propTypes = {
+  tutorialCheck: PropTypes.func.isRequired
+};
+
+export default connect(null, { tutorialCheck })(withRouter(withStyles(styles, {withTheme: true})(SolutionCheck)));
diff --git a/src/components/Tutorial/StepperHorizontal.js b/src/components/Tutorial/StepperHorizontal.js
index 6dc9dfc..7197103 100644
--- a/src/components/Tutorial/StepperHorizontal.js
+++ b/src/components/Tutorial/StepperHorizontal.js
@@ -1,7 +1,11 @@
 import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
 
 import { withRouter } from 'react-router-dom';
 
+import clsx from 'clsx';
+
 import { tutorials } from './tutorials';
 
 import { fade } from '@material-ui/core/styles/colorManipulator';
@@ -11,9 +15,11 @@ import Stepper from '@material-ui/core/Stepper';
 import Step from '@material-ui/core/Step';
 import StepLabel from '@material-ui/core/StepLabel';
 
+import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
 const styles = (theme) => ({
   stepper: {
-    backgroundColor: fade(theme.palette.primary.main, 0.6),
     width: 'calc(100% - 40px)',
     borderRadius: '25px',
     padding: '0 20px',
@@ -21,8 +27,23 @@ const styles = (theme) => ({
     display: 'flex',
     justifyContent: 'space-between'
   },
+  stepperSuccess: {
+    backgroundColor: fade(theme.palette.primary.main, 0.6),
+  },
+  stepperError: {
+    backgroundColor: fade(theme.palette.error.dark, 0.6),
+  },
+  stepperOther: {
+    backgroundColor: fade(theme.palette.secondary.main, 0.6),
+  },
   color: {
     backgroundColor: 'transparent '
+  },
+  iconDivSuccess: {
+    color: theme.palette.primary.main
+  },
+  iconDivError: {
+    color: theme.palette.error.dark
   }
 });
 
@@ -40,8 +61,10 @@ class StepperHorizontal extends Component {
 
   render() {
     var tutorialId = this.state.tutorialId;
+    var tutorialStatus = this.props.status[tutorialId-1].status === 'success' ? 'Success' :
+                          this.props.status[tutorialId-1].status === 'error' ? 'Error' : 'Other';
     return (
-      
+      
         
 : ''}>
               
{tutorials[tutorialId-1].title}
             
           
@@ -67,4 +90,14 @@ class StepperHorizontal extends Component {
   };
 }
 
-export default withRouter(withStyles(styles, {withTheme: true})(StepperHorizontal));
+StepperHorizontal.propTypes = {
+  status: PropTypes.array.isRequired,
+  change: PropTypes.number.isRequired,
+};
+
+const mapStateToProps = state => ({
+  change: state.tutorial.change,
+  status: state.tutorial.status
+});
+
+export default connect(mapStateToProps, null)(withRouter(withStyles(styles, {withTheme: true})(StepperHorizontal)));
diff --git a/src/components/Tutorial/StepperVertical.js b/src/components/Tutorial/StepperVertical.js
index 34c94a8..48ea972 100644
--- a/src/components/Tutorial/StepperVertical.js
+++ b/src/components/Tutorial/StepperVertical.js
@@ -1,4 +1,6 @@
 import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
 
 import { withRouter, Link } from 'react-router-dom';
 
@@ -20,33 +22,44 @@ const styles = (theme) => ({
     padding: 0,
     width: '30px',
   },
-  stepIconSmall: {
-    border: `2px solid ${theme.palette.primary.main}`,
+  stepIcon: {
+    borderStyle: `solid`,
+    borderWith: '2px',
     borderRadius: '50%',
     width: '12px',
     height: '12px',
     margin: '0 auto'
   },
   stepIconMedium: {
-    border: `2px solid ${theme.palette.primary.main}`,
-    borderRadius: '50%',
     width: '18px',
     height: '18px',
-    margin: '0 auto'
   },
   stepIconLarge: {
-    border: `2px solid ${theme.palette.primary.main}`,
-    borderRadius: '50%',
     width: '24px',
     height: '24px'
   },
   stepIconTransparent: {
-    border: `2px solid transparent`,
+    borderColor: `transparent`,
     cursor: 'default'
   },
-  stepIconActive: {
+  stepIconSuccess: {
+    borderColor: theme.palette.primary.main,
+  },
+  stepIconError: {
+    borderColor: theme.palette.error.dark,
+  },
+  stepIconOther: {
+    borderColor: theme.palette.secondary.main,
+  },
+  stepIconActiveSuccess: {
     backgroundColor: fade(theme.palette.primary.main, 0.6)
   },
+  stepIconActiveError: {
+    backgroundColor: fade(theme.palette.error.dark, 0.6)
+  },
+  stepIconActiveOther: {
+    backgroundColor: fade(theme.palette.secondary.main, 0.6)
+  },
   progress: {
     position: 'absolute',
     top: 0,
@@ -76,7 +89,7 @@ class StepperVertical extends Component {
                                   tutorials.slice(Number(this.props.match.params.tutorialId)-3-1, Number(this.props.match.params.tutorialId)+3)
                                 : tutorials.slice(Number(this.props.match.params.tutorialId)-2-1,Number(this.props.match.params.tutorialId)+2),
     tutorialId: Number(this.props.match.params.tutorialId),
-    verticalTutorialId: Number(this.props.match.params.tutorialId)
+    selectedVerticalTutorialId: Number(this.props.match.params.tutorialId)
   }
 
   componentDidUpdate(props, state){
@@ -92,13 +105,13 @@ class StepperVertical extends Component {
                                       tutorials.slice(Number(this.props.match.params.tutorialId)-3-1, Number(this.props.match.params.tutorialId)+3)
                                     : tutorials.slice(Number(this.props.match.params.tutorialId)-2-1,Number(this.props.match.params.tutorialId)+2),
         tutorialId: Number(this.props.match.params.tutorialId),
-        verticalTutorialId: Number(this.props.match.params.tutorialId)
+        selectedVerticalTutorialId: Number(this.props.match.params.tutorialId)
       })
     }
   }
 
   verticalStepper = (step) => {
-    var newTutorialId = this.state.verticalTutorialId + step;
+    var newTutorialId = this.state.selectedVerticalTutorialId + step;
     var tutorialArray = Number(newTutorialId) === 1 ?
                           tutorials.slice(newTutorialId-1, newTutorialId+4)
                           : newTutorialId === 2 ?
@@ -108,18 +121,18 @@ class StepperVertical extends Component {
                                   : newTutorialId === tutorials.length-1 ?
                                         tutorials.slice(newTutorialId-3-1, newTutorialId+3)
                                       : tutorials.slice(newTutorialId-2-1, newTutorialId+2);
-    this.setState({ tutorialArray: tutorialArray, verticalTutorialId: newTutorialId });
+    this.setState({ tutorialArray: tutorialArray, selectedVerticalTutorialId: newTutorialId });
   }
 
   render() {
     var tutorialId = this.state.tutorialId;
-    var verticalTutorialId = this.state.verticalTutorialId;
+    var selectedVerticalTutorialId = this.state.selectedVerticalTutorialId;
     return (
       isWidthUp('sm', this.props.width) ?