tutorial status is stored in user account if exists or in local storage
This commit is contained in:
		
							parent
							
								
									5430e783cc
								
							
						
					
					
						commit
						1821ac4e40
					
				| @ -1,4 +1,4 @@ | ||||
| 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 { MYBADGES_CONNECT, MYBADGES_DISCONNECT, GET_STATUS, 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' | ||||
| @ -12,6 +12,10 @@ export const loadUser = () => (dispatch) => { | ||||
|   }); | ||||
|   const config = { | ||||
|     success: res => { | ||||
|       dispatch({ | ||||
|         type: GET_STATUS, | ||||
|         payload: res.data.user.status | ||||
|       }); | ||||
|       dispatch({ | ||||
|         type: USER_LOADED, | ||||
|         payload: res.data.user | ||||
| @ -21,6 +25,15 @@ 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')); | ||||
|       } | ||||
|       dispatch({ | ||||
|         type: GET_STATUS, | ||||
|         payload: status | ||||
|       }); | ||||
|       dispatch({ | ||||
|         type: AUTH_ERROR | ||||
|       }); | ||||
| @ -31,6 +44,7 @@ export const loadUser = () => (dispatch) => { | ||||
|       res.config.success(res); | ||||
|     }) | ||||
|     .catch(err => { | ||||
|       console.log(err); | ||||
|       err.config.error(err); | ||||
|     }); | ||||
| }; | ||||
| @ -61,13 +75,26 @@ export const login = ({ email, password }) => (dispatch) => { | ||||
|       type: LOGIN_SUCCESS, | ||||
|       payload: res.data | ||||
|     }); | ||||
|     dispatch({ | ||||
|       type: GET_STATUS, | ||||
|       payload: res.data.user.status | ||||
|     }); | ||||
|     dispatch(returnSuccess(res.data.message, res.status, 'LOGIN_SUCCESS')); | ||||
|   }) | ||||
|   .catch(err => { | ||||
|     console.log(err); | ||||
|     dispatch(returnErrors(err.response.data.message, err.response.status, 'LOGIN_FAIL')); | ||||
|     dispatch({ | ||||
|       type: LOGIN_FAIL | ||||
|     }); | ||||
|     var status = []; | ||||
|     if (window.localStorage.getItem('status')) { | ||||
|       status = JSON.parse(window.localStorage.getItem('status')); | ||||
|     } | ||||
|     dispatch({ | ||||
|       type: GET_STATUS, | ||||
|       payload: status | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| @ -130,6 +157,14 @@ export const logout = () => (dispatch) => { | ||||
|       dispatch({ | ||||
|         type: LOGOUT_SUCCESS | ||||
|       }); | ||||
|       var status = []; | ||||
|       if (window.localStorage.getItem('status')) { | ||||
|         status = JSON.parse(window.localStorage.getItem('status')); | ||||
|       } | ||||
|       dispatch({ | ||||
|         type: GET_STATUS, | ||||
|         payload: status | ||||
|       }); | ||||
|       dispatch(returnSuccess(res.data.message, res.status, 'LOGOUT_SUCCESS')); | ||||
|       clearTimeout(logoutTimerId); | ||||
|     }, | ||||
| @ -138,6 +173,14 @@ export const logout = () => (dispatch) => { | ||||
|       dispatch({ | ||||
|         type: LOGOUT_FAIL | ||||
|       }); | ||||
|       var status = []; | ||||
|       if (window.localStorage.getItem('status')) { | ||||
|         status = JSON.parse(window.localStorage.getItem('status')); | ||||
|       } | ||||
|       dispatch({ | ||||
|         type: GET_STATUS, | ||||
|         payload: status | ||||
|       }); | ||||
|       clearTimeout(logoutTimerId); | ||||
|     } | ||||
|   }; | ||||
| @ -146,6 +189,7 @@ export const logout = () => (dispatch) => { | ||||
|     res.config.success(res); | ||||
|   }) | ||||
|   .catch(err => { | ||||
|     console.log(err); | ||||
|     if(err.response.status !== 401){ | ||||
|       err.config.error(err); | ||||
|     } | ||||
|  | ||||
| @ -3,21 +3,28 @@ import { MYBADGES_DISCONNECT, TUTORIAL_PROGRESS, GET_TUTORIAL, GET_TUTORIALS, TU | ||||
| import axios from 'axios'; | ||||
| import { returnErrors, returnSuccess } from './messageActions'; | ||||
| 
 | ||||
| export const getTutorial = (id) => (dispatch, getState) => { | ||||
| export const tutorialProgress = () => (dispatch) => { | ||||
|   dispatch({type: TUTORIAL_PROGRESS}); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| export const getTutorial = (id) => (dispatch, getState) => { | ||||
|   axios.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial/${id}`) | ||||
|     .then(res => { | ||||
|       var tutorial = res.data.tutorial; | ||||
|       existingTutorial(tutorial, getState().tutorial.status).then(status => { | ||||
|         console.log('progress',getState().auth.progress); | ||||
|         console.log('status'); | ||||
|         dispatch({ | ||||
|           type: TUTORIAL_SUCCESS, | ||||
|           payload: status | ||||
|         }); | ||||
|         dispatch({type: TUTORIAL_PROGRESS}); | ||||
|         dispatch(updateStatus(status)); | ||||
|         dispatch({ | ||||
|           type: GET_TUTORIAL, | ||||
|           payload: tutorial | ||||
|         }); | ||||
|         dispatch({type: TUTORIAL_PROGRESS}); | ||||
|         dispatch(returnSuccess(res.data.message, res.status)); | ||||
|       }); | ||||
|     }) | ||||
| @ -30,7 +37,6 @@ export const getTutorial = (id) => (dispatch, getState) => { | ||||
| }; | ||||
| 
 | ||||
| export const getTutorials = () => (dispatch, getState) => { | ||||
|   dispatch({type: TUTORIAL_PROGRESS}); | ||||
|   axios.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial`) | ||||
|     .then(res => { | ||||
|       var tutorials = res.data.tutorials; | ||||
| @ -40,6 +46,7 @@ export const getTutorials = () => (dispatch, getState) => { | ||||
|           type: TUTORIAL_SUCCESS, | ||||
|           payload: status | ||||
|         }); | ||||
|         dispatch(updateStatus(status)); | ||||
|         dispatch({ | ||||
|           type: GET_TUTORIALS, | ||||
|           payload: tutorials | ||||
| @ -75,6 +82,24 @@ export const assigneBadge = (id) => (dispatch, getState) => { | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| export const updateStatus = (status) => (dispatch, getState) => { | ||||
|   if(getState().auth.isAuthenticated){ | ||||
|     // update user account in database - sync with redux store
 | ||||
|     axios.put(`${process.env.REACT_APP_BLOCKLY_API}/user/status`, {status: status}) | ||||
|       .then(res => { | ||||
|         // dispatch(returnSuccess(badge, res.status, 'UPDATE_STATUS_SUCCESS'));
 | ||||
|       }) | ||||
|       .catch(err => { | ||||
|         if(err.response){ | ||||
|           // dispatch(returnErrors(err.response.data.message, err.response.status, 'UPDATE_STATUS_FAIL'));
 | ||||
|         } | ||||
|       }); | ||||
|   } else { | ||||
|     // update locale storage - sync with redux store
 | ||||
|     window.localStorage.setItem('status', JSON.stringify(status)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| export const deleteTutorial = (id) => (dispatch, getState) => { | ||||
|   var tutorial = getState().tutorial; | ||||
|   var id = getState().builder.id; | ||||
| @ -127,6 +152,7 @@ export const tutorialCheck = (status, step) => (dispatch, getState) => { | ||||
|     type: status === 'success' ? TUTORIAL_SUCCESS : TUTORIAL_ERROR, | ||||
|     payload: tutorialsStatus | ||||
|   }); | ||||
|   dispatch(updateStatus(tutorialsStatus)); | ||||
|   dispatch(tutorialChange()); | ||||
|   dispatch(returnSuccess('','','TUTORIAL_CHECK_SUCCESS')); | ||||
| }; | ||||
| @ -149,6 +175,7 @@ export const storeTutorialXml = (code) => (dispatch, getState) => { | ||||
|         type: TUTORIAL_XML, | ||||
|         payload: tutorialsStatus | ||||
|       }); | ||||
|       dispatch(updateStatus(tutorialsStatus)); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| @ -23,6 +23,7 @@ export const NAME = 'NAME'; | ||||
| export const TUTORIAL_PROGRESS = 'TUTORIAL_PROGRESS'; | ||||
| export const GET_TUTORIAL = 'GET_TUTORIAL'; | ||||
| export const GET_TUTORIALS = 'GET_TUTORIALS'; | ||||
| export const GET_STATUS = 'GET_STATUS'; | ||||
| export const TUTORIAL_SUCCESS = 'TUTORIAL_SUCCESS'; | ||||
| export const TUTORIAL_ERROR = 'TUTORIAL_ERROR'; | ||||
| export const TUTORIAL_CHANGE = 'TUTORIAL_CHANGE'; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import PropTypes from 'prop-types'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { workspaceName } from '../../actions/workspaceActions'; | ||||
| import { clearMessages } from '../../actions/messageActions'; | ||||
| import { getTutorial, resetTutorial, tutorialStep } from '../../actions/tutorialActions'; | ||||
| import { getTutorial, resetTutorial, tutorialStep,tutorialProgress } from '../../actions/tutorialActions'; | ||||
| 
 | ||||
| import Breadcrumbs from '../Breadcrumbs'; | ||||
| import StepperHorizontal from './StepperHorizontal'; | ||||
| @ -22,11 +22,20 @@ import Button from '@material-ui/core/Button'; | ||||
| class Tutorial extends Component { | ||||
| 
 | ||||
|   componentDidMount() { | ||||
|     this.props.tutorialProgress(); | ||||
|     // retrieve tutorials only if a potential user is loaded - authentication
 | ||||
|     // is finished (success or failed)
 | ||||
|     if(!this.props.progress){ | ||||
|       this.props.getTutorial(this.props.match.params.tutorialId); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentDidUpdate(props, state) { | ||||
|     if(this.props.tutorial && !this.props.isLoading && this.props.tutorial._id != this.props.match.params.tutorialId) { | ||||
|     if(props.progress !== this.props.progress && !this.props.progress){ | ||||
|       // authentication is completed
 | ||||
|       this.props.getTutorial(this.props.match.params.tutorialId); | ||||
|     } | ||||
|     else if(this.props.tutorial && !this.props.isLoading && this.props.tutorial._id != this.props.match.params.tutorialId) { | ||||
|       this.props.getTutorial(this.props.match.params.tutorialId); | ||||
|     } | ||||
|     if(this.props.message.id === 'GET_TUTORIAL_FAIL'){ | ||||
| @ -89,13 +98,15 @@ Tutorial.propTypes = { | ||||
|   resetTutorial: PropTypes.func.isRequired, | ||||
|   clearMessages: PropTypes.func.isRequired, | ||||
|   tutorialStep: PropTypes.func.isRequired, | ||||
|   tutorialProgress: PropTypes.func.isRequired, | ||||
|   workspaceName: PropTypes.func.isRequired, | ||||
|   status: PropTypes.array.isRequired, | ||||
|   change: PropTypes.number.isRequired, | ||||
|   activeStep: PropTypes.number.isRequired, | ||||
|   tutorial: PropTypes.object.isRequired, | ||||
|   isLoading: PropTypes.bool.isRequired, | ||||
|   message: PropTypes.object.isRequired | ||||
|   message: PropTypes.object.isRequired, | ||||
|   progress: PropTypes.bool.isRequired | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps = state => ({ | ||||
| @ -104,7 +115,8 @@ const mapStateToProps = state => ({ | ||||
|   activeStep: state.tutorial.activeStep, | ||||
|   tutorial: state.tutorial.tutorials[0], | ||||
|   isLoading: state.tutorial.progress, | ||||
|   message: state.message | ||||
|   message: state.message, | ||||
|   progress: state.auth.progress | ||||
| }); | ||||
| 
 | ||||
| export default connect(mapStateToProps, { getTutorial, resetTutorial, tutorialStep, clearMessages, workspaceName })(Tutorial); | ||||
| export default connect(mapStateToProps, { getTutorial, resetTutorial, tutorialStep, tutorialProgress, clearMessages, workspaceName })(Tutorial); | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import React, { Component } from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { getTutorials, resetTutorial } from '../../actions/tutorialActions'; | ||||
| import { getTutorials, resetTutorial, tutorialProgress } from '../../actions/tutorialActions'; | ||||
| import { clearMessages } from '../../actions/messageActions'; | ||||
| 
 | ||||
| import clsx from 'clsx'; | ||||
| @ -52,10 +52,19 @@ const styles = (theme) => ({ | ||||
| class TutorialHome extends Component { | ||||
| 
 | ||||
|   componentDidMount() { | ||||
|     this.props.tutorialProgress(); | ||||
|     // retrieve tutorials only if a potential user is loaded - authentication
 | ||||
|     // is finished (success or failed)
 | ||||
|     if(!this.props.progress){ | ||||
|       this.props.getTutorials(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentDidUpdate(props, state) { | ||||
|     if(props.progress !== this.props.progress && !this.props.progress){ | ||||
|       // authentication is completed
 | ||||
|       this.props.getTutorials(); | ||||
|     } | ||||
|     if(this.props.message.id === 'GET_TUTORIALS_FAIL'){ | ||||
|       alert(this.props.message.msg); | ||||
|     } | ||||
| @ -120,12 +129,14 @@ class TutorialHome extends Component { | ||||
| TutorialHome.propTypes = { | ||||
|   getTutorials: PropTypes.func.isRequired, | ||||
|   resetTutorial: PropTypes.func.isRequired, | ||||
|   tutorialProgress: PropTypes.func.isRequired, | ||||
|   clearMessages: PropTypes.func.isRequired, | ||||
|   status: PropTypes.array.isRequired, | ||||
|   change: PropTypes.number.isRequired, | ||||
|   tutorials: PropTypes.array.isRequired, | ||||
|   isLoading: PropTypes.bool.isRequired, | ||||
|   message: PropTypes.object.isRequired | ||||
|   message: PropTypes.object.isRequired, | ||||
|   progress: PropTypes.bool.isRequired | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps = state => ({ | ||||
| @ -133,7 +144,8 @@ const mapStateToProps = state => ({ | ||||
|   status: state.tutorial.status, | ||||
|   tutorials: state.tutorial.tutorials, | ||||
|   isLoading: state.tutorial.progress, | ||||
|   message: state.message | ||||
|   message: state.message, | ||||
|   progress: state.auth.progress | ||||
| }); | ||||
| 
 | ||||
| export default connect(mapStateToProps, { getTutorials, resetTutorial, clearMessages })(withStyles(styles, { withTheme: true })(TutorialHome)); | ||||
| export default connect(mapStateToProps, { getTutorials, resetTutorial, clearMessages, tutorialProgress })(withStyles(styles, { withTheme: true })(TutorialHome)); | ||||
|  | ||||
| @ -5,7 +5,7 @@ const initialState = { | ||||
|   token: localStorage.getItem('token'), | ||||
|   refreshToken: localStorage.getItem('refreshToken'), | ||||
|   isAuthenticated: null, | ||||
|   progress: false, | ||||
|   progress: true, | ||||
|   user: null | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -1,18 +1,20 @@ | ||||
| import { TUTORIAL_PROGRESS, GET_TUTORIAL, GET_TUTORIALS, TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE, TUTORIAL_XML, TUTORIAL_ID, TUTORIAL_STEP } from '../actions/types'; | ||||
| import { TUTORIAL_PROGRESS, GET_TUTORIAL, GET_TUTORIALS, GET_STATUS, TUTORIAL_SUCCESS, TUTORIAL_ERROR, TUTORIAL_CHANGE, TUTORIAL_XML, TUTORIAL_ID, TUTORIAL_STEP } from '../actions/types'; | ||||
| 
 | ||||
| 
 | ||||
| const initialStatus = () => { | ||||
|   if (window.localStorage.getItem('status')) { | ||||
|     var status = JSON.parse(window.localStorage.getItem('status')); | ||||
|     return status; | ||||
|   } | ||||
|   return []; | ||||
|   // // window.localStorage.getItem('status') does not exist
 | ||||
|   // return tutorials.map(tutorial => { return { id: tutorial.id, tasks: tutorial.steps.filter(step => step.type === 'task').map(task => { return { id: task.id }; }) }; });
 | ||||
| }; | ||||
| //
 | ||||
| // const initialStatus = () => {
 | ||||
| //   if(store.getState().auth.user){
 | ||||
| //     return store.getState().auth.user.status || []
 | ||||
| //   }
 | ||||
| //   else if (window.localStorage.getItem('status')) {
 | ||||
| //     var status = JSON.parse(window.localStorage.getItem('status'));
 | ||||
| //     return status;
 | ||||
| //   }
 | ||||
| //   return [];
 | ||||
| // };
 | ||||
| 
 | ||||
| const initialState = { | ||||
|   status: initialStatus(), | ||||
|   status: [], | ||||
|   activeStep: 0, | ||||
|   change: 0, | ||||
|   tutorials: [], | ||||
| @ -39,8 +41,14 @@ export default function (state = initialState, action) { | ||||
|     case TUTORIAL_SUCCESS: | ||||
|     case TUTORIAL_ERROR: | ||||
|     case TUTORIAL_XML: | ||||
|       // update locale storage - sync with redux store
 | ||||
|       window.localStorage.setItem('status', JSON.stringify(action.payload)); | ||||
|       // update store - sync with redux store is implemented outside reducer
 | ||||
|       // in every dispatch action with the types 'TUTORIAL_SUCCESS','TUTORIAL_ERROR'
 | ||||
|       // and 'TUTORIAL_XML' the function 'updateStatus' is called
 | ||||
|       return { | ||||
|         ...state, | ||||
|         status: action.payload | ||||
|       }; | ||||
|     case GET_STATUS: | ||||
|       return { | ||||
|         ...state, | ||||
|         status: action.payload | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user