From f9caeb619e07a6e2b4b492cfefc6be88411f44a3 Mon Sep 17 00:00:00 2001 From: Delucse <46593742+Delucse@users.noreply.github.com> Date: Wed, 9 Dec 2020 18:10:45 +0100 Subject: [PATCH] connect to MyBadges-account --- .env | 2 + src/actions/authActions.js | 53 ++++++- src/actions/types.js | 2 + src/components/Route/Routes.js | 6 +- src/components/User/MyBadges.js | 260 ++++++++++++++++++++++++++++++++ src/reducers/authReducer.js | 9 +- 6 files changed, 326 insertions(+), 6 deletions(-) create mode 100644 src/components/User/MyBadges.js diff --git a/.env b/.env index 9af8f29..3ba890f 100644 --- a/.env +++ b/.env @@ -2,5 +2,7 @@ REACT_APP_COMPILER_URL=https://compiler.sensebox.de REACT_APP_BOARD=sensebox-mcu REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de +REACT_APP_MYBADGES=https://mybadges.org + # in days REACT_APP_SHARE_LINK_EXPIRES=30 diff --git a/src/actions/authActions.js b/src/actions/authActions.js index c29f7cf..cb06139 100644 --- a/src/actions/authActions.js +++ b/src/actions/authActions.js @@ -1,4 +1,4 @@ -import { USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, LOGOUT_FAIL, REFRESH_TOKEN_SUCCESS } from '../actions/types'; +import { MYBADGES_CONNECT, MYBADGES_DISCONNECT, USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, LOGOUT_FAIL, REFRESH_TOKEN_SUCCESS } from '../actions/types'; import axios from 'axios'; import { returnErrors, returnSuccess } from './messageActions' @@ -64,8 +64,6 @@ export const login = ({ email, password }) => (dispatch) => { dispatch(returnSuccess(res.data.message, res.status, 'LOGIN_SUCCESS')); }) .catch(err => { - console.log('hier'); - console.log(err); dispatch(returnErrors(err.response.data.message, err.response.status, 'LOGIN_FAIL')); dispatch({ type: LOGIN_FAIL @@ -74,6 +72,55 @@ export const login = ({ email, password }) => (dispatch) => { }; +// Connect to MyBadges-Account +export const connectMyBadges = ({ username, password }) => (dispatch, getState) => { + // Headers + const config = { + headers: { + 'Content-Type': 'application/json' + } + }; + // Request Body + const body = JSON.stringify({ username, password }); + axios.post(`${process.env.REACT_APP_BLOCKLY_API}/user/badge`, body, config) + .then(res => { + var user = getState().auth.user; + user.badge = res.data.account; + dispatch({ + type: MYBADGES_CONNECT, + payload: user + }); + dispatch(returnSuccess(res.data.message, res.status, 'MYBADGES_CONNECT_SUCCESS')); + }) + .catch(err => { + dispatch(returnErrors(err.response.data.message, err.response.status, 'MYBADGES_CONNECT_FAIL')); + }); +}; + +// Disconnect MyBadges-Account +export const disconnectMyBadges = () => (dispatch, getState) => { + // Headers + const config = { + headers: { + 'Content-Type': 'application/json' + } + }; + axios.put(`${process.env.REACT_APP_BLOCKLY_API}/user/badge`, config) + .then(res => { + var user = getState().auth.user; + user.badge = null; + dispatch({ + type: MYBADGES_DISCONNECT, + payload: user + }); + dispatch(returnSuccess(res.data.message, res.status, 'MYBADGES_DISCONNECT_SUCCESS')); + }) + .catch(err => { + dispatch(returnErrors(err.response.data.message, err.response.status, 'MYBADGES_DISCONNECT_FAIL')); + }); +}; + + // Logout User export const logout = () => (dispatch) => { const config = { diff --git a/src/actions/types.js b/src/actions/types.js index 34d5889..9172b4a 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -8,6 +8,8 @@ export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'; export const LOGOUT_FAIL = 'LOGOUT_FAIL'; export const REFRESH_TOKEN_FAIL = 'REFRESH_TOKEN_FAIL'; export const REFRESH_TOKEN_SUCCESS = 'REFRESH_TOKEN_SUCCESS'; +export const MYBADGES_CONNECT = 'MYBADGES_CONNECT'; +export const MYBADGES_DISCONNECT = 'MYBADGES_DISCONNECT'; export const NEW_CODE = 'NEW_CODE'; export const CHANGE_WORKSPACE = 'CHANGE_WORKSPACE'; diff --git a/src/components/Route/Routes.js b/src/components/Route/Routes.js index 25e9aff..3121edf 100644 --- a/src/components/Route/Routes.js +++ b/src/components/Route/Routes.js @@ -21,6 +21,7 @@ import Impressum from '../Impressum'; import Privacy from '../Privacy'; import Login from '../User/Login'; import Account from '../User/Account'; +import MyBadges from '../User/MyBadges'; class Routes extends Component { @@ -57,7 +58,10 @@ class Routes extends Component { - + + + + {/* settings */} diff --git a/src/components/User/MyBadges.js b/src/components/User/MyBadges.js new file mode 100644 index 0000000..4d7dc47 --- /dev/null +++ b/src/components/User/MyBadges.js @@ -0,0 +1,260 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { connectMyBadges, disconnectMyBadges } from '../../actions/authActions'; + +import axios from 'axios'; +import { withRouter } from 'react-router-dom'; + +import Breadcrumbs from '../Breadcrumbs'; +import Alert from '../Alert'; + +import { withStyles } from '@material-ui/core/styles'; +import Paper from '@material-ui/core/Paper'; +import Button from '@material-ui/core/Button'; +import IconButton from '@material-ui/core/IconButton'; +import TextField from '@material-ui/core/TextField'; +import Divider from '@material-ui/core/Divider'; +import InputAdornment from '@material-ui/core/InputAdornment'; +import Link from '@material-ui/core/Link'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import Avatar from '@material-ui/core/Avatar'; + +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; + +const styles = (theme) => ({ + root: { + '& label.Mui-focused': { + color: '#aed9c8' + }, + '& .MuiOutlinedInput-root': { + '&.Mui-focused fieldset': { + borderColor: '#aed9c8' + }, + borderRadius: '0.75rem' + } + }, + text: { + fontFamily: [ + '"Open Sans"', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + '"Helvetica Neue"', + 'Arial', + 'sans-serif', + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + ].join(','), + fontSize: 16 + } +}); + +export class MyBadges extends Component { + + constructor(props) { + super(props); + this.state = { + username: '', + password: '', + showPassword: false, + msg: '', + badges: [], + progress: false + }; + } + + componentDidMount(){ + if(this.props.user.badge){ + this.getBadges(); + } + } + + componentDidUpdate(props){ + const { message } = this.props; + if (message !== props.message) { + // Check for login error + if(message.id === 'MYBADGES_CONNECT_FAIL'){ + this.setState({msg: 'Der Benutzername oder das Passwort ist nicht korrekt.', username: '', password: '', showPassword: false}); + } + else if(message.id === 'MYBADGES_CONNECT_SUCCESS'){ + this.getBadges(); + } + else if(message.id === 'MYBADGES_DISCONNECT_SUCCESS' || message.id === 'MYBADGES_DISCONNECT_FAIL'){ + this.setState({progress: false}); + } + else { + this.setState({msg: null}); + } + } + } + + getBadges = () => { + this.setState({progress: true}); + axios.get(`${process.env.REACT_APP_BLOCKLY_API}/user/badge`) + .then(res => { + this.setState({badges: res.data.badges, progress: false}); + }) + .catch(err => { + this.setState({progress: false}); + console.log(err); + }); + }; + + onChange = e => { + this.setState({ [e.target.name]: e.target.value, msg: '' }); + }; + + onSubmit = e => { + e.preventDefault(); + const {username, password} = this.state; + // create user object + const user = { + username, + password + }; + this.props.connectMyBadges(user); + }; + + handleClickShowPassword = () => { + this.setState({ showPassword: !this.state.showPassword }); + }; + + handleMouseDownPassword = (e) => { + e.preventDefault(); + }; + + render(){ + return( +
+ + + + + {!this.props.user.badge ? + + Du kannst dein Blockly-Konto mit deinem MyBadges-Konto verknüpfen, um Badges erwerben zu können. + + : null} + +
+
+ My Badges +
+ {!this.props.user.badge ? +
+ {this.state.msg ? +
+ {this.state.msg} +
: null + } + + + + + + + }} + onChange={this.onChange} + fullWidth={true} + /> +

+ +

+

+ Passwort vergessen? +

+ +

+ Du hast noch kein Konto? Registrieren +

+
+ :
+ MyBadges-Konto ist erfolgreich verknüpft. + +
} +
+
+
+ + {this.props.user.badge && !this.state.progress ? + + + {this.state.badges && this.state.badges.length > 0 ? + + Du hast {this.state.badges.length} {this.state.badges.length === 1 ? 'Badge' : 'Badges'} im Kontext Blockly for senseBox erreicht. + + : null} + + + {this.state.badges && this.state.badges.length > 0 ? + this.state.badges.map(badge => ( + + + {badge.image && badge.image.path ? + + : } + +
{badge.name}
+
+
+
+ )) + : + + + Du hast noch keine Badges im Kontext senseBox for Blockly erreicht. + + } +
+
+ : null} +
+
+ ); + } +} + +MyBadges.propTypes = { + connectMyBadges: PropTypes.func.isRequired, + disconnectMyBadges: PropTypes.func.isRequired, + message: PropTypes.object.isRequired, + user: PropTypes.object.isRequired +}; + +const mapStateToProps = state => ({ + message: state.message, + user: state.auth.user +}); + +export default connect(mapStateToProps, { connectMyBadges, disconnectMyBadges })(withStyles(styles, { withTheme: true })(withRouter(MyBadges))); diff --git a/src/reducers/authReducer.js b/src/reducers/authReducer.js index 653ecb0..482af0c 100644 --- a/src/reducers/authReducer.js +++ b/src/reducers/authReducer.js @@ -1,4 +1,4 @@ -import { USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, LOGOUT_FAIL, REFRESH_TOKEN_SUCCESS } from '../actions/types'; +import { MYBADGES_CONNECT, MYBADGES_DISCONNECT, USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, LOGOUT_FAIL, REFRESH_TOKEN_SUCCESS } from '../actions/types'; const initialState = { @@ -27,7 +27,6 @@ export default function(state = initialState, action){ case REFRESH_TOKEN_SUCCESS: localStorage.setItem('token', action.payload.token); localStorage.setItem('refreshToken', action.payload.refreshToken); - console.log(action.payload); return { ...state, user: action.payload.user, @@ -36,6 +35,12 @@ export default function(state = initialState, action){ isAuthenticated: true, progress: false }; + case MYBADGES_CONNECT: + case MYBADGES_DISCONNECT: + return { + ...state, + user: action.payload + }; case AUTH_ERROR: case LOGIN_FAIL: case LOGOUT_SUCCESS: