From 89d0cc380b4a9c2f50e44b3d65de283ff14ce1dd Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 8 Oct 2020 15:29:28 +0200 Subject: [PATCH] update tutorial structure --- src/actions/tutorialActions.js | 6 +- src/actions/tutorialBuilderActions.js | 66 ++++---- src/components/Blockly/helpers/types.js | 3 +- src/components/Tutorial/Builder/Builder.js | 83 +++++----- src/components/Tutorial/Builder/Id.js | 110 ++++++------- .../Tutorial/Builder/Requirements.js | 10 +- src/components/Tutorial/Hardware.js | 58 +++---- src/components/Tutorial/Requirement.js | 35 ++-- src/components/Tutorial/SolutionCheck.js | 32 ++-- src/components/Tutorial/StepperHorizontal.js | 26 +-- src/components/Tutorial/Tutorial.js | 50 +++--- src/components/Tutorial/TutorialHome.js | 32 ++-- src/data/ErsteSchritte.json | 1 + src/data/Wenn-DannBedingungen.json | 44 +++++ src/data/loops_01.json | 50 ++++++ src/data/tutorials.js | 9 ++ src/data/tutorials.json | 151 ------------------ src/data/variablen_01.json | 41 +++++ src/reducers/tutorialReducer.js | 24 +-- 19 files changed, 420 insertions(+), 411 deletions(-) create mode 100644 src/data/ErsteSchritte.json create mode 100644 src/data/Wenn-DannBedingungen.json create mode 100644 src/data/loops_01.json create mode 100644 src/data/tutorials.js delete mode 100644 src/data/tutorials.json create mode 100644 src/data/variablen_01.json diff --git a/src/actions/tutorialActions.js b/src/actions/tutorialActions.js index c902f70..4ab1980 100644 --- a/src/actions/tutorialActions.js +++ b/src/actions/tutorialActions.js @@ -1,6 +1,6 @@ import { TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE, TUTORIAL_XML, TUTORIAL_ID, TUTORIAL_STEP } from './types'; -import tutorials from '../data/tutorials.json'; +import tutorials from '../data/tutorials'; export const tutorialChange = () => (dispatch) => { dispatch({ @@ -26,10 +26,10 @@ export const tutorialCheck = (status, step) => (dispatch, getState) => { export const storeTutorialXml = (code) => (dispatch, getState) => { var id = getState().tutorial.currentId; - if(id !== null){ + if (id !== null) { var activeStep = getState().tutorial.activeStep; var steps = tutorials.filter(tutorial => tutorial.id === id)[0].steps; - if(steps[activeStep].type === 'task'){ + if (steps[activeStep].type === 'task') { var tutorialsStatus = getState().tutorial.status; var tutorialsStatusIndex = tutorialsStatus.findIndex(tutorialStatus => tutorialStatus.id === id); var tasksIndex = tutorialsStatus[tutorialsStatusIndex].tasks.findIndex(task => task.id === steps[activeStep].id); diff --git a/src/actions/tutorialBuilderActions.js b/src/actions/tutorialBuilderActions.js index 3d3effa..328c7fa 100644 --- a/src/actions/tutorialBuilderActions.js +++ b/src/actions/tutorialBuilderActions.js @@ -42,7 +42,7 @@ export const tutorialId = (id) => (dispatch) => { export const addStep = (index) => (dispatch, getState) => { var steps = getState().builder.steps; var step = { - id: index+1, + id: index + 1, type: 'instruction', headline: '', text: '' @@ -88,11 +88,11 @@ export const removeErrorStep = (index) => (dispatch, getState) => { export const changeContent = (content, index, property1, property2) => (dispatch, getState) => { var steps = getState().builder.steps; var step = steps[index]; - if(property2){ - if(step[property1] && step[property1][property2]){ + if (property2) { + if (step[property1] && step[property1][property2]) { step[property1][property2] = content; } else { - step[property1] = {[property2]: content}; + step[property1] = { [property2]: content }; } } else { step[property1] = content; @@ -107,8 +107,8 @@ export const changeContent = (content, index, property1, property2) => (dispatch export const deleteProperty = (index, property1, property2) => (dispatch, getState) => { var steps = getState().builder.steps; var step = steps[index]; - if(property2){ - if(step[property1] && step[property1][property2]){ + if (property2) { + if (step[property1] && step[property1][property2]) { delete step[property1][property2]; } } else { @@ -147,7 +147,7 @@ export const changeErrorStepIndex = (fromIndex, toIndex) => (dispatch, getState) export const setError = (index, property) => (dispatch, getState) => { var error = getState().builder.error; - if(index !== undefined){ + if (index !== undefined) { error.steps[index][property] = true; } else { @@ -162,7 +162,7 @@ export const setError = (index, property) => (dispatch, getState) => { export const deleteError = (index, property) => (dispatch, getState) => { var error = getState().builder.error; - if(index !== undefined){ + if (index !== undefined) { delete error.steps[index][property]; } else { @@ -177,44 +177,44 @@ export const deleteError = (index, property) => (dispatch, getState) => { export const setSubmitError = () => (dispatch, getState) => { var builder = getState().builder; - if(builder.id === undefined || builder.id === ''){ - dispatch(setError(undefined, 'id')); - } - if(builder.id === undefined || builder.title === ''){ + // if(builder.id === undefined || builder.id === ''){ + // dispatch(setError(undefined, 'id')); + // } + if (builder.id === undefined || builder.title === '') { dispatch(setError(undefined, 'title')); } var type = builder.steps.map((step, i) => { // media and xml are directly checked for errors in their components and // therefore do not have to be checked again - step.id = i+1; - if(i === 0){ - if(step.requirements && step.requirements.length > 0){ - var requirements = step.requirements.filter(requirement => typeof(requirement)==='number'); - if(requirements.length < step.requirements.length){ + step.id = i + 1; + if (i === 0) { + if (step.requirements && step.requirements.length > 0) { + var requirements = step.requirements.filter(requirement => typeof (requirement) === 'number'); + if (requirements.length < step.requirements.length) { dispatch(changeContent(requirements, i, 'requirements')); } } - if(step.hardware === undefined || step.hardware.length < 1){ + if (step.hardware === undefined || step.hardware.length < 1) { dispatch(setError(i, 'hardware')); } - else{ + else { var hardwareIds = data.map(hardware => hardware.id); var hardware = step.hardware.filter(hardware => hardwareIds.includes(hardware)); - if(hardware.length < step.hardware.length){ + if (hardware.length < step.hardware.length) { dispatch(changeContent(hardware, i, 'hardware')); } } } - if(step.headline === undefined || step.headline === ''){ + if (step.headline === undefined || step.headline === '') { dispatch(setError(i, 'headline')); } - if(step.text === undefined || step.text === ''){ + if (step.text === undefined || step.text === '') { dispatch(setError(i, 'text')); } return step.type; }); - if(!(type.filter(item => item === 'task').length > 0 && type.filter(item => item === 'instruction').length > 0)){ - dispatch(setError(undefined, 'type')); + if (!(type.filter(item => item === 'task').length > 0 && type.filter(item => item === 'instruction').length > 0)) { + dispatch(setError(undefined, 'type')); } }; @@ -222,11 +222,11 @@ export const setSubmitError = () => (dispatch, getState) => { export const checkError = () => (dispatch, getState) => { dispatch(setSubmitError()); var error = getState().builder.error; - if(error.id || error.title || error.type){ + if (error.id || error.title || error.type) { return true; } - for(var i = 0; i < error.steps.length; i++){ - if(Object.keys(error.steps[i]).length > 0){ + for (var i = 0; i < error.steps.length; i++) { + if (Object.keys(error.steps[i]).length > 0) { return true } } @@ -268,7 +268,7 @@ export const readJSON = (json) => (dispatch, getState) => { dispatch({ type: BUILDER_ERROR, payload: { - steps: json.steps.map(() => {return {};}) + steps: json.steps.map(() => { return {}; }) } }); // accept only valid attributes @@ -279,19 +279,19 @@ export const readJSON = (json) => (dispatch, getState) => { headline: step.headline, text: step.text }; - if(i === 0){ + if (i === 0) { object.hardware = step.hardware; object.requirements = step.requirements; } - if(step.xml){ + if (step.xml) { object.xml = step.xml; } - if(step.media && step.type === 'instruction'){ + if (step.media && step.type === 'instruction') { object.media = {}; - if(step.media.picture){ + if (step.media.picture) { object.media.picture = step.media.picture; } - else if(step.media.youtube){ + else if (step.media.youtube) { object.media.youtube = step.media.youtube; } } diff --git a/src/components/Blockly/helpers/types.js b/src/components/Blockly/helpers/types.js index 88c9348..48def90 100644 --- a/src/components/Blockly/helpers/types.js +++ b/src/components/Blockly/helpers/types.js @@ -18,6 +18,7 @@ export const CHARACTER = { export const BOOLEAN = { typeId: 'Boolean', + typeName: 'Boolean', typeMsgName: 'ARD_TYPE_BOOL', } @@ -89,7 +90,7 @@ const compatibleTypes = { boolean: ['boolean'], int: ['int'], char: ['char'], - string: ['String'], + String: ['String'], void: ['void'], long: ['int', 'long'], double: ['int', 'long', 'double'], diff --git a/src/components/Tutorial/Builder/Builder.js b/src/components/Tutorial/Builder/Builder.js index 2a177f2..5d17cdf 100644 --- a/src/components/Tutorial/Builder/Builder.js +++ b/src/components/Tutorial/Builder/Builder.js @@ -33,7 +33,7 @@ const styles = (theme) => ({ class Builder extends Component { - constructor(props){ + constructor(props) { super(props); this.state = { open: false, @@ -47,26 +47,33 @@ class Builder extends Component { this.inputRef = React.createRef(); } - componentWillUnmount(){ + componentWillUnmount() { this.reset(); } submit = () => { + console.log(this.props.id) + if (this.props.id === null) { + var randomID = Date.now(); + } else { + randomID = this.props.id; + } + var isError = this.props.checkError(); - if(isError){ - this.setState({ snackbar: true, key: Date.now(), message: `Die Angaben für das Tutorial sind nicht vollständig.`, type: 'error'}); + if (isError) { + this.setState({ snackbar: true, key: Date.now(), message: `Die Angaben für das Tutorial sind nicht vollständig.`, type: 'error' }); window.scrollTo(0, 0); } - else{ + else { // export steps without attribute 'url' var steps = this.props.steps.map(step => { - if(step.url){ + if (step.url) { delete step.url; } return step; }); var tutorial = { - id: this.props.id, + id: randomID, title: this.props.title, steps: steps } @@ -77,15 +84,15 @@ class Builder extends Component { reset = () => { this.props.resetTutorial(); - this.setState({ snackbar: true, key: Date.now(), message: `Das Tutorial wurde erfolgreich zurückgesetzt.`, type: 'success'}); + this.setState({ snackbar: true, key: Date.now(), message: `Das Tutorial wurde erfolgreich zurückgesetzt.`, type: 'success' }); window.scrollTo(0, 0); } uploadJsonFile = (jsonFile) => { this.props.progress(true); - if(jsonFile.type !== 'application/json'){ + if (jsonFile.type !== 'application/json') { this.props.progress(false); - this.setState({ open: true, string: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entspricht nicht dem geforderten Format. Es sind nur JSON-Dateien zulässig.'}); + this.setState({ open: true, string: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entspricht nicht dem geforderten Format. Es sind nur JSON-Dateien zulässig.' }); } else { var reader = new FileReader(); @@ -97,27 +104,27 @@ class Builder extends Component { } uploadJsonString = () => { - this.setState({ open: true, string: true, title: 'JSON-String einfügen', content: ''}); + this.setState({ open: true, string: true, title: 'JSON-String einfügen', content: '' }); } readJson = (jsonString, isFile) => { try { var result = JSON.parse(jsonString); - if(!this.checkSteps(result.steps)){ + if (!this.checkSteps(result.steps)) { result.steps = [{}]; } this.props.readJSON(result); - this.setState({ snackbar: true, key: Date.now(), message: `${isFile ? 'Die übergebene JSON-Datei' : 'Der übergebene JSON-String'} wurde erfolgreich übernommen.`, type: 'success'}); - } catch(err){ + this.setState({ snackbar: true, key: Date.now(), message: `${isFile ? 'Die übergebene JSON-Datei' : 'Der übergebene JSON-String'} wurde erfolgreich übernommen.`, type: 'success' }); + } catch (err) { console.log(err); this.props.progress(false); this.props.jsonString(''); - this.setState({ open: true, string: false, title: 'Ungültiges JSON-Format', content: `${isFile ? 'Die übergebene Datei' : 'Der übergebene String'} enthält nicht valides JSON. Bitte überprüfe ${isFile ? 'die JSON-Datei' : 'den JSON-String'} und versuche es erneut.`}); + this.setState({ open: true, string: false, title: 'Ungültiges JSON-Format', content: `${isFile ? 'Die übergebene Datei' : 'Der übergebene String'} enthält nicht valides JSON. Bitte überprüfe ${isFile ? 'die JSON-Datei' : 'den JSON-String'} und versuche es erneut.` }); } } checkSteps = (steps) => { - if(!(steps && steps.length > 0)){ + if (!(steps && steps.length > 0)) { return false; } return true; @@ -131,41 +138,41 @@ class Builder extends Component { render() { return (
- +

Tutorial-Builder

{/*upload JSON*/}
{this.uploadJsonFile(e.target.files[0])}} + onChange={(e) => { this.uploadJsonFile(e.target.files[0]) }} id="open-json" type="file" /> - +
- + {/*Tutorial-Builder-Form*/} {this.props.error.type ? - {`Ein Tutorial muss mindestens jeweils eine Instruktion und eine Aufgabe enthalten.`} - : null} - - + {`Ein Tutorial muss mindestens jeweils eine Instruktion und eine Aufgabe enthalten.`} + : null} + {/* */} + {this.props.steps.map((step, i) => - + )} {/*submit or reset*/} - - - + + + @@ -182,16 +189,16 @@ class Builder extends Component { button={'Schließen'} actions={ this.state.string ? -
- - -
- : null +
+ + +
+ : null } > {this.state.string ? - - : null} + + : null} ({ isProgress: state.builder.progress }); -export default connect(mapStateToProps, { checkError, readJSON, jsonString, progress, resetTutorial })(withStyles(styles, {withTheme: true})(Builder)); +export default connect(mapStateToProps, { checkError, readJSON, jsonString, progress, resetTutorial })(withStyles(styles, { withTheme: true })(Builder)); diff --git a/src/components/Tutorial/Builder/Id.js b/src/components/Tutorial/Builder/Id.js index ad18dc2..b3179ac 100644 --- a/src/components/Tutorial/Builder/Id.js +++ b/src/components/Tutorial/Builder/Id.js @@ -28,81 +28,83 @@ const styles = theme => ({ class Id extends Component { handleChange = (e) => { - var value = parseInt(e.target.value); - if(Number.isInteger(value) && value > 0){ + var value = + + parseInt(e.target.value); + if (Number.isInteger(value) && value > 0) { this.props.tutorialId(value); - if(this.props.error){ + if (this.props.error) { this.props.deleteError(undefined, 'id'); } } else { this.props.tutorialId(value.toString()); - this.props.setError(undefined,'id'); + this.props.setError(undefined, 'id'); } }; handleCounter = (step) => { - if(this.props.value+step < 1){ - this.props.setError(undefined,'id'); + if (this.props.value + step < 1) { + this.props.setError(undefined, 'id'); } - else if(this.props.error){ + else if (this.props.error) { this.props.deleteError(undefined, 'id'); } - if(!this.props.value || !Number.isInteger(this.props.value)){ - this.props.tutorialId(0+step); + if (!this.props.value || !Number.isInteger(this.props.value)) { + this.props.tutorialId(0 + step); } else { - this.props.tutorialId(this.props.value+step); + this.props.tutorialId(this.props.value + step); } } render() { return ( -
- - - ID +
+ + + ID - - - -
- } - /> - {this.props.error ? Gib eine positive ganzzahlige Zahl ein. : null} -
- Beachte, dass die ID eindeutig sein muss. Sie muss sich also zu den anderen Tutorials unterscheiden. + + + +
+ } + /> + {this.props.error ? Gib eine positive ganzzahlige Zahl ein. : null} + + Beachte, dass die ID eindeutig sein muss. Sie muss sich also zu den anderen Tutorials unterscheiden.
); }; diff --git a/src/components/Tutorial/Builder/Requirements.js b/src/components/Tutorial/Builder/Requirements.js index 2867325..8be6bf4 100644 --- a/src/components/Tutorial/Builder/Requirements.js +++ b/src/components/Tutorial/Builder/Requirements.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { changeContent } from '../../../actions/tutorialBuilderActions'; -import tutorials from '../../../data/tutorials.json'; +import tutorials from '../../../data/tutorials'; import FormGroup from '@material-ui/core/FormGroup'; import Checkbox from '@material-ui/core/Checkbox'; @@ -17,7 +17,7 @@ class Requirements extends Component { onChange = (e) => { var requirements = this.props.value; var value = parseInt(e.target.value) - if(e.target.checked){ + if (e.target.checked) { requirements.push(value); } else { @@ -28,9 +28,9 @@ class Requirements extends Component { render() { return ( - - Voraussetzungen - Beachte, dass die Reihenfolge des Anhakens maßgebend ist. + + Voraussetzungen + Beachte, dass die Reihenfolge des Anhakens maßgebend ist. {tutorials.map((tutorial, i) => ({ color: theme.palette.text.primary }, multiGridListTile: { - background: fade(theme.palette.secondary.main, 0.5), + background: "#4EAF47", + opacity: 0.9, height: '30px' }, multiGridListTileTitle: { @@ -45,46 +46,47 @@ class Hardware extends Component { }; handleClickOpen = (hardwareInfo) => { - this.setState({open: true, hardwareInfo}); + this.setState({ open: true, hardwareInfo }); }; handleClose = () => { - this.setState({open: false, hardwareInfo: {}}); + this.setState({ open: false, hardwareInfo: {} }); }; render() { var cols = isWidthDown('md', this.props.width) ? isWidthDown('sm', this.props.width) ? isWidthDown('xs', this.props.width) ? 2 : 3 : 4 : 6; return ( -
+
Für die Umsetzung benötigst du folgende Hardware: - {this.props.picture.map((picture,i) => { - var hardwareInfo = hardware.filter(hardware => hardware.id === picture)[0]; - return( - -
- {hardwareInfo.name} this.handleClickOpen(hardwareInfo)}/> -
- - {hardwareInfo.name} -
- } - actionIcon={ - this.handleClickOpen(hardwareInfo)}> - - - } - /> - - )})} + {this.props.picture.map((picture, i) => { + var hardwareInfo = hardware.filter(hardware => hardware.id === picture)[0]; + return ( + +
+ {hardwareInfo.name} this.handleClickOpen(hardwareInfo)} /> +
+ + {hardwareInfo.name} +
+ } + actionIcon={ + this.handleClickOpen(hardwareInfo)}> + + + } + /> + + ) + })}
- {this.state.hardwareInfo.name}/ + {this.state.hardwareInfo.name} Weitere Informationen zur Hardware-Komponente findest du hier.
diff --git a/src/components/Tutorial/Requirement.js b/src/components/Tutorial/Requirement.js index 9c2542e..1ebd342 100644 --- a/src/components/Tutorial/Requirement.js +++ b/src/components/Tutorial/Requirement.js @@ -5,7 +5,7 @@ import { connect } from 'react-redux'; import clsx from 'clsx'; import { withRouter, Link } from 'react-router-dom'; -import tutorials from '../../data/tutorials.json'; +import tutorials from '../../data/tutorials'; import { fade } from '@material-ui/core/styles/colorManipulator'; import { withStyles } from '@material-ui/core/styles'; @@ -63,46 +63,47 @@ class Requirement extends Component { render() { var tutorialIds = this.props.tutorialIds; return ( -
- Es bietet sich an folgende Tutorials vorab erfolgreich gelöst zu haben: +
+ Bevor du mit diesem Tutorial fortfährst solltest du folgende Tutorials erfolgreich abgeschlossen haben: {tutorialIds.map((tutorialId, i) => { var title = tutorials.filter(tutorial => tutorial.id === tutorialId)[0].title; var status = this.props.status.filter(status => status.id === tutorialId)[0]; var tasks = status.tasks; var error = status.tasks.filter(task => task.type === 'error').length > 0; - var success = status.tasks.filter(task => task.type === 'success').length/tasks.length + var success = status.tasks.filter(task => task.type === 'success').length / tasks.length var tutorialStatus = success === 1 ? 'Success' : error ? 'Error' : 'Other'; - return( + return ( - +
-
- +
+ {error || success === 1 ? - : } + : } {success < 1 && !error ? - + - : null} + : null}
{error || success === 1 ? - - : 0 ? this.props.classes.outerDivSuccess : {}}>{Math.round(success*100)}% + + : 0 ? this.props.classes.outerDivSuccess : {}}>{Math.round(success * 100)}% }
-
- {title} +
+ {title}
- )} + ) + } )}
@@ -120,4 +121,4 @@ const mapStateToProps = state => ({ status: state.tutorial.status }); -export default connect(mapStateToProps, null)(withStyles(styles, {withTheme: true})(withRouter(Requirement))); +export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(withRouter(Requirement))); diff --git a/src/components/Tutorial/SolutionCheck.js b/src/components/Tutorial/SolutionCheck.js index bc8c6c8..92c093f 100644 --- a/src/components/Tutorial/SolutionCheck.js +++ b/src/components/Tutorial/SolutionCheck.js @@ -8,7 +8,7 @@ import { withRouter } from 'react-router-dom'; import Compile from '../Compile'; import Dialog from '../Dialog'; -import tutorials from '../../data/tutorials.json'; +import tutorials from '../../data/tutorials'; import { checkXml } from '../../helpers/compareXml'; import { withStyles } from '@material-ui/core/styles'; @@ -32,16 +32,16 @@ const styles = (theme) => ({ class SolutionCheck extends Component { - state={ + state = { open: false, msg: '' } toggleDialog = () => { - if(this.state.open){ + if (this.state.open) { this.setState({ open: false, msg: '' }); } - else{ + else { this.setState({ open: !this.state }); } } @@ -61,15 +61,15 @@ class SolutionCheck extends Component { this.check()} > - + {this.state.msg.type === 'success' ? -
+
- {this.props.activeStep === steps.length-1 ? + {this.props.activeStep === steps.length - 1 ? - : + : }
- : null} + : null}
@@ -125,4 +125,4 @@ const mapStateToProps = state => ({ xml: state.workspace.code.xml }); -export default connect(mapStateToProps, { tutorialCheck, tutorialStep })(withStyles(styles, {withTheme: true})(withRouter(SolutionCheck))); +export default connect(mapStateToProps, { tutorialCheck, tutorialStep })(withStyles(styles, { withTheme: true })(withRouter(SolutionCheck))); diff --git a/src/components/Tutorial/StepperHorizontal.js b/src/components/Tutorial/StepperHorizontal.js index c446675..b4d87c0 100644 --- a/src/components/Tutorial/StepperHorizontal.js +++ b/src/components/Tutorial/StepperHorizontal.js @@ -6,7 +6,7 @@ import { withRouter } from 'react-router-dom'; import clsx from 'clsx'; -import tutorials from '../../data/tutorials.json'; +import tutorials from '../../data/tutorials'; import { fade } from '@material-ui/core/styles/colorManipulator'; import { withStyles } from '@material-ui/core/styles'; @@ -58,31 +58,31 @@ class StepperHorizontal extends Component { var tutorialStatus = success === 1 ? 'Success' : error ? 'Error' : 'Other'; var title = tutorials.filter(tutorial => tutorial.id === tutorialId)[0].title; return ( -
+
{error || success > 0 ? -
+
- : null} + : null} {success < 1 && !error ? -
+
- : null} + : null}
- +
- {tutorialStatus !== 'Other' ?
: null} - {title} + {tutorialStatus !== 'Other' ?
: null} + {title}
@@ -104,4 +104,4 @@ const mapStateToProps = state => ({ currentTutorialId: state.tutorial.currentId }); -export default connect(mapStateToProps, null)(withRouter(withStyles(styles, {withTheme: true})(StepperHorizontal))); +export default connect(mapStateToProps, null)(withRouter(withStyles(styles, { withTheme: true })(StepperHorizontal))); diff --git a/src/components/Tutorial/Tutorial.js b/src/components/Tutorial/Tutorial.js index f2a7bb7..09c8e27 100644 --- a/src/components/Tutorial/Tutorial.js +++ b/src/components/Tutorial/Tutorial.js @@ -13,24 +13,24 @@ import NotFound from '../NotFound'; import { detectWhitespacesAndReturnReadableResult } from '../../helpers/whitespace'; -import tutorials from '../../data/tutorials.json'; +import tutorials from '../../data/tutorials'; import Card from '@material-ui/core/Card'; import Button from '@material-ui/core/Button'; class Tutorial extends Component { - componentDidMount(){ + componentDidMount() { this.props.tutorialId(Number(this.props.match.params.tutorialId)); } - componentDidUpdate(props, state){ - if(props.currentTutorialId !== Number(this.props.match.params.tutorialId)){ + componentDidUpdate(props, state) { + if (props.currentTutorialId !== Number(this.props.match.params.tutorialId)) { this.props.tutorialId(Number(this.props.match.params.tutorialId)); } } - componentWillUnmount(){ + componentWillUnmount() { this.props.tutorialId(null); this.props.workspaceName(null); } @@ -43,30 +43,30 @@ class Tutorial extends Component { var name = step ? `${detectWhitespacesAndReturnReadableResult(tutorial.title)}_${detectWhitespacesAndReturnReadableResult(step.headline)}` : null; return ( !Number.isInteger(currentTutorialId) || currentTutorialId < 1 || !tutorial ? - - : -
- + + : +
+ - + -
- - {/* calc(Card-padding: 10px + Button-height: 35px + Button-marginTop: 15px)*/} - - {step ? - step.type === 'instruction' ? - - : // if step.type === 'assessment' - : null} +
+ + {/* calc(Card-padding: 10px + Button-height: 35px + Button-marginTop: 15px)*/} + + {step ? + step.type === 'instruction' ? + + : // if step.type === 'assessment' + : null} -
- - -
-
+
+ + +
+ +
-
); }; } diff --git a/src/components/Tutorial/TutorialHome.js b/src/components/Tutorial/TutorialHome.js index e56cf31..a6ffa1a 100644 --- a/src/components/Tutorial/TutorialHome.js +++ b/src/components/Tutorial/TutorialHome.js @@ -6,7 +6,8 @@ import clsx from 'clsx'; import Breadcrumbs from '../Breadcrumbs'; -import tutorials from '../../data/tutorials.json'; +import tutorials from '../../data/tutorials'; +// import tutorials from '../../data/tutorials.json'; import { Link } from 'react-router-dom'; @@ -54,7 +55,7 @@ class TutorialHome extends Component { render() { return (
- +

Tutorial-Übersicht

@@ -62,36 +63,37 @@ class TutorialHome extends Component { var status = this.props.status.filter(status => status.id === tutorial.id)[0]; var tasks = status.tasks; var error = status.tasks.filter(task => task.type === 'error').length > 0; - var success = status.tasks.filter(task => task.type === 'success').length/tasks.length + var success = status.tasks.filter(task => task.type === 'success').length / tasks.length var tutorialStatus = success === 1 ? 'Success' : error ? 'Error' : 'Other'; return ( - - + + {tutorial.title} -
- +
+ {error || success === 1 ? - - : } + + : } {success < 1 && !error ? - + - : null} + : null}
{error || success === 1 ? - - : 0 ? this.props.classes.outerDivSuccess : {}}>{Math.round(success*100)}% + + : 0 ? this.props.classes.outerDivSuccess : {}}>{Math.round(success * 100)}% }
- )})} + ) + })}
); @@ -108,4 +110,4 @@ const mapStateToProps = state => ({ status: state.tutorial.status }); -export default connect(mapStateToProps, null)(withStyles(styles, {withTheme: true})(TutorialHome)); +export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(TutorialHome)); diff --git a/src/data/ErsteSchritte.json b/src/data/ErsteSchritte.json new file mode 100644 index 0000000..b844746 --- /dev/null +++ b/src/data/ErsteSchritte.json @@ -0,0 +1 @@ +{"id":1602160534286,"title":"Erste Schritte","steps":[{"id":1,"type":"instruction","headline":"Erste Schritte","text":"In diesem Tutorial lernst du die ersten Schritte mit der senseBox kennen. Du erstellst ein erstes Programm, baust einen ersten Schaltkreis auf und lernst, wie du das Programm auf die senseBox MCU überträgst.","hardware":["senseboxmcu","led","breadboard","jst-adapter","resistor-470ohm"],"requirements":[]},{"id":2,"type":"instruction","headline":"Aufbau der Schaltung","text":"Stecke die LED auf das Breadboard und verbinde diese mithile des Widerstandes und dem JST Kabel mit dem Port Digital/Analog 1."},{"id":3,"type":"instruction","headline":"Programmierung","text":"Jedes Programm für die senseBox besteht aus zwei Funktionen. Die Setup () Funktion wird zu Begin einmalig ausgeführt und der Programmcode Schrittweise ausgeführt. Nachdem die Setup () Funktion durchlaufen worden ist wird der Programmcode aus der zweiten Funktion, der Endlosschleife, fortlaufend wiederholt.","xml":"\n \n"},{"id":4,"type":"instruction","headline":"Leuchten der LED","text":"Um nun die LED zum leuchten zu bringen wird folgender Block in die Endlosschleife eingefügt. Der Block bietet dir auszuwählen an welchen Pin die LED angeschlossen wurd und ob diese ein oder ausgeschaltet werden soll.","xml":"\n \n 1\n HIGH\n \n"},{"id":5,"type":"task","headline":"Aufgabe 1","text":"Verwende den zuvor kennengelernten Block, um die LED zum leuchten zu bringen.","xml":"\n \n \n \n 1\n HIGH\n \n \n \n"},{"id":6,"type":"instruction","headline":"Programmcode übertragen","text":"Super! Du hast dein erstes Programm erstellt und kompiliert. In nächsten Schritt muss das Programm auf deine senseBox MCU übertragen werden. Schließe diese mithilfe des USB Kabel an deinem Computer an und drücke 2 mal schnell hintereinander auf den roten Reset Button, um die senseBox MCU in den Lernmodus zu versetzten. Die senseBox MCU erscheint nun als USB-Gerät in deinem Dateiexplorer. Kopiere anschließend das Programm auf die senseBox MCU.","media":{"youtube":"jzlOJ7Zuqqw"}}]} \ No newline at end of file diff --git a/src/data/Wenn-DannBedingungen.json b/src/data/Wenn-DannBedingungen.json new file mode 100644 index 0000000..8ade20c --- /dev/null +++ b/src/data/Wenn-DannBedingungen.json @@ -0,0 +1,44 @@ +{ + "id": 1602160884767, + "title": "Wenn-Dann Bedingungen", + "steps": [ + { + "id": 1, + "type": "instruction", + "headline": "Wenn-Dann-Was?", + "text": "In diesem Tutorial lernst du die Verwendung von Wenn-Dann Bedingungen kennen. Die Wenn-Dann Bedingung ist eine der wichtigsten Kontrollstrukturen in der Programmierung und hilft dir dabei auf bestimmte Zustände einzugehen. ", + "hardware": [ + "senseboxmcu", + "breadboard", + "jst-adapter", + "resistor-470ohm" + ], + "requirements": [ + 1602160534286 + ] + }, + { + "id": 2, + "type": "instruction", + "headline": "Aufbau der Hardware", + "text": "Verbinde die LED mit Hilfe des JST-Adapter Kabel und dem 470 Ohm Widerstand mit einem der 3 digital/analog Ports der senseBox MCU. ", + "media": { + "picture": "01_circuit.png" + } + }, + { + "id": 3, + "type": "instruction", + "headline": "Die Wenn-Dann Bedingung", + "text": "Eine Wenn-Dann Bedingung kann dazu verwendet werden bestimmten Zeilen Code auszuführen, wenn eine bestimmte Bedingung erfüllt ist. \n\nwenn Bedingung dann\n Anweisung(en)\nende\n\nDas Beispiel unten zeigt dir wie eine Wenn-Dann Bedingung aufgebaut ist. Es kann zum Beispiel die Temperatur mit einem Wert verglichen werden. Ist dieser Vergleich wahr (true), dann werden die Blöcke ausgeführt, die neben \"dann\" stehen ausgeführt. Ist die Bedingung nicht erfüllt (false) dann wird einfach der Programmcode unterhalb der Wenn-Dann Bedingung ausgeführt.\n", + "xml": "\n \n \n \n \n \n EQ\n \n \n Temperature\n \n \n \n \n \n \n \n \n 0\n \n" + }, + { + "id": 4, + "type": "task", + "headline": "Leuchten der LED auf Knopfdruck", + "text": "Lasse die LED leuchten, wenn der \"Button\" auf der senseBox MCU gedrückt wird. Den Block für den Button findest du unter \"Sensoren\".", + "xml": "\n \n \n \n \n \n \n EQ\n \n \n isPressed\n 0\n \n \n \n \n TRUE\n \n \n \n \n \n \n 1\n HIGH\n \n \n \n \n EQ\n \n \n isPressed\n 0\n \n \n \n \n FALSE\n \n \n \n \n \n \n 1\n LOW\n \n \n \n \n \n" + } + ] +} \ No newline at end of file diff --git a/src/data/loops_01.json b/src/data/loops_01.json new file mode 100644 index 0000000..1f445e0 --- /dev/null +++ b/src/data/loops_01.json @@ -0,0 +1,50 @@ +{ + "id": 1602162097684, + "title": "Schleifen", + "steps": [ + { + "id": 1, + "type": "instruction", + "headline": "Schleifen", + "text": "In diesem Tutorial wird die Verwendung von Schleifen eingeführt. Eine Schleife (auch „Wiederholung“ oder englisch loop) ist eine Kontrollstruktur in Programmiersprachen. Sie wiederholt einen Anweisungs-Block – den sogenannten Schleifenrumpf oder Schleifenkörper –, solange die Schleifenbedingung als Laufbedingung gültig bleibt bzw. als Abbruchbedingung nicht eintritt. Schleifen, deren Schleifenbedingung immer zur Fortsetzung führt oder die keine Schleifenbedingung haben, sind Endlosschleifen. Die Endlosschleife hast du bereits im ersten Tutorial \"Erste Schritte\" kennengelernt", + "hardware": [ + "breadboard", + "jst-adapter", + "senseboxmcu", + "led", + "resistor-470ohm" + ], + "requirements": [ + 1602160534286 + ] + }, + { + "id": 2, + "type": "instruction", + "headline": "Verwendung von Schleifen", + "text": "Die Blöcke findest du in der Kategorie \"Schleifen\". Die einfachste Schleife, die du Verwenden kannst, ist der Block \"Wiederhole 10 mal\". Bei diesem Block kannst du die Blöcke, die eine bestimmte Zahl wiederholt werden soll einfach in den offenen Block abschnitt ziehen. ", + "xml": "\n \n \n \n 10\n \n \n \n" + }, + { + "id": 3, + "type": "task", + "headline": "Verwendung von Schleifen", + "text": "Lass die LED genau 5 mal in einem Abstand von 1000 Millisekunden blinken. Anschließend soll die LED ausgeschaltet werden. ", + "xml": "\n \n \n \n \n \n 5\n \n \n \n \n 1\n HIGH\n \n \n \n \n 1000\n \n \n \n \n 1\n LOW\n \n \n \n \n 1000\n \n \n \n \n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 4, + "type": "instruction", + "headline": "Schleife mit Laufzeitvariable", + "text": "Mit diesem Block lässt sich die Schleife noch genauer Steuern und beeinflussen. Hierbei wird nicht nur angegeben wie oft die Anweisungen innerhalb der Schleife wiederholt werden sondern auch welche Variable zum zählen verwendet wird und in welchen Schritten gezählt werden soll. Der Vorteil bei diesem Block ist, dass die Wert der Variable auch innerhalb der Anweisungen verwendet werden kann. So kannst zum Beispiel die Variable \"i\" verwenden um die Blinkfrequenz zu beeinflussen.", + "xml": "\n \n i\n \n \n \n \n i\n \n \n 100\n \n \n \n \n 1000\n \n \n \n \n 100\n \n \n \n \n 1\n HIGH\n \n \n \n \n i\n \n \n \n \n 1\n LOW\n \n \n \n \n i\n \n \n \n \n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 5, + "type": "task", + "headline": "Schleifen mit Laufzeitvariable", + "text": "Verwende die Schleife mit Laufzeitvariable und beeinflusse die Blinkfrequenz mithilfe dem Wert der Variable.", + "xml": "\n \n i\n \n \n \n \n i\n \n \n 100\n \n \n \n \n 1000\n \n \n \n \n 100\n \n \n \n \n 1\n HIGH\n \n \n \n \n i\n \n \n \n \n 1\n LOW\n \n \n \n \n i\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 1000\n \n" + } + ] +} \ No newline at end of file diff --git a/src/data/tutorials.js b/src/data/tutorials.js new file mode 100644 index 0000000..6462f46 --- /dev/null +++ b/src/data/tutorials.js @@ -0,0 +1,9 @@ + + +let tutorials = [ + require('./ErsteSchritte.json'), + require('./loops_01.json'), + require('./Wenn-DannBedingungen.json'), + require('./variablen_01.json'), +] +module.exports = tutorials; \ No newline at end of file diff --git a/src/data/tutorials.json b/src/data/tutorials.json deleted file mode 100644 index 47c4b11..0000000 --- a/src/data/tutorials.json +++ /dev/null @@ -1,151 +0,0 @@ -[ - { - "id": 1, - "title": "Erste Schritte", - "steps": [ - { - "id": 1, - "type": "instruction", - "headline": "Erste Schritte", - "text": "In diesem Tutorial lernst du die ersten Schritte mit der senseBox kennen. Du erstellst ein erstes Programm, baust einen ersten Schaltkreis auf und lernst, wie du das Programm auf die senseBox MCU überträgst.", - "hardware": [ - "senseboxmcu", - "led", - "breadboard", - "jst-adapter", - "resistor-470ohm" - ], - "requirements": [] - }, - { - "id": 2, - "type": "instruction", - "headline": "Aufbau der Schaltung", - "text": "Stecke die LED auf das Breadboard und verbinde diese mithile des Widerstandes und dem JST Kabel mit dem Port Digital/Analog 1." - }, - { - "id": 3, - "type": "instruction", - "headline": "Programmierung", - "text": "Jedes Programm für die senseBox besteht aus zwei Funktionen. Die Setup () Funktion wird zu Begin einmalig ausgeführt und der Programmcode Schrittweise ausgeführt. Nachdem die Setup () Funktion durchlaufen worden ist wird der Programmcode aus der zweiten Funktion, der Endlosschleife, fortlaufend wiederholt.", - "xml": "" - }, - { - "id": 4, - "type": "instruction", - "headline": "Leuchten der LED", - "text": "Um nun die LED zum leuchten zu bringen wird folgender Block in die Endlosschleife eingefügt. Der Block bietet dir auszuwählen an welchen Pin die LED angeschlossen wurd und ob diese ein oder ausgeschaltet werden soll.", - "xml": "" - }, - { - "id": 5, - "type": "task", - "headline": "Aufgabe 1", - "text": "Verwenden den Block zum leuchten der LED und übertrage dein erstes Programm auf die senseBox MCU.", - "xml": "" - } - ] - }, - { - "id": 2, - "title": "Schleifen", - "steps": [ - { - "id": 1, - "type": "instruction", - "headline": "Schleifen", - "text": "In diesem Tutorial wird die Verwendung von Schleifen eingeführt. Eine Schleife (auch „Wiederholung“ oder englisch loop) ist eine Kontrollstruktur in Programmiersprachen. Sie wiederholt einen Anweisungs-Block – den sogenannten Schleifenrumpf oder Schleifenkörper –, solange die Schleifenbedingung als Laufbedingung gültig bleibt bzw. als Abbruchbedingung nicht eintritt. Schleifen, deren Schleifenbedingung immer zur Fortsetzung führt oder die keine Schleifenbedingung haben, sind Endlosschleifen. Die Endlosschleife hast du bereits im ersten Tutorial \"Erste Schritte\" kennengelernt", - "hardware": [ - "breadboard", - "jst-adapter", - "senseboxmcu", - "led", - "resistor-470ohm" - ], - "requirements": [ - 1 - ] - }, - { - "id": 2, - "type": "instruction", - "headline": "Verwendung von Schleifen", - "text": "Die Blöcke findest du in der Kategorie \"Schleifen\". Die einfachste Schleife, die du Verwenden kannst, ist der Block \"Wiederhole 10 mal\". Bei diesem Block kannst du die Blöcke, die eine bestimmte Zahl wiederholt werden soll einfach in den offenen Block abschnitt ziehen. ", - "xml": "\n \n \n \n 10\n \n \n \n" - }, - { - "id": 3, - "type": "task", - "headline": "Verwendung von Schleifen", - "text": "Lass die LED genau 5 mal in einem Abstand von 1000 Millisekunden blinken. Anschließend soll die LED ausgeschaltet werden. ", - "xml": "\n \n \n \n \n \n 5\n \n \n \n \n 1\n HIGH\n \n \n \n \n 1000\n \n \n \n \n 1\n LOW\n \n \n \n \n 1000\n \n \n \n \n \n \n \n \n \n \n \n \n \n" - }, - { - "id": 4, - "type": "instruction", - "headline": "Schleife mit Laufzeitvariable", - "text": "Mit diesem Block lässt sich die Schleife noch genauer Steuern und beeinflussen. Hierbei wird nicht nur angegeben wie oft die Anweisungen innerhalb der Schleife wiederholt werden sondern auch welche Variable zum zählen verwendet wird und in welchen Schritten gezählt werden soll. Der Vorteil bei diesem Block ist, dass die Wert der Variable auch innerhalb der Anweisungen verwendet werden kann. So kannst zum Beispiel die Variable \"i\" verwenden um die Blinkfrequenz zu beeinflussen.", - "xml": "\n \n i\n \n \n \n \n i\n \n \n 100\n \n \n \n \n 1000\n \n \n \n \n 100\n \n \n \n \n 1\n HIGH\n \n \n \n \n i\n \n \n \n \n 1\n LOW\n \n \n \n \n i\n \n \n \n \n \n \n \n \n \n \n \n \n \n" - }, - { - "id": 5, - "type": "task", - "headline": "Schleifen mit Laufzeitvariable", - "text": "Verwende die Schleife mit Laufzeitvariable und beeinflusse die Blinkfrequenz mithilfe dem Wert der Variable.", - "xml": "\n \n i\n \n \n \n \n i\n \n \n 100\n \n \n \n \n 1000\n \n \n \n \n 100\n \n \n \n \n 1\n HIGH\n \n \n \n \n i\n \n \n \n \n 1\n LOW\n \n \n \n \n i\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 1000\n \n" - } - ] - }, - { - "id": 3, - "title": "WLAN einrichten", - "steps": [ - { - "id": 1, - "type": "instruction", - "headline": "Einführung", - "text": "In diesem Tutorial lernst du wie man die senseBox mit dem Internet verbindest.", - "hardware": [ - "senseboxmcu", - "wifi-bee" - ], - "requirements": [ - 1 - ] - }, - { - "id": 2, - "type": "instruction", - "headline": "Programmierung", - "text": "Man benötigt folgenden Block:", - "media": { - "picture": "block_en.svg" - }, - "xml": "SSIDPassword" - }, - { - "id": 3, - "type": "instruction", - "headline": "Block richtig einbinden", - "text": "Dies ist ein Test.", - "media": { - "youtube": "sf3RzXq6iVo" - } - }, - { - "id": 4, - "type": "task", - "headline": "Aufgabe 1", - "text": "Stelle eine WLAN-Verbindung mit einem beliebigen Netzwerk her.", - "xml": "SSIDPassword" - }, - { - "id": 5, - "type": "task", - "headline": "Aufgabe 2", - "text": "Versuche das gleiche einfach nochmal. Übung macht den Meister! ;)", - "xml": "SSIDPassword" - } - ] - } -] \ No newline at end of file diff --git a/src/data/variablen_01.json b/src/data/variablen_01.json new file mode 100644 index 0000000..7f73f99 --- /dev/null +++ b/src/data/variablen_01.json @@ -0,0 +1,41 @@ +{ + "id": 1602162172424, + "title": "Verwendung von Variablen", + "steps": [ + { + "id": 1, + "type": "instruction", + "headline": "Variablen", + "text": "Variablen, auch Platzhalter genannt, werden in der Informatik für verschiedene Dinge genutzt. Sie sind eine Art Kiste, die mit einem Namen versehen ist. In dieser Kiste kannst du verschiedene Dinge hinterlegen (z.B. Zahlen und Texte) und diese später wieder abrufen. ", + "hardware": [ + "senseboxmcu", + "oled", + "jst-jst", + "hdc1080" + ], + "requirements": [ + 1602160534286 + ] + }, + { + "id": 2, + "type": "instruction", + "headline": "Aufbau der Hardware", + "text": "Verbinde das Display und den Temperatur- und Luftfeuchtigkeitssensor jeweils mit einem JST-JST Kabel mit einem der 5 I2C Ports auf der senseBox MCU." + }, + { + "id": 3, + "type": "instruction", + "headline": "Variablen in Blockly", + "text": "Variablen können ihren Wert im Laufe des Programmes verändern, sodass du zum Beispiel der Variable „Temperatur“ immer den aktuell gemessenen Temperaturwert zuweist. Eine Variablen besitzt immer einer bestimmten Datentyp. Der Datentyp gibt im Endeffekt an, wie groß die Kiste ist und wie der Wert aussehen kann, der in der Variable gespeichert werden kann. \n\nVariablen - Datentypen\nJe nachdem, was du in einer Variable speichern möchtest, musst du den richten Datentyp auswählen.\nZeichen: Für einzelne Textzeichen\nText: Für ganze Wörter oder Sätze\nZahl: Für Zahlen von -32768 bis +32768\nGroße Zahl: Für Zahlen von -2147483648 bis\n +2147483648\nDezimalzahl: Für Kommazahlen (z.B. 25,3)", + "xml": "\n \n Temperatur\n \n \n \n \n \n \n \n Temperatur\n \n \n Temperature\n \n \n \n \n \n \n WHITE,BLACK\n 1\n 0\n 0\n \n \n \n \n \n \n \n \n Temperatur\n \n" + }, + { + "id": 4, + "type": "task", + "headline": "Aufgabe 1:", + "text": "Erste 2 Variablen vom Typ \"Kommazahl\" und weise die Werte für Temperatur und Luftfeuchtigkeit zu. Lasse anschließend den Wert der Variablen auf dem Display anzeigen.", + "xml": "\n \n Temperatur\n Luftfeuchte\n \n \n \n \n \n \n \n Temperatur\n \n \n Temperature\n \n \n \n \n Luftfeuchte\n \n \n Temperature\n \n \n \n \n \n \n WHITE,BLACK\n 1\n 0\n 0\n \n \n Luftfeuchte\n \n \n \n \n WHITE,BLACK\n 1\n 0\n 20\n \n \n Temperatur\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n" + } + ] +} \ No newline at end of file diff --git a/src/reducers/tutorialReducer.js b/src/reducers/tutorialReducer.js index e96a132..c0eb18b 100644 --- a/src/reducers/tutorialReducer.js +++ b/src/reducers/tutorialReducer.js @@ -1,41 +1,41 @@ import { TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE, TUTORIAL_XML, TUTORIAL_ID, TUTORIAL_STEP } from '../actions/types'; -import tutorials from '../data/tutorials.json'; +import tutorials from '../data/tutorials'; const initialStatus = () => { - if(window.localStorage.getItem('status')){ + if (window.localStorage.getItem('status')) { var status = JSON.parse(window.localStorage.getItem('status')); var existingTutorialIds = tutorials.map((tutorial, i) => { var tutorialsId = tutorial.id; var statusIndex = status.findIndex(status => status.id === tutorialsId); - if(statusIndex > -1){ + if (statusIndex > -1) { var tasks = tutorial.steps.filter(step => step.type === 'task'); var existingTaskIds = tasks.map((task, j) => { var tasksId = task.id; - if(status[statusIndex].tasks.findIndex(task => task.id === tasksId) === -1){ + if (status[statusIndex].tasks.findIndex(task => task.id === tasksId) === -1) { // task does not exist - status[statusIndex].tasks.push({id: tasksId}); + status[statusIndex].tasks.push({ id: tasksId }); } return tasksId; }); // deleting old tasks which do not longer exist - if(existingTaskIds.length > 0){ + if (existingTaskIds.length > 0) { status[statusIndex].tasks = status[statusIndex].tasks.filter(task => existingTaskIds.indexOf(task.id) > -1); } } - else{ - status.push({id: tutorialsId, tasks: tutorial.steps.filter(step => step.type === 'task').map(task => {return {id: task.id};})}); + else { + status.push({ id: tutorialsId, tasks: tutorial.steps.filter(step => step.type === 'task').map(task => { return { id: task.id }; }) }); } return tutorialsId; }); // deleting old tutorials which do not longer exist - if(existingTutorialIds.length > 0){ + if (existingTutorialIds.length > 0) { status = status.filter(status => existingTutorialIds.indexOf(status.id) > -1); } return status; } // window.localStorage.getItem('status') does not exist - return tutorials.map(tutorial => {return {id: tutorial.id, tasks: tutorial.steps.filter(step => step.type === 'task').map(task => {return {id: task.id};})};}); + return tutorials.map(tutorial => { return { id: tutorial.id, tasks: tutorial.steps.filter(step => step.type === 'task').map(task => { return { id: task.id }; }) }; }); }; const initialState = { @@ -45,8 +45,8 @@ const initialState = { change: 0 }; -export default function(state = initialState, action){ - switch(action.type){ +export default function (state = initialState, action) { + switch (action.type) { case TUTORIAL_SUCCESS: case TUTORIAL_ERROR: case TUTORIAL_XML: