diff --git a/src/actions/projectActions.js b/src/actions/projectActions.js new file mode 100644 index 0000000..31d3af3 --- /dev/null +++ b/src/actions/projectActions.js @@ -0,0 +1,68 @@ +import { PROJECT_PROGRESS, GET_PROJECT, GET_PROJECTS, PROJECT_TYPE } from './types'; + +import axios from 'axios'; +import { workspaceName } from './workspaceActions'; +import { returnErrors, returnSuccess } from './messageActions'; + +export const setType = (type) => (dispatch) => { + dispatch({ + type: PROJECT_TYPE, + payload: type + }); +}; + +export const getProject = (type, id) => (dispatch) => { + dispatch({type: PROJECT_PROGRESS}); + dispatch(setType(type)); + axios.get(`${process.env.REACT_APP_BLOCKLY_API}/${type}/${id}`) + .then(res => { + var data = type === 'share' ? 'content' : type; + var project = res.data[data]; + if(project){ + dispatch({ + type: GET_PROJECT, + payload: project + }); + dispatch({type: PROJECT_PROGRESS}); + dispatch(returnSuccess(res.data.message, res.status, 'GET_PROJECT_SUCCESS')); + } + else{ + dispatch({type: PROJECT_PROGRESS}); + dispatch(returnErrors(res.data.message, res.status, 'PROJECT_EMPTY')); + } + }) + .catch(err => { + if(err.response){ + dispatch(returnErrors(err.response.data.message, err.response.status, 'GET_PROJECT_FAIL')); + } + dispatch({type: PROJECT_PROGRESS}); + }); +}; + +export const getProjects = (type) => (dispatch) => { + dispatch({type: PROJECT_PROGRESS}); + axios.get(`${process.env.REACT_APP_BLOCKLY_API}/${type}`) + .then(res => { + var data = type === 'project' ? 'projects' : 'galleries'; + var projects = res.data[data]; + dispatch({ + type: GET_PROJECTS, + payload: projects + }); + dispatch({type: PROJECT_PROGRESS}); + dispatch(returnSuccess(res.data.message, res.status)); + }) + .catch(err => { + if(err.response){ + dispatch(returnErrors(err.response.data.message, err.response.status, 'GET_PROJECTS_FAIL')); + } + dispatch({type: PROJECT_PROGRESS}); + }); +}; + +export const resetProject = () => (dispatch) => { + dispatch({ + type: GET_PROJECTS, + payload: [] + }); +}; diff --git a/src/actions/types.js b/src/actions/types.js index 800b868..1afb071 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -37,3 +37,10 @@ export const VISIT = 'VISIT'; export const GET_ERRORS = 'GET_ERRORS'; export const GET_SUCCESS = 'GET_SUCCESS'; export const CLEAR_MESSAGES = 'CLEAR_MESSAGES'; + + +// projects: share, gallery, project +export const PROJECT_PROGRESS = 'PROJECT_PROGRESS'; +export const GET_PROJECT = 'GET_PROJECT'; +export const GET_PROJECTS = 'GET_PROJECTS'; +export const PROJECT_TYPE = 'PROJECT_TYPE'; diff --git a/src/components/Navbar.js b/src/components/Navbar.js index f1d037b..3bb1b51 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -53,7 +53,7 @@ class Navbar extends Component {
@@ -102,7 +102,7 @@ class Navbar extends Component { {[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, { text: 'Tutorial-Builder', icon: faTools, link: "/tutorial/builder" }, { text: 'Galerie', icon: faLightbulb, link: "/gallery" }, - { text: 'Projekte', icon: faLayerGroup, link: "/project" }, + { text: 'Projekte', icon: faLayerGroup, link: "/project" }, { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => ( @@ -122,7 +122,7 @@ class Navbar extends Component { ))} */} - {this.props.isLoading ? + {this.props.tutorialIsLoading || this.props.projectIsLoading ? : null}
@@ -131,11 +131,13 @@ class Navbar extends Component { } Navbar.propTypes = { - isLoading: PropTypes.bool.isRequired + tutorialIsLoading: PropTypes.bool.isRequired, + projectIsLoading: PropTypes.bool.isRequired }; const mapStateToProps = state => ({ - isLoading: state.tutorial.progress, + tutorialIsLoading: state.tutorial.progress, + projectIsLoading: state.project.progress }); export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(withRouter(Navbar))); diff --git a/src/components/Project/Project.js b/src/components/Project/Project.js index da813e6..3e7244d 100644 --- a/src/components/Project/Project.js +++ b/src/components/Project/Project.js @@ -2,6 +2,8 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { workspaceName } from '../../actions/workspaceActions'; +import { getProject, resetProject } from '../../actions/projectActions'; +import { clearMessages } from '../../actions/messageActions'; import axios from 'axios'; import { createNameId } from 'mnemonic-id'; @@ -15,69 +17,77 @@ import CircularProgress from '@material-ui/core/CircularProgress'; class Project extends Component { - state = { - project: {}, - progress: false, - type: '' - } - componentDidMount() { this.getProject(); } componentDidUpdate(props) { - if(props.location.path !== this.props.location.path){ + if(props.location.path !== this.props.location.path || + props.match.params[`${this.props.type}Id`] !== this.props.match.params[`${this.props.type}Id`]){ + if(this.props.message.msg){ + this.props.clearMessages(); + } this.getProject(); } + if(this.props.message !== props.message){ + if(this.props.message.id === 'PROJECT_EMPTY' || this.props.message.id === 'GET_PROJECT_FAIL'){ + this.props.workspaceName(createNameId()); + this.props.history.push('/'); + } + if(this.props.message.id === 'GET_PROJECT_SUCCESS'){ + this.props.workspaceName(this.props.project.title); + } + } + } + + componentWillUnmount() { + this.props.resetProject(); + this.props.workspaceName(null); + if(this.props.message.msg){ + this.props.clearMessages(); + } } getProject = () => { var param = this.props.match.params.shareId ? 'share' : this.props.match.params.galleryId ? 'gallery' : 'project'; - this.setState({ type: param, progress: true }); var id = this.props.match.params[`${param}Id`]; - axios.get(`${process.env.REACT_APP_BLOCKLY_API}/${param}/${id}`) - .then(res => { - var data = param === 'share' ? 'content' : param; - if(res.data[data]){ - this.props.workspaceName(res.data[data].title); - this.setState({ project: res.data[data], progress: false }); - } - else { - this.props.workspaceName(createNameId()); - this.setState({ progress: false }); - this.props.history.push('/'); - } - }) - .catch(err => { - // TODO: - this.setState({ progress: false, snackbar: true, key: Date.now(), message: `Fehler beim Aufrufen des angeforderten Programms. Versuche es noch einmal.`, type: 'error' }); - this.props.workspaceName(createNameId()); - this.props.history.push('/'); - window.scrollTo(0, 0); - }); + this.props.getProject(param, id); } render() { - var data = this.state.type === 'project' ? 'Projekte' : 'Galerie'; + var data = this.props.type === 'project' ? 'Projekte' : 'Galerie'; return ( - this.state.progress ? + this.props.progress ? - : + : this.props.project ?
- {this.state.type !== 'share' ? - + {this.props.type !== 'share' ? + : null} - -
+ + : null ); }; } Project.propTypes = { - workspaceName: PropTypes.func.isRequired + workspaceName: PropTypes.func.isRequired, + getProject: PropTypes.func.isRequired, + resetProject: PropTypes.func.isRequired, + clearMessages: PropTypes.func.isRequired, + project: PropTypes.object.isRequired, + type: PropTypes.string.isRequired, + message: PropTypes.object.isRequired, + progress: PropTypes.bool.isRequired }; +const mapStateToProps = state => ({ + project: state.project.projects[0], + progress: state.project.progress, + type: state.project.type, + message: state.message +}); -export default connect(null, { workspaceName })(Project); +export default connect(mapStateToProps, { workspaceName, getProject, resetProject, clearMessages })(Project); diff --git a/src/components/Project/ProjectHome.js b/src/components/Project/ProjectHome.js index 1dd7708..907b846 100644 --- a/src/components/Project/ProjectHome.js +++ b/src/components/Project/ProjectHome.js @@ -1,4 +1,7 @@ import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { getProjects, resetProject } from '../../actions/projectActions'; import axios from 'axios'; import { Link } from 'react-router-dom'; @@ -14,32 +17,21 @@ import Typography from '@material-ui/core/Typography'; class ProjectHome extends Component { - state = { - projects: [] - } - componentDidMount() { - this.getProjects(); + this.props.getProjects(this.props.match.path.replace('/','')); } componentDidUpdate(props) { if(props.match.path !== this.props.match.path){ - this.setState({projects: []}); - this.getProjects(); + this.props.getProjects(this.props.match.path.replace('/','')); } } - getProjects = () => { - var data = this.props.match.path === '/project' ? 'projects' : 'galleries'; - axios.get(`${process.env.REACT_APP_BLOCKLY_API}${this.props.match.path}`) - .then(res => { - this.setState({ projects: res.data[data] }); - }) - .catch(err => { - // TODO: - }); + componentWillUnmount() { + this.props.resetProject(); } + render() { var data = this.props.match.path === '/project' ? 'Projekte' : 'Galerie'; return ( @@ -47,8 +39,9 @@ class ProjectHome extends Component {

{data}

+ {this.props.progress ? null : - {this.state.projects.map((project, i) => { + {this.props.projects.map((project, i) => { return ( @@ -66,10 +59,23 @@ class ProjectHome extends Component { ) })} - + } ); }; } -export default ProjectHome; +ProjectHome.propTypes = { + getProjects: PropTypes.func.isRequired, + resetProject: PropTypes.func.isRequired, + projects: PropTypes.array.isRequired, + progress: PropTypes.bool.isRequired +}; + +const mapStateToProps = state => ({ + projects: state.project.projects, + progress: state.project.progress +}); + + +export default connect(mapStateToProps, { getProjects, resetProject })(ProjectHome); diff --git a/src/reducers/index.js b/src/reducers/index.js index 16eae53..5ff8fed 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -3,12 +3,14 @@ import workspaceReducer from './workspaceReducer'; import tutorialReducer from './tutorialReducer'; import tutorialBuilderReducer from './tutorialBuilderReducer'; import generalReducer from './generalReducer'; +import projectReducer from './projectReducer'; import messageReducer from './messageReducer'; export default combineReducers({ workspace: workspaceReducer, tutorial: tutorialReducer, builder: tutorialBuilderReducer, + project: projectReducer, general: generalReducer, message: messageReducer }); diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js new file mode 100644 index 0000000..c34a760 --- /dev/null +++ b/src/reducers/projectReducer.js @@ -0,0 +1,34 @@ +import { PROJECT_PROGRESS, GET_PROJECT, GET_PROJECTS, PROJECT_TYPE } from '../actions/types'; + +const initialState = { + projects: [], + type: '', + progress: false +}; + +export default function (state = initialState, action) { + switch (action.type) { + case PROJECT_PROGRESS: + return { + ...state, + progress: !state.progress + } + case GET_PROJECTS: + return { + ...state, + projects: action.payload + }; + case GET_PROJECT: + return { + ...state, + projects: [action.payload] + } + case PROJECT_TYPE: + return { + ...state, + type: action.payload + } + default: + return state; + } +}