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);
|
||||
newTutorial.append('badge', this.props.badge);
|
||||
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