displaying the status of the tutorial
This commit is contained in:
		
							parent
							
								
									b42e466304
								
							
						
					
					
						commit
						4c66ab9173
					
				
							
								
								
									
										24
									
								
								src/actions/tutorialActions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/actions/tutorialActions.js
									
									
									
									
									
										Normal file
									
								
							| @ -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)); | ||||
| }; | ||||
| @ -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'; | ||||
|  | ||||
| @ -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))); | ||||
|  | ||||
| @ -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 ( | ||||
|       <div className={this.props.classes.stepper}> | ||||
|       <div className={clsx(this.props.classes.stepper, this.props.classes['stepper'+tutorialStatus])}> | ||||
|         <Button | ||||
|           disabled={tutorialId-1 === 0} | ||||
|           onClick={() => {this.props.history.push(`/tutorial/${tutorialId-1}`)}} | ||||
| @ -51,7 +74,7 @@ class StepperHorizontal extends Component { | ||||
|         <Stepper activeStep={tutorialId} orientation="horizontal" | ||||
|                  style={{padding: 0}} classes={{root: this.props.classes.color}}> | ||||
|           <Step expanded completed={false}> | ||||
|             <StepLabel icon={``}> | ||||
|             <StepLabel icon={tutorialStatus !== 'Other' ? <div className={clsx(tutorialStatus === 'Error' ? this.props.classes.iconDivError: this.props.classes.iconDivSuccess)}><FontAwesomeIcon className={this.props.classes.icon} icon={tutorialStatus === 'Success' ? faCheck : faTimes}/></div> : ''}> | ||||
|               <h1 style={{margin: 0}}>{tutorials[tutorialId-1].title}</h1> | ||||
|             </StepLabel> | ||||
|           </Step> | ||||
| @ -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))); | ||||
|  | ||||
| @ -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) ? | ||||
|         <div style={{marginRight: '10px'}}> | ||||
|             <Button | ||||
|               style={{minWidth: '30px', margin: 'auto', minHeight: '25px', padding: '0', writingMode: 'vertical-rl'}} | ||||
|               disabled={this.state.verticalTutorialId === 1} | ||||
|               disabled={this.state.selectedVerticalTutorialId === 1} | ||||
|               onClick={() => {this.verticalStepper(-1)}} | ||||
|             > | ||||
|               {'<'} | ||||
| @ -128,11 +141,11 @@ class StepperVertical extends Component { | ||||
|               <div style={{position: 'relative'}}> | ||||
|                 <div | ||||
|                   className={clsx(this.props.classes.progress, this.props.classes.progressForeground)} | ||||
|                   style={{ zIndex: 1, borderRadius: `${verticalTutorialId/tutorials.length === 1 ? '2px' : '2px 2px 0 0'}`, height: `${(verticalTutorialId/tutorials.length)*100}%`}}> | ||||
|                   style={{ zIndex: 1, borderRadius: `${selectedVerticalTutorialId/tutorials.length === 1 ? '2px' : '2px 2px 0 0'}`, height: `${(selectedVerticalTutorialId/tutorials.length)*100}%`}}> | ||||
|                 </div> | ||||
|                 <div | ||||
|                   className={clsx(this.props.classes.progress, this.props.classes.progressBackground)} | ||||
|                   style={{borderRadius: `${verticalTutorialId/tutorials.length === 1 ? '2px' : '2px 2px 0 0'}`}}> | ||||
|                   style={{borderRadius: `${selectedVerticalTutorialId/tutorials.length === 1 ? '2px' : '2px 2px 0 0'}`}}> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <Stepper | ||||
| @ -142,25 +155,28 @@ class StepperVertical extends Component { | ||||
|                 classes={{root: this.props.classes.verticalStepper}} | ||||
|               > | ||||
|                 {this.state.tutorialArray.map((tutorial, i) => { | ||||
|                   var index = this.state.tutorialArray.indexOf(tutorials[verticalTutorialId-1]); | ||||
|                   var index = this.state.tutorialArray.indexOf(tutorials[selectedVerticalTutorialId-1]); | ||||
|                   var verticalTutorialId = i === index ? selectedVerticalTutorialId : selectedVerticalTutorialId - index + i; | ||||
|                   var tutorialStatus = this.props.status[verticalTutorialId-1].status === 'success' ? 'Success' : | ||||
|                                         this.props.status[verticalTutorialId-1].status === 'error' ? 'Error' : 'Other'; | ||||
|                   return ( | ||||
|                     <Step key={i}> | ||||
|                       <Tooltip title={Object.keys(tutorial).length > 0 ? tutorial.title : ''} placement='right' arrow > | ||||
|                         <Link to={`/tutorial/${i === index ? verticalTutorialId : verticalTutorialId - index + i}`}> | ||||
|                         <Link to={`/tutorial/${verticalTutorialId}`}> | ||||
|                           <StepLabel | ||||
|                             StepIconComponent={'div'} | ||||
|                             classes={{ | ||||
|                               root: tutorial === tutorials[verticalTutorialId-1] ? | ||||
|                               root: tutorial === tutorials[selectedVerticalTutorialId-1] ? | ||||
|                                       tutorial === tutorials[tutorialId-1] ? | ||||
|                                         clsx(this.props.classes.stepIconLarge, this.props.classes.stepIconActive) | ||||
|                                       : this.props.classes.stepIconLarge | ||||
|                                     : tutorial === tutorials[verticalTutorialId-2] || tutorial === tutorials[verticalTutorialId] ? | ||||
|                                          clsx(this.props.classes.stepIcon, this.props.classes.stepIconLarge, this.props.classes['stepIcon'+tutorialStatus], this.props.classes['stepIconActive'+tutorialStatus]) | ||||
|                                       : clsx(this.props.classes.stepIcon, this.props.classes.stepIconLarge, this.props.classes['stepIcon'+tutorialStatus]) | ||||
|                                     : tutorial === tutorials[verticalTutorialId-2] || tutorial === tutorials[selectedVerticalTutorialId] ? | ||||
|                                         tutorial === tutorials[tutorialId-1] ? | ||||
|                                           clsx(this.props.classes.stepIconMedium, this.props.classes.stepIconActive) | ||||
|                                         : this.props.classes.stepIconMedium | ||||
|                                           clsx(this.props.classes.stepIcon, this.props.classes.stepIconMedium, this.props.classes['stepIcon'+tutorialStatus], this.props.classes['stepIconActive'+tutorialStatus]) | ||||
|                                         : clsx(this.props.classes.stepIcon, this.props.classes.stepIconMedium, this.props.classes['stepIcon'+tutorialStatus]) | ||||
|                                     : tutorial === tutorials[tutorialId-1] ? | ||||
|                                         clsx(this.props.classes.stepIconSmall, this.props.classes.stepIconActive) | ||||
|                                       : this.props.classes.stepIconSmall | ||||
|                                         clsx(this.props.classes.stepIcon, this.props.classes['stepIcon'+tutorialStatus], this.props.classes['stepIconActive'+tutorialStatus]) | ||||
|                                       : clsx(this.props.classes.stepIcon, this.props.classes['stepIcon'+tutorialStatus]) | ||||
|                             }} | ||||
|                           > | ||||
|                           </StepLabel> | ||||
| @ -172,7 +188,7 @@ class StepperVertical extends Component { | ||||
|             </div> | ||||
|             <Button | ||||
|               style={{minWidth: '30px', minHeight: '25px', padding: '0', writingMode: 'vertical-rl'}} | ||||
|               disabled={this.state.verticalTutorialId === tutorials.length} | ||||
|               disabled={this.state.selectedVerticalTutorialId === tutorials.length} | ||||
|               onClick={() => {this.verticalStepper(1)}} | ||||
|             > | ||||
|               {'>'} | ||||
| @ -183,4 +199,15 @@ class StepperVertical extends Component { | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export default withRouter(withStyles(styles, {withTheme: true})(withWidth()(StepperVertical))); | ||||
| 
 | ||||
| StepperVertical.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})(withWidth()(StepperVertical)))); | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| import React, { Component } from 'react'; | ||||
| 
 | ||||
| import * as Blockly from 'blockly/core'; | ||||
| 
 | ||||
| import Breadcrumbs from '../Breadcrumbs'; | ||||
| import StepperHorizontal from './StepperHorizontal'; | ||||
| import StepperVertical from './StepperVertical'; | ||||
| @ -11,7 +9,6 @@ import CodeViewer from '../CodeViewer'; | ||||
| import NotFound from '../NotFound'; | ||||
| 
 | ||||
| import { tutorials } from './tutorials'; | ||||
| import { initialXml } from '../Blockly/initialXml.js'; | ||||
| 
 | ||||
| import withWidth, { isWidthUp } from '@material-ui/core/withWidth'; | ||||
| import Tabs from '@material-ui/core/Tabs'; | ||||
| @ -28,14 +25,7 @@ class Tutorial extends Component { | ||||
| 
 | ||||
|   componentDidUpdate(props, state){ | ||||
|     if(state.tutorialId !== Number(this.props.match.params.tutorialId)){ | ||||
|       this.setState({tutorialId: Number(this.props.match.params.tutorialId)}); | ||||
|       // clear workspace
 | ||||
|       const workspace = Blockly.getMainWorkspace(); | ||||
|       Blockly.Events.disable(); // https://groups.google.com/forum/#!topic/blockly/m7e3g0TC75Y
 | ||||
|       // if events are disabled, then the workspace will be cleared AND the blocks are not in the trashcan
 | ||||
|       const xmlDom = Blockly.Xml.textToDom(initialXml) | ||||
|       Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace); | ||||
|       Blockly.Events.enable(); | ||||
|       this.setState({ value: 'introduction', tutorialId: Number(this.props.match.params.tutorialId) }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,8 @@ | ||||
| import React, { Component } from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { connect } from 'react-redux'; | ||||
| 
 | ||||
| import clsx from 'clsx'; | ||||
| 
 | ||||
| import Breadcrumbs from '../Breadcrumbs'; | ||||
| 
 | ||||
| @ -6,10 +10,43 @@ import { tutorials } from './tutorials'; | ||||
| 
 | ||||
| import { Link } from 'react-router-dom'; | ||||
| 
 | ||||
| import { fade } from '@material-ui/core/styles/colorManipulator'; | ||||
| import { withStyles } from '@material-ui/core/styles'; | ||||
| import Grid from '@material-ui/core/Grid'; | ||||
| import Paper from '@material-ui/core/Paper'; | ||||
| 
 | ||||
| import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| 
 | ||||
| const styles = (theme) => ({ | ||||
|   outerDiv: { | ||||
|     position: 'absolute', | ||||
|     right: '-29px', | ||||
|     bottom: '-29px', | ||||
|     width: '140px', | ||||
|     height: '140px', | ||||
|     borderStyle: 'solid', | ||||
|     borderWidth: '10px', | ||||
|     borderRadius: '50%', | ||||
|     borderColor: fade(theme.palette.primary.main, 0.2), | ||||
|     color: fade(theme.palette.primary.main, 0.2) | ||||
|   }, | ||||
|   outerDivError: { | ||||
|     borderColor: fade(theme.palette.error.dark, 0.2), | ||||
|     color: fade(theme.palette.error.dark, 0.2) | ||||
|   }, | ||||
|   innerDiv: { | ||||
|     width: 'inherit', | ||||
|     height: 'inherit', | ||||
|     display: 'table-cell', | ||||
|     verticalAlign: 'middle', | ||||
|     textAlign: 'center' | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| class TutorialHome extends Component { | ||||
| 
 | ||||
|   render() { | ||||
|     return ( | ||||
|       <div> | ||||
| @ -17,17 +54,41 @@ class TutorialHome extends Component { | ||||
| 
 | ||||
|         <h1>Tutorial-Übersicht</h1> | ||||
|         <Grid container spacing={2}> | ||||
|           {tutorials.map((tutorial, i) => ( | ||||
|             <Grid item xs={12} sm={6} md={4} xl={3} key={i}> | ||||
|               <Link to={`/tutorial/${i+1}`} style={{textDecoration: 'none', color: 'inherit'}}> | ||||
|                 <Paper style={{height: '150px', padding: '10px'}}>{tutorials[i].title}</Paper> | ||||
|               </Link> | ||||
|             </Grid> | ||||
|           ))} | ||||
|           {tutorials.map((tutorial, i) => { | ||||
|             var tutorialStatus = this.props.status[i].status === 'success' ? 'Success' : | ||||
|                                   this.props.status[i].status === 'error' ? 'Error' : 'Other'; | ||||
|             return ( | ||||
|               <Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}> | ||||
|                 <Link to={`/tutorial/${i+1}`} style={{textDecoration: 'none', color: 'inherit'}}> | ||||
|                   <Paper style={{height: '150px', padding: '10px', position:'relative', overflow: 'hidden'}}> | ||||
|                     {tutorials[i].title} | ||||
|                     {tutorialStatus !== 'Other' ? | ||||
|                       <div className={clsx(this.props.classes.outerDiv, tutorialStatus === 'Error' ? this.props.classes.outerDivError : null)}> | ||||
|                         <div className={this.props.classes.innerDiv}> | ||||
|                           <FontAwesomeIcon size='4x' icon={tutorialStatus === 'Success' ? faCheck : faTimes}/> | ||||
|                         </div> | ||||
|                       </div> | ||||
|                       : null | ||||
|                     } | ||||
|                   </Paper> | ||||
|                 </Link> | ||||
| 
 | ||||
|               </Grid> | ||||
|           )})} | ||||
|         </Grid> | ||||
|       </div> | ||||
|     ); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export default TutorialHome; | ||||
| TutorialHome.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)(withStyles(styles, {withTheme: true})(TutorialHome)); | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| import { combineReducers } from 'redux'; | ||||
| import workspaceReducer from './workspaceReducer'; | ||||
| import tutorialReducer from './tutorialReducer'; | ||||
| 
 | ||||
| export default combineReducers({ | ||||
|   workspace: workspaceReducer | ||||
|   workspace: workspaceReducer, | ||||
|   tutorial: tutorialReducer | ||||
| }); | ||||
|  | ||||
							
								
								
									
										25
									
								
								src/reducers/tutorialReducer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/reducers/tutorialReducer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| import { TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE } from '../actions/types'; | ||||
| 
 | ||||
| 
 | ||||
| const initialState = { | ||||
|   status: JSON.parse(window.localStorage.getItem('tutorial')), | ||||
|   change: 0 | ||||
| }; | ||||
| 
 | ||||
| export default function(state = initialState, action){ | ||||
|   switch(action.type){ | ||||
|     case TUTORIAL_SUCCESS: | ||||
|     case TUTORIAL_ERROR: | ||||
|       return { | ||||
|         ...state, | ||||
|         status: action.payload | ||||
|       }; | ||||
|     case TUTORIAL_CHANGE: | ||||
|       return { | ||||
|         ...state, | ||||
|         change: state.change += 1 | ||||
|       } | ||||
|     default: | ||||
|       return state; | ||||
|   } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user