badge selection
This commit is contained in:
		
							parent
							
								
									4f002d8694
								
							
						
					
					
						commit
						42981a4f11
					
				
							
								
								
									
										1
									
								
								.env
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								.env
									
									
									
									
									
								
							| @ -3,6 +3,7 @@ REACT_APP_BOARD=sensebox-mcu | ||||
| REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de | ||||
| 
 | ||||
| REACT_APP_MYBADGES=https://mybadges.org | ||||
| REACT_APP_MYBADGES_API=https://mybadges.org/api/v1 | ||||
| 
 | ||||
| # in days | ||||
| REACT_APP_SHARE_LINK_EXPIRES=30 | ||||
|  | ||||
| @ -32,7 +32,7 @@ | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "start": "react-scripts start", | ||||
|     "dev": "set \"REACT_APP_BLOCKLY_API=http://localhost:8080\" && npm start", | ||||
|     "dev": "set \"REACT_APP_BLOCKLY_API=http://localhost:8080\" && set \"REACT_APP_MYBADGES_API=http://localhost:3001/api/v1\"&& npm start", | ||||
|     "build": "react-scripts build", | ||||
|     "test": "react-scripts test", | ||||
|     "eject": "react-scripts eject" | ||||
|  | ||||
| @ -25,7 +25,6 @@ export const loadUser = () => (dispatch) => { | ||||
|       if(err.response){ | ||||
|         dispatch(returnErrors(err.response.data.message, err.response.status)); | ||||
|       } | ||||
|       console.log('auth failed'); | ||||
|       var status = []; | ||||
|       if (window.localStorage.getItem('status')) { | ||||
|         status = JSON.parse(window.localStorage.getItem('status')); | ||||
|  | ||||
| @ -191,6 +191,9 @@ export const setSubmitError = () => (dispatch, getState) => { | ||||
|   if (builder.title === '') { | ||||
|     dispatch(setError(undefined, 'title')); | ||||
|   } | ||||
|   if (builder.title === null) { | ||||
|     dispatch(setError(undefined, 'badge')); | ||||
|   } | ||||
|   var type = builder.steps.map((step, i) => { | ||||
|     // media and xml are directly checked for errors in their components and
 | ||||
|     // therefore do not have to be checked again
 | ||||
| @ -230,7 +233,7 @@ export const setSubmitError = () => (dispatch, getState) => { | ||||
| export const checkError = () => (dispatch, getState) => { | ||||
|   dispatch(setSubmitError()); | ||||
|   var error = getState().builder.error; | ||||
|   if (error.id || error.title || error.type) { | ||||
|   if (error.id || error.title || error.badge ||error.type) { | ||||
|     return true; | ||||
|   } | ||||
|   for (var i = 0; i < error.steps.length; i++) { | ||||
| @ -251,7 +254,7 @@ export const progress = (inProgress) => (dispatch) => { | ||||
| export const resetTutorial = () => (dispatch, getState) => { | ||||
|   dispatch(jsonString('')); | ||||
|   dispatch(tutorialTitle('')); | ||||
|   dispatch(tutorialBadge('')); | ||||
|   dispatch(tutorialBadge(undefined)); | ||||
|   var steps = [ | ||||
|     { | ||||
|       type: 'instruction', | ||||
|  | ||||
							
								
								
									
										189
									
								
								src/components/Tutorial/Builder/Badge.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								src/components/Tutorial/Builder/Badge.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,189 @@ | ||||
| import React, { Component } from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { tutorialBadge, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions'; | ||||
| 
 | ||||
| import axios from 'axios'; | ||||
| 
 | ||||
| import { withStyles } from '@material-ui/core/styles'; | ||||
| import Switch from '@material-ui/core/Switch'; | ||||
| import FormControlLabel from '@material-ui/core/FormControlLabel'; | ||||
| import FormHelperText from '@material-ui/core/FormHelperText'; | ||||
| import List from '@material-ui/core/List'; | ||||
| import ListItem from '@material-ui/core/ListItem'; | ||||
| import ListItemText from '@material-ui/core/ListItemText'; | ||||
| import IconButton from '@material-ui/core/IconButton'; | ||||
| import OutlinedInput from '@material-ui/core/OutlinedInput'; | ||||
| import InputLabel from '@material-ui/core/InputLabel'; | ||||
| import FormControl from '@material-ui/core/FormControl'; | ||||
| 
 | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { faTimes } from "@fortawesome/free-solid-svg-icons"; | ||||
| 
 | ||||
| const styles = (theme) => ({ | ||||
|   errorColor: { | ||||
|     color: `${theme.palette.error.dark} !important` | ||||
|   }, | ||||
|   errorColorShrink: { | ||||
|     color: `rgba(0, 0, 0, 0.54) !important` | ||||
|   }, | ||||
|   errorBorder: { | ||||
|     borderColor: `${theme.palette.error.dark} !important` | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| class Badge extends Component { | ||||
| 
 | ||||
|   constructor(props){ | ||||
|     super(props); | ||||
|     this.state={ | ||||
|       checked: props.badge ? true : false, | ||||
|       badgeName: '', | ||||
|       filteredBadges: [], | ||||
|       badges: [] | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   componentDidMount(){ | ||||
|     this.getBadges(); | ||||
|   } | ||||
| 
 | ||||
|   componentDidUpdate(props){ | ||||
|     if(props.badge !== this.props.badge){ | ||||
|       this.setState({ checked: this.props.badge !== undefined ? true : false, badgeName: this.props.badge ? this.state.badges.filter(badge => badge._id === this.props.badge)[0].name : '' }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   getBadges = () => { | ||||
|     axios.get(`${process.env.REACT_APP_MYBADGES_API}/badge`) | ||||
|       .then(res => { | ||||
|         this.setState({badges: res.data.badges, badgeName: this.props.badge ? res.data.badges.filter(badge => badge._id === this.props.badge)[0].name : '' }); | ||||
|       }) | ||||
|       .catch(err => { | ||||
|         console.log(err); | ||||
|       }); | ||||
|   }; | ||||
| 
 | ||||
|   deleteBadge = () => { | ||||
|     this.setState({ filteredBadges: [], badgeName: '' }); | ||||
|     this.props.tutorialBadge(null); | ||||
|     this.props.setError(this.props.index, 'badge'); | ||||
|   }; | ||||
| 
 | ||||
|   setBadge = (badge) => { | ||||
|     this.setState({ filteredBadges: [] }); | ||||
|     this.props.tutorialBadge(badge._id); | ||||
|     this.props.deleteError(this.props.index, 'badge'); | ||||
|   }; | ||||
| 
 | ||||
|   onChange = e => { | ||||
|     this.setState({ badgeName: e.target.value }); | ||||
|   }; | ||||
| 
 | ||||
|   onChangeBadge = e => { | ||||
|     if(e.target.value && this.props.badge === null){ | ||||
|       var filteredBadges = this.state.badges.filter(badge => new RegExp(e.target.value, 'i').test(badge.name)); | ||||
|       if(filteredBadges.length < 1){ | ||||
|         filteredBadges = ['Keine Übereinstimmung gefunden.']; | ||||
|       } | ||||
|       this.setState({filteredBadges: filteredBadges}); | ||||
|     } | ||||
|     else { | ||||
|       this.setState({filteredBadges: []}); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   onChangeSwitch = (value) => { | ||||
|     var oldValue = this.state.checked; | ||||
|     this.setState({checked: value}); | ||||
|     if(oldValue !== value){ | ||||
|       if(value){ | ||||
|         this.props.setError(this.props.index, 'badge'); | ||||
|         this.props.tutorialBadge(null); | ||||
|       } else { | ||||
|         this.props.deleteError(this.props.index, 'badge'); | ||||
|         this.props.tutorialBadge(undefined); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   render() { | ||||
|     return ( | ||||
|       <div style={{marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)'}}> | ||||
|         <FormControlLabel | ||||
|           labelPlacement="end" | ||||
|           label={"Badge"} | ||||
|           control={ | ||||
|             <Switch | ||||
|               checked={this.state.checked} | ||||
|               onChange={(e) => this.onChangeSwitch(e.target.checked)} | ||||
|               color="primary" | ||||
|             /> | ||||
|           } | ||||
|         /> | ||||
|         {this.state.checked ? | ||||
|           <div style={{marginTop: '10px'}}> | ||||
|             <FormControl variant="outlined" fullWidth> | ||||
|               <InputLabel | ||||
|                 htmlFor={'badge'} | ||||
|                 classes={{shrink: this.props.error ? this.props.classes.errorColorShrink : null}} | ||||
|               > | ||||
|                 {'Badge'} | ||||
|               </InputLabel> | ||||
|               <OutlinedInput | ||||
|                 style={{borderRadius: '25px'}} | ||||
|                 classes={{notchedOutline: this.props.error ? this.props.classes.errorBorder : null}} | ||||
|                 error={this.props.error} | ||||
|                 value={this.state.badgeName} | ||||
|                 label={'Badge'} | ||||
|                 id={'badge'} | ||||
|                 onChange={(e) => this.onChange(e)} | ||||
|                 onInput={(e) => this.onChangeBadge(e)} | ||||
|                 fullWidth={true} | ||||
|                 endAdornment={ | ||||
|                       <IconButton | ||||
|                         onClick={this.deleteBadge} | ||||
|                         edge="end" | ||||
|                       > | ||||
|                         <FontAwesomeIcon size='xs' icon={faTimes} /> | ||||
|                       </IconButton> | ||||
|                     } | ||||
|               /> | ||||
|               {this.props.error && this.state.filteredBadges.length === 0 ? | ||||
|               <FormHelperText className={this.props.classes.errorColor}>Wähle ein Badge aus.</FormHelperText> | ||||
|               : null} | ||||
|             </FormControl> | ||||
|             <List style={{paddingTop: 0}}> | ||||
|             {this.state.filteredBadges.map((badge, i) => ( | ||||
|               badge === 'Keine Übereinstimmung gefunden.' ? | ||||
|                 <ListItem button key={i} onClick={this.deleteBadge} style={{border: '1px solid rgba(0, 0, 0, 0.23)', borderRadius: '25px'}}> | ||||
|                   <ListItemText>{badge}</ListItemText> | ||||
|                 </ListItem> | ||||
|               : | ||||
|               <ListItem button key={i} onClick={() => {this.setBadge(badge)}} style={{border: '1px solid rgba(0, 0, 0, 0.23)', borderRadius: '25px'}}> | ||||
|                 <ListItemText>{`${badge.name}`}</ListItemText> | ||||
|               </ListItem> | ||||
|             ))} | ||||
|             </List> | ||||
|           </div> | ||||
|         : null} | ||||
|       </div> | ||||
|     ); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| Badge.propTypes = { | ||||
|   tutorialBadge: PropTypes.func.isRequired, | ||||
|   deleteProperty: PropTypes.func.isRequired, | ||||
|   setError: PropTypes.func.isRequired, | ||||
|   deleteError: PropTypes.func.isRequired, | ||||
|   badge: PropTypes.string.isRequired | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps = state => ({ | ||||
|   badge: state.builder.badge, | ||||
|   change: state.builder.change | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| export default connect(mapStateToProps, { tutorialBadge, deleteProperty, setError, deleteError })(withStyles(styles, {withTheme: true})(Badge)); | ||||
| @ -12,6 +12,7 @@ import { saveAs } from 'file-saver'; | ||||
| import { detectWhitespacesAndReturnReadableResult } from '../../../helpers/whitespace'; | ||||
| 
 | ||||
| import Breadcrumbs from '../../Breadcrumbs'; | ||||
| import Badge from './Badge'; | ||||
| import Textfield from './Textfield'; | ||||
| import Step from './Step'; | ||||
| import Dialog from '../../Dialog'; | ||||
| @ -190,7 +191,9 @@ class Builder extends Component { | ||||
|       var steps = this.props.steps; | ||||
|       var newTutorial = new FormData(); | ||||
|       newTutorial.append('title', this.props.title); | ||||
|       if(this.props.badge){ | ||||
|         newTutorial.append('badge', this.props.badge); | ||||
|       } | ||||
|       steps.forEach((step, i) => { | ||||
|         if(step._id){ | ||||
|           newTutorial.append(`steps[${i}][_id]`, step._id); | ||||
| @ -348,7 +351,7 @@ class Builder extends Component { | ||||
|             : null} | ||||
|           {/* <Id error={this.props.error.id} value={this.props.id} /> */} | ||||
|           <Textfield value={this.props.title} property={'title'} label={'Titel'} error={this.props.error.title} /> | ||||
|           <Textfield value={this.props.badge} property={'badge'} label={'Badge'} /> | ||||
|           <Badge error={this.props.error.badge}/> | ||||
| 
 | ||||
|           {this.props.steps.map((step, i) => | ||||
|             <Step step={step} index={i} key={i} /> | ||||
| @ -435,7 +438,6 @@ Builder.propTypes = { | ||||
|   change: PropTypes.number.isRequired, | ||||
|   error: PropTypes.object.isRequired, | ||||
|   json: PropTypes.string.isRequired, | ||||
|   badge: PropTypes.string.isRequired, | ||||
|   isProgress: PropTypes.bool.isRequired, | ||||
|   tutorials: PropTypes.array.isRequired, | ||||
|   message: PropTypes.object.isRequired, | ||||
|  | ||||
| @ -5,7 +5,6 @@ const initialState = { | ||||
|   progress: false, | ||||
|   json: '', | ||||
|   title: '', | ||||
|   badge: '', | ||||
|   id: '', | ||||
|   steps: [ | ||||
|     { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user