Merge pull request #118 from sensebox/feat/senseBoxConnect

init senseBox connect features
This commit is contained in:
Mario Pesch 2021-11-23 11:56:11 +01:00 committed by GitHub
commit 181df84d2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 421 additions and 133 deletions

View File

@ -1,32 +1,38 @@
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from './types'; import { VISIT, LANGUAGE, RENDERER, STATISTICS, PLATFORM } from "./types";
export const visitPage = () => (dispatch) => { export const visitPage = () => (dispatch) => {
dispatch({ dispatch({
type: VISIT type: VISIT,
});
};
export const setPlatform = (platform) => (dispatch) => {
dispatch({
type: PLATFORM,
payload: platform,
}); });
}; };
export const setLanguage = (language) => (dispatch, getState) => { export const setLanguage = (language) => (dispatch, getState) => {
if (!getState().auth.progress && !getState().auth.isAuthenticated) { if (!getState().auth.progress && !getState().auth.isAuthenticated) {
window.localStorage.setItem('locale', language); window.localStorage.setItem("locale", language);
} }
dispatch({ dispatch({
type: LANGUAGE, type: LANGUAGE,
payload: language payload: language,
}); });
}; };
export const setRenderer = (renderer) => (dispatch) => { export const setRenderer = (renderer) => (dispatch) => {
dispatch({ dispatch({
type: RENDERER, type: RENDERER,
payload: renderer payload: renderer,
}); });
}; };
export const setStatistics = (showStatistics) => (dispatch) => { export const setStatistics = (showStatistics) => (dispatch) => {
dispatch({ dispatch({
type: STATISTICS, type: STATISTICS,
payload: showStatistics payload: showStatistics,
}); });
}; };

View File

@ -43,6 +43,7 @@ export const PROGRESS = "PROGRESS";
export const VISIT = "VISIT"; export const VISIT = "VISIT";
export const LANGUAGE = "LANGUAGE"; export const LANGUAGE = "LANGUAGE";
export const PLATFORM = "PLATFORM";
export const RENDERER = "RENDERER"; export const RENDERER = "RENDERER";
export const STATISTICS = "STATISTICS"; export const STATISTICS = "STATISTICS";

View File

@ -26,6 +26,17 @@
import * as Blockly from "blockly/core"; import * as Blockly from "blockly/core";
import store from "../../../store";
var ota = store.getState().general.platform
? store.getState().general.platform
: null;
store.subscribe(() => {
ota = store.getState().general.platform
? store.getState().general.platform
: null;
});
/** /**
* Arduino code generator. * Arduino code generator.
* @type !Blockly.Generator * @type !Blockly.Generator
@ -254,7 +265,29 @@ Blockly["Arduino"].finish = function (code) {
"\n}\n"; "\n}\n";
let loopCode = "\nvoid loop() { \n" + loopCodeOnce + code + "\n}\n"; let loopCode = "\nvoid loop() { \n" + loopCodeOnce + code + "\n}\n";
// only add OTA code if tablet mode is enabled
if (ota === true) {
code =
devVariables +
"\n" +
"#include <SenseBoxOTA.h>" +
"\n" +
libraryCode +
"\n" +
variablesCode +
"\n" +
definitionsCode +
"\n" +
codeFunctions +
"\n" +
Blockly["Arduino"].variablesInitCode_ +
"\n" +
functionsCode +
"\n" +
setupCode +
"\n" +
loopCode;
} else {
// Convert the definitions dictionary into a list. // Convert the definitions dictionary into a list.
code = code =
devVariables + devVariables +
@ -274,6 +307,7 @@ Blockly["Arduino"].finish = function (code) {
setupCode + setupCode +
"\n" + "\n" +
loopCode; loopCode;
}
// Clean up temporary data. // Clean up temporary data.
delete Blockly["Arduino"].definitions_; delete Blockly["Arduino"].definitions_;

View File

@ -90,6 +90,16 @@ export const UI = {
messages_LOGIN_FAIL: "Der Benutzername oder das Passwort ist nicht korrekt.", messages_LOGIN_FAIL: "Der Benutzername oder das Passwort ist nicht korrekt.",
messages_copy_code: "Code wurde in die Zwischenablage kopiert", messages_copy_code: "Code wurde in die Zwischenablage kopiert",
/**
* Tablet Dialog
*/
tabletDialog_headline: "Tablet Modus ist aktiviert!",
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",
tabletDialog_more:
"Weitere Informationen und den Link zum Download der App findest du unter: ",
/** /**
* Reset Dialog * Reset Dialog
*/ */
@ -161,6 +171,11 @@ export const UI = {
"Die Anzeige von Statistiken zur Nutzung der Blöcke oberhalb der Arbeitsfläche kann ein- oder ausgeblendet werden.", "Die Anzeige von Statistiken zur Nutzung der Blöcke oberhalb der Arbeitsfläche kann ein- oder ausgeblendet werden.",
settings_statistics_on: "An", settings_statistics_on: "An",
settings_statistics_off: "Aus", settings_statistics_off: "Aus",
settings_ota_head: "Tablet Modus",
settings_ota_text:
"Der Tablet Modus deaktiviert die Code anzeige und aktiviert die Möglichkeit den Programmcode über die senseBox Connect App zu übertragen. Weitere Informationen dazu findest du unter: ",
settings_ota_on: "Aktiviert",
settings_ota_off: "Deaktiviert",
/** /**
* 404 * 404

View File

@ -88,6 +88,15 @@ export const UI = {
messages_login_error: "Enter both a username and a password.", messages_login_error: "Enter both a username and a password.",
messages_copy_code: "Copy code to clipboard succesfull", messages_copy_code: "Copy code to clipboard succesfull",
/**
* Tablet Dialog
*/
tabletDialog_headline: "Tablet mode is enabled!",
tabletDialog_text:
"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:
"For more information and the link to download the app, please visit: ",
/** /**
* Reset Dialog * Reset Dialog
*/ */
@ -157,6 +166,11 @@ export const UI = {
"The display of statistics on the usage of the blocks above the workspace can be shown or hidden.", "The display of statistics on the usage of the blocks above the workspace can be shown or hidden.",
settings_statistics_on: "On", settings_statistics_on: "On",
settings_statistics_off: "Off", settings_statistics_off: "Off",
settings_ota_head: "tablet mode",
settings_ota_text:
"Tablet mode disables the code display and enables the possibility to transfer the program code via the senseBox Connect app. You can find more information on: ",
settings_ota_on: "Activated",
settings_ota_off: "Deactivated",
/** /**
* 404 * 404

View File

@ -14,6 +14,7 @@ import TrashcanButtons from "./Workspace/TrashcanButtons";
import HintTutorialExists from "./Tutorial/HintTutorialExists"; import HintTutorialExists from "./Tutorial/HintTutorialExists";
import Snackbar from "./Snackbar"; import Snackbar from "./Snackbar";
import Grid from "@material-ui/core/Grid"; import Grid from "@material-ui/core/Grid";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import Tooltip from "@material-ui/core/Tooltip"; import Tooltip from "@material-ui/core/Tooltip";
@ -22,6 +23,7 @@ import { withStyles } from "@material-ui/core/styles";
import { faCode } from "@fortawesome/free-solid-svg-icons"; import { faCode } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import TooltipViewer from "./TooltipViewer"; import TooltipViewer from "./TooltipViewer";
import Dialog from "./Dialog";
const styles = (theme) => ({ const styles = (theme) => ({
codeOn: { codeOn: {
@ -45,15 +47,23 @@ const styles = (theme) => ({
}); });
class Home extends Component { class Home extends Component {
state = { constructor(props) {
super(props);
this.state = {
codeOn: true, codeOn: true,
snackbar: false, snackbar: false,
type: "", type: "",
key: "", key: "",
message: "", message: "",
open: true,
}; };
}
componentDidMount() { componentDidMount() {
console.log(this.props.platform);
if (this.props.platform === true) {
this.setState({ codeOn: false });
}
this.setState({ stats: window.localStorage.getItem("stats") }); this.setState({ stats: window.localStorage.getItem("stats") });
if (!this.props.project) { if (!this.props.project) {
this.props.workspaceName(createNameId()); this.props.workspaceName(createNameId());
@ -82,6 +92,18 @@ class Home extends Component {
this.props.workspaceName(null); this.props.workspaceName(null);
} }
toggleDialog = () => {
this.setState({ open: !this.state });
};
onChangeCheckbox = (e) => {
if (e.target.checked) {
window.localStorage.setItem("ota", e.target.checked);
} else {
window.localStorage.removeItem("ota");
}
};
onChange = () => { onChange = () => {
this.setState({ codeOn: !this.state.codeOn }); this.setState({ codeOn: !this.state.codeOn });
const workspace = Blockly.getMainWorkspace(); const workspace = Blockly.getMainWorkspace();
@ -127,7 +149,7 @@ class Home extends Component {
this.state.codeOn this.state.codeOn
? this.props.classes.codeOn ? this.props.classes.codeOn
: this.props.classes.codeOff : this.props.classes.codeOff
}`} }}
style={{ style={{
width: "40px", width: "40px",
height: "40px", height: "40px",
@ -161,12 +183,31 @@ class Home extends Component {
) : null} ) : null}
</Grid> </Grid>
<HintTutorialExists /> <HintTutorialExists />
<Snackbar {this.props.platform ? (
open={this.state.snackbar} <Dialog
message={this.state.message} style={{ zIndex: 9999999 }}
type={this.state.type} fullWidth
key={this.state.key} maxWidth={"sm"}
/> open={this.state.open}
title={Blockly.Msg.tabletDialog_headline}
content={""}
onClose={this.toggleDialog}
onClick={this.toggleDialog}
button={Blockly.Msg.button_close}
>
<div>{Blockly.Msg.tabletDialog_text}</div>
<div>
{Blockly.Msg.tabletDialog_more}{" "}
<a
href="https://sensebox.de/app"
target="_blank"
rel="noreferrer"
>
https://sensebox.de/app
</a>
</div>
</Dialog>
) : null}
</div> </div>
); );
} }
@ -177,11 +218,14 @@ Home.propTypes = {
workspaceName: PropTypes.func.isRequired, workspaceName: PropTypes.func.isRequired,
message: PropTypes.object.isRequired, message: PropTypes.object.isRequired,
statistics: PropTypes.bool.isRequired, statistics: PropTypes.bool.isRequired,
platform: PropTypes.object.isRequired,
}; };
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
message: state.message, message: state.message,
statistics: state.general.statistics, statistics: state.general.statistics,
platform: state.general.platform,
}); });
export default connect(mapStateToProps, { clearStats, workspaceName })( export default connect(mapStateToProps, { clearStats, workspaceName })(

View File

@ -0,0 +1,66 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { setPlatform } from "../../actions/generalActions";
import * as Blockly from "blockly/core";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";
import Typography from "@material-ui/core/Typography";
import FormHelperText from "@material-ui/core/FormHelperText";
class OtaSelector 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();
}
render() {
return (
<div>
<Typography style={{ fontWeight: "bold" }}>
{Blockly.Msg.settings_ota_head}
</Typography>
<FormHelperText
style={{ color: "black", lineHeight: 1.3, marginBottom: "8px" }}
>
{Blockly.Msg.settings_ota_text}
<a href="https://sensebox.de/app" target="_blank" rel="noreferrer">
https://sensebox.de/app
</a>
</FormHelperText>
<FormControl>
<InputLabel id="demo-simple-select-label">
{Blockly.Msg.settings_statistics}
</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.props.platform}
onChange={(e) => this.props.setPlatform(e.target.value)}
>
<MenuItem value={true}>{Blockly.Msg.settings_ota_on}</MenuItem>
<MenuItem value={false}>{Blockly.Msg.settings_ota_off}</MenuItem>
</Select>
</FormControl>
</div>
);
}
}
OtaSelector.propTypes = {
setPlatform: PropTypes.func.isRequired,
language: PropTypes.string.isRequired,
platform: PropTypes.bool.isRequired,
};
const mapStateToProps = (state) => ({
language: state.general.language,
platform: state.general.platform,
});
export default connect(mapStateToProps, { setPlatform })(OtaSelector);

View File

@ -1,21 +1,21 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { withRouter } from 'react-router-dom'; import { withRouter } from "react-router-dom";
import * as Blockly from 'blockly/core'; import * as Blockly from "blockly/core";
import Breadcrumbs from '../Breadcrumbs'; import Breadcrumbs from "../Breadcrumbs";
import LanguageSelector from './LanguageSelector'; import LanguageSelector from "./LanguageSelector";
import RenderSelector from './RenderSelector'; import RenderSelector from "./RenderSelector";
import StatsSelector from './StatsSelector'; import StatsSelector from "./StatsSelector";
import OtaSelector from "./OtaSelector";
import Button from '@material-ui/core/Button'; import Button from "@material-ui/core/Button";
import Paper from '@material-ui/core/Paper'; import Paper from "@material-ui/core/Paper";
class Settings extends Component { class Settings extends Component {
componentDidMount() { componentDidMount() {
// Ensure that Blockly.setLocale is adopted in the component. // Ensure that Blockly.setLocale is adopted in the component.
// Otherwise, the text will not be displayed until the next update of the component. // Otherwise, the text will not be displayed until the next update of the component.
@ -25,41 +25,55 @@ class Settings extends Component {
render() { render() {
return ( return (
<div> <div>
<Breadcrumbs content={[{ link: this.props.location.pathname, title: Blockly.Msg.settings_head }]} /> <Breadcrumbs
content={[
{
link: this.props.location.pathname,
title: Blockly.Msg.settings_head,
},
]}
/>
<h1>{Blockly.Msg.settings_head}</h1> <h1>{Blockly.Msg.settings_head}</h1>
<Paper style={{margin: '10px 0px', padding: '10px'}}> <Paper style={{ margin: "10px 0px", padding: "10px" }}>
<LanguageSelector /> <LanguageSelector />
</Paper> </Paper>
<Paper style={{margin: '10px 0px', padding: '10px'}}> <Paper style={{ margin: "10px 0px", padding: "10px" }}>
<RenderSelector /> <RenderSelector />
</Paper> </Paper>
<Paper style={{margin: '10px 0px', padding: '10px'}}> <Paper style={{ margin: "10px 0px", padding: "10px" }}>
<StatsSelector /> <StatsSelector />
</Paper> </Paper>
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
<OtaSelector />
</Paper>
<Button <Button
style={{ marginTop: '10px' }} style={{ marginTop: "10px" }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={this.props.pageVisits > 0 ? () => this.props.history.goBack() : () => this.props.history.push('/')} onClick={
this.props.pageVisits > 0
? () => this.props.history.goBack()
: () => this.props.history.push("/")
}
> >
{Blockly.Msg.button_back} {Blockly.Msg.button_back}
</Button> </Button>
</div> </div>
); );
}; }
} }
Settings.propTypes = { Settings.propTypes = {
language: PropTypes.string.isRequired, language: PropTypes.string.isRequired,
pageVisits: PropTypes.number.isRequired pageVisits: PropTypes.number.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
language: state.general.language, language: state.general.language,
pageVisits: state.general.pageVisits pageVisits: state.general.pageVisits,
}); });
export default connect(mapStateToProps, null)(withRouter(Settings)); export default connect(mapStateToProps, null)(withRouter(Settings));

View File

@ -21,6 +21,7 @@ import "prismjs/themes/prism.css";
import "prismjs/plugins/line-numbers/prism-line-numbers"; import "prismjs/plugins/line-numbers/prism-line-numbers";
import "prismjs/plugins/line-numbers/prism-line-numbers.css"; import "prismjs/plugins/line-numbers/prism-line-numbers.css";
import MuiDrawer from "@material-ui/core/Drawer"; import MuiDrawer from "@material-ui/core/Drawer";
import Dialog from "../Dialog";
const styles = (theme) => ({ const styles = (theme) => ({
backdrop: { backdrop: {
@ -65,6 +66,8 @@ class Compile extends Component {
content: "", content: "",
name: props.name, name: props.name,
error: "", error: "",
appLink: "",
appDialog: false,
}; };
} }
@ -126,10 +129,19 @@ class Compile extends Component {
}; };
toggleDialog = () => { toggleDialog = () => {
this.setState({ open: !this.state, progress: false }); this.setState({ open: !this.state, progress: false, appDialog: false });
}; };
createFileName = () => { createFileName = () => {
if (this.props.platform === true) {
const filename = detectWhitespacesAndReturnReadableResult(
this.state.name
);
this.setState({
link: `blocklyconnect-app://sketch/${filename}/${this.state.id}`,
});
this.setState({ appDialog: true });
} else {
if (this.state.name) { if (this.state.name) {
this.download(); this.download();
} else { } else {
@ -141,6 +153,19 @@ class Compile extends Component {
"Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf 'Eingabe'.", "Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf 'Eingabe'.",
}); });
} }
}
// if (this.state.name) {
// this.download();
// } else {
// this.setState({
// file: true,
// open: true,
// title: "Projekt kompilieren",
// content:
// "Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf 'Eingabe'.",
// });
// }
}; };
setFileName = (e) => { setFileName = (e) => {
@ -188,6 +213,8 @@ class Compile extends Component {
Kompilieren Kompilieren
</Button> </Button>
)} )}
{this.props.platform === false ? (
<Backdrop <Backdrop
className={this.props.classes.backdrop} className={this.props.classes.backdrop}
open={this.state.progress} open={this.state.progress}
@ -205,6 +232,25 @@ class Compile extends Component {
<CircularProgress color="inherit" /> <CircularProgress color="inherit" />
</div> </div>
</Backdrop> </Backdrop>
) : (
<Backdrop
className={this.props.classes.backdrop}
open={this.state.progress}
>
<div className="overlay">
{/* <img src={Copy} width="400" alt="copyimage"></img> */}
<h2>Dein Code wird kompiliert!</h2>
<p>übertrage ihn anschließend mithlfe der senseBoxConnect-App</p>
<p>
{Blockly.Msg.compile_overlay_help}
<a href="/faq" target="_blank">
FAQ
</a>
</p>
<CircularProgress color="inherit" />
</div>
</Backdrop>
)}
<Drawer <Drawer
anchor={"bottom"} anchor={"bottom"}
open={this.state.open} open={this.state.open}
@ -240,29 +286,35 @@ class Compile extends Component {
{`${this.state.error}`}{" "} {`${this.state.error}`}{" "}
</p> </p>
</Drawer> </Drawer>
{/* <Dialog <Dialog
open={this.state.open} style={{ zIndex: 9999999 }}
title={this.state.title} fullWidth
content={this.state.content} maxWidth={"sm"}
open={this.state.appDialog}
title=""
content={""}
onClose={this.toggleDialog} onClose={this.toggleDialog}
onClick={this.state.file ? () => { this.toggleDialog(); this.setState({ name: this.props.name }) } : this.toggleDialog} onClick={this.toggleDialog}
button={this.state.file ? Blockly.Msg.button_cancel : Blockly.Msg.button_close} button={Blockly.Msg.button_close}
> >
{this.state.file ? <div>
<div style={{ marginTop: '10px' }}> <p>Dein Code wurde erfolgreich kompiliert</p>
<TextField autoFocus placeholder='Dateiname' value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} /> <a href={this.state.link}>
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => this.download()}>Eingabe</Button> <Button
style={{ color: "white" }}
variant="contained"
className={this.props.classes.button}
onClick={() => this.toggleDialog()}
>
<FontAwesomeIcon
icon={faClipboardCheck}
style={{ marginRight: "5px" }}
/>{" "}
Starte Übertragung
</Button>
</a>
</div> </div>
: </Dialog>
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: '100%', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}><code className="language-json">
{`${this.state.error}`}
</code></pre>
</AccordionDetails>
</Accordion>
}
</Dialog> */}
</div> </div>
); );
} }
@ -272,11 +324,13 @@ Compile.propTypes = {
arduino: PropTypes.string.isRequired, arduino: PropTypes.string.isRequired,
name: PropTypes.string, name: PropTypes.string,
workspaceName: PropTypes.func.isRequired, workspaceName: PropTypes.func.isRequired,
platform: PropTypes.bool.isRequired,
}; };
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
arduino: state.workspace.code.arduino, arduino: state.workspace.code.arduino,
name: state.workspace.name, name: state.workspace.name,
platform: state.general.platform,
}); });
export default connect(mapStateToProps, { workspaceName })( export default connect(mapStateToProps, { workspaceName })(

View File

@ -1,35 +1,69 @@
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from '../actions/types'; import {
VISIT,
LANGUAGE,
RENDERER,
STATISTICS,
PLATFORM,
} from "../actions/types";
const initialLanguage = () => { const initialLanguage = () => {
if (window.localStorage.getItem('locale')) { if (window.localStorage.getItem("locale")) {
return window.localStorage.getItem('locale'); return window.localStorage.getItem("locale");
} }
if (navigator.language === 'de-DE'){ if (navigator.language === "de-DE") {
return 'de_DE'; return "de_DE";
} }
return 'en_US'; return "en_US";
};
const initialPlatform = () => {
return getPlatform();
};
const getPlatform = () => {
if (window.localStorage.getItem("platform")) {
return JSON.parse(window.localStorage.getItem("platform"));
}
var userAgent = window.navigator.userAgent,
platform = window.navigator.platform,
macosPlatforms = ["Macintosh", "MacIntel", "MacPPC", "Mac68K"],
windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"],
iosPlatforms = ["iPhone", "iPad", "iPod"],
os = null;
if (macosPlatforms.indexOf(platform) !== -1) {
os = false;
} else if (iosPlatforms.indexOf(platform) !== -1) {
os = true;
} else if (windowsPlatforms.indexOf(userAgent) !== -1) {
os = false;
} else if (/Android/.test(userAgent)) {
os = true;
} else if (!os && /Linux/.test(platform)) {
os = false;
}
return os;
}; };
const initialRenderer = () => { const initialRenderer = () => {
if (window.localStorage.getItem('renderer')) { if (window.localStorage.getItem("renderer")) {
return window.localStorage.getItem('renderer'); return window.localStorage.getItem("renderer");
} }
return 'geras'; return "geras";
}; };
const initialStatistics = () => { const initialStatistics = () => {
if (window.localStorage.getItem('statistics')) { if (window.localStorage.getItem("statistics")) {
return JSON.parse(window.localStorage.getItem('statistics')); return JSON.parse(window.localStorage.getItem("statistics"));
} }
return false; return false;
}; };
const initialState = { const initialState = {
pageVisits: 0, // detect if previous URL was pageVisits: 0, // detect if previous URL was
language: initialLanguage(), language: initialLanguage(),
renderer: initialRenderer(), renderer: initialRenderer(),
statistics: initialStatistics() statistics: initialStatistics(),
platform: initialPlatform(),
}; };
export default function foo(state = initialState, action) { export default function foo(state = initialState, action) {
@ -37,24 +71,30 @@ export default function foo(state = initialState, action){
case VISIT: case VISIT:
return { return {
...state, ...state,
pageVisits: state.pageVisits += 1 pageVisits: (state.pageVisits += 1),
}; };
case LANGUAGE: case LANGUAGE:
return { return {
...state, ...state,
language: action.payload language: action.payload,
};
case PLATFORM:
window.localStorage.setItem("platform", action.payload);
return {
...state,
platform: action.payload,
}; };
case RENDERER: case RENDERER:
window.localStorage.setItem('renderer', action.payload); window.localStorage.setItem("renderer", action.payload);
return { return {
...state, ...state,
renderer: action.payload renderer: action.payload,
}; };
case STATISTICS: case STATISTICS:
window.localStorage.setItem('statistics', action.payload); window.localStorage.setItem("statistics", action.payload);
return { return {
...state, ...state,
statistics: action.payload statistics: action.payload,
}; };
default: default:
return state; return state;