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_BLOCKLY_API=https://api.blockly.sensebox.de
|
||||||
|
|
||||||
REACT_APP_MYBADGES=https://mybadges.org
|
REACT_APP_MYBADGES=https://mybadges.org
|
||||||
|
REACT_APP_MYBADGES_API=https://mybadges.org/api/v1
|
||||||
|
|
||||||
# in days
|
# in days
|
||||||
REACT_APP_SHARE_LINK_EXPIRES=30
|
REACT_APP_SHARE_LINK_EXPIRES=30
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"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",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
|
@ -25,7 +25,6 @@ export const loadUser = () => (dispatch) => {
|
|||||||
if(err.response){
|
if(err.response){
|
||||||
dispatch(returnErrors(err.response.data.message, err.response.status));
|
dispatch(returnErrors(err.response.data.message, err.response.status));
|
||||||
}
|
}
|
||||||
console.log('auth failed');
|
|
||||||
var status = [];
|
var status = [];
|
||||||
if (window.localStorage.getItem('status')) {
|
if (window.localStorage.getItem('status')) {
|
||||||
status = JSON.parse(window.localStorage.getItem('status'));
|
status = JSON.parse(window.localStorage.getItem('status'));
|
||||||
|
@ -191,6 +191,9 @@ export const setSubmitError = () => (dispatch, getState) => {
|
|||||||
if (builder.title === '') {
|
if (builder.title === '') {
|
||||||
dispatch(setError(undefined, 'title'));
|
dispatch(setError(undefined, 'title'));
|
||||||
}
|
}
|
||||||
|
if (builder.title === null) {
|
||||||
|
dispatch(setError(undefined, 'badge'));
|
||||||
|
}
|
||||||
var type = builder.steps.map((step, i) => {
|
var type = builder.steps.map((step, i) => {
|
||||||
// media and xml are directly checked for errors in their components and
|
// media and xml are directly checked for errors in their components and
|
||||||
// therefore do not have to be checked again
|
// therefore do not have to be checked again
|
||||||
@ -230,7 +233,7 @@ export const setSubmitError = () => (dispatch, getState) => {
|
|||||||
export const checkError = () => (dispatch, getState) => {
|
export const checkError = () => (dispatch, getState) => {
|
||||||
dispatch(setSubmitError());
|
dispatch(setSubmitError());
|
||||||
var error = getState().builder.error;
|
var error = getState().builder.error;
|
||||||
if (error.id || error.title || error.type) {
|
if (error.id || error.title || error.badge ||error.type) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (var i = 0; i < error.steps.length; i++) {
|
for (var i = 0; i < error.steps.length; i++) {
|
||||||
@ -251,7 +254,7 @@ export const progress = (inProgress) => (dispatch) => {
|
|||||||
export const resetTutorial = () => (dispatch, getState) => {
|
export const resetTutorial = () => (dispatch, getState) => {
|
||||||
dispatch(jsonString(''));
|
dispatch(jsonString(''));
|
||||||
dispatch(tutorialTitle(''));
|
dispatch(tutorialTitle(''));
|
||||||
dispatch(tutorialBadge(''));
|
dispatch(tutorialBadge(undefined));
|
||||||
var steps = [
|
var steps = [
|
||||||
{
|
{
|
||||||
type: 'instruction',
|
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 { detectWhitespacesAndReturnReadableResult } from '../../../helpers/whitespace';
|
||||||
|
|
||||||
import Breadcrumbs from '../../Breadcrumbs';
|
import Breadcrumbs from '../../Breadcrumbs';
|
||||||
|
import Badge from './Badge';
|
||||||
import Textfield from './Textfield';
|
import Textfield from './Textfield';
|
||||||
import Step from './Step';
|
import Step from './Step';
|
||||||
import Dialog from '../../Dialog';
|
import Dialog from '../../Dialog';
|
||||||
@ -190,7 +191,9 @@ class Builder extends Component {
|
|||||||
var steps = this.props.steps;
|
var steps = this.props.steps;
|
||||||
var newTutorial = new FormData();
|
var newTutorial = new FormData();
|
||||||
newTutorial.append('title', this.props.title);
|
newTutorial.append('title', this.props.title);
|
||||||
|
if(this.props.badge){
|
||||||
newTutorial.append('badge', this.props.badge);
|
newTutorial.append('badge', this.props.badge);
|
||||||
|
}
|
||||||
steps.forEach((step, i) => {
|
steps.forEach((step, i) => {
|
||||||
if(step._id){
|
if(step._id){
|
||||||
newTutorial.append(`steps[${i}][_id]`, step._id);
|
newTutorial.append(`steps[${i}][_id]`, step._id);
|
||||||
@ -348,7 +351,7 @@ class Builder extends Component {
|
|||||||
: null}
|
: null}
|
||||||
{/* <Id error={this.props.error.id} value={this.props.id} /> */}
|
{/* <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.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) =>
|
{this.props.steps.map((step, i) =>
|
||||||
<Step step={step} index={i} key={i} />
|
<Step step={step} index={i} key={i} />
|
||||||
@ -435,7 +438,6 @@ Builder.propTypes = {
|
|||||||
change: PropTypes.number.isRequired,
|
change: PropTypes.number.isRequired,
|
||||||
error: PropTypes.object.isRequired,
|
error: PropTypes.object.isRequired,
|
||||||
json: PropTypes.string.isRequired,
|
json: PropTypes.string.isRequired,
|
||||||
badge: PropTypes.string.isRequired,
|
|
||||||
isProgress: PropTypes.bool.isRequired,
|
isProgress: PropTypes.bool.isRequired,
|
||||||
tutorials: PropTypes.array.isRequired,
|
tutorials: PropTypes.array.isRequired,
|
||||||
message: PropTypes.object.isRequired,
|
message: PropTypes.object.isRequired,
|
||||||
|
@ -5,7 +5,6 @@ const initialState = {
|
|||||||
progress: false,
|
progress: false,
|
||||||
json: '',
|
json: '',
|
||||||
title: '',
|
title: '',
|
||||||
badge: '',
|
|
||||||
id: '',
|
id: '',
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user