delete (gallery-)project
This commit is contained in:
		
							parent
							
								
									c5fd5c6239
								
							
						
					
					
						commit
						155675821a
					
				| @ -83,6 +83,27 @@ export const updateProject = () => (dispatch, getState) => { | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export const deleteProject = () => (dispatch, getState) => { | ||||
|   var project = getState().project; | ||||
|   var 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: []}); | ||||
|       if(type === 'project'){ | ||||
|         dispatch(returnSuccess(res.data.message, res.status, 'PROJECT_DELETE_SUCCESS')); | ||||
|       } else { | ||||
|         dispatch(returnSuccess(res.data.message, res.status, 'GALLERY_DELETE_SUCCESS')); | ||||
|       } | ||||
|     }) | ||||
|     .catch(err => { | ||||
|       if(err.response){ | ||||
|         dispatch(returnErrors(err.response.data.message, err.response.status, 'PROJECT_DELETE_FAIL')); | ||||
|       } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export const resetProject = () => (dispatch) => { | ||||
|   dispatch({ | ||||
|     type: GET_PROJECTS, | ||||
|  | ||||
| @ -12,6 +12,7 @@ import BlocklyWindow from './Blockly/BlocklyWindow'; | ||||
| import CodeViewer from './CodeViewer'; | ||||
| import TrashcanButtons from './TrashcanButtons'; | ||||
| import HintTutorialExists from './Tutorial/HintTutorialExists'; | ||||
| import Snackbar from './Snackbar'; | ||||
| 
 | ||||
| import Grid from '@material-ui/core/Grid'; | ||||
| import IconButton from '@material-ui/core/IconButton'; | ||||
| @ -47,7 +48,11 @@ class Home extends Component { | ||||
| 
 | ||||
|   state = { | ||||
|     codeOn: false, | ||||
|     stats: window.localStorage.getItem('stats') | ||||
|     stats: window.localStorage.getItem('stats'), | ||||
|     snackbar: false, | ||||
|     type: '', | ||||
|     key: '', | ||||
|     message: '' | ||||
|   } | ||||
| 
 | ||||
|   componentDidMount() { | ||||
| @ -55,6 +60,9 @@ class Home extends Component { | ||||
|     if(!this.props.project){ | ||||
|       this.props.workspaceName(createNameId()); | ||||
|     } | ||||
|     if(this.props.message && this.props.message.id === 'GET_SHARE_FAIL'){ | ||||
|       this.setState({ snackbar: true, key: Date.now(), message: `Das angefragte geteilte Projekt konnte nicht gefunden werden.`, type: 'error' }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentDidUpdate(props) { | ||||
| @ -112,6 +120,12 @@ class Home extends Component { | ||||
|           : null} | ||||
|         </Grid> | ||||
|         <HintTutorialExists /> | ||||
|         <Snackbar | ||||
|           open={this.state.snackbar} | ||||
|           message={this.state.message} | ||||
|           type={this.state.type} | ||||
|           key={this.state.key} | ||||
|         /> | ||||
|       </div> | ||||
|     ); | ||||
|   }; | ||||
| @ -119,8 +133,13 @@ class Home extends Component { | ||||
| 
 | ||||
| Home.propTypes = { | ||||
|   clearStats: PropTypes.func.isRequired, | ||||
|   workspaceName: PropTypes.func.isRequired | ||||
|   workspaceName: PropTypes.func.isRequired, | ||||
|   message: PropTypes.object.isRequired | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps = state => ({ | ||||
|   message: state.message | ||||
| }); | ||||
| 
 | ||||
| export default connect(null, { clearStats, workspaceName })(withStyles(styles, { withTheme: true })(Home)); | ||||
| 
 | ||||
| export default connect(mapStateToProps, { clearStats, workspaceName })(withStyles(styles, { withTheme: true })(Home)); | ||||
|  | ||||
| @ -3,7 +3,7 @@ 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 { clearMessages, returnErrors } from '../../actions/messageActions'; | ||||
| 
 | ||||
| import axios from 'axios'; | ||||
| import { createNameId } from 'mnemonic-id'; | ||||
| @ -18,6 +18,7 @@ import CircularProgress from '@material-ui/core/CircularProgress'; | ||||
| class Project extends Component { | ||||
| 
 | ||||
|   componentDidMount() { | ||||
|     this.props.resetProject(); | ||||
|     this.getProject(); | ||||
|   } | ||||
| 
 | ||||
| @ -31,8 +32,13 @@ class Project extends Component { | ||||
|     } | ||||
|     if(this.props.message !== props.message){ | ||||
|       if(this.props.message.id === 'PROJECT_EMPTY' || this.props.message.id === 'GET_PROJECT_FAIL'){ | ||||
|         this.props.workspaceName(createNameId()); | ||||
|         if(this.props.type!=='share'){ | ||||
|           this.props.returnErrors('', 404, 'GET_PROJECT_FAIL'); | ||||
|           this.props.history.push(`/${this.props.type}`); | ||||
|         } else { | ||||
|           this.props.history.push('/'); | ||||
|           this.props.returnErrors('', 404, 'GET_SHARE_FAIL'); | ||||
|         } | ||||
|       } | ||||
|       if(this.props.message.id === 'GET_PROJECT_SUCCESS'){ | ||||
|         this.props.workspaceName(this.props.project.title); | ||||
| @ -43,9 +49,6 @@ class Project extends Component { | ||||
|   componentWillUnmount() { | ||||
|     this.props.resetProject(); | ||||
|     this.props.workspaceName(null); | ||||
|     if(this.props.message.msg){ | ||||
|       this.props.clearMessages(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   getProject = () => { | ||||
| @ -77,6 +80,7 @@ Project.propTypes = { | ||||
|   getProject: PropTypes.func.isRequired, | ||||
|   resetProject: PropTypes.func.isRequired, | ||||
|   clearMessages: PropTypes.func.isRequired, | ||||
|   returnErrors: PropTypes.func.isRequired, | ||||
|   project: PropTypes.object.isRequired, | ||||
|   type: PropTypes.string.isRequired, | ||||
|   message: PropTypes.object.isRequired, | ||||
| @ -90,4 +94,4 @@ const mapStateToProps = state => ({ | ||||
|   message: state.message | ||||
| }); | ||||
| 
 | ||||
| export default connect(mapStateToProps, { workspaceName, getProject, resetProject, clearMessages })(Project); | ||||
| export default connect(mapStateToProps, { workspaceName, getProject, resetProject, clearMessages, returnErrors })(Project); | ||||
|  | ||||
| @ -2,36 +2,60 @@ import React, { Component } from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { getProjects, resetProject } from '../../actions/projectActions'; | ||||
| import { clearMessages } from '../../actions/messageActions'; | ||||
| 
 | ||||
| import axios from 'axios'; | ||||
| import { Link } from 'react-router-dom'; | ||||
| 
 | ||||
| import Breadcrumbs from '../Breadcrumbs'; | ||||
| import BlocklyWindow from '../Blockly/BlocklyWindow'; | ||||
| import Snackbar from '../Snackbar'; | ||||
| 
 | ||||
| import Grid from '@material-ui/core/Grid'; | ||||
| import Paper from '@material-ui/core/Paper'; | ||||
| import Divider from '@material-ui/core/Divider'; | ||||
| import Typography from '@material-ui/core/Typography'; | ||||
| import Backdrop from '@material-ui/core/Backdrop'; | ||||
| import CircularProgress from '@material-ui/core/CircularProgress'; | ||||
| 
 | ||||
| 
 | ||||
| class ProjectHome extends Component { | ||||
| 
 | ||||
|   state = { | ||||
|     snackbar: false, | ||||
|     type: '', | ||||
|     key: '', | ||||
|     message: '' | ||||
|   } | ||||
| 
 | ||||
|   componentDidMount() { | ||||
|     this.props.getProjects(this.props.match.path.replace('/','')); | ||||
|     var type = this.props.match.path.replace('/',''); | ||||
|     this.props.getProjects(type); | ||||
|     if(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' }); | ||||
|       } | ||||
|       else if(this.props.message.id === 'GET_PROJECT_FAIL'){ | ||||
|         this.setState({ snackbar: true, key: Date.now(), message: `Dein angefragtes ${type === 'gallery' ? 'Galerie-':''}Projekt konnte nicht gefunden werden.`, type: 'error' }); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentDidUpdate(props) { | ||||
|     if(props.match.path !== this.props.match.path){ | ||||
|       this.setState({snackbar: false}); | ||||
|       this.props.getProjects(this.props.match.path.replace('/','')); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentWillUnmount() { | ||||
|     this.props.resetProject(); | ||||
|     this.props.clearMessages(); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   render() { | ||||
|     var data = this.props.match.path === '/project' ? 'Projekte' : 'Galerie'; | ||||
|     return ( | ||||
| @ -39,7 +63,11 @@ class ProjectHome extends Component { | ||||
|         <Breadcrumbs content={[{ link: this.props.match.path, title: data }]} /> | ||||
| 
 | ||||
|         <h1>{data}</h1> | ||||
|         {this.props.progress ? null : | ||||
|         {this.props.progress ? | ||||
|           <Backdrop open invisible> | ||||
|             <CircularProgress color="primary" /> | ||||
|           </Backdrop> | ||||
|         : | ||||
|         <Grid container spacing={2}> | ||||
|           {this.props.projects.map((project, i) => { | ||||
|             return ( | ||||
| @ -60,6 +88,12 @@ class ProjectHome extends Component { | ||||
|             ) | ||||
|           })} | ||||
|         </Grid>} | ||||
|         <Snackbar | ||||
|           open={this.state.snackbar} | ||||
|           message={this.state.message} | ||||
|           type={this.state.type} | ||||
|           key={this.state.key} | ||||
|         /> | ||||
|       </div> | ||||
|     ); | ||||
|   }; | ||||
| @ -68,14 +102,17 @@ class ProjectHome extends Component { | ||||
| ProjectHome.propTypes = { | ||||
|   getProjects: PropTypes.func.isRequired, | ||||
|   resetProject: PropTypes.func.isRequired, | ||||
|   clearMessages: PropTypes.func.isRequired, | ||||
|   projects: PropTypes.array.isRequired, | ||||
|   progress: PropTypes.bool.isRequired | ||||
|   progress: PropTypes.bool.isRequired, | ||||
|   message: PropTypes.object.isRequired | ||||
| }; | ||||
| 
 | ||||
| const mapStateToProps = state => ({ | ||||
|   projects: state.project.projects, | ||||
|   progress: state.project.progress | ||||
|   progress: state.project.progress, | ||||
|   message: state.message | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| export default connect(mapStateToProps, { getProjects, resetProject })(ProjectHome); | ||||
| export default connect(mapStateToProps, { getProjects, resetProject, clearMessages })(ProjectHome); | ||||
|  | ||||
| @ -30,8 +30,8 @@ class Routes extends Component { | ||||
|           <Route path="/" exact component={Home} /> | ||||
|           // Tutorials
 | ||||
|           <Route path="/tutorial" exact component={TutorialHome} /> | ||||
|           <Route path="/tutorial/:tutorialId" exact component={Tutorial} /> | ||||
|           <Route path="/tutorial/builder" exact component={Builder} /> | ||||
|           <Route path="/tutorial/:tutorialId" exact component={Tutorial} /> | ||||
|           // Sharing
 | ||||
|           <Route path="/share/:shareId" exact component={Project} /> | ||||
|           // Gallery-Projects
 | ||||
|  | ||||
| @ -35,6 +35,12 @@ class Snackbar extends Component { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentDidUpdate(){ | ||||
|     if(!this.state.open){ | ||||
|       clearTimeout(this.timeout); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentWillUnmount(){ | ||||
|     if(this.state.open){ | ||||
|       clearTimeout(this.timeout); | ||||
|  | ||||
| @ -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 } from '../actions/projectActions'; | ||||
| import { updateProject, deleteProject } from '../actions/projectActions'; | ||||
| 
 | ||||
| import * as Blockly from 'blockly/core'; | ||||
| 
 | ||||
| @ -28,7 +28,7 @@ import Tooltip from '@material-ui/core/Tooltip'; | ||||
| import TextField from '@material-ui/core/TextField'; | ||||
| import Typography from '@material-ui/core/Typography'; | ||||
| 
 | ||||
| import { faPen, faSave, faUpload, faFileDownload, faCamera, faShare, faShareAlt, faCopy } from "@fortawesome/free-solid-svg-icons"; | ||||
| import { faPen, faSave, faUpload, faFileDownload, faTrashAlt, faCamera, faShare, faShareAlt, faCopy } from "@fortawesome/free-solid-svg-icons"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| 
 | ||||
| const styles = (theme) => ({ | ||||
| @ -51,6 +51,16 @@ const styles = (theme) => ({ | ||||
|       color: theme.palette.primary.main, | ||||
|     } | ||||
|   }, | ||||
|   buttonTrash: { | ||||
|     backgroundColor: theme.palette.error.dark, | ||||
|     color: theme.palette.primary.contrastText, | ||||
|     width: '40px', | ||||
|     height: '40px', | ||||
|     '&:hover': { | ||||
|       backgroundColor: theme.palette.error.dark, | ||||
|       color: theme.palette.primary.contrastText, | ||||
|     } | ||||
|   }, | ||||
|   link: { | ||||
|     color: theme.palette.primary.main, | ||||
|     textDecoration: 'none', | ||||
| @ -92,9 +102,15 @@ class WorkspaceFunc extends Component { | ||||
|       if(this.props.message.id === 'PROJECT_UPDATE_SUCCESS'){ | ||||
|         this.setState({ snackbar: true, key: Date.now(), message: `Das Projekt wurde erfolgreich aktualisiert.`, type: 'success' }); | ||||
|       } | ||||
|       else if(this.props.message.id === 'PROJECT_DELETE_SUCCESS'){ | ||||
|         this.props.history.push(`/${this.props.projectType}`); | ||||
|       } | ||||
|       else if(this.props.message.id === 'PROJECT_UPDATE_FAIL'){ | ||||
|         this.setState({ snackbar: true, key: Date.now(), message: `Fehler beim Aktualisieren des Projektes. Versuche es noch einmal.`, type: 'error' }); | ||||
|       } | ||||
|       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' }); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -239,8 +255,12 @@ class WorkspaceFunc extends Component { | ||||
|   renameWorkspace = () => { | ||||
|     this.props.workspaceName(this.state.name); | ||||
|     this.toggleDialog(); | ||||
|     if(this.props.projectType === 'project'){ | ||||
|       this.props.updateProject(); | ||||
|     } else { | ||||
|       this.setState({ snackbar: true, type: 'success', key: Date.now(), message: `Das Projekt wurde erfolgreich in '${this.state.name}' umbenannt.` }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   resetWorkspace = () => { | ||||
|     const workspace = Blockly.getMainWorkspace(); | ||||
| @ -264,9 +284,9 @@ class WorkspaceFunc extends Component { | ||||
|     return ( | ||||
|       <div style={{ width: 'max-content', display: 'flex' }}> | ||||
|         {!this.props.assessment ? | ||||
|           <Tooltip title={`Name des Projektes${this.props.name ? `: ${this.props.name}` : ''}`} arrow style={{ marginRight: '5px' }}> | ||||
|           <Tooltip title={`Titel des Projektes${this.props.name ? `: ${this.props.name}` : ''}`} arrow style={{ marginRight: '5px' }}> | ||||
|             <div className={this.props.classes.workspaceName} onClick={() => { this.setState({ file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}> | ||||
|               {this.props.name && !isWidthDown('xs', this.props.width) ? <Typography style={{ margin: 'auto -3px auto 12px' }}>{this.props.name}</Typography> : null} | ||||
|               {this.props.name && !isWidthDown(this.props.projectType === 'project' || this.props.projectType === 'gallery' ? 'xl':'xs', this.props.width) ? <Typography style={{ margin: 'auto -3px auto 12px' }}>{this.props.name}</Typography> : null} | ||||
|               <div style={{ width: '40px', display: 'flex' }}> | ||||
|                 <FontAwesomeIcon icon={faPen} style={{ height: '18px', width: '18px', margin: 'auto' }} /> | ||||
|               </div> | ||||
| @ -322,7 +342,17 @@ class WorkspaceFunc extends Component { | ||||
|             </IconButton> | ||||
|           </Tooltip> | ||||
|         : null} | ||||
|         <Tooltip title='Workspace zurücksetzen' arrow style={this.props.assessment ? null : { marginRight: '5px' }}> | ||||
|         {!this.props.assessment? | ||||
|           <Tooltip title='Projekt teilen' arrow style={{marginRight: '5px'}}> | ||||
|             <IconButton | ||||
|               className={this.props.classes.button} | ||||
|               onClick={() => this.shareBlocks()} | ||||
|             > | ||||
|               <FontAwesomeIcon icon={faShareAlt} size="xs" /> | ||||
|             </IconButton> | ||||
|           </Tooltip> | ||||
|         :null} | ||||
|         <Tooltip title='Workspace zurücksetzen' arrow style={this.props.projectType === 'project' || this.props.projectType === 'gallery' ? { marginRight: '5px' }:null}> | ||||
|           <IconButton | ||||
|             className={this.props.classes.button} | ||||
|             onClick={() => this.resetWorkspace()} | ||||
| @ -330,13 +360,13 @@ class WorkspaceFunc extends Component { | ||||
|             <FontAwesomeIcon icon={faShare} size="xs" flip='horizontal' /> | ||||
|           </IconButton> | ||||
|         </Tooltip> | ||||
|         {!this.props.assessment? | ||||
|           <Tooltip title='Projekt teilen' arrow> | ||||
|         {!this.props.assessment && (this.props.projectType === 'project' || this.props.projectType === 'gallery') ? | ||||
|           <Tooltip title='Projekt löschen' arrow> | ||||
|             <IconButton | ||||
|               className={this.props.classes.button} | ||||
|               onClick={() => this.shareBlocks()} | ||||
|               className={this.props.classes.buttonTrash} | ||||
|               onClick={() => this.props.deleteProject()} | ||||
|             > | ||||
|               <FontAwesomeIcon icon={faShareAlt} size="xs" flip='horizontal' /> | ||||
|               <FontAwesomeIcon icon={faTrashAlt} size="xs" /> | ||||
|             </IconButton> | ||||
|           </Tooltip> | ||||
|         :null} | ||||
| @ -351,7 +381,7 @@ class WorkspaceFunc extends Component { | ||||
|         > | ||||
|           {this.state.file ? | ||||
|             <div style={{ marginTop: '10px' }}> | ||||
|               <TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projektname'} value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} /> | ||||
|               <TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projekttitel'} value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} /> | ||||
|               <Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => { this.state.saveFile ? this.state.file === 'xml' ? this.downloadXmlFile() : this.getSvg() : this.renameWorkspace(); this.toggleDialog(); }}>Eingabe</Button> | ||||
|             </div> | ||||
|           : this.state.share ? | ||||
| @ -389,6 +419,7 @@ WorkspaceFunc.propTypes = { | ||||
|   onChangeCode: PropTypes.func.isRequired, | ||||
|   workspaceName: PropTypes.func.isRequired, | ||||
|   updateProject: PropTypes.func.isRequired, | ||||
|   deleteProject: PropTypes.func.isRequired, | ||||
|   arduino: PropTypes.string.isRequired, | ||||
|   xml: PropTypes.string.isRequired, | ||||
|   name: PropTypes.string, | ||||
| @ -404,4 +435,4 @@ const mapStateToProps = state => ({ | ||||
|   message: state.message | ||||
| }); | ||||
| 
 | ||||
| export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName, updateProject })(withStyles(styles, { withTheme: true })(withWidth()(withRouter(WorkspaceFunc)))); | ||||
| export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName, updateProject, deleteProject })(withStyles(styles, { withTheme: true })(withWidth()(withRouter(WorkspaceFunc)))); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user