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,27 +96,38 @@ 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 ?
|
||||
<div>
|
||||
<Grid container className={!this.props.value ? this.props.classes.errorBorder : null}>
|
||||
<Grid item xs={12}>
|
||||
<BlocklyWindow initialXml={this.props.value}/>
|
||||
{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={initialXml}/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Button
|
||||
className={!this.props.value ? this.props.classes.errorButton : null }
|
||||
style={{marginTop: '5px', height: '40px'}}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
onClick={() => {this.props.changeContent(this.props.index, 'xml', this.props.xml); this.setState({input: moment(Date.now()).format('LTS')})}}
|
||||
>
|
||||
{this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'}
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
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'
|
||||
onClick={() => {this.props.changeContent(this.props.index, 'xml', this.props.xml); this.setState({input: moment(Date.now()).format('LTS')})}}
|
||||
>
|
||||
{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