diff --git a/src/actions/projectActions.js b/src/actions/projectActions.js
index 94909ef..a41e685 100644
--- a/src/actions/projectActions.js
+++ b/src/actions/projectActions.js
@@ -71,24 +71,25 @@ export const getProjects = (type) => (dispatch) => {
});
};
-export const updateProject = () => (dispatch, getState) => {
+export const updateProject = (type, id) => (dispatch, getState) => {
var workspace = getState().workspace;
var body = {
xml: workspace.code.xml,
title: workspace.name
}
var project = getState().project;
- var id = project.projects[0]._id._id ? project.projects[0]._id._id : project.projects[0]._id;
- var type = project.type;
if(type==='gallery'){
body.description = project.description;
}
axios.put(`${process.env.REACT_APP_BLOCKLY_API}/${type}/${id}`, body)
.then(res => {
var project = res.data[type];
+ var projects = getState().project.projects;
+ var index = projects.findIndex(res => res._id === project._id);
+ projects[index] = project;
dispatch({
- type: GET_PROJECT,
- payload: project
+ type: GET_PROJECTS,
+ payload: projects
});
if(type === 'project'){
dispatch(returnSuccess(res.data.message, res.status, 'PROJECT_UPDATE_SUCCESS'));
@@ -103,13 +104,17 @@ export const updateProject = () => (dispatch, getState) => {
});
}
-export const deleteProject = () => (dispatch, getState) => {
+export const deleteProject = (type, id) => (dispatch, getState) => {
var project = getState().project;
- var id = project.projects[0]._id._id ? project.projects[0]._id._id : project.projects[0]._id;
- var type = project.type;
axios.delete(`${process.env.REACT_APP_BLOCKLY_API}/${type}/${id}`)
.then(res => {
- dispatch({type: GET_PROJECTS, payload: []});
+ var projects = getState().project.projects;
+ var index = projects.findIndex(res => res._id === id || res._id._id === id);
+ projects.splice(index, 1)
+ dispatch({
+ type: GET_PROJECTS,
+ payload: projects
+ });
if(type === 'project'){
dispatch(returnSuccess(res.data.message, res.status, 'PROJECT_DELETE_SUCCESS'));
} else {
@@ -121,7 +126,41 @@ export const deleteProject = () => (dispatch, getState) => {
dispatch(returnErrors(err.response.data.message, err.response.status, 'PROJECT_DELETE_FAIL'));
}
});
-}
+};
+
+
+export const shareProject = (title, type, id) => (dispatch, getState) => {
+ var body = {
+ title: title
+ };
+ if(type === 'project'){
+ body.projectId = id;
+ } else {
+ body.xml = getState().workspace.code.xml;
+ }
+ axios.post(`${process.env.REACT_APP_BLOCKLY_API}/share`, body)
+ .then(res => {
+ var shareContent = res.data.content;
+ if(body.projectId){
+ var projects = getState().project.projects;
+ var index = projects.findIndex(res => res._id === id);
+ projects[index]._id = {
+ _id: shareContent._id,
+ expiresAt: shareContent.expiresAt
+ };
+ dispatch({
+ type: GET_PROJECTS,
+ payload: projects
+ });
+ }
+ dispatch(returnSuccess(res.data.message, shareContent._id, 'SHARE_SUCCESS'));
+ })
+ .catch(err => {
+ if(err.response){
+ dispatch(returnErrors(err.response.data.message, err.response.status, 'SHARE_FAIL'));
+ }
+ });
+};
export const resetProject = () => (dispatch) => {
diff --git a/src/components/Home.js b/src/components/Home.js
index 38368d8..bade15d 100644
--- a/src/components/Home.js
+++ b/src/components/Home.js
@@ -95,7 +95,9 @@ class Home extends Component {
: null
}
-
+
+
+
@@ -109,7 +111,7 @@ class Home extends Component {
{this.props.project ?
- < BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.props.project} />
+ < BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.props.project.xml} />
: < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
}
diff --git a/src/components/Navbar.js b/src/components/Navbar.js
index b7fa021..2bc7b62 100644
--- a/src/components/Navbar.js
+++ b/src/components/Navbar.js
@@ -157,7 +157,7 @@ const mapStateToProps = state => ({
tutorialIsLoading: state.tutorial.progress,
projectIsLoading: state.project.progress,
isAuthenticated: state.auth.isAuthenticated,
- userRole: state.auth.user
+ user: state.auth.user
});
export default connect(mapStateToProps, { logout })(withStyles(styles, { withTheme: true })(withRouter(Navbar)));
diff --git a/src/components/Project/Project.js b/src/components/Project/Project.js
index 80eb59d..a3a2403 100644
--- a/src/components/Project/Project.js
+++ b/src/components/Project/Project.js
@@ -75,7 +75,7 @@ class Project extends Component {
{this.props.type !== 'share' ?
: null}
-
+
: null
);
};
diff --git a/src/components/Project/ProjectHome.js b/src/components/Project/ProjectHome.js
index 5ccd49b..b373f02 100644
--- a/src/components/Project/ProjectHome.js
+++ b/src/components/Project/ProjectHome.js
@@ -10,6 +10,7 @@ import { Link, withRouter } from 'react-router-dom';
import Breadcrumbs from '../Breadcrumbs';
import BlocklyWindow from '../Blockly/BlocklyWindow';
import Snackbar from '../Snackbar';
+import WorkspaceFunc from '../WorkspaceFunc';
import { withStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
@@ -61,6 +62,14 @@ class ProjectHome extends Component {
this.setState({snackbar: false});
this.props.getProjects(this.props.location.pathname.replace('/',''));
}
+ if(props.message !== this.props.message){
+ if(this.props.message.id === 'PROJECT_DELETE_SUCCESS'){
+ this.setState({ snackbar: true, key: Date.now(), message: `Dein Projekt wurde erfolgreich gelöscht.`, type: 'success' });
+ }
+ else if(this.props.message.id === 'GALLERY_DELETE_SUCCESS'){
+ this.setState({ snackbar: true, key: Date.now(), message: `Dein Galerie-Projekt wurde erfolgreich gelöscht.`, type: 'success' });
+ }
+ }
}
componentWillUnmount() {
@@ -86,8 +95,8 @@ class ProjectHome extends Component {
{this.props.projects.map((project, i) => {
return (
-
-
+
+
{project.title}
{project.description}
-
-
+
+ {this.props.user && this.props.user.email === project.creator ?
+
+ : null}
+
)
})}
@@ -128,12 +149,14 @@ ProjectHome.propTypes = {
clearMessages: PropTypes.func.isRequired,
projects: PropTypes.array.isRequired,
progress: PropTypes.bool.isRequired,
+ user: PropTypes.object,
message: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
projects: state.project.projects,
progress: state.project.progress,
+ user: state.auth.user,
message: state.message
});
diff --git a/src/components/Route/PrivateRouteCreator.js b/src/components/Route/PrivateRouteCreator.js
index b4734da..0efd48c 100644
--- a/src/components/Route/PrivateRouteCreator.js
+++ b/src/components/Route/PrivateRouteCreator.js
@@ -39,7 +39,7 @@ PrivateRoute.propTypes = {
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated,
- userRole: state.auth.user
+ user: state.auth.user
});
export default connect(mapStateToProps, null)(withRouter(PrivateRoute));
diff --git a/src/components/Tutorial/Builder/Builder.js b/src/components/Tutorial/Builder/Builder.js
index 398c79f..753edd0 100644
--- a/src/components/Tutorial/Builder/Builder.js
+++ b/src/components/Tutorial/Builder/Builder.js
@@ -6,6 +6,7 @@ import { getTutorials, resetTutorial} from '../../../actions/tutorialActions';
import { clearMessages } from '../../../actions/messageActions';
import axios from 'axios';
+import { withRouter } from 'react-router-dom';
import { saveAs } from 'file-saver';
import { detectWhitespacesAndReturnReadableResult } from '../../../helpers/whitespace';
@@ -378,4 +379,4 @@ const mapStateToProps = state => ({
message: state.message
});
-export default connect(mapStateToProps, { checkError, readJSON, jsonString, progress, tutorialId, resetTutorialBuilder, getTutorials, resetTutorial, clearMessages })(withStyles(styles, { withTheme: true })(Builder));
+export default connect(mapStateToProps, { checkError, readJSON, jsonString, progress, tutorialId, resetTutorialBuilder, getTutorials, resetTutorial, clearMessages })(withStyles(styles, { withTheme: true })(withRouter(Builder)));
diff --git a/src/components/WorkspaceFunc.js b/src/components/WorkspaceFunc.js
index a0a7600..f11e620 100644
--- a/src/components/WorkspaceFunc.js
+++ b/src/components/WorkspaceFunc.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { clearStats, onChangeCode, workspaceName } from '../actions/workspaceActions';
-import { updateProject, deleteProject, setDescription } from '../actions/projectActions';
+import { updateProject, deleteProject, shareProject, setDescription } from '../actions/projectActions';
import * as Blockly from 'blockly/core';
@@ -100,6 +100,9 @@ class WorkspaceFunc extends Component {
if (props.name !== this.props.name) {
this.setState({ name: this.props.name });
}
+ if (props.description !== this.props.description) {
+ this.setState({ description: this.props.description });
+ }
if(this.props.message !== props.message){
if(this.props.message.id === 'PROJECT_UPDATE_SUCCESS'){
this.setState({ snackbar: true, key: Date.now(), message: `Das Projekt wurde erfolgreich aktualisiert.`, type: 'success' });
@@ -116,6 +119,15 @@ class WorkspaceFunc extends Component {
else if(this.props.message.id === 'PROJECT_DELETE_FAIL'){
this.setState({ snackbar: true, key: Date.now(), message: `Fehler beim Löschen des Projektes. Versuche es noch einmal.`, type: 'error' });
}
+ else if(this.props.message.id === 'SHARE_SUCCESS' && (!this.props.multiple ||
+ (this.props.message.status === this.props.project._id || this.props.message.status === this.props.project._id._id))){
+ this.setState({ share: true, open: true, title: 'Programm teilen', id: this.props.message.status });
+ }
+ else if(this.props.message.id === 'SHARE_FAIL' && (!this.props.multiple ||
+ (this.props.message.status === this.props.project._id || this.props.message.status === this.props.project._id._id))){
+ this.setState({ snackbar: true, key: Date.now(), message: `Fehler beim Erstellen eines Links zum Teilen deines Programmes. Versuche es noch einmal.`, type: 'error' });
+ window.scrollTo(0, 0);
+ }
}
}
@@ -155,23 +167,7 @@ class WorkspaceFunc extends Component {
this.setState({ share: true, open: true, title: 'Programm teilen', id: this.props.project._id._id });
}
else {
- var body = {
- title: this.state.name
- };
- if(this.props.projectType === 'project'){
- body.projectId = this.props.project._id._id ? this.props.project._id._id : this.props.project._id
- } else {
- body.xml = this.props.xml;
- }
- axios.post(`${process.env.REACT_APP_BLOCKLY_API}/share`, body)
- .then(res => {
- var shareContent = res.data.content;
- this.setState({ share: true, open: true, title: 'Programm teilen', id: shareContent._id });
- })
- .catch(err => {
- this.setState({ snackbar: true, key: Date.now(), message: `Fehler beim Erstellen eines Links zum Teilen deines Programmes. Versuche es noch einmal.`, type: 'error' });
- window.scrollTo(0, 0);
- });
+ this.props.shareProject(this.state.name || this.props.project.title, this.props.projectType, this.props.project ? this.props.project._id._id ? this.props.project._id._id : this.props.project._id : undefined);
}
}
@@ -274,11 +270,12 @@ class WorkspaceFunc extends Component {
renameWorkspace = () => {
this.props.workspaceName(this.state.name);
this.toggleDialog();
+ console.log(this.props.projectType);
if(this.props.projectType === 'project' || this.props.projectType === 'gallery'){
if(this.props.projectType === 'gallery'){
this.props.setDescription(this.state.description);
}
- this.props.updateProject();
+ this.props.updateProject(this.props.projectType, this.props.project._id._id ? this.props.project._id._id : this.props.project._id);
} else {
this.setState({ snackbar: true, type: 'success', key: Date.now(), message: `Das Projekt wurde erfolgreich in '${this.state.name}' umbenannt.` });
}
@@ -307,7 +304,7 @@ class WorkspaceFunc extends Component {
{!this.props.assessment ?
- { this.setState({ file: true, open: true, saveFile: false, title: this.props.projectType === 'gallery' ? 'Projektdaten eintragen':'Projekt benennen', content: this.props.projectType === 'gallery' ? 'Bitte gib einen Titel und eine Beschreibung für das Galerie-Projekt ein und bestätige die Angaben mit einem Klick auf \'Eingabe\'.':'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}>
+
{if(this.props.multiple){this.props.workspaceName(this.props.project.title);if(this.props.projectType === 'gallery'){this.props.setDescription(this.props.project.description);}} this.setState({ file: true, open: true, saveFile: false, title: this.props.projectType === 'gallery' ? 'Projektdaten eintragen':'Projekt benennen', content: this.props.projectType === 'gallery' ? 'Bitte gib einen Titel und eine Beschreibung für das Galerie-Projekt ein und bestätige die Angaben mit einem Klick auf \'Eingabe\'.':'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}>
{this.props.name && !isWidthDown(this.props.projectType === 'project' || this.props.projectType === 'gallery' ? 'xl':'xs', this.props.width) ?
{this.props.name} : null}
@@ -315,24 +312,28 @@ class WorkspaceFunc extends Component {
: null}
- {this.props.assessment ?
:
}
-
- this.props.updateProject() : () => this.saveProject()}
- >
-
-
-
-
- { this.createFileName('xml'); }}
- >
-
-
-
- {!this.props.assessment?
+ {this.props.assessment ?
: !this.props.multiple ?
: null}
+ {this.props.user && !this.props.multiple?
+
+ this.props.updateProject(this.props.projectType, this.props.project._id._id ? this.props.project._id._id : this.props.project._id) : () => this.saveProject()}
+ >
+
+
+
+ : null}
+ {!this.props.multiple ?
+
+ { this.createFileName('xml'); }}
+ >
+
+
+
+ : null}
+ {!this.props.assessment && !this.props.multiple?
: null}
- {!this.props.assessment?
+ {!this.props.assessment && !this.props.multiple?
: null}
- {!this.props.assessment?
+ {this.props.projectType !== 'gallery' && !this.props.assessment ?
:null}
-
- this.resetWorkspace()}
- >
-
-
-
+ {!this.props.multiple ?
+
+ this.resetWorkspace()}
+ >
+
+
+
+ : null}
{!this.props.assessment && (this.props.projectType === 'project' || this.props.projectType === 'gallery') ?
this.props.deleteProject()}
+ onClick={() => this.props.deleteProject(this.props.projectType, this.props.project._id._id ? this.props.project._id._id : this.props.project._id)}
>
@@ -406,7 +409,7 @@ class WorkspaceFunc extends Component {
{this.props.projectType === 'gallery' ?
-
+
: }
{ this.state.saveFile ? this.state.file === 'xml' ? this.downloadXmlFile() : this.getSvg() : this.renameWorkspace(); this.toggleDialog(); }}>Eingabe
@@ -426,7 +429,7 @@ class WorkspaceFunc extends Component {
{this.props.project && this.props.project._id._id ?
-
{`Das Projekt wurde bereits geteilt. Der Link ist noch ${
+ {`Das Projekt wurde bereits geteilt. Der Link ist noch mindestens ${
moment(this.props.project._id.expiresAt).diff(moment().utc(), 'days') === 0 ?
moment(this.props.project._id.expiresAt).diff(moment().utc(), 'hours') === 0 ?
`${moment(this.props.project._id.expiresAt).diff(moment().utc(), 'minutes')} Minuten`
@@ -454,15 +457,15 @@ WorkspaceFunc.propTypes = {
onChangeCode: PropTypes.func.isRequired,
workspaceName: PropTypes.func.isRequired,
updateProject: PropTypes.func.isRequired,
+ shareProject: PropTypes.func.isRequired,
deleteProject: PropTypes.func.isRequired,
setDescription: PropTypes.func.isRequired,
arduino: PropTypes.string.isRequired,
xml: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
- projectType: PropTypes.string.isRequired,
- project: PropTypes.object.isRequired,
- message: PropTypes.object.isRequired
+ message: PropTypes.object.isRequired,
+ user: PropTypes.object
};
const mapStateToProps = state => ({
@@ -470,9 +473,8 @@ const mapStateToProps = state => ({
xml: state.workspace.code.xml,
name: state.workspace.name,
description: state.project.description,
- projectType: state.project.type,
- project: state.project.projects[0],
- message: state.message
+ message: state.message,
+ user: state.auth.user
});
-export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName, updateProject, deleteProject, setDescription })(withStyles(styles, { withTheme: true })(withWidth()(withRouter(WorkspaceFunc))));
+export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName, updateProject, shareProject, deleteProject, setDescription })(withStyles(styles, { withTheme: true })(withWidth()(withRouter(WorkspaceFunc))));