Merge branch 'snackbar'

This commit is contained in:
Delucse 2020-09-21 12:16:57 +02:00
commit 9e9c523955
5 changed files with 108 additions and 4 deletions

View File

@ -220,6 +220,7 @@ export const progress = (inProgress) => (dispatch) => {
}; };
export const resetTutorial = () => (dispatch, getState) => { export const resetTutorial = () => (dispatch, getState) => {
dispatch(jsonString(''));
dispatch(tutorialTitle('')); dispatch(tutorialTitle(''));
dispatch(tutorialId('')); dispatch(tutorialId(''));
var steps = [ var steps = [

View File

@ -0,0 +1,50 @@
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import MaterialUISnackbar from '@material-ui/core/Snackbar';
import SnackbarContent from '@material-ui/core/SnackbarContent';
import { faTimes } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const styles = (theme) => ({
success: {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText
},
error: {
backgroundColor: theme.palette.error.dark,
color: theme.palette.error.contrastText
}
});
class Snackbar extends Component {
render() {
return (
<MaterialUISnackbar
anchorOrigin={{vertical: 'bottom', horizontal: 'left' }}
open={this.props.open}
onClose={this.props.onClose}
key={Date.now()+this.props.message}
autoHideDuration={5000}
style={{left: '22px', bottom: '40px', width: '300px', zIndex: '100'}}
>
<SnackbarContent
style={{flexWrap: 'nowrap'}}
className={this.props.type === 'error' ? this.props.classes.error : this.props.classes.success}
action={
<IconButton onClick={this.props.onClose} style={{color: 'inherit'}}>
<FontAwesomeIcon icon={faTimes} size="xs"/>
</IconButton>
}
message={this.props.message}
/>
</MaterialUISnackbar>
);
};
}
export default withStyles(styles, {withTheme: true})(Snackbar);

View File

@ -12,6 +12,7 @@ import Id from './Id';
import Textfield from './Textfield'; import Textfield from './Textfield';
import Step from './Step'; import Step from './Step';
import Dialog from '../../Dialog'; import Dialog from '../../Dialog';
import Snackbar from '../../Snackbar';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
@ -34,14 +35,21 @@ class Builder extends Component {
open: false, open: false,
title: '', title: '',
content: '', content: '',
string: false string: false,
snackbar: false,
message: ''
}; };
this.inputRef = React.createRef(); this.inputRef = React.createRef();
} }
componentWillUnmount(){
this.reset();
}
submit = () => { submit = () => {
var isError = this.props.checkError(); var isError = this.props.checkError();
if(isError){ if(isError){
this.setState({ snackbar: true, message: `Die Angaben für das Tutorial sind nicht vollständig.`, type: 'error'});
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
else{ else{
@ -57,6 +65,7 @@ class Builder extends Component {
reset = () => { reset = () => {
this.props.resetTutorial(); this.props.resetTutorial();
this.setState({ snackbar: true, message: `Das Tutorial wurde erfolgreich zurückgesetzt.`, type: 'success'});
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
@ -86,6 +95,7 @@ class Builder extends Component {
result.steps = [{}]; result.steps = [{}];
} }
this.props.readJSON(result); this.props.readJSON(result);
this.setState({ snackbar: true, message: `${isFile ? 'Die übergebene JSON-Datei' : 'Der übergebene JSON-String'} wurde erfolgreich übernommen.`, type: 'success'});
} catch(err){ } catch(err){
console.log(err); console.log(err);
this.props.progress(false); this.props.progress(false);
@ -105,6 +115,10 @@ class Builder extends Component {
this.setState({ open: !this.state }); this.setState({ open: !this.state });
} }
toggleSnackbar = () => {
this.setState({ snackbar: !this.state, message: '', type: null });
}
render() { render() {
return ( return (
@ -169,6 +183,13 @@ class Builder extends Component {
: null} : null}
</Dialog> </Dialog>
<Snackbar
open={this.state.snackbar}
onClose={this.toggleSnackbar}
message={this.state.message}
type={this.state.type}
/>
</div> </div>
); );
}; };

View File

@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { addStep, removeStep, changeStepIndex } from '../../../actions/tutorialBuilderActions'; import { addStep, removeStep, changeStepIndex } from '../../../actions/tutorialBuilderActions';
import clsx from 'clsx';
import Textfield from './Textfield'; import Textfield from './Textfield';
import StepType from './StepType'; import StepType from './StepType';
import BlocklyExample from './BlocklyExample'; import BlocklyExample from './BlocklyExample';
@ -27,6 +29,14 @@ const styles = (theme) => ({
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
} }
},
delete: {
backgroundColor: theme.palette.error.dark,
color: theme.palette.error.contrastText,
'&:hover': {
backgroundColor: theme.palette.error.dark,
color: theme.palette.error.contrastText,
}
} }
}); });
@ -74,7 +84,7 @@ class Step extends Component {
<Tooltip title={`Schritt ${index+1} löschen`} arrow> <Tooltip title={`Schritt ${index+1} löschen`} arrow>
<IconButton <IconButton
disabled={index === 0} disabled={index === 0}
className={this.props.classes.button} className={clsx(this.props.classes.button, this.props.classes.delete)}
onClick={() => this.props.removeStep(index)} onClick={() => this.props.removeStep(index)}
> >
<FontAwesomeIcon icon={faTrash} size="xs"/> <FontAwesomeIcon icon={faTrash} size="xs"/>

View File

@ -13,6 +13,7 @@ import { initialXml } from './Blockly/initialXml.js';
import Compile from './Compile'; import Compile from './Compile';
import SolutionCheck from './Tutorial/SolutionCheck'; import SolutionCheck from './Tutorial/SolutionCheck';
import Dialog from './Dialog'; import Dialog from './Dialog';
import Snackbar from './Snackbar';
import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
@ -59,7 +60,9 @@ class WorkspaceFunc extends Component {
open: false, open: false,
file: false, file: false,
saveXml: false, saveXml: false,
name: props.name name: props.name,
snackbar: false,
message: ''
}; };
} }
@ -73,6 +76,10 @@ class WorkspaceFunc extends Component {
this.setState({ open: !this.state }); this.setState({ open: !this.state });
} }
toggleSnackbar = () => {
this.setState({ snackbar: !this.state, message: '' });
}
saveXmlFile = () => { saveXmlFile = () => {
var code = this.props.xml; var code = this.props.xml;
this.toggleDialog(); this.toggleDialog();
@ -121,6 +128,7 @@ class WorkspaceFunc extends Component {
var extensionPosition = xmlFile.name.lastIndexOf('.'); var extensionPosition = xmlFile.name.lastIndexOf('.');
this.props.workspaceName(xmlFile.name.substr(0, extensionPosition)); this.props.workspaceName(xmlFile.name.substr(0, extensionPosition));
} }
this.setState({ snackbar: true, message: 'Das Projekt aus gegebener XML-Datei wurde erfolgreich eingefügt.' });
} }
} catch(err){ } catch(err){
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.' }); 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.' });
@ -129,6 +137,12 @@ class WorkspaceFunc extends Component {
} }
} }
renameWorkspace = () => {
this.props.workspaceName(this.state.name);
this.toggleDialog();
this.setState({ snackbar: true, message: `Das Projekt wurde erfolgreich in '${this.state.name}' umbenannt.` });
}
resetWorkspace = () => { resetWorkspace = () => {
const workspace = Blockly.getMainWorkspace(); const workspace = Blockly.getMainWorkspace();
Blockly.Events.disable(); // https://groups.google.com/forum/#!topic/blockly/m7e3g0TC75Y Blockly.Events.disable(); // https://groups.google.com/forum/#!topic/blockly/m7e3g0TC75Y
@ -142,6 +156,7 @@ class WorkspaceFunc extends Component {
if(!this.props.solutionCheck){ if(!this.props.solutionCheck){
this.props.workspaceName(null); this.props.workspaceName(null);
} }
this.setState({ snackbar: true, message: 'Das Projekt wurde erfolgreich zurückgesetzt.' });
} }
render() { render() {
@ -204,11 +219,18 @@ class WorkspaceFunc extends Component {
{this.state.file ? {this.state.file ?
<div style={{marginTop: '10px'}}> <div style={{marginTop: '10px'}}>
<TextField autoFocus placeholder={this.state.saveXml ?'Dateiname' : 'Projektname'} value={this.state.name} onChange={this.setFileName} style={{marginRight: '10px'}}/> <TextField autoFocus placeholder={this.state.saveXml ?'Dateiname' : 'Projektname'} value={this.state.name} onChange={this.setFileName} style={{marginRight: '10px'}}/>
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => {this.state.saveXml ? this.saveXmlFile() : this.props.workspaceName(this.state.name); this.toggleDialog();}}>Eingabe</Button> <Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => {this.state.saveXml ? this.saveXmlFile() : this.renameWorkspace()}}>Eingabe</Button>
</div> </div>
: null} : null}
</Dialog> </Dialog>
<Snackbar
open={this.state.snackbar}
onClose={this.toggleSnackbar}
message={this.state.message}
type='success'
/>
</div> </div>
); );
}; };