From 111b9249889e57b8ba21327211fb7e8ae1638b7e Mon Sep 17 00:00:00 2001 From: Delucse <46593742+Delucse@users.noreply.github.com> Date: Sat, 19 Sep 2020 09:38:38 +0200 Subject: [PATCH] error validation --- src/actions/tutorialBuilderActions.js | 100 +++++++++++++++++- src/actions/types.js | 1 + .../Tutorial/Builder/BlocklyExample.js | 36 +++++-- src/components/Tutorial/Builder/Builder.js | 25 ++--- src/components/Tutorial/Builder/Hardware.js | 25 ++++- src/components/Tutorial/Builder/Id.js | 56 +++++++--- .../Tutorial/Builder/Requirements.js | 3 +- src/components/Tutorial/Builder/Step.js | 17 ++- src/components/Tutorial/Builder/Textfield.js | 64 +++++++---- src/reducers/tutorialBuilderReducer.js | 14 ++- 10 files changed, 268 insertions(+), 73 deletions(-) diff --git a/src/actions/tutorialBuilderActions.js b/src/actions/tutorialBuilderActions.js index a26f5b6..2ccca5b 100644 --- a/src/actions/tutorialBuilderActions.js +++ b/src/actions/tutorialBuilderActions.js @@ -1,4 +1,4 @@ -import { BUILDER_CHANGE, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types'; +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'; export const changeTutorialBuilder = () => (dispatch) => { dispatch({ @@ -35,9 +35,19 @@ export const addStep = (index) => (dispatch, getState) => { type: BUILDER_ADD_STEP, payload: steps }); + dispatch(addErrorStep(index)); dispatch(changeTutorialBuilder()); }; +export const addErrorStep = (index) => (dispatch, getState) => { + var error = getState().builder.error; + error.steps.splice(index, 0, {}); + dispatch({ + type: BUILDER_ERROR, + payload: error + }); +}; + export const removeStep = (index) => (dispatch, getState) => { var steps = getState().builder.steps; steps.splice(index, 1); @@ -45,9 +55,19 @@ export const removeStep = (index) => (dispatch, getState) => { type: BUILDER_DELETE_STEP, payload: steps }); + dispatch(removeErrorStep(index)); dispatch(changeTutorialBuilder()); }; +export const removeErrorStep = (index) => (dispatch, getState) => { + var error = getState().builder.error; + error.steps.splice(index, 1); + dispatch({ + type: BUILDER_ERROR, + payload: error + }); +}; + export const changeContent = (index, property, content) => (dispatch, getState) => { var steps = getState().builder.steps; var step = steps[index]; @@ -79,5 +99,83 @@ export const changeStepIndex = (fromIndex, toIndex) => (dispatch, getState) => { type: BUILDER_CHANGE_ORDER, payload: steps }); + dispatch(changeErrorStepIndex(fromIndex, toIndex)); dispatch(changeTutorialBuilder()); }; + +export const changeErrorStepIndex = (fromIndex, toIndex) => (dispatch, getState) => { + var error = getState().builder.error; + var errorStep = error.steps[fromIndex]; + error.steps.splice(fromIndex, 1); + error.steps.splice(toIndex, 0, errorStep); + dispatch({ + type: BUILDER_ERROR, + payload: error + }); +}; + +export const setError = (index, property) => (dispatch, getState) => { + var error = getState().builder.error; + console.log(index); + if(index !== undefined){ + error.steps[index][property] = true; + } + else { + error[property] = true; + } + dispatch({ + type: BUILDER_ERROR, + payload: error + }); + dispatch(changeTutorialBuilder()); +}; + +export const deleteError = (index, property) => (dispatch, getState) => { + var error = getState().builder.error; + if(index !== undefined){ + delete error.steps[index][property]; + } + else { + delete error[property]; + } + dispatch({ + type: BUILDER_ERROR, + payload: error + }); + dispatch(changeTutorialBuilder()); +}; + +export const setSubmitError = () => (dispatch, getState) => { + var builder = getState().builder; + if(builder.id === ''){ + dispatch(setError(undefined, 'id')); + } + if(builder.title === ''){ + dispatch(setError(undefined, 'title')); + } + for(var i = 0; i < builder.steps.length; i++){ + if(i === 0 && builder.steps[i].hardware.length < 1){ + dispatch(setError(i, 'hardware')); + } + if(builder.steps[i].headline === ''){ + dispatch(setError(i, 'headline')); + } + if(builder.steps[i].text === ''){ + dispatch(setError(i, 'text')); + } + } +}; + +export const checkError = () => (dispatch, getState) => { + dispatch(setSubmitError()); + var error = getState().builder.error; + if(error.id || error.title){ + return false; + } + for(var i = 0; i < error.steps.length; i++){ + if(Object.keys(error.steps[i]).length > 0){ + return false + } + } + return true; +} diff --git a/src/actions/types.js b/src/actions/types.js index a8fde8a..c5fb2a5 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -24,3 +24,4 @@ export const BUILDER_DELETE_STEP = 'BUILDER_DELETE_STEP'; 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'; diff --git a/src/components/Tutorial/Builder/BlocklyExample.js b/src/components/Tutorial/Builder/BlocklyExample.js index 9029bec..c8e8994 100644 --- a/src/components/Tutorial/Builder/BlocklyExample.js +++ b/src/components/Tutorial/Builder/BlocklyExample.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { changeContent, deleteProperty } from '../../../actions/tutorialBuilderActions'; +import { changeContent, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions'; import moment from 'moment'; import localization from 'moment/locale/de'; @@ -11,7 +11,7 @@ import BlocklyWindow from '../../Blockly/BlocklyWindow'; import { withStyles } from '@material-ui/core/styles'; import Switch from '@material-ui/core/Switch'; import FormControlLabel from '@material-ui/core/FormControlLabel'; -import FormLabel from '@material-ui/core/FormLabel'; +import FormHelperText from '@material-ui/core/FormHelperText'; import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; @@ -42,9 +42,29 @@ class BlocklyExample extends Component { }; } - componentDidUpdate(props){ + componentDidMount(){ + if(this.props.task){ + this.props.setError(this.props.index, 'xml'); + } + } + + componentDidUpdate(props, state){ if(props.task !== this.props.task || props.value !== this.props.value){ - this.setState({checked: this.props.task ? this.props.task : this.props.value ? true : false}); + this.setState({checked: this.props.task ? this.props.task : this.props.value ? true : false}, + () => this.isError() + ); + } + if(state.checked !== this.state.checked){ + this.isError(); + } + } + + isError = () => { + if(this.state.checked && !this.props.value){ + this.props.setError(this.props.index, 'xml'); + } + else { + this.props.deleteError(this.props.index, 'xml'); } } @@ -75,8 +95,8 @@ class BlocklyExample extends Component { } /> {this.state.checked ? !this.props.value ? - Es ist noch keine Eingabe gemacht worden. - : Die letzte Einreichung erfolgte um {this.state.input} Uhr. + Reiche deine Blöcke ein, indem du auf den rot gefärbten Button klickst. + : Die letzte Einreichung erfolgte um {this.state.input} Uhr. : null} {this.state.checked ?
@@ -104,6 +124,8 @@ class BlocklyExample extends Component { BlocklyExample.propTypes = { changeContent: PropTypes.func.isRequired, deleteProperty: PropTypes.func.isRequired, + setError: PropTypes.func.isRequired, + deleteError: PropTypes.func.isRequired, xml: PropTypes.string.isRequired }; @@ -112,4 +134,4 @@ const mapStateToProps = state => ({ }); -export default connect(mapStateToProps, { changeContent, deleteProperty })(withStyles(styles, {withTheme: true})(BlocklyExample)); +export default connect(mapStateToProps, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, {withTheme: true})(BlocklyExample)); diff --git a/src/components/Tutorial/Builder/Builder.js b/src/components/Tutorial/Builder/Builder.js index 948c3e1..aaea9c3 100644 --- a/src/components/Tutorial/Builder/Builder.js +++ b/src/components/Tutorial/Builder/Builder.js @@ -1,21 +1,14 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; +import { checkError } from '../../../actions/tutorialBuilderActions'; import Breadcrumbs from '../../Breadcrumbs'; import Id from './Id'; import Title from './Textfield'; import Step from './Step'; -import Typography from '@material-ui/core/Typography'; import Button from '@material-ui/core/Button'; -import TextField from '@material-ui/core/TextField'; -import OutlinedInput from '@material-ui/core/OutlinedInput'; -import InputLabel from '@material-ui/core/InputLabel'; -import FormControl from '@material-ui/core/FormControl'; - -import { faPlus, faMinus } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; class Builder extends Component { @@ -27,8 +20,8 @@ class Builder extends Component {

Tutorial-Builder

- - + <Id error={this.props.error} value={this.props.id}/> + <Title value={this.props.title} property={'title'} label={'Titel'} error={this.props.error}/> {this.props.steps.map((step, i) => <Step step={step} index={i} /> @@ -36,7 +29,7 @@ class Builder extends Component { )} - <Button variant='contained' color='primary' onClick={() => {alert('hi')}}>Submit</Button> + <Button variant='contained' color='primary' onClick={() => {var error = this.props.checkError(); alert(error);}}>Tutorial-Vorlage erstellen</Button> </div> @@ -49,15 +42,19 @@ class Builder extends Component { } Builder.propTypes = { + checkError: PropTypes.func.isRequired, title: PropTypes.string.isRequired, steps: PropTypes.array.isRequired, - change: PropTypes.number.isRequired + change: PropTypes.number.isRequired, + error: PropTypes.object.isRequired }; const mapStateToProps = state => ({ title: state.builder.title, + id: state.builder.id, steps: state.builder.steps, - change: state.builder.change + change: state.builder.change, + error: state.builder.error }); -export default connect(mapStateToProps, null)(Builder); +export default connect(mapStateToProps, { checkError })(Builder); diff --git a/src/components/Tutorial/Builder/Hardware.js b/src/components/Tutorial/Builder/Hardware.js index 6bf50c2..f0e3cd3 100644 --- a/src/components/Tutorial/Builder/Hardware.js +++ b/src/components/Tutorial/Builder/Hardware.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { changeContent } from '../../../actions/tutorialBuilderActions'; +import { changeContent, setError, deleteError } from '../../../actions/tutorialBuilderActions'; import hardware from '../../../data/hardware.json'; @@ -11,6 +11,7 @@ import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; import GridList from '@material-ui/core/GridList'; import GridListTile from '@material-ui/core/GridListTile'; import GridListTileBar from '@material-ui/core/GridListTileBar'; +import FormHelperText from '@material-ui/core/FormHelperText'; const styles = theme => ({ multiGridListTile: { @@ -31,6 +32,11 @@ const styles = theme => ({ width: 'calc(100% - 4px)', height: 'calc(100% - 4px)', border: `2px solid ${theme.palette.primary.main}` + }, + errorColor: { + color: theme.palette.error.dark, + lineHeight: 'initial', + marginBottom: '10px' } }); @@ -43,13 +49,22 @@ class Requirements extends Component { } else { hardwareArray.push(hardware); + if(this.props.error.steps[this.props.index].hardware){ + this.props.deleteError(this.props.index, 'hardware'); + } } this.props.changeContent(this.props.index, 'hardware', hardwareArray); + if(hardwareArray.length === 0){ + this.props.setError(this.props.index, 'hardware'); + } } render() { var cols = isWidthDown('md', this.props.width) ? isWidthDown('sm', this.props.width) ? isWidthDown('xs', this.props.width) ? 2 : 3 : 4 : 6; return ( + <div> + <FormHelperText style={this.props.error.steps[this.props.index].hardware ? {lineHeight: 'initial', marginTop: '5px'} : {marginTop: '5px', lineHeight: 'initial', marginBottom: '10px'}}>Beachte, dass die Reihenfolge des Auswählens maßgebend ist.</FormHelperText> + {this.props.error.steps[this.props.index].hardware ? <FormHelperText className={this.props.classes.errorColor}>Wähle mindestens eine Hardware aus.</FormHelperText> : null} <GridList cellHeight={100} cols={cols} spacing={10}> {hardware.map((picture,i) => ( <GridListTile key={i} onClick={() => this.onChange(picture.id)} classes={{tile: this.props.value.filter(value => value === picture.id).length > 0 ? this.props.classes.active : this.props.classes.border}}> @@ -67,16 +82,20 @@ class Requirements extends Component { </GridListTile> ))} </GridList> + </div> ); }; } Requirements.propTypes = { - changeContent: PropTypes.func.isRequired + changeContent: PropTypes.func.isRequired, + setError: PropTypes.func.isRequired, + deleteError: PropTypes.func.isRequired, + change: PropTypes.number.isRequired }; const mapStateToProps = state => ({ change: state.builder.change }); -export default connect(mapStateToProps, { changeContent })(withStyles(styles, { withTheme: true })(withWidth()(Requirements))); +export default connect(mapStateToProps, { changeContent, setError, deleteError })(withStyles(styles, { withTheme: true })(withWidth()(Requirements))); diff --git a/src/components/Tutorial/Builder/Id.js b/src/components/Tutorial/Builder/Id.js index 2f8d5cd..e329d77 100644 --- a/src/components/Tutorial/Builder/Id.js +++ b/src/components/Tutorial/Builder/Id.js @@ -1,5 +1,9 @@ import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { tutorialId, setError, deleteError } from '../../../actions/tutorialBuilderActions'; +import { withStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; import OutlinedInput from '@material-ui/core/OutlinedInput'; import InputLabel from '@material-ui/core/InputLabel'; @@ -9,29 +13,40 @@ import FormHelperText from '@material-ui/core/FormHelperText'; import { faPlus, faMinus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -class Id extends Component { - - state = { - id: 0, - error: false +const styles = theme => ({ + errorColor: { + color: theme.palette.error.dark } +}); + +class Id extends Component { handleChange = (e) => { var value = parseInt(e.target.value); - if(Number.isInteger(value)){ - this.setState({id: value, error: false}); + if(Number.isInteger(value) && value > 0){ + this.props.tutorialId(value); + if(this.props.error.id){ + this.props.deleteError(undefined, 'id'); + } } else { - this.setState({id: e.target.value, error: true}); + this.props.tutorialId(value); + this.props.setError(undefined,'id'); } }; handleCounter = (step) => { - if(!this.state.id){ - this.setState({id: 0+step}); + if(this.props.value+step < 1){ + this.props.setError(undefined,'id'); + } + else if(this.props.error.id){ + this.props.deleteError(undefined, 'id'); + } + if(!this.props.value){ + this.props.tutorialId(0+step); } else { - this.setState({id: this.state.id+step}); + this.props.tutorialId(this.props.value+step); } } @@ -41,8 +56,8 @@ class Id extends Component { <InputLabel htmlFor="id">ID</InputLabel> <OutlinedInput style={{borderRadius: '25px', padding: '0 0 0 10px', width: '200px'}} - error={this.state.error} - value={this.state.id} + error={this.props.error.id} + value={this.props.value} name='id' label='ID' id='id' @@ -53,6 +68,7 @@ class Id extends Component { endAdornment={ <div style={{display: 'flex'}}> <Button + disabled={this.props.value === 1 || !this.props.value} onClick={() => this.handleCounter(-1)} variant='contained' color='primary' @@ -71,10 +87,20 @@ class Id extends Component { </div> } /> - {this.state.error ? <FormHelperText style={{color: 'red'}}>Es muss eine positive ganzzahlige Zahl sein.</FormHelperText> : null} + {this.props.error.id ? <FormHelperText className={this.props.classes.errorColor}>Gib eine positive ganzzahlige Zahl ein.</FormHelperText> : null} </FormControl> ); }; } -export default Id; +Id.propTypes = { + tutorialId: PropTypes.func.isRequired, + setError: PropTypes.func.isRequired, + deleteError: PropTypes.func.isRequired +}; + +const mapStateToProps = state => ({ + change: state.builder.change +}); + +export default connect(mapStateToProps, { tutorialId, setError, deleteError })(withStyles(styles, { withTheme: true })(Id)); diff --git a/src/components/Tutorial/Builder/Requirements.js b/src/components/Tutorial/Builder/Requirements.js index c97ad6c..17bf574 100644 --- a/src/components/Tutorial/Builder/Requirements.js +++ b/src/components/Tutorial/Builder/Requirements.js @@ -9,6 +9,7 @@ import FormGroup from '@material-ui/core/FormGroup'; import Checkbox from '@material-ui/core/Checkbox'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormLabel from '@material-ui/core/FormLabel'; +import FormHelperText from '@material-ui/core/FormHelperText'; import FormControl from '@material-ui/core/FormControl'; class Requirements extends Component { @@ -29,7 +30,7 @@ class Requirements extends Component { return ( <FormControl style={{marginBottom: '10px'}}> <FormLabel style={{color: 'black'}}>Voraussetzungen</FormLabel> - <FormLabel style={{marginTop: '5px'}}>Beachte, dass die Reihenfolge des Anhakens maßgebend ist.</FormLabel> + <FormHelperText style={{marginTop: '5px'}}>Beachte, dass die Reihenfolge des Anhakens maßgebend ist.</FormHelperText> <FormGroup> {tutorials.map((tutorial, i) => <FormControlLabel diff --git a/src/components/Tutorial/Builder/Step.js b/src/components/Tutorial/Builder/Step.js index 1d57690..7124131 100644 --- a/src/components/Tutorial/Builder/Step.js +++ b/src/components/Tutorial/Builder/Step.js @@ -13,9 +13,6 @@ import { withStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import IconButton from '@material-ui/core/IconButton'; import Tooltip from '@material-ui/core/Tooltip'; -import OutlinedInput from '@material-ui/core/OutlinedInput'; -import InputLabel from '@material-ui/core/InputLabel'; -import FormControl from '@material-ui/core/FormControl'; import { faPlus, faAngleDoubleUp, faAngleDoubleDown, faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -88,15 +85,15 @@ class Step extends Component { </div> <div style={{width: '100%', marginLeft: '54px'}}> <StepType value={this.props.step.type} index={index} /> - <Textfield value={this.props.step.headline} property={'headline'} label={'Überschrift'} index={index}/> - <Textfield value={this.props.step.text} property={'text'} label={this.props.step.type === 'task' ? 'Aufgabenstellung' : 'Instruktionen'} index={index} multiline/> + <Textfield value={this.props.step.headline} property={'headline'} label={'Überschrift'} index={index} error={this.props.error} errorText={`Gib eine Überschrift für die ${this.props.step.type === 'task' ? 'Aufgabe' : 'Anleitung'} ein.`} /> + <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} /> + <Hardware value={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'} /> </div> </div> </div> @@ -109,12 +106,14 @@ Step.propTypes = { removeStep: PropTypes.func.isRequired, changeStepIndex: PropTypes.func.isRequired, steps: PropTypes.array.isRequired, - change: PropTypes.number.isRequired + change: PropTypes.number.isRequired, + error: PropTypes.object.isRequired, }; const mapStateToProps = state => ({ steps: state.builder.steps, - change: state.builder.change + change: state.builder.change, + error: state.builder.error }); export default connect(mapStateToProps, { addStep, removeStep, changeStepIndex })(withStyles(styles, {withTheme: true})(Step)); diff --git a/src/components/Tutorial/Builder/Textfield.js b/src/components/Tutorial/Builder/Textfield.js index 7636a96..caeaba1 100644 --- a/src/components/Tutorial/Builder/Textfield.js +++ b/src/components/Tutorial/Builder/Textfield.js @@ -1,45 +1,62 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { tutorialTitle, changeContent } from '../../../actions/tutorialBuilderActions'; +import { tutorialTitle, changeContent, setError, deleteError } from '../../../actions/tutorialBuilderActions'; -import Button from '@material-ui/core/Button'; +import { withStyles } from '@material-ui/core/styles'; import OutlinedInput from '@material-ui/core/OutlinedInput'; import InputLabel from '@material-ui/core/InputLabel'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; +const styles = theme => ({ + multiline: { + padding: '18.5px 14px 18.5px 24px' + }, + errorColor: { + color: theme.palette.error.dark + } +}); + class Textfield extends Component { - // handleChange = (e) => { - // var value = e.target.value; - // if(value.replace(/\s/g,'') !== ''){ - // this.setState({[e.target.name]: value, error: false}); - // } - // else { - // this.setState({[e.target.name]: value, error: true}); - // } - // }; + handleChange = (e) => { + var value = e.target.value; + if(this.props.property === 'title'){ + this.props.tutorialTitle(value); + } + else { + this.props.changeContent(this.props.index, this.props.property, value); + } + if(value.replace(/\s/g,'') === ''){ + this.props.setError(this.props.index, this.props.property); + } + else{ + this.props.deleteError(this.props.index, this.props.property); + } + }; render() { return ( <FormControl variant="outlined" fullWidth style={{marginBottom: '10px'}}> <InputLabel htmlFor={this.props.property}>{this.props.label}</InputLabel> <OutlinedInput - style={this.props.multiline ? {borderRadius: '25px', padding: '18.5px 14px 18.5px 24px'} : {borderRadius: '25px', padding: '0 0 0 10px'}} - /* error={this.state.error}*/ + style={{borderRadius: '25px'}} + classes={{multiline: this.props.classes.multiline}} + error={this.props.index !== undefined ? this.props.error.steps[this.props.index][this.props.property] : this.props.error[this.props.property]} value={this.props.value} label={this.props.label} id={this.props.property} multiline={this.props.multiline} rows={2} rowsMax={10} - onChange={(e) => {this.props.property === 'title' ? - this.props.tutorialTitle(e.target.value) - : this.props.changeContent(this.props.index, this.props.property, e.target.value) - }} + onChange={(e) => this.handleChange(e)} /> - {/* {this.state.error ? <FormHelperText style={{color: 'red'}}>Gib einen Titel für das Tutorial ein.</FormHelperText> : null}*/} + {this.props.index !== undefined ? + this.props.error.steps[this.props.index][this.props.property] ? <FormHelperText className={this.props.classes.errorColor}>{this.props.errorText}</FormHelperText> + : null + : this.props.error[this.props.property] ? <FormHelperText className={this.props.classes.errorColor}>Gib einen Titel für das Tutorial ein.</FormHelperText> + : null} </FormControl> ); }; @@ -47,7 +64,14 @@ class Textfield extends Component { Textfield.propTypes = { tutorialTitle: PropTypes.func.isRequired, - changeContent: PropTypes.func.isRequired + changeContent: PropTypes.func.isRequired, + error: PropTypes.object.isRequired, + change: PropTypes.number.isRequired }; -export default connect(null, { tutorialTitle, changeContent })(Textfield); +const mapStateToProps = state => ({ + error: state.builder.error, + change: state.builder.change +}); + +export default connect(mapStateToProps, { tutorialTitle, changeContent, setError, deleteError })(withStyles(styles, { withTheme: true })(Textfield)); diff --git a/src/reducers/tutorialBuilderReducer.js b/src/reducers/tutorialBuilderReducer.js index 326ed11..3103403 100644 --- a/src/reducers/tutorialBuilderReducer.js +++ b/src/reducers/tutorialBuilderReducer.js @@ -1,9 +1,9 @@ -import { BUILDER_CHANGE, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP,BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from '../actions/types'; +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'; const initialState = { change: 0, title: '', - id: 0, + id: '', steps: [ { id: 1, @@ -13,7 +13,10 @@ const initialState = { hardware: [], requirements: [] } - ] + ], + error: { + steps: [{}] + } }; export default function(state = initialState, action){ @@ -42,6 +45,11 @@ export default function(state = initialState, action){ ...state, steps: action.payload }; + case BUILDER_ERROR: + return { + ...state, + error: action.payload + } default: return state; }