Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd6358ea2b | ||
|
|
912440f64c |
@@ -29,7 +29,6 @@
|
|||||||
"qrcode.react": "^3.1.0",
|
"qrcode.react": "^3.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-cookie-consent": "^7.2.1",
|
"react-cookie-consent": "^7.2.1",
|
||||||
"react-country-flag": "^3.0.2",
|
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-markdown": "^8.0.0",
|
"react-markdown": "^8.0.0",
|
||||||
"react-markdown-editor-lite": "^1.3.3",
|
"react-markdown-editor-lite": "^1.3.3",
|
||||||
|
|||||||
@@ -301,12 +301,21 @@ export const resetTutorial = () => (dispatch, getState) => {
|
|||||||
hardware: [],
|
hardware: [],
|
||||||
requirements: [],
|
requirements: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
type: "finalpage",
|
||||||
|
headline: "",
|
||||||
|
text: "",
|
||||||
|
samplesolutions: false,
|
||||||
|
solutions: [],
|
||||||
|
furthertutorials: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
dispatch(tutorialSteps(steps));
|
dispatch(tutorialSteps(steps));
|
||||||
dispatch({
|
dispatch({
|
||||||
type: BUILDER_ERROR,
|
type: BUILDER_ERROR,
|
||||||
payload: {
|
payload: {
|
||||||
steps: [{}],
|
steps: [{}, {}],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -99,14 +99,11 @@ export const UI = {
|
|||||||
* Tablet Dialog
|
* Tablet Dialog
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tabletDialog_connect: "senseBox Connect App öffnen",
|
|
||||||
tabletDialog_headline: "Tablet Modus ist aktiviert!",
|
tabletDialog_headline: "Tablet Modus ist aktiviert!",
|
||||||
tabletDialog_text:
|
tabletDialog_text:
|
||||||
"Der Tablet Modus wurde aktiviert. Du kannst nun Programmcodes über die senseBox Connect App auf deine senseBox kopieren. Der Tablet Modus kann in den Einstellungen deaktiviert werden",
|
"Der Tablet Modus wurde aktiviert. Du kannst nun Programmcodes über die senseBox Connect App auf deine senseBox kopieren. Der Tablet Modus kann in den Einstellungen deaktiviert werden",
|
||||||
tabletDialog_more:
|
tabletDialog_more:
|
||||||
"Weitere Informationen und den Link zum Download der App findest du unter: ",
|
"Weitere Informationen und den Link zum Download der App findest du unter: ",
|
||||||
compiledialog_process: "Dein Code wird compiliert!",
|
|
||||||
compiledialog_instructions: "Übertrage ihn anschließend mithlfe der senseBoxConnect-App..",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset Dialog
|
* Reset Dialog
|
||||||
@@ -135,7 +132,7 @@ export const UI = {
|
|||||||
* Compile Dialog
|
* Compile Dialog
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
compiledialog_success: "Dein Programm wurde erfolgreich kompiliert.",
|
|
||||||
compiledialog_headline: "Fehler",
|
compiledialog_headline: "Fehler",
|
||||||
compiledialog_text:
|
compiledialog_text:
|
||||||
"Beim kompilieren ist ein Fehler aufgetreten. Überprüfe deine Blöcke und versuche es erneut",
|
"Beim kompilieren ist ein Fehler aufgetreten. Überprüfe deine Blöcke und versuche es erneut",
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ export const IO = {
|
|||||||
ARD_DIGITALREAD_TIP: "Read digital value on a pin: HIGH or LOW",
|
ARD_DIGITALREAD_TIP: "Read digital value on a pin: HIGH or LOW",
|
||||||
ARD_DIGITALWRITE: "set digitial pin#",
|
ARD_DIGITALWRITE: "set digitial pin#",
|
||||||
ARD_DIGITALWRITE_TIP: "Write digital value HIGH or LOW to a specific Port",
|
ARD_DIGITALWRITE_TIP: "Write digital value HIGH or LOW to a specific Port",
|
||||||
ARD_FUN_RUN_LOOP: "Loop()",
|
ARD_FUN_RUN_LOOP: "Arduino loop forever:",
|
||||||
ARD_FUN_RUN_SETUP: "Setup()",
|
ARD_FUN_RUN_SETUP: "Arduino run first:",
|
||||||
ARD_FUN_RUN_TIP: "Defines the Arduino setup() and loop() functions.",
|
ARD_FUN_RUN_TIP: "Defines the Arduino setup() and loop() functions.",
|
||||||
ARD_HIGH: "HIGH",
|
ARD_HIGH: "HIGH",
|
||||||
ARD_HIGHLOW_TIP: "Set a pin state logic High or Low.",
|
ARD_HIGHLOW_TIP: "Set a pin state logic High or Low.",
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ export const UI = {
|
|||||||
"Tablet mode has been activated. You can now copy program codes to your senseBox via the senseBox Connect app. Tablet mode can be deactivated in the settings",
|
"Tablet mode has been activated. You can now copy program codes to your senseBox via the senseBox Connect app. Tablet mode can be deactivated in the settings",
|
||||||
tabletDialog_more:
|
tabletDialog_more:
|
||||||
"For more information and the link to download the app, please visit: ",
|
"For more information and the link to download the app, please visit: ",
|
||||||
tabletDialog_connect: "Open senseBox Connect App",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset Dialog
|
* Reset Dialog
|
||||||
@@ -129,12 +128,10 @@ export const UI = {
|
|||||||
* Compile Dialog
|
* Compile Dialog
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
compiledialog_success: "Your code has been compiled successfully.",
|
|
||||||
compiledialog_headline: "Error",
|
compiledialog_headline: "Error",
|
||||||
compiledialog_text:
|
compiledialog_text:
|
||||||
"While compiling an error occured. Please check your blocks and try again",
|
"While compiling an error occured. Please check your blocks and try again",
|
||||||
compiledialog_process: "Your code is being compiled!",
|
|
||||||
compiledialog_instructions: "After that, transfer it using the senseBoxConnect app.",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buttons
|
* Buttons
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class Compile extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() { }
|
componentDidMount() {}
|
||||||
|
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props) {
|
||||||
if (props.name !== this.props.name) {
|
if (props.name !== this.props.name) {
|
||||||
@@ -232,8 +232,8 @@ class Compile extends Component {
|
|||||||
>
|
>
|
||||||
<div className="overlay">
|
<div className="overlay">
|
||||||
{/* <img src={Copy} width="400" alt="copyimage"></img> */}
|
{/* <img src={Copy} width="400" alt="copyimage"></img> */}
|
||||||
<h2>{Blockly.Msg.compiledialog_process}</h2>
|
<h2>Dein Code wird kompiliert!</h2>
|
||||||
<p>{Blockly.Msg.compiledialog_instructions}</p>
|
<p>übertrage ihn anschließend mithlfe der senseBoxConnect-App</p>
|
||||||
<p>
|
<p>
|
||||||
{Blockly.Msg.compile_overlay_help}
|
{Blockly.Msg.compile_overlay_help}
|
||||||
<a href="/faq" target="_blank">
|
<a href="/faq" target="_blank">
|
||||||
@@ -291,7 +291,7 @@ class Compile extends Component {
|
|||||||
button={Blockly.Msg.button_close}
|
button={Blockly.Msg.button_close}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p>{Blockly.Msg.compiledialog_success}</p>
|
<p>Dein Code wurde erfolgreich kompiliert</p>
|
||||||
<a href={this.state.link}>
|
<a href={this.state.link}>
|
||||||
<Button
|
<Button
|
||||||
style={{ color: "white" }}
|
style={{ color: "white" }}
|
||||||
@@ -303,7 +303,7 @@ class Compile extends Component {
|
|||||||
icon={faClipboardCheck}
|
icon={faClipboardCheck}
|
||||||
style={{ marginRight: "5px" }}
|
style={{ marginRight: "5px" }}
|
||||||
/>{" "}
|
/>{" "}
|
||||||
{Blockly.Msg.tabletDialog_connect}
|
Starte Übertragung
|
||||||
</Button>
|
</Button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+10
-12
@@ -41,7 +41,6 @@ import {
|
|||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import Tooltip from "@material-ui/core/Tooltip";
|
||||||
import NavbarSettings from "./NavbarSettings";
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
drawerWidth: {
|
drawerWidth: {
|
||||||
@@ -128,7 +127,6 @@ class Navbar extends Component {
|
|||||||
<Link to={"/"} style={{ marginLeft: "10px" }}>
|
<Link to={"/"} style={{ marginLeft: "10px" }}>
|
||||||
<img src={senseboxLogo} alt="senseBox-Logo" width="30" />
|
<img src={senseboxLogo} alt="senseBox-Logo" width="30" />
|
||||||
</Link>
|
</Link>
|
||||||
<NavbarSettings />
|
|
||||||
{isTutorial ? (
|
{isTutorial ? (
|
||||||
<Link
|
<Link
|
||||||
to={"/tutorial"}
|
to={"/tutorial"}
|
||||||
@@ -151,7 +149,7 @@ class Navbar extends Component {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.openTour();
|
this.openTour();
|
||||||
}}
|
}}
|
||||||
style={{ margin: "0 30px 0 0" }}
|
style={{ margin: "0 30px 0 auto" }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faQuestionCircle} />
|
<FontAwesomeIcon icon={faQuestionCircle} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -165,7 +163,7 @@ class Navbar extends Component {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.openTour();
|
this.openTour();
|
||||||
}}
|
}}
|
||||||
style={{ margin: "0 30px 0 0" }}
|
style={{ margin: "0 30px 0 auto" }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faQuestionCircle} />
|
<FontAwesomeIcon icon={faQuestionCircle} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -216,11 +214,11 @@ class Navbar extends Component {
|
|||||||
</div>
|
</div>
|
||||||
<List>
|
<List>
|
||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
text: Blockly.Msg.navbar_blockly,
|
text: Blockly.Msg.navbar_blockly,
|
||||||
icon: faPuzzlePiece,
|
icon: faPuzzlePiece,
|
||||||
link: "/",
|
link: "/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: Blockly.Msg.navbar_tutorials,
|
text: Blockly.Msg.navbar_tutorials,
|
||||||
icon: faChalkboardTeacher,
|
icon: faChalkboardTeacher,
|
||||||
@@ -331,9 +329,9 @@ class Navbar extends Component {
|
|||||||
onClick={
|
onClick={
|
||||||
item.function
|
item.function
|
||||||
? () => {
|
? () => {
|
||||||
item.function();
|
item.function();
|
||||||
this.toggleDrawer();
|
this.toggleDrawer();
|
||||||
}
|
}
|
||||||
: this.toggleDrawer
|
: this.toggleDrawer
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { setLanguage } from '../actions/generalActions';
|
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
|
||||||
import Select from '@material-ui/core/Select';
|
|
||||||
import { setBoard } from '../actions/boardAction';
|
|
||||||
import ReactCountryFlag from "react-country-flag";
|
|
||||||
import { MuiThemeProvider, createTheme } from '@material-ui/core/styles';
|
|
||||||
|
|
||||||
const theme = createTheme({
|
|
||||||
overrides: {
|
|
||||||
MuiSelect: {
|
|
||||||
select: {
|
|
||||||
'&:focus': {
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class NavbarSettings extends Component {
|
|
||||||
componentDidMount() {
|
|
||||||
// Ensure that Blockly.setLocale is adopted in the component.
|
|
||||||
// Otherwise, the text will not be displayed until the next update of the component.
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange = (event) => {
|
|
||||||
this.props.setLanguage(event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div style={{ margin: "0 0 0 auto", display: "flex" }}>
|
|
||||||
<div style={{ margin: "0 30px 0 auto", display: "flex" }}>
|
|
||||||
<MuiThemeProvider theme={theme}>
|
|
||||||
<Select
|
|
||||||
value={this.props.selectedBoard}
|
|
||||||
onChange={(e) => this.props.setBoard(e.target.value)}
|
|
||||||
disableUnderline={true}
|
|
||||||
style={{ backgroundColor: "transparent !important" }}
|
|
||||||
// IconComponent={() => <div />}
|
|
||||||
>
|
|
||||||
<MenuItem value="mcu">senseBox MCU</MenuItem>
|
|
||||||
<MenuItem value="mini">senseBox MCU mini</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</MuiThemeProvider>
|
|
||||||
</div>
|
|
||||||
<div style={{ margin: "0 0 0 auto", display: "flex" }}>
|
|
||||||
<MuiThemeProvider theme={theme}>
|
|
||||||
<Select
|
|
||||||
value={this.props.language}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
disableUnderline={true}
|
|
||||||
IconComponent={() => null}
|
|
||||||
>
|
|
||||||
<MenuItem value={'en_US'} >
|
|
||||||
<ReactCountryFlag
|
|
||||||
countryCode="US"
|
|
||||||
svg
|
|
||||||
cdnSuffix="svg"
|
|
||||||
title="US"
|
|
||||||
/>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={'de_DE'}>
|
|
||||||
<ReactCountryFlag
|
|
||||||
countryCode="DE"
|
|
||||||
svg
|
|
||||||
cdnSuffix="svg"
|
|
||||||
title="DE"
|
|
||||||
/>
|
|
||||||
</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</MuiThemeProvider>
|
|
||||||
</div>
|
|
||||||
</div >
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
language: state.general.language,
|
|
||||||
selectedBoard: state.board.board
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, { setLanguage, setBoard })(NavbarSettings);
|
|
||||||
@@ -259,7 +259,7 @@ class Builder extends Component {
|
|||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
submit = () => {
|
submit = () => {;
|
||||||
var isError = this.props.checkError();
|
var isError = this.props.checkError();
|
||||||
if (isError) {
|
if (isError) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -273,6 +273,8 @@ class Builder extends Component {
|
|||||||
} else {
|
} else {
|
||||||
// export steps without attribute 'url'
|
// export steps without attribute 'url'
|
||||||
var steps = this.props.steps;
|
var steps = this.props.steps;
|
||||||
|
// console.log(steps);
|
||||||
|
var length = steps.length;
|
||||||
var newTutorial = new FormData();
|
var newTutorial = new FormData();
|
||||||
newTutorial.append("title", this.props.title);
|
newTutorial.append("title", this.props.title);
|
||||||
newTutorial.append("difficulty", this.props.difficulty);
|
newTutorial.append("difficulty", this.props.difficulty);
|
||||||
@@ -299,11 +301,30 @@ class Builder extends Component {
|
|||||||
newTutorial.append(`steps[${i}][hardware][${j}]`, hardware);
|
newTutorial.append(`steps[${i}][hardware][${j}]`, hardware);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (i === length-1 && step.type === "finalpage") {
|
||||||
|
newTutorial.append(`steps[${i}][samplesolutions]`, step.samplesolutions);
|
||||||
|
newTutorial.append(`steps[${i}][furthertutorials]`, step.furthertutorials);
|
||||||
|
|
||||||
|
if (step.samplesolutions === true) {
|
||||||
|
var solutionindex = 0;
|
||||||
|
steps.forEach((solutionstep) => {
|
||||||
|
if (solutionstep.type === "task"&& solutionstep.xml) {
|
||||||
|
newTutorial.append(`steps[${i}][solutions][${solutionindex}][type]`, solutionstep.type);
|
||||||
|
newTutorial.append(`steps[${i}][solutions][${solutionindex}][headline]`, solutionstep.headline);
|
||||||
|
newTutorial.append(`steps[${i}][solutions][${solutionindex}][xml]`, solutionstep.xml);
|
||||||
|
solutionindex++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
if (step.xml) {
|
if (step.xml) {
|
||||||
// optional
|
// optional
|
||||||
newTutorial.append(`steps[${i}][xml]`, step.xml);
|
newTutorial.append(`steps[${i}][xml]`, step.xml);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
for (const pair of newTutorial.entries()) {
|
||||||
|
console.log(`${pair[0]}, ${pair[1]}`);
|
||||||
|
}
|
||||||
return newTutorial;
|
return newTutorial;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import React, { Component } from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { changeContent } from "../../../actions/tutorialBuilderActions";
|
||||||
|
|
||||||
|
import { withStyles } from "@material-ui/core/styles";
|
||||||
|
import Switch from "@material-ui/core/Switch";
|
||||||
|
import FormGroup from '@material-ui/core/FormGroup';
|
||||||
|
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
errorColor: {
|
||||||
|
color: theme.palette.error.dark,
|
||||||
|
},
|
||||||
|
errorBorder: {
|
||||||
|
border: `1px solid ${theme.palette.error.dark}`,
|
||||||
|
},
|
||||||
|
errorButton: {
|
||||||
|
marginTop: "5px",
|
||||||
|
height: "40px",
|
||||||
|
backgroundColor: theme.palette.error.dark,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.error.dark,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
class FinalPageOptions extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
checkedSampleSolutions: props.checkedSampleSolutions,
|
||||||
|
checkedFurtherTutorials: props.checkedFurtherTutorials,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeSampleSolutions = (value) => {
|
||||||
|
var oldValue = this.state.checked;
|
||||||
|
this.setState({ checked: value });
|
||||||
|
if (oldValue !== value) {
|
||||||
|
this.props.changeContent(value, this.props.index, "samplesolutions");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onChangeFurtherTutorials = (value) => {
|
||||||
|
var oldValue = this.state.checked;
|
||||||
|
this.setState({ checked: value });
|
||||||
|
if (oldValue !== value) {
|
||||||
|
this.props.changeContent(value, this.props.index, "furthertutorials");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var steps = this.props.steps;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginBottom: "10px",
|
||||||
|
padding: "18.5px 14px",
|
||||||
|
borderRadius: "25px",
|
||||||
|
border: "1px solid lightgrey",
|
||||||
|
width: "calc(100% - 28px)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormGroup>
|
||||||
|
<FormControlLabel
|
||||||
|
labelPlacement="end"
|
||||||
|
label={
|
||||||
|
"Musterlösung(en) der Aufgabe(n) auf der Abschlussseite anzeigen"
|
||||||
|
}
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={this.state.checked}
|
||||||
|
onChange={(e) => this.onChangeSampleSolutions(e.target.checked)}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<FormControlLabel
|
||||||
|
labelPlacement="end"
|
||||||
|
label={
|
||||||
|
"Vorschläge für weitere Tutorials auf der Abschlussseite anzeigen"
|
||||||
|
}
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={this.state.checked}
|
||||||
|
onChange={(e) => this.onChangeFurtherTutorials(e.target.checked)}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FinalPageOptions.propTypes = {
|
||||||
|
changeContent: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, {
|
||||||
|
changeContent,
|
||||||
|
})(withStyles(styles, { withTheme: true })(FinalPageOptions));
|
||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import MarkdownEditor from "./MarkdownEditor";
|
import MarkdownEditor from "./MarkdownEditor";
|
||||||
|
import FinalPageOptions from "./FinalPageOptions";
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
button: {
|
button: {
|
||||||
@@ -55,6 +56,8 @@ class Step extends Component {
|
|||||||
render() {
|
render() {
|
||||||
var index = this.props.index;
|
var index = this.props.index;
|
||||||
var steps = this.props.steps;
|
var steps = this.props.steps;
|
||||||
|
// console.log(this.props.steps);
|
||||||
|
// console.log(this.props.step);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -64,12 +67,21 @@ class Step extends Component {
|
|||||||
marginBottom: "20px",
|
marginBottom: "20px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
{this.props.step.type !== "finalpage" ? (
|
||||||
variant="h6"
|
<Typography
|
||||||
style={{ marginBottom: "10px", marginLeft: "4px" }}
|
variant="h6"
|
||||||
>
|
style={{ marginBottom: "10px", marginLeft: "4px" }}
|
||||||
Schritt {index + 1}
|
>
|
||||||
</Typography>
|
Schritt {index + 1}
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
style={{ marginBottom: "10px", marginLeft: "4px" }}
|
||||||
|
>
|
||||||
|
Abschlussseite
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
<div style={{ display: "flex", position: "relative" }}>
|
<div style={{ display: "flex", position: "relative" }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -80,60 +92,66 @@ class Step extends Component {
|
|||||||
bottom: "10px",
|
bottom: "10px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tooltip title="Schritt hinzufügen" arrow>
|
{this.props.step.type !== "finalpage" ? (
|
||||||
<IconButton
|
|
||||||
className={this.props.classes.button}
|
|
||||||
style={index === 0 ? {} : { marginBottom: "5px" }}
|
|
||||||
onClick={() => this.props.addStep(index + 1)}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faPlus} size="xs" />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
{index !== 0 ? (
|
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip title="Schritt hinzufügen" arrow>
|
||||||
title={`Schritt ${index + 1} nach oben schieben`}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
disabled={index < 2}
|
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
style={{ marginBottom: "5px" }}
|
style={index === 0 ? {} : { marginBottom: "5px" }}
|
||||||
onClick={() => this.props.changeStepIndex(index, index - 1)}
|
onClick={() => this.props.addStep(index + 1)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleDoubleUp} size="xs" />
|
<FontAwesomeIcon icon={faPlus} size="xs" />
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip
|
|
||||||
title={`Schritt ${index + 1} nach unten schieben`}
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
disabled={index === steps.length - 1}
|
|
||||||
className={this.props.classes.button}
|
|
||||||
style={{ marginBottom: "5px" }}
|
|
||||||
onClick={() => this.props.changeStepIndex(index, index + 1)}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faAngleDoubleDown} size="xs" />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip title={`Schritt ${index + 1} löschen`} arrow>
|
|
||||||
<IconButton
|
|
||||||
disabled={index === 0}
|
|
||||||
className={clsx(
|
|
||||||
this.props.classes.button,
|
|
||||||
this.props.classes.delete
|
|
||||||
)}
|
|
||||||
onClick={() => this.props.removeStep(index)}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faTrash} size="xs" />
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{index !== 0 ? (
|
||||||
|
<div>
|
||||||
|
<Tooltip
|
||||||
|
title={`Schritt ${index + 1} nach oben schieben`}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
disabled={index < 2}
|
||||||
|
className={this.props.classes.button}
|
||||||
|
style={{ marginBottom: "5px" }}
|
||||||
|
onClick={() => this.props.changeStepIndex(index, index - 1)}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faAngleDoubleUp} size="xs" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
title={`Schritt ${index + 1} nach unten schieben`}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
disabled={index >= this.props.steps.length - 2}
|
||||||
|
className={this.props.classes.button}
|
||||||
|
style={{ marginBottom: "5px" }}
|
||||||
|
onClick={() => this.props.changeStepIndex(index, index + 1)}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faAngleDoubleDown} size="xs" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title={`Schritt ${index + 1} löschen`} arrow>
|
||||||
|
<IconButton
|
||||||
|
disabled={index === 0 && index === steps.length - 1}
|
||||||
|
className={clsx(
|
||||||
|
this.props.classes.button,
|
||||||
|
this.props.classes.delete
|
||||||
|
)}
|
||||||
|
onClick={() => this.props.removeStep(index)}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faTrash} size="xs" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: "100%", marginLeft: "54px" }}>
|
<div style={{ width: "100%", marginLeft: "54px" }}>
|
||||||
<StepType value={this.props.step.type} index={index} />
|
{this.props.step.type !== "finalpage" ? (
|
||||||
|
<StepType value={this.props.step.type} index={index} />
|
||||||
|
) : null}
|
||||||
<Textfield
|
<Textfield
|
||||||
value={this.props.step.headline}
|
value={this.props.step.headline}
|
||||||
property={"headline"}
|
property={"headline"}
|
||||||
@@ -178,12 +196,21 @@ class Step extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<BlocklyExample
|
{this.props.step.type !== "finalpage" ? (
|
||||||
value={this.props.step.xml}
|
<BlocklyExample
|
||||||
index={index}
|
value={this.props.step.xml}
|
||||||
task={this.props.step.type === "task"}
|
index={index}
|
||||||
error={this.props.error.steps[index].xml ? true : false}
|
task={this.props.step.type === "task"}
|
||||||
/>
|
error={this.props.error.steps[index].xml ? true : false}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FinalPageOptions
|
||||||
|
steps={steps}
|
||||||
|
checkedSampleSolutions={this.props.step.samplesolutions}
|
||||||
|
checkedFurtherTutorials={this.props.step.furthertutorials}
|
||||||
|
index={index}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,430 @@
|
|||||||
|
import React, { Component } from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
import BlocklyWindow from "../Blockly/BlocklyWindow";
|
||||||
|
|
||||||
|
import clsx from "clsx";
|
||||||
|
import { alpha } from "@material-ui/core/styles";
|
||||||
|
import { withStyles } from "@material-ui/core/styles";
|
||||||
|
|
||||||
|
import {
|
||||||
|
faCheck,
|
||||||
|
faTimes,
|
||||||
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import ReactStars from "react-rating-stars-component";
|
||||||
|
import Grid from "@material-ui/core/Grid";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import Paper from "@material-ui/core/Paper";
|
||||||
|
import ReactMarkdown from "react-markdown";
|
||||||
|
import remarkGfm from "remark-gfm";
|
||||||
|
import remarkGemoji from "remark-gemoji";
|
||||||
|
import Dialog from "../Dialog";
|
||||||
|
import { IconButton } from "@material-ui/core";
|
||||||
|
import { clearMessages } from "../../actions/messageActions";
|
||||||
|
|
||||||
|
import * as Blockly from "blockly/core";
|
||||||
|
|
||||||
|
// import { getTutorials,
|
||||||
|
// tutorialProgress,
|
||||||
|
// resetTutorial
|
||||||
|
// } from "../../actions/tutorialActions";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
outerDiv: {
|
||||||
|
position: "absolute",
|
||||||
|
right: "-30px",
|
||||||
|
bottom: "-30px",
|
||||||
|
width: "160px",
|
||||||
|
height: "160px",
|
||||||
|
color: alpha(theme.palette.secondary.main, 0.6),
|
||||||
|
},
|
||||||
|
outerDivError: {
|
||||||
|
stroke: alpha(theme.palette.error.dark, 0.6),
|
||||||
|
color: alpha(theme.palette.error.dark, 0.6),
|
||||||
|
},
|
||||||
|
outerDivSuccess: {
|
||||||
|
stroke: alpha(theme.palette.primary.main, 0.6),
|
||||||
|
color: alpha(theme.palette.primary.main, 0.6),
|
||||||
|
},
|
||||||
|
outerDivOther: {
|
||||||
|
stroke: alpha(theme.palette.secondary.main, 0.6),
|
||||||
|
},
|
||||||
|
innerDiv: {
|
||||||
|
width: "inherit",
|
||||||
|
height: "inherit",
|
||||||
|
display: "table-cell",
|
||||||
|
verticalAlign: "middle",
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
// button: {
|
||||||
|
// backgroundColor: theme.palette.primary.main,
|
||||||
|
// color: theme.palette.primary.contrastText,
|
||||||
|
// width: "40px",
|
||||||
|
// height: "40px",
|
||||||
|
// "&:hover": {
|
||||||
|
// backgroundColor: theme.palette.primary.main,
|
||||||
|
// color: theme.palette.primary.contrastText,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// link: {
|
||||||
|
// color: theme.palette.primary.main,
|
||||||
|
// textDecoration: "none",
|
||||||
|
// "&:hover": {
|
||||||
|
// color: theme.palette.primary.main,
|
||||||
|
// textDecoration: "underline",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
});
|
||||||
|
|
||||||
|
class FinalPage extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
open: false,
|
||||||
|
title: "",
|
||||||
|
content: "",
|
||||||
|
tutorials: [],
|
||||||
|
randomtutorials: [],
|
||||||
|
activeXML: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
if (this.props.step.furthertutorials === true) {
|
||||||
|
axios
|
||||||
|
.get(`${process.env.REACT_APP_BLOCKLY_API}/tutorial`)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({ tutorials: res.data.tutorials });
|
||||||
|
this.setState({ randomtutorials: this.getRandomTutorials(this.state.tutorials, 3) });
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleDialog = (solution) => {
|
||||||
|
console.log(solution)
|
||||||
|
if (this.state.open === true) {
|
||||||
|
this.setState({ open: !this.state.open, title: "", activeXML: "" });
|
||||||
|
} else if (this.state.open === false) {
|
||||||
|
this.setState({ open: !this.state.open, title: "Task - " + solution.headline, activeXML: solution.xml });
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
getRandomTutorials = (tutorials, n) => {
|
||||||
|
var length = tutorials.length;
|
||||||
|
var taken = new Array(length);
|
||||||
|
var result = new Array(n);
|
||||||
|
if (n > length)
|
||||||
|
throw new RangeError("getRandom: more elements taken than available");
|
||||||
|
while (n--) {
|
||||||
|
var x = Math.floor(Math.random() * length);
|
||||||
|
result[n] = tutorials[x in taken ? taken[x] : x];
|
||||||
|
taken[x] = --length in taken ? taken[length] : length;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// toggleDialog = (solution) => {
|
||||||
|
// this.setState({ open: !this.state.open });
|
||||||
|
// // if (solution) {
|
||||||
|
// // this.setState({ open: !this.state.open, activeSolution: solution });
|
||||||
|
// // } else {
|
||||||
|
// // this.setState({ open: !this.state.open, activeSolution: null });
|
||||||
|
// // }
|
||||||
|
// };
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var step = this.props.step;
|
||||||
|
var tutorials = this.state.tutorials;
|
||||||
|
var randomtutorials = this.state.randomtutorials;
|
||||||
|
// var randomtutorials = this.getRandomTutorials(tutorials, 3);
|
||||||
|
// console.log(randomtutorials)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Typography>
|
||||||
|
<ReactMarkdown
|
||||||
|
className={"tutorial"}
|
||||||
|
linkTarget={"_blank"}
|
||||||
|
skipHtml={false}
|
||||||
|
allowDangerousHtml={true}
|
||||||
|
remarkPlugins={[remarkGfm, remarkGemoji]}
|
||||||
|
>
|
||||||
|
{step.text}
|
||||||
|
</ReactMarkdown>
|
||||||
|
</Typography>
|
||||||
|
{step.media ? (
|
||||||
|
step.media.picture ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
marginBottom: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={`${process.env.REACT_APP_BLOCKLY_API}/media/${step.media.picture.path}`}
|
||||||
|
alt=""
|
||||||
|
style={{ maxHeight: "40vH", maxWidth: "100%" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : step.media.youtube ? (
|
||||||
|
/*16:9; width: 800px; height: width/16*9=450px*/
|
||||||
|
<div style={{ maxWidth: "800px", margin: "auto" }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
height: 0,
|
||||||
|
paddingBottom: "calc(100% / 16 * 9)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<iframe
|
||||||
|
title={step.media.youtube}
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "0",
|
||||||
|
left: "0",
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "800px",
|
||||||
|
height: "100%",
|
||||||
|
maxHeight: "450px",
|
||||||
|
}}
|
||||||
|
src={`https://www.youtube.com/embed/${step.media.youtube}`}
|
||||||
|
frameBorder="0"
|
||||||
|
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
allowFullScreen
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
) : null}
|
||||||
|
{step.samplesolutions === true ? (
|
||||||
|
<div>
|
||||||
|
<h2 style={{ justifyContent: "center" }}>Musterlösungen</h2>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
style={{ marginBottom: "5px", justifyContent: "space-evenly" }}
|
||||||
|
>
|
||||||
|
{step.solutions.map((solution) => {
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
sm={6}
|
||||||
|
md={4}
|
||||||
|
xl={3}
|
||||||
|
style={{ display: "flex", justifyContent: "center" }}
|
||||||
|
// onclick={this.toggleDialog(solution)}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => this.toggleDialog(solution)}
|
||||||
|
>
|
||||||
|
<Paper
|
||||||
|
style={{
|
||||||
|
padding: "10px",
|
||||||
|
position: "relative",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h3>{"Task - " + solution.headline}</h3>
|
||||||
|
<BlocklyWindow
|
||||||
|
svg
|
||||||
|
blockDisabled
|
||||||
|
initialXml={solution.xml}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
open={this.state.open}
|
||||||
|
onClose={this.toggleDialog}
|
||||||
|
onClick={this.toggleDialog}
|
||||||
|
title={this.state.title}
|
||||||
|
button={Blockly.Msg.button_close}
|
||||||
|
>
|
||||||
|
<BlocklyWindow
|
||||||
|
svg
|
||||||
|
blockDisabled
|
||||||
|
initialXml={this.state.activeXML}
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{step.furthertutorials === true ? (
|
||||||
|
<div>
|
||||||
|
<h2 style={{ justifyContent: "center" }}>Weitere Tutorials</h2>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
style={{ justifyContent: "space-evenly" }}
|
||||||
|
>
|
||||||
|
{randomtutorials.map((tutorial, i) => {
|
||||||
|
var status = this.props.status.filter(
|
||||||
|
(status) => status._id === tutorial._id
|
||||||
|
)[0];
|
||||||
|
var tasks = status.tasks;
|
||||||
|
var error =
|
||||||
|
status.tasks.filter((task) => task.type === "error").length > 0;
|
||||||
|
var success =
|
||||||
|
status.tasks.filter((task) => task.type === "success").length /
|
||||||
|
tasks.length;
|
||||||
|
var tutorialStatus =
|
||||||
|
success === 1 ? "Success" : error ? "Error" : "Other";
|
||||||
|
const firstExample = {
|
||||||
|
size: 30,
|
||||||
|
value: tutorial.difficulty,
|
||||||
|
edit: false,
|
||||||
|
isHalf: true,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}>
|
||||||
|
<Link
|
||||||
|
to={`/tutorial/${tutorial._id}`}
|
||||||
|
style={{ textDecoration: "none", color: "inherit" }}
|
||||||
|
>
|
||||||
|
<Paper
|
||||||
|
style={{
|
||||||
|
height: "150px",
|
||||||
|
padding: "10px",
|
||||||
|
position: "relative",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tutorial.title}
|
||||||
|
<ReactStars {...firstExample} />
|
||||||
|
<div
|
||||||
|
className={clsx(this.props.classes.outerDiv)}
|
||||||
|
style={{ width: "160px", height: "160px", border: 0 }}
|
||||||
|
>
|
||||||
|
<svg style={{ width: "100%", height: "100%" }}>
|
||||||
|
{error || success === 1 ? (
|
||||||
|
<circle
|
||||||
|
className={
|
||||||
|
error
|
||||||
|
? this.props.classes.outerDivError
|
||||||
|
: this.props.classes.outerDivSuccess
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
transform: "rotate(-44deg)",
|
||||||
|
transformOrigin: "50% 50%",
|
||||||
|
}}
|
||||||
|
r="75"
|
||||||
|
cx="50%"
|
||||||
|
cy="50%"
|
||||||
|
fill="none"
|
||||||
|
stroke-width="10"
|
||||||
|
></circle>
|
||||||
|
) : (
|
||||||
|
<circle
|
||||||
|
className={this.props.classes.outerDivOther}
|
||||||
|
style={{
|
||||||
|
transform: "rotate(-44deg)",
|
||||||
|
transformOrigin: "50% 50%",
|
||||||
|
}}
|
||||||
|
r="75"
|
||||||
|
cx="50%"
|
||||||
|
cy="50%"
|
||||||
|
fill="none"
|
||||||
|
stroke-width="10"
|
||||||
|
stroke-dashoffset={`${75 * 2 * Math.PI * (1 - (50 / 100 + success / 2))
|
||||||
|
}`}
|
||||||
|
stroke-dasharray={`${75 * 2 * Math.PI * (1 - (50 / 100 - success / 2))
|
||||||
|
} ${75 * 2 * Math.PI * (1 - (50 / 100 + success / 2))
|
||||||
|
}`}
|
||||||
|
></circle>
|
||||||
|
)}
|
||||||
|
{success < 1 && !error ? (
|
||||||
|
<circle
|
||||||
|
className={this.props.classes.outerDivSuccess}
|
||||||
|
style={{
|
||||||
|
transform: "rotate(-44deg)",
|
||||||
|
transformOrigin: "50% 50%",
|
||||||
|
}}
|
||||||
|
r="75"
|
||||||
|
cx="50%"
|
||||||
|
cy="50%"
|
||||||
|
fill="none"
|
||||||
|
stroke-width="10"
|
||||||
|
stroke-dashoffset={`${75 * 2 * Math.PI * (1 - (50 / 100 + success / 2))
|
||||||
|
}`}
|
||||||
|
stroke-dasharray={`${75 * 2 * Math.PI}`}
|
||||||
|
></circle>
|
||||||
|
) : null}
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
this.props.classes.outerDiv,
|
||||||
|
tutorialStatus === "Error"
|
||||||
|
? this.props.classes.outerDivError
|
||||||
|
: tutorialStatus === "Success"
|
||||||
|
? this.props.classes.outerDivSuccess
|
||||||
|
: null
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={this.props.classes.innerDiv}>
|
||||||
|
{error || success === 1 ? (
|
||||||
|
<FontAwesomeIcon
|
||||||
|
size="4x"
|
||||||
|
icon={
|
||||||
|
tutorialStatus === "Success" ? faCheck : faTimes
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
variant="h3"
|
||||||
|
className={
|
||||||
|
success > 0
|
||||||
|
? this.props.classes.outerDivSuccess
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{Math.round(success * 100)}%
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
</Link>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
tutorials: state.tutorial.tutorials,
|
||||||
|
status: state.tutorial.status,
|
||||||
|
isLoading: state.tutorial.progress,
|
||||||
|
message: state.message,
|
||||||
|
progress: state.auth.progress,
|
||||||
|
user: state.auth.user,
|
||||||
|
authProgress: state.auth.progress,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, {
|
||||||
|
// getTutorials,
|
||||||
|
// resetTutorial,
|
||||||
|
// tutorialProgress,
|
||||||
|
clearMessages,
|
||||||
|
})(withStyles(styles, { withTheme: true })(FinalPage));
|
||||||
@@ -31,6 +31,9 @@ const styles = (theme) => ({
|
|||||||
width: "24px",
|
width: "24px",
|
||||||
height: "24px",
|
height: "24px",
|
||||||
},
|
},
|
||||||
|
stepIconSuccess: {
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
stepIconLargeSuccess: {
|
stepIconLargeSuccess: {
|
||||||
borderColor: theme.palette.primary.main,
|
borderColor: theme.palette.primary.main,
|
||||||
},
|
},
|
||||||
@@ -130,12 +133,25 @@ class StepperVertical extends Component {
|
|||||||
"stepIconLarge" + taskStatus
|
"stepIconLarge" + taskStatus
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
: i === activeStep
|
: step.type === "instruction"
|
||||||
? clsx(
|
? i === activeStep
|
||||||
this.props.classes.stepIcon,
|
? clsx(
|
||||||
this.props.classes.stepIconActiveOther
|
this.props.classes.stepIcon,
|
||||||
)
|
this.props.classes.stepIconActiveOther
|
||||||
: clsx(this.props.classes.stepIcon),
|
)
|
||||||
|
: clsx(this.props.classes.stepIcon)
|
||||||
|
: step.type === "finalpage"
|
||||||
|
? i === activeStep
|
||||||
|
? clsx(
|
||||||
|
this.props.classes.stepIcon,
|
||||||
|
this.props.classes.stepIconSuccess,
|
||||||
|
this.props.classes.stepIconActiveSuccess
|
||||||
|
)
|
||||||
|
: clsx(
|
||||||
|
this.props.classes.stepIcon,
|
||||||
|
this.props.classes.stepIconSuccess
|
||||||
|
)
|
||||||
|
: null,
|
||||||
}}
|
}}
|
||||||
></StepLabel>
|
></StepLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import StepperHorizontal from "./StepperHorizontal";
|
|||||||
import StepperVertical from "./StepperVertical";
|
import StepperVertical from "./StepperVertical";
|
||||||
import Instruction from "./Instruction";
|
import Instruction from "./Instruction";
|
||||||
import Assessment from "./Assessment";
|
import Assessment from "./Assessment";
|
||||||
|
import FinalPage from "./FinalPage";
|
||||||
import NotFound from "../NotFound";
|
import NotFound from "../NotFound";
|
||||||
import * as Blockly from "blockly";
|
import * as Blockly from "blockly";
|
||||||
import { detectWhitespacesAndReturnReadableResult } from "../../helpers/whitespace";
|
import { detectWhitespacesAndReturnReadableResult } from "../../helpers/whitespace";
|
||||||
@@ -74,7 +75,9 @@ class Tutorial extends Component {
|
|||||||
(() => {
|
(() => {
|
||||||
var tutorial = this.props.tutorial;
|
var tutorial = this.props.tutorial;
|
||||||
var steps = this.props.tutorial.steps;
|
var steps = this.props.tutorial.steps;
|
||||||
|
console.log(steps)
|
||||||
var step = steps[this.props.activeStep];
|
var step = steps[this.props.activeStep];
|
||||||
|
console.log(step)
|
||||||
var name = `${detectWhitespacesAndReturnReadableResult(
|
var name = `${detectWhitespacesAndReturnReadableResult(
|
||||||
tutorial.title
|
tutorial.title
|
||||||
)}_${detectWhitespacesAndReturnReadableResult(step.headline)}`;
|
)}_${detectWhitespacesAndReturnReadableResult(step.headline)}`;
|
||||||
@@ -107,8 +110,10 @@ class Tutorial extends Component {
|
|||||||
{step ? (
|
{step ? (
|
||||||
step.type === "instruction" ? (
|
step.type === "instruction" ? (
|
||||||
<Instruction step={step} />
|
<Instruction step={step} />
|
||||||
) : (
|
) : step.type === "task" ? (
|
||||||
<Assessment step={step} name={name} />
|
<Assessment step={step} name={name} />
|
||||||
|
) : (
|
||||||
|
<FinalPage step={step} />
|
||||||
) // if step.type === 'assessment'
|
) // if step.type === 'assessment'
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class Compile extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() { }
|
componentDidMount() {}
|
||||||
|
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props) {
|
||||||
if (props.name !== this.props.name) {
|
if (props.name !== this.props.name) {
|
||||||
@@ -232,8 +232,8 @@ class Compile extends Component {
|
|||||||
>
|
>
|
||||||
<div className="overlay">
|
<div className="overlay">
|
||||||
{/* <img src={Copy} width="400" alt="copyimage"></img> */}
|
{/* <img src={Copy} width="400" alt="copyimage"></img> */}
|
||||||
<h2>{Blockly.Msg.compiledialog_process}</h2>
|
<h2>Dein Code wird kompiliert!</h2>
|
||||||
<p>{Blockly.Msg.compiledialog_instructions}</p>
|
<p>übertrage ihn anschließend mithlfe der senseBoxConnect-App</p>
|
||||||
<p>
|
<p>
|
||||||
{Blockly.Msg.compile_overlay_help}
|
{Blockly.Msg.compile_overlay_help}
|
||||||
<a href="/faq" target="_blank">
|
<a href="/faq" target="_blank">
|
||||||
@@ -291,7 +291,7 @@ class Compile extends Component {
|
|||||||
button={Blockly.Msg.button_close}
|
button={Blockly.Msg.button_close}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p>{Blockly.Msg.compiledialog_success}</p>
|
<p>Dein Code wurde erfolgreich kompiliert</p>
|
||||||
<a href={this.state.link}>
|
<a href={this.state.link}>
|
||||||
<Button
|
<Button
|
||||||
style={{ color: "white" }}
|
style={{ color: "white" }}
|
||||||
@@ -303,7 +303,7 @@ class Compile extends Component {
|
|||||||
icon={faClipboardCheck}
|
icon={faClipboardCheck}
|
||||||
style={{ marginRight: "5px" }}
|
style={{ marginRight: "5px" }}
|
||||||
/>{" "}
|
/>{" "}
|
||||||
{Blockly.Msg.tabletDialog_connect}
|
Starte Übertragung
|
||||||
</Button>
|
</Button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,9 +33,18 @@ const initialState = {
|
|||||||
hardware: [],
|
hardware: [],
|
||||||
requirements: [],
|
requirements: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
type: "finalpage",
|
||||||
|
headline: "",
|
||||||
|
text: "",
|
||||||
|
samplesolutions: false,
|
||||||
|
solutions: [],
|
||||||
|
furthertutorials: false,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
error: {
|
error: {
|
||||||
steps: [{}],
|
steps: [{},{}],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user