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) ?