login
This commit is contained in:
		
							parent
							
								
									4f57e7fd32
								
							
						
					
					
						commit
						5d9bfa97af
					
				
							
								
								
									
										184
									
								
								src/actions/authActions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								src/actions/authActions.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,184 @@ | |||||||
|  | import { 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' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // // Check token & load user
 | ||||||
|  | // export const loadUser = () => (dispatch) => {
 | ||||||
|  | //   // user loading
 | ||||||
|  | //   dispatch({
 | ||||||
|  | //     type: USER_LOADING
 | ||||||
|  | //   });
 | ||||||
|  | //   const config = {
 | ||||||
|  | //     success: res => {
 | ||||||
|  | //       dispatch({
 | ||||||
|  | //         type: USER_LOADED,
 | ||||||
|  | //         payload: res.data.user
 | ||||||
|  | //       });
 | ||||||
|  | //     },
 | ||||||
|  | //     error: err => {
 | ||||||
|  | //       if(err.response){
 | ||||||
|  | //         dispatch(returnErrors(err.response.data.message, err.response.status));
 | ||||||
|  | //       }
 | ||||||
|  | //       dispatch({
 | ||||||
|  | //         type: AUTH_ERROR
 | ||||||
|  | //       });
 | ||||||
|  | //     }
 | ||||||
|  | //   };
 | ||||||
|  | //   axios.get('/api/v1/user/me', config, dispatch(authInterceptor()))
 | ||||||
|  | //     .then(res => {
 | ||||||
|  | //       res.config.success(res);
 | ||||||
|  | //     })
 | ||||||
|  | //     .catch(err => {
 | ||||||
|  | //       err.config.error(err);
 | ||||||
|  | //     });
 | ||||||
|  | // };
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | var logoutTimerId; | ||||||
|  | const timeToLogout = 14.9*60*1000; // nearly 15 minutes corresponding to the API
 | ||||||
|  | 
 | ||||||
|  | // Login user
 | ||||||
|  | export const login = ({ email, password }) => (dispatch) => { | ||||||
|  |   // Headers
 | ||||||
|  |   const config = { | ||||||
|  |     headers: { | ||||||
|  |       'Content-Type': 'application/json' | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   // Request Body
 | ||||||
|  |   const body = JSON.stringify({ email, password }); | ||||||
|  |   axios.post('https://api.opensensemap.org/users/sign-in', body, config) | ||||||
|  |   .then(res => { | ||||||
|  |     // Logout automatically if refreshToken "expired"
 | ||||||
|  |     const logoutTimer = () => setTimeout( | ||||||
|  |       () => dispatch(logout()), | ||||||
|  |       timeToLogout | ||||||
|  |     ); | ||||||
|  |     logoutTimerId = logoutTimer(); | ||||||
|  |     dispatch(returnSuccess(res.data.message, res.status, 'LOGIN_SUCCESS')); | ||||||
|  |     dispatch({ | ||||||
|  |       type: LOGIN_SUCCESS, | ||||||
|  |       payload: res.data | ||||||
|  |     }); | ||||||
|  |   }) | ||||||
|  |   .catch(err => { | ||||||
|  |     console.log('hier'); | ||||||
|  |     console.log(err); | ||||||
|  |     dispatch(returnErrors(err.response.data.message, err.response.status, 'LOGIN_FAIL')); | ||||||
|  |     dispatch({ | ||||||
|  |       type: LOGIN_FAIL | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Logout User
 | ||||||
|  | export const logout = () => (dispatch) => { | ||||||
|  |   const config = { | ||||||
|  |     success: res => { | ||||||
|  |       dispatch({ | ||||||
|  |         type: LOGOUT_SUCCESS | ||||||
|  |       }); | ||||||
|  |       dispatch(returnSuccess(res.data.message, res.status, 'LOGOUT_SUCCESS')); | ||||||
|  |       clearTimeout(logoutTimerId); | ||||||
|  |     }, | ||||||
|  |     error: err => { | ||||||
|  |       dispatch(returnErrors(err.response.data.message, err.response.status, 'LOGOUT_FAIL')); | ||||||
|  |       dispatch({ | ||||||
|  |         type: LOGOUT_FAIL | ||||||
|  |       }); | ||||||
|  |       clearTimeout(logoutTimerId); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |   axios.post('https://api.opensensemap.org/users/sign-out', {}, config, dispatch(authInterceptor())) | ||||||
|  |   .then(res => { | ||||||
|  |     res.config.success(res); | ||||||
|  |   }) | ||||||
|  |   .catch(err => { | ||||||
|  |     if(err.response.status !== 401){ | ||||||
|  |       err.config.error(err); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export const authInterceptor = () => (dispatch, getState) => { | ||||||
|  |   // Add a request interceptor
 | ||||||
|  |   axios.interceptors.request.use( | ||||||
|  |     config => { | ||||||
|  |       config.headers['Content-Type'] = 'application/json'; | ||||||
|  |       const token = getState().auth.token; | ||||||
|  |       if (token) { | ||||||
|  |        config.headers['Authorization'] = `Bearer ${token}`; | ||||||
|  |       } | ||||||
|  |       return config; | ||||||
|  |    }, | ||||||
|  |    error => { | ||||||
|  |      Promise.reject(error); | ||||||
|  |    } | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   // Add a response interceptor
 | ||||||
|  |   axios.interceptors.response.use( | ||||||
|  |     response => { | ||||||
|  |       // request was successfull
 | ||||||
|  |       return response; | ||||||
|  |     }, | ||||||
|  |     error => { | ||||||
|  |       const originalRequest = error.config; | ||||||
|  |       const refreshToken = getState().auth.refreshToken; | ||||||
|  |       if(refreshToken){ | ||||||
|  |         // try to refresh the token failed
 | ||||||
|  |         if (error.response.status === 401 && originalRequest._retry) { | ||||||
|  |               // router.push('/login');
 | ||||||
|  |               return Promise.reject(error); | ||||||
|  |         } | ||||||
|  |         // token was not valid and 1st try to refresh the token
 | ||||||
|  |         if (error.response.status === 401 && !originalRequest._retry) { | ||||||
|  |           originalRequest._retry = true; | ||||||
|  |           const refreshToken = getState().auth.refreshToken; | ||||||
|  |           // request to refresh the token, in request-body is the refreshToken
 | ||||||
|  |           axios.post('/api/v1/user/token/refresh', {"refreshToken": refreshToken}) | ||||||
|  |                .then(res => { | ||||||
|  |                  if (res.status === 200) { | ||||||
|  |                    clearTimeout(logoutTimerId); | ||||||
|  |                    const logoutTimer = () => setTimeout( | ||||||
|  |                      () => dispatch(logout()), | ||||||
|  |                      timeToLogout | ||||||
|  |                    ); | ||||||
|  |                    logoutTimerId = logoutTimer(); | ||||||
|  |                    dispatch({ | ||||||
|  |                      type: REFRESH_TOKEN_SUCCESS, | ||||||
|  |                      payload: res.data | ||||||
|  |                    }); | ||||||
|  |                    axios.defaults.headers.common['Authorization'] = 'Bearer ' + getState().auth.token; | ||||||
|  |                    // request was successfull, new request with the old parameters and the refreshed token
 | ||||||
|  |                    return axios(originalRequest) | ||||||
|  |                           .then(res => { | ||||||
|  |                              originalRequest.success(res); | ||||||
|  |                            }) | ||||||
|  |                            .catch(err => { | ||||||
|  |                              originalRequest.error(err); | ||||||
|  |                            }); | ||||||
|  |                  } | ||||||
|  |                  return Promise.reject(error); | ||||||
|  |                }) | ||||||
|  |                .catch(err => { | ||||||
|  |                  // request failed, token could not be refreshed
 | ||||||
|  |                  if(err.response){ | ||||||
|  |                    dispatch(returnErrors(err.response.data.message, err.response.status)); | ||||||
|  |                  } | ||||||
|  |                  dispatch({ | ||||||
|  |                    type: AUTH_ERROR | ||||||
|  |                  }); | ||||||
|  |                  return Promise.reject(error); | ||||||
|  |                }); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       // request status was unequal to 401, no possibility to refresh the token
 | ||||||
|  |       return Promise.reject(error); | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  | }; | ||||||
| @ -1,3 +1,14 @@ | |||||||
|  | // authentication
 | ||||||
|  | export const USER_LOADING = 'USER_LOADING'; | ||||||
|  | export const USER_LOADED = 'USER_LOADED'; | ||||||
|  | export const AUTH_ERROR = 'AUTH_ERROR'; | ||||||
|  | export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; | ||||||
|  | export const LOGIN_FAIL = 'LOGIN_FAIL'; | ||||||
|  | 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 NEW_CODE = 'NEW_CODE'; | export const NEW_CODE = 'NEW_CODE'; | ||||||
| export const CHANGE_WORKSPACE = 'CHANGE_WORKSPACE'; | export const CHANGE_WORKSPACE = 'CHANGE_WORKSPACE'; | ||||||
| export const CREATE_BLOCK = 'CREATE_BLOCK'; | export const CREATE_BLOCK = 'CREATE_BLOCK'; | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ import React, { Component } from 'react'; | |||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
| import { connect } from 'react-redux'; | import { connect } from 'react-redux'; | ||||||
| import { Link } from 'react-router-dom'; | import { Link } from 'react-router-dom'; | ||||||
|  | import { logout } from '../actions/authActions'; | ||||||
| 
 | 
 | ||||||
| import senseboxLogo from './sensebox_logo.svg'; | import senseboxLogo from './sensebox_logo.svg'; | ||||||
| 
 | 
 | ||||||
| @ -20,7 +21,7 @@ import ListItemIcon from '@material-ui/core/ListItemIcon'; | |||||||
| import ListItemText from '@material-ui/core/ListItemText'; | import ListItemText from '@material-ui/core/ListItemText'; | ||||||
| import LinearProgress from '@material-ui/core/LinearProgress'; | import LinearProgress from '@material-ui/core/LinearProgress'; | ||||||
| 
 | 
 | ||||||
| import { faBars, faChevronLeft, faLayerGroup, faBuilding, faIdCard, faEnvelope, faCog, faChalkboardTeacher, faFolderPlus, faTools, faLightbulb } from "@fortawesome/free-solid-svg-icons"; | import { faBars, faChevronLeft, faLayerGroup, faSignInAlt, faSignOutAlt, faCertificate, faUserCircle, faIdCard, faEnvelope, faCog, faChalkboardTeacher, faFolderPlus, faTools, faLightbulb } from "@fortawesome/free-solid-svg-icons"; | ||||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||||
| 
 | 
 | ||||||
| const styles = (theme) => ({ | const styles = (theme) => ({ | ||||||
| @ -102,8 +103,7 @@ class Navbar extends Component { | |||||||
|             {[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, |             {[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, | ||||||
|               { text: 'Tutorial-Builder', icon: faTools, link: "/tutorial/builder" }, |               { text: 'Tutorial-Builder', icon: faTools, link: "/tutorial/builder" }, | ||||||
|               { text: 'Galerie', icon: faLightbulb, link: "/gallery" }, |               { text: 'Galerie', icon: faLightbulb, link: "/gallery" }, | ||||||
|               { text: 'Projekte', icon: faLayerGroup, link: "/project" }, |               { text: 'Projekte', icon: faLayerGroup, link: "/project" }].map((item, index) => ( | ||||||
|               { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => ( |  | ||||||
|               <Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}> |               <Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}> | ||||||
|                 <ListItem button onClick={this.toggleDrawer}> |                 <ListItem button onClick={this.toggleDrawer}> | ||||||
|                   <ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon> |                   <ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon> | ||||||
| @ -113,14 +113,25 @@ class Navbar extends Component { | |||||||
|             ))} |             ))} | ||||||
|           </List> |           </List> | ||||||
|           <Divider classes={{ root: this.props.classes.appBarColor }} style={{ marginTop: 'auto' }} /> |           <Divider classes={{ root: this.props.classes.appBarColor }} style={{ marginTop: 'auto' }} /> | ||||||
|           {/* <List> |           <List> | ||||||
|             {[{ text: 'Über uns', icon: faBuilding }, { text: 'Kontakt', icon: faEnvelope }, { text: 'Impressum', icon: faIdCard }].map((item, index) => ( |             {[{ text: 'Anmelden', icon: faSignInAlt, link: '/user/login', restriction: !this.props.isAuthenticated }, | ||||||
|               <ListItem button key={index} onClick={this.toggleDrawer}> |               { text: 'Konto', icon: faUserCircle, link: '/user', restriction: this.props.isAuthenticated }, | ||||||
|                 <ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon> |               { text: 'MyBadges', icon: faCertificate, link: '/user/badge', restriction: this.props.isAuthenticated }, | ||||||
|                 <ListItemText primary={item.text} /> |               { text: 'Abmelden', icon: faSignOutAlt, function: this.props.logout, restriction: this.props.isAuthenticated }, | ||||||
|               </ListItem> |               { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => { | ||||||
|             ))} |                 if(item.restriction || Object.keys(item).filter(attribute => attribute === 'restriction').length === 0){ | ||||||
|           </List> */} |                   return( | ||||||
|  |                     <Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}> | ||||||
|  |                       <ListItem button onClick={item.function ? () => {item.function(); this.toggleDrawer();} : this.toggleDrawer}> | ||||||
|  |                         <ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon> | ||||||
|  |                         <ListItemText primary={item.text} /> | ||||||
|  |                       </ListItem> | ||||||
|  |                     </Link> | ||||||
|  |                   ); | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             )} | ||||||
|  |           </List> | ||||||
|         </Drawer> |         </Drawer> | ||||||
|         {this.props.tutorialIsLoading || this.props.projectIsLoading ? |         {this.props.tutorialIsLoading || this.props.projectIsLoading ? | ||||||
|           <LinearProgress style={{marginBottom: '30px', boxShadow: '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)'}}/> |           <LinearProgress style={{marginBottom: '30px', boxShadow: '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)'}}/> | ||||||
| @ -132,12 +143,14 @@ class Navbar extends Component { | |||||||
| 
 | 
 | ||||||
| Navbar.propTypes = { | Navbar.propTypes = { | ||||||
|   tutorialIsLoading: PropTypes.bool.isRequired, |   tutorialIsLoading: PropTypes.bool.isRequired, | ||||||
|   projectIsLoading: PropTypes.bool.isRequired |   projectIsLoading: PropTypes.bool.isRequired, | ||||||
|  |   isAuthenticated: PropTypes.bool.isRequired | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const mapStateToProps = state => ({ | const mapStateToProps = state => ({ | ||||||
|   tutorialIsLoading: state.tutorial.progress, |   tutorialIsLoading: state.tutorial.progress, | ||||||
|   projectIsLoading: state.project.progress |   projectIsLoading: state.project.progress, | ||||||
|  |   isAuthenticated: state.auth.isAuthenticated | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(withRouter(Navbar))); | export default connect(mapStateToProps, { logout })(withStyles(styles, { withTheme: true })(withRouter(Navbar))); | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ import Project from './Project/Project'; | |||||||
| import Settings from './Settings/Settings'; | import Settings from './Settings/Settings'; | ||||||
| import Impressum from './Impressum'; | import Impressum from './Impressum'; | ||||||
| import Privacy from './Privacy'; | import Privacy from './Privacy'; | ||||||
|  | import Login from './User/Login'; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Routes extends Component { | class Routes extends Component { | ||||||
| @ -40,6 +41,8 @@ class Routes extends Component { | |||||||
|           // User-Projects
 |           // User-Projects
 | ||||||
|           <Route path="/project" exact component={ProjectHome} /> |           <Route path="/project" exact component={ProjectHome} /> | ||||||
|           <Route path="/project/:projectId" exact component={Project} /> |           <Route path="/project/:projectId" exact component={Project} /> | ||||||
|  |           // User
 | ||||||
|  |           <Route path="/user/login" exact component={Login} /> | ||||||
|           // settings
 |           // settings
 | ||||||
|           <Route path="/settings" exact component={Settings} /> |           <Route path="/settings" exact component={Settings} /> | ||||||
|           // privacy
 |           // privacy
 | ||||||
|  | |||||||
							
								
								
									
										157
									
								
								src/components/User/Login.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/components/User/Login.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | |||||||
|  | import React, { Component } from 'react'; | ||||||
|  | import PropTypes from 'prop-types'; | ||||||
|  | import { connect } from 'react-redux'; | ||||||
|  | import { login } from '../../actions/authActions' | ||||||
|  | import { clearMessages } from '../../actions/messageActions' | ||||||
|  | 
 | ||||||
|  | import { withRouter } from 'react-router-dom'; | ||||||
|  | 
 | ||||||
|  | import Snackbar from '../Snackbar'; | ||||||
|  | import Breadcrumbs from '../Breadcrumbs'; | ||||||
|  | 
 | ||||||
|  | import Button from '@material-ui/core/Button'; | ||||||
|  | import IconButton from '@material-ui/core/IconButton'; | ||||||
|  | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||||
|  | import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; | ||||||
|  | import TextField from '@material-ui/core/TextField'; | ||||||
|  | import Divider from '@material-ui/core/Divider'; | ||||||
|  | import InputAdornment from '@material-ui/core/InputAdornment'; | ||||||
|  | import CircularProgress from '@material-ui/core/CircularProgress'; | ||||||
|  | import Link from '@material-ui/core/Link'; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export class Login extends Component { | ||||||
|  | 
 | ||||||
|  |   constructor(props) { | ||||||
|  |     super(props); | ||||||
|  |     this.state = { | ||||||
|  |       email: '', | ||||||
|  |       password: '', | ||||||
|  |       snackbar: false, | ||||||
|  |       type: '', | ||||||
|  |       key: '', | ||||||
|  |       message: '', | ||||||
|  |       showPassword: false | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   componentDidUpdate(props){ | ||||||
|  |     const { message } = this.props; | ||||||
|  |     if (message !== props.message) { | ||||||
|  |       if(message.id === 'LOGIN_SUCCESS'){ | ||||||
|  |         this.props.history.goBack(); | ||||||
|  |       } | ||||||
|  |       // Check for login error
 | ||||||
|  |       else if(message.id === 'LOGIN_FAIL'){ | ||||||
|  |         this.setState({ email: '', password: '', snackbar: true, key: Date.now(), message: 'Der Benutzername oder das Passwort ist nicht korrekt.', type: 'error' }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onChange = e => { | ||||||
|  |     this.setState({ [e.target.name]: e.target.value }); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   onSubmit = e => { | ||||||
|  |     e.preventDefault(); | ||||||
|  |     const {email, password} = this.state; | ||||||
|  |     if(email !== '' && password !== ''){ | ||||||
|  |       // create user object
 | ||||||
|  |       const user = { | ||||||
|  |         email, | ||||||
|  |         password | ||||||
|  |       }; | ||||||
|  |       this.props.login(user); | ||||||
|  |     } else { | ||||||
|  |       this.setState({ snackbar: true, key: Date.now(), message: 'Gib sowohl ein Benutzername als auch ein Passwort ein.', type: 'error' }); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   handleClickShowPassword = () => { | ||||||
|  |     this.setState({ showPassword: !this.state.showPassword }); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   handleMouseDownPassword = (e) => { | ||||||
|  |     e.preventDefault(); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   render(){ | ||||||
|  |     return( | ||||||
|  |       <div> | ||||||
|  |         <Breadcrumbs content={[{ link: '/user/login', title: 'Anmelden' }]} /> | ||||||
|  | 
 | ||||||
|  |         <div style={{maxWidth: '500px', marginLeft: 'auto', marginRight: 'auto'}}> | ||||||
|  |           <h1>Anmelden</h1> | ||||||
|  |           <Snackbar | ||||||
|  |             open={this.state.snackbar} | ||||||
|  |             message={this.state.message} | ||||||
|  |             type={this.state.type} | ||||||
|  |             key={this.state.key} | ||||||
|  |           /> | ||||||
|  |           <TextField | ||||||
|  |             style={{marginBottom: '10px'}} | ||||||
|  |             // variant='outlined'
 | ||||||
|  |             type='text' | ||||||
|  |             label='E-Mail oder Nutzername' | ||||||
|  |             name='email' | ||||||
|  |             value={this.state.email} | ||||||
|  |             onChange={this.onChange} | ||||||
|  |             fullWidth={true} | ||||||
|  |           /> | ||||||
|  |           <TextField | ||||||
|  |             // variant='outlined'
 | ||||||
|  |             type={this.state.showPassword ? 'text' : 'password'} | ||||||
|  |             label='Passwort' | ||||||
|  |             name='password' | ||||||
|  |             value={this.state.password} | ||||||
|  |             InputProps={{ | ||||||
|  |               endAdornment: | ||||||
|  |                 <InputAdornment | ||||||
|  |                   position="end" | ||||||
|  |                 > | ||||||
|  |                   <IconButton | ||||||
|  |                     onClick={this.handleClickShowPassword} | ||||||
|  |                     onMouseDown={this.handleMouseDownPassword} | ||||||
|  |                     edge="end" | ||||||
|  |                   > | ||||||
|  |                     <FontAwesomeIcon size='xs' icon={this.state.showPassword ? faEyeSlash : faEye} /> | ||||||
|  |                   </IconButton> | ||||||
|  |                 </InputAdornment> | ||||||
|  |             }} | ||||||
|  |             onChange={this.onChange} | ||||||
|  |             fullWidth={true} | ||||||
|  |           /> | ||||||
|  |           <p> | ||||||
|  |             <Button color="primary" variant='contained' onClick={this.onSubmit} style={{width: '100%'}}> | ||||||
|  |               {this.props.progress ? | ||||||
|  |                 <div style={{height: '24.5px'}}><CircularProgress color="inherit" size={20}/></div> | ||||||
|  |               : 'Anmelden'} | ||||||
|  |             </Button> | ||||||
|  |           </p> | ||||||
|  |           <p style={{textAlign: 'center', fontSize: '0.8rem'}}> | ||||||
|  |             <Link rel="noreferrer" target="_blank" href={'https://opensensemap.org/'} color="primary">Passwort vergessen?</Link> | ||||||
|  |           </p> | ||||||
|  |           <Divider variant='fullWidth'/> | ||||||
|  |           <p style={{textAlign: 'center', paddingRight: "34px", paddingLeft: "34px"}}> | ||||||
|  |             Du hast noch kein Konto? <Link rel="noreferrer" target="_blank" href={'https://opensensemap.org/'}>Registrieren</Link> | ||||||
|  |           </p> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Login.propTypes = { | ||||||
|  |   message: PropTypes.object.isRequired, | ||||||
|  |   login: PropTypes.func.isRequired, | ||||||
|  |   clearMessages: PropTypes.func.isRequired, | ||||||
|  |   message: PropTypes.object.isRequired, | ||||||
|  |   progress: PropTypes.bool.isRequired | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const mapStateToProps = state => ({ | ||||||
|  |   message: state.message, | ||||||
|  |   progress: state.auth.progress | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | export default connect(mapStateToProps, { login, clearMessages })(withRouter(Login)); | ||||||
							
								
								
									
										56
									
								
								src/reducers/authReducer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/reducers/authReducer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | import { USER_LOADED, USER_LOADING, AUTH_ERROR, LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT_SUCCESS, LOGOUT_FAIL, REFRESH_TOKEN_SUCCESS } from '../actions/types'; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | const initialState = { | ||||||
|  |   token: localStorage.getItem('token'), | ||||||
|  |   refreshToken: localStorage.getItem('refreshToken'), | ||||||
|  |   isAuthenticated: null, | ||||||
|  |   progress: false, | ||||||
|  |   user: null | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default function(state = initialState, action){ | ||||||
|  |   switch(action.type){ | ||||||
|  |     case USER_LOADING: | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         progress: true | ||||||
|  |       }; | ||||||
|  |     case USER_LOADED: | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         isAuthenticated: true, | ||||||
|  |         progress: false, | ||||||
|  |         user: action.payload | ||||||
|  |       }; | ||||||
|  |     case LOGIN_SUCCESS: | ||||||
|  |     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.data.user, | ||||||
|  |         token: action.payload.token, | ||||||
|  |         refreshToken: action.payload.refreshToken, | ||||||
|  |         isAuthenticated: true, | ||||||
|  |         progress: false | ||||||
|  |       }; | ||||||
|  |     case AUTH_ERROR: | ||||||
|  |     case LOGIN_FAIL: | ||||||
|  |     case LOGOUT_SUCCESS: | ||||||
|  |     case LOGOUT_FAIL: | ||||||
|  |       localStorage.removeItem('token'); | ||||||
|  |       localStorage.removeItem('refreshToken'); | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         token: null, | ||||||
|  |         refreshToken: null, | ||||||
|  |         user: null, | ||||||
|  |         isAuthenticated: false, | ||||||
|  |         progress: false | ||||||
|  |       }; | ||||||
|  |     default: | ||||||
|  |       return state; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -5,8 +5,10 @@ import tutorialBuilderReducer from './tutorialBuilderReducer'; | |||||||
| import generalReducer from './generalReducer'; | import generalReducer from './generalReducer'; | ||||||
| import projectReducer from './projectReducer'; | import projectReducer from './projectReducer'; | ||||||
| import messageReducer from './messageReducer'; | import messageReducer from './messageReducer'; | ||||||
|  | import authReducer from './authReducer'; | ||||||
| 
 | 
 | ||||||
| export default combineReducers({ | export default combineReducers({ | ||||||
|  |   auth: authReducer, | ||||||
|   workspace: workspaceReducer, |   workspace: workspaceReducer, | ||||||
|   tutorial: tutorialReducer, |   tutorial: tutorialReducer, | ||||||
|   builder: tutorialBuilderReducer, |   builder: tutorialBuilderReducer, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user