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