import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { checkError, readJSON, jsonString, progress, tutorialId, resetTutorial as resetTutorialBuilder} from '../../../actions/tutorialBuilderActions'; import { getTutorials, resetTutorial} from '../../../actions/tutorialActions'; import { clearMessages } from '../../../actions/messageActions'; import axios from 'axios'; import { saveAs } from 'file-saver'; import { detectWhitespacesAndReturnReadableResult } from '../../../helpers/whitespace'; import Breadcrumbs from '../../Breadcrumbs'; import Textfield from './Textfield'; import Step from './Step'; import Dialog from '../../Dialog'; import Snackbar from '../../Snackbar'; 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'; import FormHelperText from '@material-ui/core/FormHelperText'; import Radio from '@material-ui/core/Radio'; import RadioGroup from '@material-ui/core/RadioGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import InputLabel from '@material-ui/core/InputLabel'; import MenuItem from '@material-ui/core/MenuItem'; import FormControl from '@material-ui/core/FormControl'; import Select from '@material-ui/core/Select'; const styles = (theme) => ({ backdrop: { zIndex: theme.zIndex.drawer + 1, color: '#fff', }, errorColor: { color: theme.palette.error.dark } }); class Builder extends Component { constructor(props) { super(props); this.state = { tutorial: 'new', open: false, title: '', content: '', string: false, snackbar: false, key: '', message: '' }; this.inputRef = React.createRef(); } componentDidMount() { this.props.getTutorials(); } componentDidUpdate(props, state) { if(this.props.message.id === 'GET_TUTORIALS_FAIL'){ alert(this.props.message.msg); this.props.clearMessages(); } } componentWillUnmount() { this.resetFull(); this.props.resetTutorial(); if(this.props.message.msg){ this.props.clearMessages(); } } uploadJsonFile = (jsonFile) => { this.props.progress(true); 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.' }); } else { var reader = new FileReader(); reader.readAsText(jsonFile); reader.onloadend = () => { this.readJson(reader.result, true); }; } } uploadJsonString = () => { 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)) { 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.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.` }); } } checkSteps = (steps) => { if (!(steps && steps.length > 0)) { return false; } return true; } toggle = () => { this.setState({ open: !this.state }); } onChange = (value) => { this.props.resetTutorialBuilder(); this.props.tutorialId(''); this.setState({tutorial: value}); } onChangeId = (value) => { this.props.tutorialId(value); this.props.progress(true); var tutorial = this.props.tutorials.filter(tutorial => tutorial._id === value)[0]; this.props.readJSON(tutorial); this.setState({ snackbar: true, key: Date.now(), message: `Das ausgewählte Tutorial "${tutorial.title}" wurde erfolgreich übernommen.`, type: 'success' }); } resetFull = () => { this.props.resetTutorialBuilder(); this.setState({ snackbar: true, key: Date.now(), message: `Das Tutorial wurde erfolgreich zurückgesetzt.`, type: 'success' }); window.scrollTo(0, 0); } resetTutorial = () => { var tutorial = this.props.tutorials.filter(tutorial => tutorial._id === this.props.id)[0]; this.props.readJSON(tutorial); this.setState({ snackbar: true, key: Date.now(), message: `Das Tutorial ${tutorial.title} wurde erfolgreich auf den ursprünglichen Stand zurückgesetzt.`, type: 'success' }); window.scrollTo(0, 0); } submit = () => { 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' }); window.scrollTo(0, 0); return false; } else { // export steps without attribute 'url' var steps = this.props.steps; var newTutorial = new FormData(); newTutorial.append('title', this.props.title); steps.forEach((step, i) => { newTutorial.append(`steps[${i}][type]`, step.type); newTutorial.append(`steps[${i}][headline]`, step.headline); newTutorial.append(`steps[${i}][text]`, step.text); if(i === 0 && step.type === 'instruction'){ if(step.requirements){ // optional step.requirements.forEach((requirement, j) => { newTutorial.append(`steps[${i}][requirements][${j}]`, requirement); }); } step.hardware.forEach((hardware, j) => { newTutorial.append(`steps[${i}][hardware][${j}]`, hardware); }); } if(step.xml){ // optional newTutorial.append(`steps[${i}][xml]`, step.xml); } if(step.media){ // optional if(step.media.youtube){ newTutorial.append(`steps[${i}][media][youtube]`, step.media.youtube); } if(step.media.picture){ newTutorial.append(`steps[${i}][media][picture]`, step.media.picture); } } }); return newTutorial; } } submitNew = () => { var newTutorial = this.submit(); if(newTutorial){ axios.post(`${process.env.REACT_APP_BLOCKLY_API}/tutorial/`, newTutorial) .then(res => { var tutorial = res.data.tutorial; this.props.history.push(`/tutorial/${tutorial._id}`); }) .catch(err => { this.setState({ snackbar: true, key: Date.now(), message: `Fehler beim Erstellen des Tutorials. Versuche es noch einmal.`, type: 'error' }); window.scrollTo(0, 0); }); } } submitUpdate = () => { var updatedTutorial = this.submit(); if(updatedTutorial){ axios.put(`${process.env.REACT_APP_BLOCKLY_API}/tutorial/${this.props.id}`, updatedTutorial) .then(res => { var tutorial = res.data.tutorial; this.props.history.push(`/tutorial/${tutorial._id}`); }) .catch(err => { this.setState({ snackbar: true, key: Date.now(), message: `Fehler beim Ändern des Tutorials. Versuche es noch einmal.`, type: 'error' }); window.scrollTo(0, 0); }); } } render() { return (