upload JSON file
This commit is contained in:
		
							parent
							
								
									28ced177bd
								
							
						
					
					
						commit
						7579be52c9
					
				| @ -1,4 +1,4 @@ | ||||
| import { BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types'; | ||||
| import { PROGRESS, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types'; | ||||
| 
 | ||||
| export const changeTutorialBuilder = () => (dispatch) => { | ||||
|   dispatch({ | ||||
| @ -14,6 +14,14 @@ export const tutorialTitle = (title) => (dispatch) => { | ||||
|   dispatch(changeTutorialBuilder()); | ||||
| }; | ||||
| 
 | ||||
| export const tutorialSteps = (steps) => (dispatch) => { | ||||
|   dispatch({ | ||||
|     type: BUILDER_ADD_STEP, | ||||
|     payload: steps | ||||
|   }); | ||||
|   dispatch(changeTutorialBuilder()); | ||||
| }; | ||||
| 
 | ||||
| export const tutorialId = (id) => (dispatch) => { | ||||
|   dispatch({ | ||||
|     type: BUILDER_ID, | ||||
| @ -116,7 +124,6 @@ export const changeErrorStepIndex = (fromIndex, toIndex) => (dispatch, getState) | ||||
| 
 | ||||
| export const setError = (index, property) => (dispatch, getState) => { | ||||
|   var error = getState().builder.error; | ||||
|   console.log(index); | ||||
|   if(index !== undefined){ | ||||
|     error.steps[index][property] = true; | ||||
|   } | ||||
| @ -147,21 +154,21 @@ export const deleteError = (index, property) => (dispatch, getState) => { | ||||
| 
 | ||||
| export const setSubmitError = () => (dispatch, getState) => { | ||||
|   var builder = getState().builder; | ||||
|   if(builder.id === ''){ | ||||
|   if(builder.id === undefined || builder.id === ''){ | ||||
|     dispatch(setError(undefined, 'id')); | ||||
|   } | ||||
|   if(builder.title === ''){ | ||||
|   if(builder.id === undefined || builder.title === ''){ | ||||
|     dispatch(setError(undefined, 'title')); | ||||
|   } | ||||
|   for(var i = 0; i < builder.steps.length; i++){ | ||||
|     builder.steps[i].id = i+1; | ||||
|     if(i === 0 && builder.steps[i].hardware.length < 1){ | ||||
|     if(i === 0 && (builder.steps[i].hardware === undefined || builder.steps[i].hardware.length < 1)){ | ||||
|       dispatch(setError(i, 'hardware')); | ||||
|     } | ||||
|     if(builder.steps[i].headline === ''){ | ||||
|     if(builder.steps[i].headline === undefined || builder.steps[i].headline === ''){ | ||||
|       dispatch(setError(i, 'headline')); | ||||
|     } | ||||
|     if(builder.steps[i].text === ''){ | ||||
|     if(builder.steps[i].text === undefined || builder.steps[i].text === ''){ | ||||
|       dispatch(setError(i, 'text')); | ||||
|     } | ||||
|   } | ||||
| @ -180,3 +187,45 @@ export const checkError = () => (dispatch, getState) => { | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| export const progress = (inProgress) => (dispatch) => { | ||||
|   dispatch({ | ||||
|     type: PROGRESS, | ||||
|     payload: inProgress | ||||
|   }) | ||||
| }; | ||||
| 
 | ||||
| export const resetTutorial = () => (dispatch, getState) => { | ||||
|   dispatch(tutorialTitle('')); | ||||
|   dispatch(tutorialId('')); | ||||
|   var steps = [ | ||||
|     { | ||||
|       id: 1, | ||||
|       type: 'instruction', | ||||
|       headline: '', | ||||
|       text: '', | ||||
|       hardware: [], | ||||
|       requirements: [] | ||||
|     } | ||||
|   ]; | ||||
|   dispatch(tutorialSteps(steps)); | ||||
|   dispatch({ | ||||
|     type: BUILDER_ERROR, | ||||
|     payload: { | ||||
|       steps: [{}] | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| export const readJSON = (json) => (dispatch, getState) => { | ||||
|   dispatch(resetTutorial()); | ||||
|   dispatch({ | ||||
|     type: BUILDER_ERROR, | ||||
|     payload: {steps: [{},{}]} | ||||
|   }); | ||||
|   dispatch(tutorialTitle(json.title)); | ||||
|   dispatch(tutorialId(json.id)); | ||||
|   dispatch(tutorialSteps(json.steps)); | ||||
|   dispatch(setSubmitError()); | ||||
|   dispatch(progress(false)); | ||||
| }; | ||||
|  | ||||
| @ -25,3 +25,4 @@ export const BUILDER_CHANGE_STEP = 'BUILDER_CHANGE_STEP'; | ||||
| export const BUILDER_CHANGE_ORDER = 'BUILDER_CHANGE_ORDER'; | ||||
| export const BUILDER_DELETE_PROPERTY = 'BUILDER_DELETE_PROPERTY'; | ||||
| export const BUILDER_ERROR = 'BUILDER_ERROR'; | ||||
| export const PROGRESS = 'PROGRESS'; | ||||
|  | ||||
| @ -5,7 +5,9 @@ import { changeContent, deleteProperty, setError, deleteError } from '../../../a | ||||
| 
 | ||||
| import moment from 'moment'; | ||||
| import localization from 'moment/locale/de'; | ||||
| import * as Blockly from 'blockly/core'; | ||||
| 
 | ||||
| import { parseXml } from '../../../helpers/compareXml'; | ||||
| import BlocklyWindow from '../../Blockly/BlocklyWindow'; | ||||
| 
 | ||||
| import { withStyles } from '@material-ui/core/styles'; | ||||
| @ -94,19 +96,29 @@ class BlocklyExample extends Component { | ||||
|             /> | ||||
|           } | ||||
|         /> | ||||
|         {this.state.checked ? !this.props.value  ? | ||||
|         {this.state.checked ? !this.props.value || this.props.error.steps[this.props.index].xml ? | ||||
|           <FormHelperText style={{lineHeight: 'initial', marginBottom: '10px'}} className={this.props.classes.errorColor}>Reiche deine Blöcke ein, indem du auf den rot gefärbten Button klickst.</FormHelperText> | ||||
|         : <FormHelperText style={{lineHeight: 'initial', marginBottom: '10px'}}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText> | ||||
|         : null} | ||||
|         {this.state.checked ? | ||||
|         {this.state.checked ? () => { | ||||
|           var initialXml = this.props.value; | ||||
|           // check if value is valid xml;
 | ||||
|           try{ | ||||
|             Blockly.Xml.textToDom(initialXml); | ||||
|           } | ||||
|           catch(err){ | ||||
|             initialXml = null; | ||||
|             this.props.setError(this.props.index, 'xml'); | ||||
|           } | ||||
|           return( | ||||
|             <div> | ||||
|               <Grid container className={!this.props.value ? this.props.classes.errorBorder : null}> | ||||
|                 <Grid item xs={12}> | ||||
|                 <BlocklyWindow initialXml={this.props.value}/> | ||||
|                   <BlocklyWindow initialXml={initialXml}/> | ||||
|                 </Grid> | ||||
|               </Grid> | ||||
|               <Button | ||||
|               className={!this.props.value ? this.props.classes.errorButton : null } | ||||
|                 className={!this.props.value || this.props.error.steps[this.props.index].xml ? this.props.classes.errorButton : null } | ||||
|                 style={{marginTop: '5px', height: '40px'}} | ||||
|                 variant='contained' | ||||
|                 color='primary' | ||||
| @ -115,6 +127,7 @@ class BlocklyExample extends Component { | ||||
|                 {this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'} | ||||
|               </Button> | ||||
|             </div> | ||||
|           )} | ||||
|         : null} | ||||
|       </div> | ||||
|     ); | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import React, { Component } from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { checkError } from '../../../actions/tutorialBuilderActions'; | ||||
| import { checkError, readJSON, progress, resetTutorial } from '../../../actions/tutorialBuilderActions'; | ||||
| 
 | ||||
| import { saveAs } from 'file-saver'; | ||||
| 
 | ||||
| import data from '../../../data/hardware.json'; | ||||
| import { detectWhitespacesAndReturnReadableResult } from '../../../helpers/whitespace'; | ||||
| 
 | ||||
| import Breadcrumbs from '../../Breadcrumbs'; | ||||
| @ -12,14 +13,30 @@ import Id from './Id'; | ||||
| import Title from './Textfield'; | ||||
| import Step from './Step'; | ||||
| 
 | ||||
| import { withStyles } from '@material-ui/core/styles'; | ||||
| import Button from '@material-ui/core/Button'; | ||||
| import Backdrop from '@material-ui/core/Backdrop'; | ||||
| import CircularProgress from '@material-ui/core/CircularProgress'; | ||||
| import Divider from '@material-ui/core/Divider'; | ||||
| 
 | ||||
| const styles = (theme) => ({ | ||||
|   backdrop: { | ||||
|     zIndex: theme.zIndex.drawer + 1, | ||||
|     color: '#fff', | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| class Builder extends Component { | ||||
| 
 | ||||
|   constructor(props){ | ||||
|     super(props); | ||||
|     this.inputRef = React.createRef(); | ||||
|   } | ||||
| 
 | ||||
|   submit = () => { | ||||
|     var isError = this.props.checkError(); | ||||
|     if(isError){ | ||||
|       alert('Error'); | ||||
|       window.scrollTo(0, 0); | ||||
|     } | ||||
|     else{ | ||||
|       var tutorial = { | ||||
| @ -32,6 +49,74 @@ class Builder extends Component { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   reset = () => { | ||||
|     this.props.resetTutorial(); | ||||
|     window.scrollTo(0, 0); | ||||
|   } | ||||
| 
 | ||||
|   uploadJsonFile = (jsonFile) => { | ||||
|     this.props.progress(true); | ||||
|     if(jsonFile.type !== 'application/json'){ | ||||
|       alert('falscher Dateityp'); | ||||
|       this.props.progress(false); | ||||
|       this.setState({ open: true, file: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entsprach nicht dem geforderten Format. Es sind nur JSON-Dateien zulässig.' }); | ||||
|     } | ||||
|     else { | ||||
|       var reader = new FileReader(); | ||||
|       reader.readAsText(jsonFile); | ||||
|       reader.onloadend = () => { | ||||
|         try { | ||||
|           var result = JSON.parse(reader.result); | ||||
|           if(this.checkSteps(result.steps)){ | ||||
|             alert('Hier'); | ||||
|             this.props.readJSON(result); | ||||
|           } | ||||
|           else{ | ||||
|             this.props.progress(false); | ||||
|             alert('die JSON-Datei hat nicht die richtige Form'); | ||||
|           } | ||||
|         } catch(err){ | ||||
|           this.props.progress(false); | ||||
|           alert('ungültige JSON-Datei'); | ||||
|           this.setState({ open: true, file: false, title: 'Ungültige XML', content: 'Die XML-Datei konnte nicht in Blöcke zerlegt werden. Bitte überprüfe den XML-Code und versuche es erneut.' }); | ||||
|         } | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   checkSteps = (steps) => { | ||||
|     if(!(steps && steps.length > 0)){ | ||||
|       alert(1); | ||||
|       return false; | ||||
|     } | ||||
|     steps.map((step, i) => { | ||||
|       if(i === 0){ | ||||
|         if(!(step.requirements && | ||||
|              step.requirements.length > 0 && | ||||
|              step.requirements.filter(requirement => typeof(requirement) === 'number').length === step.requirements.length)){ | ||||
|           alert(3); | ||||
|           return false; | ||||
|         } | ||||
|         var hardwareIds = data.map(hardware => hardware.id); | ||||
|         if(!(step.hardware && | ||||
|              step.hardware.length > 0 && | ||||
|              step.hardware.filter(hardware => typeof(hardware) === 'string' && hardwareIds.includes(hardware)).length === step.hardware.length)){ | ||||
|           alert(4); | ||||
|           return false; | ||||
|         } | ||||
|       } | ||||
|       if(!(step.headline && typeof(step.headline)==='string')){ | ||||
|         alert(5); | ||||
|         return false; | ||||
|       } | ||||
|       if(!(step.text && typeof(step.text)==='string')){ | ||||
|         alert(6); | ||||
|         return false; | ||||
|       } | ||||
|     }); | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   render() { | ||||
|     return ( | ||||
| @ -40,6 +125,20 @@ class Builder extends Component { | ||||
| 
 | ||||
|         <h1>Tutorial-Builder</h1> | ||||
| 
 | ||||
|         <div ref={this.inputRef}> | ||||
|           <input | ||||
|             style={{display: 'none'}} | ||||
|             accept="application/json" | ||||
|             onChange={(e) => {this.uploadJsonFile(e.target.files[0])}} | ||||
|             id="open-json" | ||||
|             type="file" | ||||
|           /> | ||||
|           <label htmlFor="open-json"> | ||||
|             <Button component="span" style={{marginRight: '10px', marginBottom: '10px'}} variant='contained' color='primary'>Datei laden</Button> | ||||
|           </label> | ||||
|         </div> | ||||
|         <Divider variant='fullWidth' style={{margin: '10px 0 30px 0'}}/> | ||||
| 
 | ||||
|         <Id error={this.props.error} value={this.props.id}/> | ||||
|         <Title value={this.props.title} property={'title'} label={'Titel'} error={this.props.error}/> | ||||
| 
 | ||||
| @ -49,7 +148,11 @@ class Builder extends Component { | ||||
|         )} | ||||
| 
 | ||||
| 
 | ||||
|         <Button variant='contained' color='primary' onClick={() => this.submit()}>Tutorial-Vorlage erstellen</Button> | ||||
|         <Button style={{marginRight: '10px'}} variant='contained' color='primary' onClick={() => this.submit()}>Tutorial-Vorlage erstellen</Button> | ||||
|         <Button variant='contained' onClick={() => this.reset()}>Zurücksetzen</Button> | ||||
|         <Backdrop className={this.props.classes.backdrop} open={this.props.isProgress}> | ||||
|           <CircularProgress color="inherit" /> | ||||
|         </Backdrop> | ||||
| 
 | ||||
| 
 | ||||
|       </div> | ||||
| @ -63,10 +166,14 @@ class Builder extends Component { | ||||
| 
 | ||||
| Builder.propTypes = { | ||||
|   checkError: PropTypes.func.isRequired, | ||||
|   readJSON: PropTypes.func.isRequired, | ||||
|   progress: PropTypes.func.isRequired, | ||||
|   resetTutorial: PropTypes.func.isRequired, | ||||
|   title: PropTypes.string.isRequired, | ||||
|   steps: PropTypes.array.isRequired, | ||||
|   change: PropTypes.number.isRequired, | ||||
|   error: PropTypes.object.isRequired | ||||
|   error: PropTypes.object.isRequired, | ||||
|   isProgress: PropTypes.bool.isRequired | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps = state => ({ | ||||
| @ -74,7 +181,8 @@ const mapStateToProps = state => ({ | ||||
|   id: state.builder.id, | ||||
|   steps: state.builder.steps, | ||||
|   change: state.builder.change, | ||||
|   error: state.builder.error | ||||
|   error: state.builder.error, | ||||
|   isProgress: state.builder.progress | ||||
| }); | ||||
| 
 | ||||
| export default connect(mapStateToProps, { checkError })(Builder); | ||||
| export default connect(mapStateToProps, { checkError, readJSON, progress, resetTutorial })(withStyles(styles, {withTheme: true})(Builder)); | ||||
|  | ||||
| @ -89,11 +89,11 @@ class Step extends Component { | ||||
|             <Textfield value={this.props.step.text} property={'text'} label={this.props.step.type === 'task' ? 'Aufgabenstellung' : 'Instruktionen'} index={index} multiline error={this.props.error} errorText={`Gib Instruktionen für die ${this.props.step.type === 'task' ? 'Aufgabe' : 'Anleitung'} ein.`}/> | ||||
|             {index === 0 ? | ||||
|               <div> | ||||
|                 <Requirements value={this.props.step.requirements} index={index}/> | ||||
|                 <Hardware value={this.props.step.hardware} index={index} error={this.props.error}/> | ||||
|                 <Requirements value={this.props.step.requirements ? this.props.step.requirements : []} index={index}/> | ||||
|                 <Hardware value={this.props.step.hardware ? this.props.step.hardware : []} index={index} error={this.props.error}/> | ||||
|               </div> | ||||
|             : null} | ||||
|             <BlocklyExample value={this.props.step.xml} index={index} task={this.props.step.type === 'task'} /> | ||||
|             <BlocklyExample value={this.props.step.xml} index={index} task={this.props.step.type === 'task'} error={this.props.error}/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
| @ -11,7 +11,7 @@ class StepType extends Component { | ||||
| 
 | ||||
|   render() { | ||||
|     return ( | ||||
|       <RadioGroup row value={this.props.value} onChange={(e) => {this.props.changeContent(this.props.index, 'type', e.target.value)}}> | ||||
|       <RadioGroup row value={this.props.value === 'task' ? 'task' : 'instruction'} onChange={(e) => {this.props.changeContent(this.props.index, 'type', e.target.value)}}> | ||||
|         <FormControlLabel style={{color: 'black'}} | ||||
|           value="instruction" | ||||
|           control={<Radio color="primary" />} | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| import { BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP,BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from '../actions/types'; | ||||
| import { PROGRESS, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP,BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from '../actions/types'; | ||||
| 
 | ||||
| const initialState = { | ||||
|   change: 0, | ||||
|   progress: false, | ||||
|   title: '', | ||||
|   id: '', | ||||
|   steps: [ | ||||
| @ -50,6 +51,11 @@ export default function(state = initialState, action){ | ||||
|         ...state, | ||||
|         error: action.payload | ||||
|       } | ||||
|     case PROGRESS: | ||||
|       return { | ||||
|         ...state, | ||||
|         progress: action.payload | ||||
|       } | ||||
|     default: | ||||
|       return state; | ||||
|   } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user