create and display content to share

This commit is contained in:
Delucse 2020-12-01 13:29:52 +01:00
parent d0dda4038e
commit 6db8c094ea
2 changed files with 106 additions and 98 deletions

View File

@ -5,6 +5,8 @@ import { clearStats, workspaceName } from '../actions/workspaceActions';
import * as Blockly from 'blockly/core';
import axios from 'axios';
import WorkspaceStats from './WorkspaceStats';
import WorkspaceFunc from './WorkspaceFunc';
import BlocklyWindow from './Blockly/BlocklyWindow';
@ -17,6 +19,8 @@ import Grid from '@material-ui/core/Grid';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import { withStyles } from '@material-ui/core/styles';
import Backdrop from '@material-ui/core/Backdrop';
import CircularProgress from '@material-ui/core/CircularProgress';
import { faCode } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -50,17 +54,28 @@ class Home extends Component {
gallery: [],
share: [],
projectToLoad: undefined,
progress: false,
stats: window.localStorage.getItem('stats'),
}
componentDidMount() {
this.setState({ stats: window.localStorage.getItem('stats') })
this.props.workspaceName(createNameId());
fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname)
.then(res => res.json())
.then((data) => {
this.setState({ projectToLoad: data })
})
if(this.props.match.params.shareId || this.props.match.params.galleryId){
this.setState({progress: true});
axios.get(`${process.env.REACT_APP_BLOCKLY_API}${this.props.location.pathname}`)
.then(res => {
var shareContent = res.data.content;
this.props.workspaceName(res.data.content.name);
this.setState({ projectToLoad: res.data.content, progress: false });
})
.catch(err => {
this.setState({ progress: false, 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);
});
}
else {
this.props.workspaceName(createNameId());
}
}
@ -91,35 +106,44 @@ class Home extends Component {
render() {
return (
<div>
{this.state.stats ?
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div>
: null
}
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
<Grid container spacing={2}>
<Grid item xs={12} md={this.state.codeOn ? 8 : 12} style={{ position: 'relative' }}>
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} >
<IconButton
className={this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}
style={{ width: '40px', height: '40px', position: 'absolute', top: -12, right: 8, zIndex: 21 }}
onClick={() => this.onChange()}
>
<FontAwesomeIcon icon={faCode} size="xs" />
</IconButton>
</Tooltip>
<TrashcanButtons />
{this.state.projectToLoad ?
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.state.projectToLoad.xml} /> : < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
}
{this.state.progress ?
<Backdrop open invisible>
<CircularProgress color="primary" />
</Backdrop>
:
<div>
{this.state.stats ?
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div>
: null
}
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
<Grid container spacing={2}>
<Grid item xs={12} md={this.state.codeOn ? 8 : 12} style={{ position: 'relative' }}>
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} >
<IconButton
className={this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}
style={{ width: '40px', height: '40px', position: 'absolute', top: -12, right: 8, zIndex: 21 }}
onClick={() => this.onChange()}
>
<FontAwesomeIcon icon={faCode} size="xs" />
</IconButton>
</Tooltip>
<TrashcanButtons />
{this.state.projectToLoad ?
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.state.projectToLoad.xml} />
: < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
}
</Grid>
{this.state.codeOn ?
<Grid item xs={12} md={4}>
<CodeViewer />
</Grid>
: null}
</Grid>
<HintTutorialExists />
{this.state.codeOn ?
<Grid item xs={12} md={4}>
<CodeViewer />
</Grid>
: null}
</Grid>
<HintTutorialExists />
</div>
}
</div>
);
};

View File

@ -5,7 +5,9 @@ import { clearStats, onChangeCode, workspaceName } from '../actions/workspaceAct
import * as Blockly from 'blockly/core';
import axios from 'axios';
import { saveAs } from 'file-saver';
import { createId } from 'mnemonic-id';
import { detectWhitespacesAndReturnReadableResult } from '../helpers/whitespace';
import { initialXml } from './Blockly/initialXml.js';
@ -14,6 +16,8 @@ import Compile from './Compile';
import SolutionCheck from './Tutorial/SolutionCheck';
import Snackbar from './Snackbar';
import { Link } from 'react-router-dom';
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
@ -21,7 +25,6 @@ import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import { createId } from 'mnemonic-id';
import Dialog from './Dialog';
@ -33,7 +36,7 @@ import DialogTitle from '@material-ui/core/DialogTitle';
import { faPen, faSave, faUpload, faCamera, faShare, faShareAlt } from "@fortawesome/free-solid-svg-icons";
import { faPen, faSave, faUpload, faCamera, faShare, faShareAlt, faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const styles = (theme) => ({
@ -55,6 +58,14 @@ const styles = (theme) => ({
'&:hover': {
color: theme.palette.primary.main,
}
},
link: {
color: theme.palette.primary.main,
textDecoration: 'none',
'&:hover': {
color: theme.palette.primary.main,
textDecoration: 'underline'
}
}
});
@ -74,14 +85,13 @@ class WorkspaceFunc extends Component {
share: false,
name: props.name,
snackbar: false,
type: '',
key: '',
message: '',
id: ''
};
}
componentDidUpdate(props) {
if (props.name !== this.props.name) {
this.setState({ name: this.props.name });
@ -89,7 +99,7 @@ class WorkspaceFunc extends Component {
}
toggleDialog = () => {
this.setState({ open: !this.state, share: false });
this.setState({ open: !this.state, share: false, file: false, saveFile: false, title: '', content: '' });
}
saveXmlFile = () => {
@ -103,38 +113,20 @@ class WorkspaceFunc extends Component {
}
shareBlocks = () => {
let code = this.props.xml;
let requestOptions = '';
let id = '';
if (this.state.id !== '') {
requestOptions = {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: this.state.id,
name: this.state.name,
xml: code
})
};
fetch(process.env.REACT_APP_BLOCKLY_API + '/share' + this.state.id, requestOptions)
.then(response => response.json())
.then(data => this.setState({ share: true }));
}
else {
id = createId(10);
requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: id,
name: this.state.name,
xml: code
})
};
fetch(process.env.REACT_APP_BLOCKLY_API + '/share', requestOptions)
.then(response => response.json())
.then(data => this.setState({ id: data.id, share: true }));
}
var body = {
_id: createId(10),
name: this.state.name,
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);
});
}
getSvg = () => {
@ -220,7 +212,7 @@ class WorkspaceFunc extends Component {
var extensionPosition = xmlFile.name.lastIndexOf('.');
this.props.workspaceName(xmlFile.name.substr(0, extensionPosition));
}
this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt aus gegebener XML-Datei wurde erfolgreich eingefügt.' });
this.setState({ snackbar: true, type: 'success', key: Date.now(), message: 'Das Projekt aus gegebener XML-Datei wurde erfolgreich eingefügt.' });
}
} catch (err) {
this.setState({ open: true, file: false, title: 'Ungültige XML', content: 'Die XML-Datei konnte nicht in Blöcke zerlegt werden. Bitte überprüfe den XML-Code und versuche es erneut.' });
@ -232,7 +224,7 @@ class WorkspaceFunc extends Component {
renameWorkspace = () => {
this.props.workspaceName(this.state.name);
this.toggleDialog();
this.setState({ snackbar: true, key: Date.now(), message: `Das Projekt wurde erfolgreich in '${this.state.name}' umbenannt.` });
this.setState({ snackbar: true, type: 'success', key: Date.now(), message: `Das Projekt wurde erfolgreich in '${this.state.name}' umbenannt.` });
}
resetWorkspace = () => {
@ -248,7 +240,7 @@ class WorkspaceFunc extends Component {
if (!this.props.solutionCheck) {
this.props.workspaceName(null);
}
this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt wurde erfolgreich zurückgesetzt.' });
this.setState({ snackbar: true, type: 'success', key: Date.now(), message: 'Das Projekt wurde erfolgreich zurückgesetzt.' });
}
@ -320,29 +312,6 @@ class WorkspaceFunc extends Component {
</IconButton>
</Tooltip>
<Dialog open={this.state.share} onClose={this.toggleDialog} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Dein Link wurde erstellt.</DialogTitle>
<DialogContent>
<DialogContentText>
Über den folgenden Link kannst du dein Programm teilen.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
defaultValue={window.location.origin + "/share/" + this.state.id}
label="url"
type="email"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={this.toggleDialog} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
<Dialog
open={this.state.open}
title={this.state.title}
@ -356,13 +325,28 @@ class WorkspaceFunc extends Component {
<TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projektname'} 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.saveXmlFile() : this.getSvg() : this.renameWorkspace(); this.toggleDialog(); }}>Eingabe</Button>
</div>
: null}
: this.state.share ?
<div style={{ marginTop: '10px' }}>
<Typography>Über den folgenden Link kannst du dein Programm teilen:</Typography>
<Link to={`/share/${this.state.id}`} className={this.props.classes.link}>{`${window.location.origin}/share/${this.state.id}`}</Link>
<Tooltip title='Link kopieren' arrow style={{ marginRight: '5px' }}>
<IconButton
onClick={() => {
navigator.clipboard.writeText(`${window.location.origin}/share/${this.state.id}`);
this.setState({ snackbar: true, key: Date.now(), message: 'Link erfolgreich in Zwischenablage gespeichert.', type: 'success' });
}}
>
<FontAwesomeIcon icon={faCopy} size="xs" />
</IconButton>
</Tooltip>
</div>
: null}
</Dialog>
<Snackbar
open={this.state.snackbar}
message={this.state.message}
type='success'
type={this.state.type}
key={this.state.key}
/>