Merge branch 'dev' of lab.si.usi.ch:sa4-2020/the-sanmarinoes/frontend into base64

This commit is contained in:
Nicola Brunner 2020-03-24 15:55:51 +01:00
commit 10aeb75730
57 changed files with 2973 additions and 2463 deletions

View file

@ -42,3 +42,6 @@ smartHut_deploy:
- "docker push smarthutsm/smarthut:${CI_COMMIT_BRANCH}" - "docker push smarthutsm/smarthut:${CI_COMMIT_BRANCH}"
after_script: after_script:
- docker logout - docker logout
only:
- dev
- master

12
hooks/pre-commit.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
FILES=$(git diff --cached --name-only --diff-filter=ACMR "*.js" "*.jsx" | sed 's| |\\ |g')
[ -z "$FILES" ] && exit 0
# Prettify all selected files
echo "$FILES" | xargs ./smart-hut/node_modules/.bin/prettier --write
# Add back the modified/prettified files to staging
echo "$FILES" | xargs git add
exit 0

14
hooks/setup.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
git config --unset core.hooksPath
if [[ -z $(which realpath) ]]; then
this_dir="$(pwd)/hooks"
else
this_dir="$(dirname $(realpath "$0"))"
fi
hook_script="$this_dir/pre-commit.sh"
ln -svf "$hook_script" "$this_dir/../.git/hooks/pre-commit"
echo "Commit hook installed"

View file

@ -15,6 +15,7 @@
"react-axios": "^2.0.3", "react-axios": "^2.0.3",
"react-circular-input": "^0.1.6", "react-circular-input": "^0.1.6",
"react-circular-slider-svg": "^0.1.5", "react-circular-slider-svg": "^0.1.5",
"react-device-detect": "^1.11.14",
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
"react-round-slider": "^1.0.1", "react-round-slider": "^1.0.1",
"react-router": "^5.1.2", "react-router": "^5.1.2",
@ -43,5 +44,8 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"prettier": "2.0.1"
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View file

@ -1,21 +1,29 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head> <meta charset="utf-8" />
<meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="style.css"> <link
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css" /> rel="stylesheet"
<meta name="viewport" content="width=device-width, initial-scale=1" /> href="//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"
<meta name="theme-color" content="#000000" /> />
<meta name="description" content="Web site created using create-react-app" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" /> <meta name="theme-color" content="#000000" />
<!-- <meta
name="description"
content="Web site created using create-react-app"
/>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
<!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML. Only files inside the `public` folder can be referenced from the HTML.
@ -24,13 +32,13 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>React App</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!-- <!--
This HTML file is a template. This HTML file is a template.
If you open it directly in the browser, you will see an empty page. If you open it directly in the browser, you will see an empty page.
@ -40,6 +48,5 @@
To begin the development, run `npm start` or `yarn start`. To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> -->
</body> </body>
</html> </html>

View file

@ -1,8 +1,7 @@
{ {
"short_name": "React App", "short_name": "React App",
"name": "Create React App Sample", "name": "Create React App Sample",
"icons": [ "icons": [],
],
"start_url": ".", "start_url": ".",
"display": "standalone", "display": "standalone",
"theme_color": "#000000", "theme_color": "#000000",

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -1,7 +1,6 @@
*{ * {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: "Lato", Helvetica, SansSerif, serif; font-family: "Lato", Helvetica, SansSerif, serif;
} }
/*background: linear-gradient(to bottom, rgba(0, 46, 200, 0.51), rgba(0, 0, 0, 0.51));*/ /*background: linear-gradient(to bottom, rgba(0, 46, 200, 0.51), rgba(0, 0, 0, 0.51));*/

View file

@ -1,5 +1,5 @@
import React, {Component} from "react"; import React, { Component } from "react";
import {BrowserRouter, Switch, Route, Redirect } from "react-router-dom"; import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom";
import Home from "./views/Home"; import Home from "./views/Home";
import Dashboard from "./views/Dashboard"; import Dashboard from "./views/Dashboard";
import Signup from "./views/Signup"; import Signup from "./views/Signup";
@ -10,9 +10,9 @@ import ChangePass from "./views/Forgot-pass-reset";
import ConfirmForgotPasswrod from "./views/ConfirmForgotPassword"; import ConfirmForgotPasswrod from "./views/ConfirmForgotPassword";
import ConfirmRegistration from "./views/ConfirmRegistration"; import ConfirmRegistration from "./views/ConfirmRegistration";
import Instruction from "./views/Instruction"; import Instruction from "./views/Instruction";
import queryString from 'query-string'; import queryString from "query-string";
import { call } from './client_server'; import { call } from "./client_server";
/*let userJsonString = JSON.parse(localStorage.getItem("token")); /*let userJsonString = JSON.parse(localStorage.getItem("token"));
let date = new Date().getTime().toString(); let date = new Date().getTime().toString();
@ -27,20 +27,21 @@ class App extends Component {
let loggedIn = false; let loggedIn = false;
try { try {
let userJsonString = localStorage.getItem("token"); let userJsonString = localStorage.getItem("token");
let exp = localStorage.getItem("exp"); let exp = localStorage.getItem("exp");
let date = new Date().getTime(); let date = new Date().getTime();
if (userJsonString && exp && date < exp) { if (userJsonString && exp && date < exp) {
loggedIn = true; loggedIn = true;
} else {
localStorage.removeItem("token");
localStorage.removeItem("exp");
} }
}catch(exception) { } catch (exception) {}
} this.state = {
loggedIn: loggedIn,
this.state = { };
loggedIn: loggedIn,
};
this.auth = this.auth.bind(this); this.auth = this.auth.bind(this);
this.logout = this.logout.bind(this); this.logout = this.logout.bind(this);
@ -49,80 +50,89 @@ class App extends Component {
componentDidMount() { componentDidMount() {
if (window.location) { if (window.location) {
const values = queryString.parse(window.location.search); const values = queryString.parse(window.location.search);
console.log(values);
this.setState({ this.setState({
query : values query: values,
}); });
} else { } else {
this.setState({ this.setState({
query : "ciao" query: "ciao",
}); });
} }
} }
auth(data) { auth(data) {
return call.login(data.params) return call
.then(res => { .login(data.params)
.then((res) => {
if (res.data && res.status === 200) { if (res.data && res.status === 200) {
let expire = new Date().getTime() + 60 * 60 * 5 * 1000;
localStorage.setItem("token", res.data.jwttoken); localStorage.setItem("token", res.data.jwttoken);
localStorage.setItem("exp", new Date().getTime() + (60*60*5)) localStorage.setItem("exp", expire);
call.setToken(res.data.jwttoken); call.setToken(res.data.jwttoken);
this.setState( this.setState({
{ user: data.params.user,
user: data.params.user, token: res.data.jwttoken,
token: res.data.jwttoken, loggedIn: true,
loggedIn: true, });
}
);
return res; return res;
//this.props.history.push("/dashboard"); //this.props.history.push("/dashboard");
} else { } else {
this.setState({ this.setState({
error: res.data.message error: res.data.message,
}); });
return this.state.error; return this.state.error;
} }
}).catch(err => { })
console.log(err); .catch((err) => {
return {status : "Errore"}; console.log(err);
return { status: "Errore" };
}); });
}; }
logout() { logout() {
this.setState({ this.setState({
loggedIn : false, loggedIn: false,
}); });
localStorage.removeItem("token"); localStorage.removeItem("token");
}; localStorage.removeItem("exp");
}
render() { render() {
return ( return (
<BrowserRouter> <BrowserRouter>
<Switch> <Switch>
<Route path="/" exact component={Home} /> <Route path="/" exact component={Home} />
<Route path="/login" > <Route path="/login">
{ this.state.loggedIn && this.state.token ? <Redirect tkn={this.state.token} to="/dashboard" /> : <Login auth={this.auth} /> } {this.state.loggedIn && this.state.token ? (
<Redirect tkn={this.state.token} to="/dashboard" />
) : (
<Login auth={this.auth} />
)}
</Route> </Route>
<Route path="/signup" exact component={Signup} /> <Route path="/signup" exact component={Signup} />
<Route path="/dashboard" > <Route path="/dashboard">
{this.state.loggedIn ? <Dashboard tkn={this.state.token} logout={this.logout} /> : <Redirect to="/login" />} {this.state.loggedIn ? (
<Dashboard tkn={this.state.token} logout={this.logout} />
) : (
<Redirect to="/login" />
)}
</Route> </Route>
<Route path="/forgot-password" > <Route path="/forgot-password">
<ForgotPass /> <ForgotPass />
</Route> </Route>
<Route path="/sent-email" > <Route path="/sent-email">
<ConfirmForgotPasswrod /> <ConfirmForgotPasswrod />
</Route> </Route>
<Route path="/sent-email-reg" > <Route path="/sent-email-reg">
<ConfirmRegistration /> <ConfirmRegistration />
</Route> </Route>
<Route path="/instruction" > <Route path="/instruction">
<Instruction /> <Instruction />
</Route> </Route>
<Route path="/forgot-pass-reset" > </Route> <Route path="/forgot-pass-reset"> </Route>
<Route path="/password-reset" > <Route path="/password-reset">
<ChangePass query={this.state.query}/> <ChangePass query={this.state.query} />
</Route> </Route>
<Route component={FourOhFour} /> <Route component={FourOhFour} />
</Switch> </Switch>
@ -132,4 +142,3 @@ class App extends Component {
} }
export default App; export default App;

View file

@ -1,8 +1,8 @@
import React from 'react'; import React from "react";
import { render } from '@testing-library/react'; import { render } from "@testing-library/react";
import { Router } from "react-router"; import { Router } from "react-router";
import { createMemoryHistory } from "history"; import { createMemoryHistory } from "history";
import App from './App'; import App from "./App";
test("redirects to homepage", () => { test("redirects to homepage", () => {
const history = createMemoryHistory(); const history = createMemoryHistory();
@ -13,4 +13,3 @@ test("redirects to homepage", () => {
); );
expect(history.location.pathname).toBe("/"); expect(history.location.pathname).toBe("/");
}); });

View file

@ -1,90 +1,244 @@
import axios from 'axios'; // vim: set ts=2 sw=2 et tw=80:
let config = 'http://localhost:8080/'; import axios from "axios";
let config = "http://localhost:8080/";
var tkn = localStorage.getItem("token"); var tkn = localStorage.getItem("token");
/** the ServiceSocket instance valid for the current session */
var socket;
// requests data devices // requests data devices
/* /*
{ {
params : data, params : data,
device: 'tipoDiDevice', device: 'tipoDiDevice',
id: se serve id: se serve
} }
device routes: device routes:
- buttonDimmer - buttonDimmer
- dimmableLight - dimmableLight
- knobDimmer - knobDimmer
- motionSensor - motionSensor
- regularLight - regularLight
- sensor - sensor
- smartPlug - smartPlug
- switch - switch
*/ */
export var call = { /** The number of times a connection to the socket was tried */
setToken: function(token) { var retries = 0;
tkn = token;
}, /** Class to handle connection with the sensor socket */
login: function(data, headers) { class ServiceSocket {
return axios.post(config +'auth/login', data) /**
}, * Create a new sensor socket connection
register: function(data, headers) { * @param {string} token - The JWT token (needed for authentication)
return axios.post(config + 'register', data) * @param {Object.<number, function>|null} callbacks - A callback map from
}, * device id to callback function
initResetPassword: function(data, headers) { */
return axios.post(config + 'register/init-reset-password', data) constructor(token, callbacks) {
}, this.token = token;
resetPassword: function(data, headers) { this.authenticated = false;
return axios.put(config + 'register/reset-password', data) this.callbacks = callbacks || {};
},
getAllRooms: function(token) { this.connection = new WebSocket("ws://localhost:8080/sensor-socket");
if (!token){
token = tkn; this.connection.onopen = (evt) => {
this.connection.send(JSON.stringify({ token }));
};
this.connection.onmessage = (evt) => {
let data = JSON.parse(evt.data);
if (!this.authenticated) {
if (data.authenticated) {
this.authenticated = true;
retries = 0;
} else {
console.error("socket authentication failed");
} }
return axios.get(config + 'room', { headers: { Authorization : "Bearer " + token } }) } else {
}, if (data.id && this.callbacks[data.id]) {
getAllDevices: function(token) { this.callbacks[data.id].forEach((f) => f(data));
if (!token){
token = tkn;
} }
return axios.get(config + 'device', { headers: { Authorization : "Bearer " + token } }); }
}, };
getAllDevicesByRoom: function(id, token) {
if (!token){ this.connection.onerror = (evt) => {
token = tkn; if (retries >= 5) {
} console.error("too many socket connection retries");
return axios.get(config + 'room/' + id + '/devices' , { headers: { Authorization : "Bearer " + token } }); return;
}, }
createRoom: function(data, headers) { retries++;
return axios.post(config + 'room', data, { headers: { Authorization : "Bearer " + tkn } }) socket = new ServiceSocket(this.token, this.callbacks);
}, };
updateRoom: function(data, headers) { }
return axios.put(config + 'room?name='+ data.name, data, { headers: { Authorization : "Bearer " + tkn } })
}, /**
deleteRoom: function(data, headers) { * Registers a new callback function to be called when updates on the device
return axios.delete(config + 'room/'+data.id, { headers: { Authorization : "Bearer " + tkn } }); * with the id given are recieved
}, * @param {number} id - the id of the device to check updates for
devicePost: function(data, headers) { * @param {function} stateCallback - a function that recieves a device as the
return axios.post(config + data.device, data.params, { headers: { Authorization : "Bearer " + tkn } }) * first parameter, that will be called whenever a update is recieved
}, */
deviceUpdate: function(data, typeDevice) { subscribe(id, stateCallback) {
let url = 'device'; if (this.callbacks[id] === undefined) {
if (typeDevice) { this.callbacks[id] = [];
url = typeDevice;
}
return axios.put(config + url, data, { headers: { Authorization : "Bearer " + tkn } })
},
deviceDelete: function(data, headers) {
return axios.delete(config + data.device + '/' + data.id, {}, { headers: { Authorization : "Bearer " + tkn } })
},
deviceGetById: function(data, headers) {
return axios.get(config + data.device + '/' + data.id)
},
deviceGetAll: function(data, headers) {
return axios.get(config + data.device)
} }
this.callbacks[id].push(stateCallback);
}
/**
* Unregisters a function previously registered with `subscribe(...)`.
* @param {number} id - the id of the device to stop checking updates for
* @param {function} stateCallback - the callback to unregister
*/
unsubscribe(id, stateCallback) {
this.callbacks[id].splice(this.callbacks[id].indexOf(stateCallback), 1);
}
/**
* Closes the underlying websocket connection
*/
close() {
this.connection.close();
}
}
if (tkn) {
socket = new ServiceSocket(tkn);
}
export var call = {
setToken: function (token) {
tkn = token;
if (tkn) {
if (socket) {
socket.close();
}
socket = new ServiceSocket(tkn);
}
},
/**
* Registers a new callback function to be called when updates on the device
* with the id given are recieved
* @param {number} id - the id of the device to check updates for
* @param {function} stateCallback - a function that recieves a device as the
* first parameter, that will be called whenever a update is recieved
*/
socketSubscribe: function (id, callback) {
socket.subscribe(id, callback);
},
/**
* Unregisters a function previously registered with `subscribe(...)`.
* @param {number} id - the id of the device to stop checking updates for
* @param {function} stateCallback - the callback to unregister
*/
socketUnsubscribe: function (id, callback) {
socket.unsubscribe(id, callback);
},
login: function (data, headers) {
return axios.post(config + "auth/login", data);
},
register: function (data, headers) {
return axios.post(config + "register", data);
},
initResetPassword: function (data, headers) {
return axios.post(config + "register/init-reset-password", data);
},
resetPassword: function (data, headers) {
return axios.put(config + "register/reset-password", data);
},
getAllRooms: function (token) {
if (!token) {
token = tkn;
}
return axios.get(config + "room", {
headers: { Authorization: "Bearer " + token },
});
},
getAllDevices: function (token) {
if (!token) {
token = tkn;
}
return axios.get(config + "device", {
headers: { Authorization: "Bearer " + token },
});
},
getAllDevicesByRoom: function (id, token) {
if (!token) {
token = tkn;
}
return axios.get(config + "room/" + id + "/devices", {
headers: { Authorization: "Bearer " + token },
});
},
createRoom: function (data, headers) {
return axios.post(config + "room", data, {
headers: { Authorization: "Bearer " + tkn },
});
},
updateRoom: function (data, headers) {
return axios.put(config + "room/" + data.id, data, {
headers: { Authorization: "Bearer " + tkn },
});
},
deleteRoom: function (data, headers) {
return axios.delete(config + "room/" + data.id, {
headers: { Authorization: "Bearer " + tkn },
});
},
devicePost: function (data, headers) {
return axios
.post(config + data.device, data.params, {
headers: { Authorization: "Bearer " + tkn },
})
.then((res) => {
if (res.status === 200 && data.device === "switch") {
data.params.lights.forEach((e) => {
let urlUp =
config +
data.device +
"/" +
res.data.id +
"/lights?switchableId=" +
e;
axios.post(
urlUp,
{},
{ headers: { Authorization: "Bearer " + tkn } }
);
});
}
return res;
});
},
deviceUpdate: function (data, typeDevice) {
let url = "device";
if (typeDevice) {
url = typeDevice;
}
return axios.put(config + url, data, {
headers: { Authorization: "Bearer " + tkn },
});
},
deviceDelete: function (data, headers) {
return axios.delete(config + data.device + "/" + data.id, {
headers: { Authorization: "Bearer " + tkn },
});
},
deviceGetById: function (data, headers) {
return axios.get(config + data.device + "/" + data.id);
},
deviceGetAll: function (data, headers) {
return axios.get(config + data.device);
},
}; };

View file

@ -1,69 +1,82 @@
import React from 'react'; import React from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from "@material-ui/core/styles";
import Paper from '@material-ui/core/Paper'; import Paper from "@material-ui/core/Paper";
import Typography from '@material-ui/core/Typography'; import Typography from "@material-ui/core/Typography";
import Grid from '@material-ui/core/Grid'; import Grid from "@material-ui/core/Grid";
import Link from '@material-ui/core/Link'; import Link from "@material-ui/core/Link";
const useStyles = makeStyles(theme => ({ const useStyles = makeStyles((theme) => ({
mainFeaturedPost: { mainFeaturedPost: {
position: 'relative', position: "relative",
backgroundColor: theme.palette.grey[800], backgroundColor: theme.palette.grey[800],
color: theme.palette.common.white, color: theme.palette.common.white,
marginBottom: theme.spacing(4), marginBottom: theme.spacing(4),
backgroundImage: 'img/banner.jpg', backgroundImage: "img/banner.jpg",
backgroundSize: 'cover', backgroundSize: "cover",
backgroundRepeat: 'no-repeat', backgroundRepeat: "no-repeat",
backgroundPosition: 'center', backgroundPosition: "center",
}, },
overlay: { overlay: {
position: 'absolute', position: "absolute",
top: 0, top: 0,
bottom: 0, bottom: 0,
right: 0, right: 0,
left: 0, left: 0,
backgroundColor: 'rgba(0,0,0,.3)', backgroundColor: "rgba(0,0,0,.3)",
}, },
mainFeaturedPostContent: { mainFeaturedPostContent: {
position: 'relative', position: "relative",
padding: theme.spacing(3), padding: theme.spacing(3),
[theme.breakpoints.up('md')]: { [theme.breakpoints.up("md")]: {
padding: theme.spacing(6), padding: theme.spacing(6),
paddingRight: 0, paddingRight: 0,
},
}, },
},
})); }));
export default function Banner(props) { export default function Banner(props) {
const classes = useStyles(); const classes = useStyles();
const { post } = props; const { post } = props;
return ( return (
<Paper className={classes.mainFeaturedPost} style={{ backgroundImage: `url(${post.image})` }}> <Paper
{/* Increase the priority of the hero background image */} className={classes.mainFeaturedPost}
{<img style={{ display: 'none' }} src={post.image} alt={post.imageText} />} style={{ backgroundImage: `url(${post.image})` }}
<div className={classes.overlay} /> >
<Grid container> {/* Increase the priority of the hero background image */}
<Grid item md={6}> {
<div className={classes.mainFeaturedPostContent}> <img
<Typography component="h1" variant="h3" color="inherit" gutterBottom> style={{ display: "none" }}
{post.title} src={post.image}
</Typography> alt={post.imageText}
<Typography variant="h5" color="inherit" paragraph> />
{post.description} }
</Typography> <div className={classes.overlay} />
<Link variant="subtitle1" href="#"> <Grid container>
{post.linkText} <Grid item md={6}>
</Link> <div className={classes.mainFeaturedPostContent}>
</div> <Typography
</Grid> component="h1"
</Grid> variant="h3"
</Paper> color="inherit"
); gutterBottom
>
{post.title}
</Typography>
<Typography variant="h5" color="inherit" paragraph>
{post.description}
</Typography>
<Link variant="subtitle1" href="#">
{post.linkText}
</Link>
</div>
</Grid>
</Grid>
</Paper>
);
} }
Banner.propTypes = { Banner.propTypes = {
post: PropTypes.object, post: PropTypes.object,
}; };

View file

@ -1,9 +1,9 @@
import React from 'react'; import React from "react";
export default function Footer() { export default function Footer() {
return( return (
<div> <div>
<p>This is the footer</p> <p>This is the footer</p>
</div> </div>
) );
} }

View file

@ -1,73 +1,78 @@
import React from 'react'; import React from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from "@material-ui/core/styles";
import Toolbar from '@material-ui/core/Toolbar'; import Toolbar from "@material-ui/core/Toolbar";
import Button from '@material-ui/core/Button'; import Button from "@material-ui/core/Button";
import IconButton from '@material-ui/core/IconButton'; import IconButton from "@material-ui/core/IconButton";
import SearchIcon from '@material-ui/icons/Search'; import SearchIcon from "@material-ui/icons/Search";
import Typography from '@material-ui/core/Typography'; import Typography from "@material-ui/core/Typography";
import Link from '@material-ui/core/Link'; import Link from "@material-ui/core/Link";
const useStyles = makeStyles(theme => ({ const useStyles = makeStyles((theme) => ({
toolbar: { toolbar: {
borderBottom: `1px solid ${theme.palette.divider}`, borderBottom: `1px solid ${theme.palette.divider}`,
}, },
toolbarTitle: { toolbarTitle: {
flex: 1, flex: 1,
}, },
toolbarSecondary: { toolbarSecondary: {
justifyContent: 'space-between', justifyContent: "space-between",
overflowX: 'auto', overflowX: "auto",
}, },
toolbarLink: { toolbarLink: {
padding: theme.spacing(1), padding: theme.spacing(1),
flexShrink: 0, flexShrink: 0,
}, },
})); }));
export default function Header(props) { export default function Header(props) {
const classes = useStyles(); const classes = useStyles();
const { sections, title } = props; const { sections, title } = props;
return ( return (
<React.Fragment> <React.Fragment>
<Toolbar className={classes.toolbar}> <Toolbar className={classes.toolbar}>
<Typography <Typography
component="h2" component="h2"
variant="h5" variant="h5"
color="inherit" color="inherit"
align="center" align="center"
noWrap noWrap
className={classes.toolbarTitle} className={classes.toolbarTitle}
> >
{title} {title}
</Typography> </Typography>
<Toolbar component="nav" variant="dense" className={classes.toolbarSecondary}> <Toolbar
{sections.map(section => ( component="nav"
<Link variant="dense"
color="inherit" className={classes.toolbarSecondary}
noWrap >
key={section.title} {sections.map((section) => (
variant="body2" <Link
href={section.url} color="inherit"
className={classes.toolbarLink} noWrap
> key={section.title}
{section.title} variant="body2"
</Link> href={section.url}
))} className={classes.toolbarLink}
</Toolbar> >
<Button size="small" variant="outlined" style={{margin: "0 1rem"}}>Login</Button> {section.title}
</Link>
))}
</Toolbar>
<Button size="small" variant="outlined" style={{ margin: "0 1rem" }}>
Login
</Button>
<Button variant="outlined" size="small">
<Button variant="outlined" size="small"> Sign up
Sign up </Button>
</Button> </Toolbar>
</Toolbar> </React.Fragment>
</React.Fragment> );
);
} }
Header.propTypes = { Header.propTypes = {
sections: PropTypes.array, sections: PropTypes.array,
title: PropTypes.string, title: PropTypes.string,
}; };

View file

@ -1,52 +1,103 @@
import React from "react"; import React from "react";
import { Dropdown, Icon, Grid, Divider} from 'semantic-ui-react' import { Dropdown, Icon, Grid, Divider } from "semantic-ui-react";
import { Segment, Image } from 'semantic-ui-react' import { Segment, Image } from "semantic-ui-react";
import {
BrowserView,
MobileView,
isBrowser,
isMobile
} from "react-device-detect";
const AvatarImage = () => ( const AvatarImage = () => (
<Image <Image
src='avatar3.png' src="avatar3.png"
style={{width: '25px', height: 'auto'}} style={{ width: "25px", height: "auto" }}
centered centered />
/> );
)
const IconHomeImage = () => ( const IconHomeImage = () => (
<Image <Image
src='smart-home.png' src="smart-home.png"
style={{width: '50px', height: 'auto'}} style={{ width: "50px", height: "auto" }}
centered centered
as='a' as="a"
href='/' href="/"
/> />
) );
const IconHomeImageMobile = () => (
<Image
src="smart-home.png"
style={{ width: "10px", height: "auto" }}
centered
as="a"
href="/"
/>
);
const TitleImage = () => ( const TitleImage = () => (
<Image src='title7.png' size='medium' centered/> <Image
) src="title7.png"
size="medium"
centered
/>
);
const BrowserStructure = (props) => (
<Grid columns="equal" divided inverted padded>
const GridExampleInverted = (props) => ( <Grid.Row color="black" textAlign="center">
<Grid columns='equal' divided inverted padded> <Grid.Column width={3} height={0.5}>
<Grid.Row color='black' textAlign='center' > <Segment color="black" inverted>
<Grid.Column width={3} height={0.5}> <IconHomeImage />
<Segment color='black' inverted> </Segment>
<IconHomeImage /> </Grid.Column>
</Segment> <Grid.Column>
</Grid.Column> <Segment color="black" inverted>
<Grid.Column>
<Segment color='black' inverted>
<TitleImage /> <TitleImage />
</Segment> </Segment>
</Grid.Column> </Grid.Column>
<Grid.Column width={2} heigth={1}> <Grid.Column width={2} heigth={1}>
<AvatarImage /> <AvatarImage />
<Divider /> <Divider />
<Dropdown item icon='setting' size='huge'> <Dropdown item icon="setting" size="huge">
<Dropdown.Menu>
<Dropdown.Item>
<Icon name="dropdown" />
<span className="text">Settings</span>
<Dropdown.Menu>
<Dropdown.Item>Document</Dropdown.Item>
<Dropdown.Item>Image</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Item>
<Dropdown.Item>See profile...</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item onClick={props.logout}>Logout</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</Grid.Column>
</Grid.Row>
</Grid>
);
const MobileStructure = (props) => (
<Grid columns="equal" divided inverted padded>
<Grid.Row color="black" textAlign="center">
<Segment color="black" inverted>
<TitleImage />
</Segment>
</Grid.Row>
<Grid.Row color="black" textAlign="center">
<Grid.Column>
<IconHomeImage />
</Grid.Column>
<Grid.Column >
<AvatarImage />
<Divider />
<Dropdown item icon="setting" size="huge">
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item> <Dropdown.Item>
<Icon name='dropdown' /> <Icon name="dropdown" />
<span className='text'>Settings</span> <span className="text">Settings</span>
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item>Document</Dropdown.Item> <Dropdown.Item>Document</Dropdown.Item>
<Dropdown.Item>Image</Dropdown.Item> <Dropdown.Item>Image</Dropdown.Item>
@ -54,135 +105,32 @@ const GridExampleInverted = (props) => (
</Dropdown.Item> </Dropdown.Item>
<Dropdown.Item>See profile...</Dropdown.Item> <Dropdown.Item>See profile...</Dropdown.Item>
<Dropdown.Divider /> <Dropdown.Divider />
<Dropdown.Item onClick={props.logout }>Logout</Dropdown.Item> <Dropdown.Item onClick={props.logout}>Logout</Dropdown.Item>
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>
) );
export default class MyHeader extends React.Component { export default class MyHeader extends React.Component {
render() { render() {
return ( return (
<div> <div>
<GridExampleInverted logout={this.props.logout} /> <BrowserView>
</div> <BrowserStructure logout={this.props.logout} />
); </BrowserView>
} <MobileView>
<MobileStructure />
</MobileView>
</div>
);
} }
}
// const navbar = {
// backgroundColor: "#20222b",
// color: "white",
// marginBottom: "4.6rem",
// padding: "3.2rem 0"
// };
// const navbar__buttons = {
// borderBottom: "1px solid lighten($light-blue, 10%)",
// display: "flex",
// justifyContent: "space-between",
// padding: "3.2rem 1.6rem"
// }
// const button = {
// background: "#8357c5",
// border: "none",
// borderBottom: "1px solid purple",
// color: "white",
// fontWeight: "500",
// padding: "1.2rem"
// }
// const MenuExampleButtons = () => (
// <Menu>
// <Menu.Item>
// <Button primary>Sign up</Button>
// </Menu.Item>
// <Menu.Item>
// <Button>Log-in</Button>
// </Menu.Item>
// <Menu.Item>
// <Button>Log-in</Button>
// </Menu.Item>
// <Menu.Item>
// <Button>Log-in</Button>
// </Menu.Item>
// </Menu>
// )
// class MenuExampleInvertedSegment extends Component {
// state = { activeItem: 'home' }
// handleItemClick = (e, { name }) => this.setState({ activeItem: name })
// render() {
// const { activeItem } = this.state
// return (
// <Segment inverted>
// <Menu inverted secondary>
// <Menu.Item
// name='home'
// active={activeItem === 'home'}
// onClick={this.handleItemClick}
// />
// <Menu.Item
// name='messages'
// active={activeItem === 'messages'}
// onClick={this.handleItemClick}
// />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item />
// <HeaderExampleIconProp />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item />
// <Menu.Item
// name='messages'
// active={activeItem === 'messages'}
// onClick={this.handleItemClick}
// />
// <Dropdown item icon='wrench' simple>
// <Dropdown.Menu>
// <Dropdown.Item>
// <Icon name='dropdown' />
// <span className='text'>New</span>
// <Dropdown.Menu>
// <Dropdown.Item>Document</Dropdown.Item>
// <Dropdown.Item>Image</Dropdown.Item>
// </Dropdown.Menu>
// </Dropdown.Item>
// <Dropdown.Item>Open</Dropdown.Item>
// <Dropdown.Item>Save...</Dropdown.Item>
// <Dropdown.Item>Edit Permissions</Dropdown.Item>
// <Dropdown.Divider />
// <Dropdown.Header>Export</Dropdown.Header>
// <Dropdown.Item>Share</Dropdown.Item>
// </Dropdown.Menu>
// </Dropdown>
// <ImageExampleWrapped />
// <Menu.Item />
// </Menu>
// </Segment>
// )
// }
// }

View file

@ -6,77 +6,81 @@ import {
Image, Image,
Menu, Menu,
Sidebar, Sidebar,
Responsive Responsive,
} from "semantic-ui-react"; } from "semantic-ui-react";
const NavBarMobile = ({ const NavBarMobile = ({
children, children,
leftItems, leftItems,
onPusherClick, onPusherClick,
onToggle, onToggle,
rightItems, rightItems,
visible visible,
}) => ( }) => (
<Sidebar.Pushable> <Sidebar.Pushable>
<Sidebar <Sidebar
as={Menu} as={Menu}
animation="overlay" animation="overlay"
icon="labeled" icon="labeled"
inverted inverted
items={leftItems} items={leftItems}
vertical vertical
visible={visible} visible={visible}
/> />
<Sidebar.Pusher <Sidebar.Pusher
dimmed={visible} dimmed={visible}
onClick={onPusherClick} onClick={onPusherClick}
style={{ minHeight: "100vh" }} style={{ minHeight: "100vh" }}
> >
<Menu fixed="top" inverted> <Menu fixed="top" inverted>
<Menu.Item> <Menu.Item>
<Image size="mini" src="smart-home_index.png" /> <Image size="mini" src="smart-home_index.png" />
</Menu.Item> </Menu.Item>
<Menu.Item onClick={onToggle}> <Menu.Item onClick={onToggle}>
<Icon name="sidebar" /> <Icon name="sidebar" />
</Menu.Item> </Menu.Item>
<Menu.Menu position="right"> <Menu.Menu position="right">
{_.map(rightItems, item => <Menu.Item {...item} />)} {_.map(rightItems, (item) => (
</Menu.Menu> <Menu.Item {...item} />
</Menu> ))}
{children} </Menu.Menu>
</Sidebar.Pusher> </Menu>
</Sidebar.Pushable> {children}
); </Sidebar.Pusher>
</Sidebar.Pushable>
const NavBarDesktop = ({ leftItems, rightItems }) => ( );
<Menu fixed="top" inverted>
<Menu.Item> const NavBarDesktop = ({ leftItems, rightItems }) => (
<Image size="mini" src="smart-home_index.png" /> <Menu fixed="top" inverted>
</Menu.Item> <Menu.Item>
{_.map(leftItems, item => <Menu.Item {...item} />)} <Image size="mini" src="smart-home_index.png" />
<Menu.Menu position="right"> </Menu.Item>
{_.map(rightItems, item => <Menu.Item {...item} />)} {_.map(leftItems, (item) => (
</Menu.Menu> <Menu.Item {...item} />
</Menu> ))}
); <Menu.Menu position="right">
{_.map(rightItems, (item) => (
const NavBarChildren = ({ children }) => ( <Menu.Item {...item} />
<Container style={{ marginTop: "5em" }}>{children}</Container> ))}
); </Menu.Menu>
</Menu>
);
const NavBarChildren = ({ children }) => (
<Container style={{ marginTop: "5em" }}>{children}</Container>
);
class HomeNavabarApp extends Component { class HomeNavabarApp extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
logged : true, logged: true,
email: "", email: "",
password : "" password: "",
}; };
} }
state = { state = {
visible: false visible: false,
}; };
handlePusher = () => { handlePusher = () => {
@ -113,17 +117,17 @@ class HomeNavabarApp extends Component {
} }
} }
const leftItems = [ const leftItems = [{ as: "a", content: "Home", key: "home", href: "/" }];
{ as: "a", content: "Home", key: "home", href:"/" }, const rightItems = [
]; { as: "a", content: "Login", key: "login", href: "/login" },
const rightItems = [ { as: "a", content: "Sign up", key: "register", href: "/signup" },
{ as: "a", content: "Login", key: "login", href:"/login" }, ];
{ as: "a", content: "Sign up", key: "register", href:"/signup" }
];
const HomeNavbarApp = () => ( const HomeNavbarApp = () => (
<HomeNavabarApp leftItems={leftItems} rightItems={rightItems}> <HomeNavabarApp
</HomeNavabarApp> leftItems={leftItems}
); rightItems={rightItems}
></HomeNavabarApp>
);
export default HomeNavbarApp; export default HomeNavbarApp;

View file

@ -2,32 +2,32 @@ import React, { Component } from 'react';
import { Button, Grid, Responsive } from 'semantic-ui-react' import { Button, Grid, Responsive } from 'semantic-ui-react'
export default class SelectIcons extends Component { export default class SelectIcons extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
currentIcon: this.props.currentIcon currentIcon: this.props.currentIcon,
} };
} }
selectIcon = (e) => { selectIcon = (e) => {
let el = e.target.name; let el = e.target.name;
if (e.target.tagName === "I"){ if (e.target.tagName === "I") {
console.log(e.target.parentNode);
el = e.target.parentNode.name; el = e.target.parentNode.name;
} }
this.props.updateIcon(el); this.props.updateIcon(el);
this.setState({currentIcon : el}) this.setState({ currentIcon: el });
} };
render(){ render() {
const myicons = [['home', 'coffee', 'beer', 'glass martini', 'film', 'video'], const myicons = [
['music', 'headphones', 'fax', 'phone', 'laptop','bath'], ["home", "coffee", "beer", "glass martini", "film", "video"],
['shower', 'bed', 'child', 'warehouse', 'car', 'bicycle'], ["music", "headphones", "fax", "phone", "laptop", "bath"],
['motorcycle', 'archive', 'boxes', 'cubes', 'chess', 'gamepad'], ["shower", "bed", "child", "warehouse", "car", "bicycle"],
['futbol', 'table tennis', 'server', 'tv', 'heart', 'camera'], ["motorcycle", "archive", "boxes", "cubes", "chess", "gamepad"],
['trophy', 'wrench', 'image', 'book', 'university', 'medkit'], ["futbol", "table tennis", "server", "tv", "heart", "camera"],
['paw', 'tree', 'utensils', 'male', 'female', 'life ring outline']]; ["trophy", "wrench", "image", "book", "university", "medkit"],
["paw", "tree", "utensils", "male", "female", "life ring outline"],
];
return ( return (
<Grid centered relaxed> <Grid centered relaxed>
@ -35,16 +35,23 @@ export default class SelectIcons extends Component {
myicons.map((e, i) => { myicons.map((e, i) => {
return ( return (
<Grid.Row key={i}> <Grid.Row key={i}>
{e.map((e, i) => { {e.map((e, i) => {
return(<Grid.Column key={i}> return (
<Button name={e} color={e === this.state.currentIcon ? "black" : null } icon={e} size="small" onClick={this.selectIcon}/> <Grid.Column key={i}>
</Grid.Column>) <Button
})} name={e}
color={e === this.state.currentIcon ? "black" : null}
icon={e}
size="small"
onClick={this.selectIcon}
/>
</Grid.Column>
);
})}
</Grid.Row> </Grid.Row>
) );
}) })}
} </Grid>
</ Grid> );
)
} }
} }

View file

@ -1,175 +1,180 @@
import React, {Component} from 'react'; // vim: set ts=2 sw=2 et tw=80:
import {
Grid, import React, { Component } from "react";
} from "semantic-ui-react"; import { Grid } from "semantic-ui-react";
import {editButtonStyle, panelStyle} from "./devices/styleComponents"; import { editButtonStyle, panelStyle } from "./devices/styleComponents";
import {checkMaxLength, DEVICE_NAME_MAX_LENGTH} from "./devices/constants"; import { checkMaxLength, DEVICE_NAME_MAX_LENGTH } from "./devices/constants";
import DeviceType from './devices/DeviceTypeController'; import DeviceType from "./devices/DeviceTypeController";
import NewDevice from "./devices/NewDevice"; import NewDevice from "./devices/NewDevice";
import SettingsModal from "./devices/SettingsModal"; import SettingsModal from "./devices/SettingsModal";
import { call } from '../../client_server'; import { call } from "../../client_server";
export default class DevicePanel extends Component { export default class DevicePanel extends Component {
constructor(props) {
constructor(props) { super(props);
super(props); this.state = {
this.state = { editMode: false,
editMode : false,
};
this.addDevice = this.addDevice.bind(this);
}
editModeController = (e) => this.setState((prevState) => ({ editMode: !prevState.editMode }));
openModal = (settingsDeviceId) => {
this.setState(prevState => ({
openSettingsModal: !prevState.openSettingsModal,
settingsDeviceId: settingsDeviceId
}))
}
changeDeviceData = (deviceId, newSettings) => {
console.log(newSettings.name, " <-- new name --> ", deviceId );
this.props.devices.map(device => {
if(device.id === deviceId){
for(let prop in newSettings){
if(device.hasOwnProperty(prop)){
if(prop==="name"){
if(checkMaxLength(newSettings[prop])){
device[prop] = newSettings[prop];
}
else{
alert("Name must be less than " + DEVICE_NAME_MAX_LENGTH + " characters.");
}
}else{
device[prop] = newSettings[prop];
}
}
}
}
return null;
});
this.forceUpdate();
}; };
getDevices() { this.addDevice = this.addDevice.bind(this);
if (this.props.activeItem === -1) { }
call.getAllDevices()
.then(res => {
if ( res.status === 200) {
this.setState({
devices: res.data
});
}
}).catch(err => {
console.log(err);
});
} else {
call.getAllDevicesByRoom(this.props.activeItem)
.then(res => {
if (res.status === 200) {
this.setState({
devices: res.data
});
}
}).catch(err => {
}); editModeController = (e) =>
} this.setState((prevState) => ({ editMode: !prevState.editMode }));
}
async addDevice(data) { openModal = (settingsDeviceId) => {
const ds = await this.props.addDevice(data); this.setState((prevState) => ({
this.setState({ openSettingsModal: !prevState.openSettingsModal,
devices: ds settingsDeviceId: settingsDeviceId,
}); }));
this.forceUpdate(); };
}
updateDevice = (data) => { changeDeviceData = (deviceId, newSettings) => {
const roomId = this.props.devices.filter(d => d.id === this.state.settingsDeviceId)[0].roomId; console.log(newSettings.name, " <-- new name --> ", deviceId);
console.log(roomId) this.props.devices.map((device) => {
data["id"] = this.state.settingsDeviceId; if (device.id === deviceId) {
data["roomId"] = roomId; for (let prop in newSettings) {
call.deviceUpdate(data) if (device.hasOwnProperty(prop)) {
.then(res => { if (prop === "name") {
if (res.status === 200) { if (checkMaxLength(newSettings[prop])) {
this.getDevices(); device[prop] = newSettings[prop];
this.forceUpdate(); } else {
alert(
"Name must be less than " +
DEVICE_NAME_MAX_LENGTH +
" characters."
);
}
} else {
device[prop] = newSettings[prop];
} }
}).catch(err => { }
}
}) }
} return null;
});
removeDevice = () => { this.forceUpdate();
const item = this.props.devices.filter(d => d.id === this.state.settingsDeviceId)[0]; };
console.log(item)
const data = {
device: item.kind,
id: this.state.settingsDeviceId
};
call.deviceDelete(data)
.then(res => {
console.log(res)
if (res.status === 200) {
this.getDevices();
}
}).catch(err => {
getDevices() {
if (this.props.activeItem === -1) {
call
.getAllDevices()
.then((res) => {
if (res.status === 200) {
this.setState({
devices: res.data,
}); });
}
})
.catch((err) => {
console.log(err);
});
} else {
call
.getAllDevicesByRoom(this.props.activeItem)
.then((res) => {
if (res.status === 200) {
this.setState({
devices: res.data,
});
}
})
.catch((err) => {});
} }
}
async addDevice(data) {
const ds = await this.props.addDevice(data);
this.setState({
devices: ds,
});
this.forceUpdate();
}
updateDevice = (data) => {
const roomId = this.props.devices.filter(
(d) => d.id === this.state.settingsDeviceId
)[0].roomId;
console.log(roomId);
data["id"] = this.state.settingsDeviceId;
data["roomId"] = roomId;
console.log(data);
call
.deviceUpdate(data)
.then((res) => {
if (res.status === 200) {
this.getDevices();
this.forceUpdate();
}
})
.catch((err) => {});
};
removeDevice = () => {
const item = this.props.devices.filter(
(d) => d.id === this.state.settingsDeviceId
)[0];
const data = {
device: item.kind,
id: this.state.settingsDeviceId,
};
call
.deviceDelete(data)
.then((res) => {
if (res.status === 200) {
this.openModal();
this.getDevices();
this.forceUpdate();
}
})
.catch((err) => {});
};
render() {
render() { const edit = {
const edit = { mode: this.state.editMode,
mode: this.state.editMode, openModal: this.openModal,
openModal: this.openModal, };
}; const ds = this.state.devices ? this.state.devices : this.props.devices;
const ds = this.state.devices ? this.state.devices : this.props.devices; return (
return ( <div style={panelStyle}>
<div style={panelStyle}> <button style={editButtonStyle} onClick={this.editModeController}>
<button style={editButtonStyle} onClick={this.editModeController}>Edit</button> Edit
<Grid doubling columns={4} divided="vertically"> </button>
{this.state.openSettingsModal ? <Grid doubling columns={4} divided="vertically">
<SettingsModal openModal={this.openModal} {this.state.openSettingsModal ? (
updateDevice={this.updateDevice} <SettingsModal
removeDevice={this.removeDevice} openModal={this.openModal}
device={ds.filter(d => d.id === this.state.settingsDeviceId)[0]}/> : "" updateDevice={this.updateDevice}
} removeDevice={this.removeDevice}
{ device={ds.filter((d) => d.id === this.state.settingsDeviceId)[0]}
ds ? />
ds.map((e, i) => { ) : (
""
return ( )}
<Grid.Column key={i}> {ds
<DeviceType type={e.kind} onChangeData={this.changeDeviceData} device={e} edit={edit}/> ? ds.map((e, i) => {
</Grid.Column> return (
) <Grid.Column key={i}>
}) <DeviceType
: type={e.kind}
null onChangeData={this.changeDeviceData}
} device={e}
{ edit={edit}
this.props.activeItem !== -1 ? />
<Grid.Column> </Grid.Column>
<NewDevice addDevice={this.addDevice} devices={ds}/> );
</Grid.Column> })
: : null}
null {this.props.activeItem !== -1 ? (
} <Grid.Column>
</Grid> <NewDevice addDevice={this.addDevice} devices={ds} />
</div> </Grid.Column>
) ) : null}
} </Grid>
</div>
} );
}
}

View file

@ -1,34 +1,26 @@
import React, {Component} from "react"; import React, { Component } from "react";
import {editModeIconStyle, editModeStyle} from "./styleComponents"; import { editModeIconStyle, editModeStyle } from "./styleComponents";
export default class Settings extends Component { export default class Settings extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
displayForm: true, displayForm: true,
} };
}; }
displayForm = () => { displayForm = () => {
this.setState((prevState) => ({displayForm: !prevState.displayForm})); this.setState((prevState) => ({ displayForm: !prevState.displayForm }));
}; };
render() { render() {
const view = ( const view = (
<div onClick={() => this.props.edit.openModal(this.props.deviceId)}> <div onClick={() => this.props.edit.openModal(this.props.deviceId)}>
<span style={editModeStyle}> <span style={editModeStyle}>
<img <img src="/img/settings.svg" alt="" style={editModeIconStyle} />
src="/img/settings.svg" </span>
alt="" </div>
style={editModeIconStyle}/>
</span>
</div>
); );
return ( return <React.Fragment>{this.props.edit.mode ? view : ""}</React.Fragment>;
<React.Fragment> }
{this.props.edit.mode ? view : ("")}
</React.Fragment>
)
};
} }

View file

@ -1,28 +1,63 @@
import React from 'react'; import React from "react";
import Light from "./Light"; import Light from "./Light";
import SmartPlug from "./SmartPlug"; import SmartPlug from "./SmartPlug";
import Sensor from "./Sensor"; import Sensor from "./Sensor";
import DefaultDimmer from "./Dimmer"; import DefaultDimmer from "./Dimmer";
import Switcher from "./Switch"; import Switcher from "./Switch";
const DeviceType = (props) => { const DeviceType = (props) => {
switch(props.type) { switch (props.type) {
case "regular-light": case "regularLight":
return (<Light onChangeData={props.changeDeviceData} device={props.device} edit={props.edit} />) return (
<Light
onChangeData={props.changeDeviceData}
device={props.device}
edit={props.edit}
/>
);
case "sensor": case "sensor":
return <Sensor onChangeData={props.changeDeviceData} device={props.device} edit={props.edit} /> return (
case "dimmer": <Sensor
return <DefaultDimmer onChangeData={props.changeDeviceData} device={props.device} edit={props.edit} /> onChangeData={props.changeDeviceData}
case "smartplug": device={props.device}
return <SmartPlug onChangeData={props.changeDeviceData} device={props.device} edit={props.edit} /> edit={props.edit}
/>
);
case "buttonDimmer":
return (
<DefaultDimmer
onChangeData={props.changeDeviceData}
device={props.device}
edit={props.edit}
/>
);
case "smartPlug":
return (
<SmartPlug
onChangeData={props.changeDeviceData}
device={props.device}
edit={props.edit}
/>
);
case "switch": case "switch":
return <Switcher onChangeData={props.changeDeviceData} device={props.device} edit={props.edit} /> return (
case "light": <Switcher
return (<Light onChangeData={props.changeDeviceData} device={props.device} edit={props.edit} />) onChangeData={props.changeDeviceData}
device={props.device}
edit={props.edit}
/>
);
case "dimmableLight":
return (
<Light
onChangeData={props.changeDeviceData}
device={props.device}
edit={props.edit}
/>
);
default: default:
return "" return "";
} }
} };
export default DeviceType; export default DeviceType;

View file

@ -6,13 +6,17 @@
* For this story, make the sensors return a constant value with some small random error. * For this story, make the sensors return a constant value with some small random error.
*/ */
import React, {Component} from "react"; import React, { Component } from "react";
import {CircularInput, CircularProgress, CircularTrack} from "react-circular-input"; import {
import {errorStyle, sensorText, style, valueStyle} from "./SensorStyle"; CircularInput,
import {StyledDiv} from "./styleComponents"; CircularProgress,
CircularTrack,
} from "react-circular-input";
import { errorStyle, sensorText, style, valueStyle } from "./SensorStyle";
import { StyledDiv } from "./styleComponents";
import Settings from "./DeviceSettings"; import Settings from "./DeviceSettings";
import {Image} from "semantic-ui-react"; import { Image } from "semantic-ui-react";
import {imageStyle, nameStyle} from "./DigitalSensorStyle"; import { imageStyle, nameStyle } from "./DigitalSensorStyle";
export default class DigitalSensor extends Component { export default class DigitalSensor extends Component {
constructor(props) { constructor(props) {
@ -22,26 +26,24 @@ export default class DigitalSensor extends Component {
}; };
this.iconOn = "/img/sensorOn.svg"; this.iconOn = "/img/sensorOn.svg";
this.iconOff = "/img/sensorOff.svg" this.iconOff = "/img/sensorOff.svg";
} }
setName = () => { setName = () => {
if(this.props.device.name.length > 15){ if (this.props.device.name.length > 15) {
return this.props.device.name.slice(0,12) + "..." return this.props.device.name.slice(0, 12) + "...";
} }
return this.props.device.name; return this.props.device.name;
}; };
getIcon = () => { getIcon = () => {
if(this.state.value){ if (this.state.value) {
return this.iconOn; return this.iconOn;
} }
return this.iconOff; return this.iconOff;
}; };
componentDidMount() { componentDidMount() {}
}
render() { render() {
return ( return (
@ -49,10 +51,13 @@ export default class DigitalSensor extends Component {
<Settings <Settings
deviceId={this.props.device.id} deviceId={this.props.device.id}
edit={this.props.edit} edit={this.props.edit}
onChangeData={(id, newSettings) => this.props.onChangeData(id, newSettings)}/> onChangeData={(id, newSettings) =>
<Image src={this.getIcon()} style={imageStyle}/> this.props.onChangeData(id, newSettings)
}
/>
<Image src={this.getIcon()} style={imageStyle} />
<h5 style={nameStyle}>{this.props.device.name}</h5> <h5 style={nameStyle}>{this.props.device.name}</h5>
</StyledDiv> </StyledDiv>
) );
} }
} }

View file

@ -5,13 +5,13 @@ export const imageStyle = {
top: "20%", top: "20%",
left: "50%", left: "50%",
transform: "translateX(-50%)", transform: "translateX(-50%)",
filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))" filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))",
}; };
export const nameStyle = { export const nameStyle = {
color : "black", color: "black",
position: "absolute", position: "absolute",
top: "40%", top: "40%",
left: "50%", left: "50%",
transform: "translateX(-50%)" transform: "translateX(-50%)",
}; };

View file

@ -7,46 +7,36 @@
The user can change the state of a dimmer through an intuitive UI in SmartHut . The user can change the state of a dimmer through an intuitive UI in SmartHut .
**/ **/
import React, {Component} from 'react'; import React, { Component } from "react";
export class StatefulDimmer extends Component{ export class StatefulDimmer extends Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state = { this.state = {
intensityLevel : 0, intensityLevel: 0,
pointingLDevices:[] pointingLDevices: [],
} };
} }
componentDidMount() { componentDidMount() {}
}
render() { render() {
return( return <div>This is a Dimmer</div>;
<div> }
This is a Dimmer
</div>
)
}
} }
export default class DefaultDimmer extends Component{ export default class DefaultDimmer extends Component {
// As far as I am concern, even though this dimmer doesn't have state, internally it's needed // As far as I am concern, even though this dimmer doesn't have state, internally it's needed
constructor(props){ constructor(props) {
super(props); super(props);
this.state = { this.state = {
pointingDevices :[] pointingDevices: [],
} };
} }
componentDidMount() { componentDidMount() {}
}
render() { render() {
return( return <div>This is a Dimmer</div>;
<div> }
This is a Dimmer
</div>
)
}
} }

View file

@ -6,13 +6,23 @@
* be shown accordingly in the SmartHut views (house view and room views). * be shown accordingly in the SmartHut views (house view and room views).
*/ */
import React, {Component} from "react"; import React, { Component } from "react";
import {iconStyle, StyledDiv} from "./styleComponents"; import { iconStyle, StyledDiv } from "./styleComponents";
import Settings from "./DeviceSettings"; import Settings from "./DeviceSettings";
import {Image} from "semantic-ui-react"; import { Image } from "semantic-ui-react";
import {CircularInput, CircularProgress, CircularThumb, CircularTrack} from "react-circular-input"; import {
import {valueStyle, intensityLightStyle, style, nameStyle} from "./LightStyle"; CircularInput,
import { call } from '../../../client_server'; CircularProgress,
CircularThumb,
CircularTrack,
} from "react-circular-input";
import {
valueStyle,
intensityLightStyle,
style,
nameStyle,
} from "./LightStyle";
import { call } from "../../../client_server";
export default class Light extends Component { export default class Light extends Component {
constructor(props) { constructor(props) {
@ -21,22 +31,26 @@ export default class Light extends Component {
turnedOn: false, turnedOn: false,
}; };
this.iconOn = "/img/lightOn.svg"; this.iconOn = "/img/lightOn.svg";
this.iconOff = "/img/lightOff.svg" this.iconOff = "/img/lightOff.svg";
} }
onClickDevice = () => { onClickDevice = () => {
this.setState((prevState) => ({turnedOn: !prevState.turnedOn})); this.props.device.on = !this.state.turnedOn;
call.deviceUpdate(this.props.device, "regularLight").then((res) => {
if (res.status === 200) {
this.setState((prevState) => ({ turnedOn: !prevState.turnedOn }));
}
});
}; };
setIntensity = (newValue) => { setIntensity = (newValue) => {
this.props.device.intensity = Math.round(newValue) <= 1 ? 1 : Math.round(newValue ); this.props.device.intensity =
console.log(this.props.device.intensity) Math.round(newValue * 100) <= 1 ? 1 : Math.round(newValue * 100);
call.deviceUpdate(this.props.device, 'dimmableLight') call.deviceUpdate(this.props.device, "dimmableLight").then((res) => {
.then(res => { if (res.status === 200) {
if (res.status === 200 ) { this.setState({ intensity: newValue });
this.setState({intensity: newValue}); }
} });
})
}; };
getIcon = () => { getIcon = () => {
@ -49,50 +63,69 @@ export default class Light extends Component {
componentDidMount() { componentDidMount() {
if (this.props.device.hasOwnProperty("intensity")) { if (this.props.device.hasOwnProperty("intensity")) {
this.setState({ this.setState({
intensity: this.props.device.intensity intensity: this.props.device.intensity,
}); });
} }
this.setState({
turnedOn: this.props.device.on,
});
// Get the state and update it // Get the state and update it
} }
render() { render() {
const intensityLightView = ( const intensityLightView = (
<CircularInput <CircularInput
value={this.props.device.intensity} value={+(Math.round(this.props.device.intensity / 100 + "e+2") + "e-2")}
onChange={this.setIntensity} onChange={this.setIntensity}
style={style} style={style}
> >
<CircularTrack/> <CircularTrack />
<CircularProgress/> <CircularProgress />
<CircularThumb/> <CircularThumb />
<text style={valueStyle} x={100} y={100} textAnchor="middle" dy="0.3em" fontWeight="bold"> <text
style={valueStyle}
x={100}
y={100}
textAnchor="middle"
dy="0.3em"
fontWeight="bold"
>
{Math.round(this.props.device.intensity)}% {Math.round(this.props.device.intensity)}%
</text> </text>
<text style={intensityLightStyle} x={100} y={150} textAnchor="middle" dy="0.3em" fontWeight="bold"> <text
style={intensityLightStyle}
x={100}
y={150}
textAnchor="middle"
dy="0.3em"
fontWeight="bold"
>
{this.props.device.name} {this.props.device.name}
</text> </text>
</CircularInput> </CircularInput>
); );
const normalLightView = ( const normalLightView = (
<div onClick={this.props.edit.mode ? () => { <div onClick={this.props.edit.mode ? () => {} : this.onClickDevice}>
} : this.onClickDevice}> <Image src={this.getIcon()} style={iconStyle} />
<Image src={this.getIcon()} style={iconStyle}/>
<h5 style={nameStyle}>{this.props.device.name}</h5> <h5 style={nameStyle}>{this.props.device.name}</h5>
</div> </div>
); );
return ( return (
<StyledDiv> <StyledDiv>
<Settings <Settings
deviceId={this.props.device.id} deviceId={this.props.device.id}
edit={this.props.edit} edit={this.props.edit}
onChangeData={(id, newSettings) => this.props.onChangeData(id, newSettings)}/> onChangeData={(id, newSettings) =>
{this.props.device.intensity ? (intensityLightView) : (normalLightView)} this.props.onChangeData(id, newSettings)
}
/>
{this.props.device.intensity >= 0
? intensityLightView
: normalLightView}
</StyledDiv> </StyledDiv>
) );
} }
} }

View file

@ -1,23 +1,29 @@
export const style = {width: "10rem", height: "10rem", position: "absolute", top: "0", left: "0"}; export const style = {
width: "10rem",
height: "10rem",
position: "absolute",
top: "0",
left: "0",
};
export const valueStyle = { export const valueStyle = {
fill: "#3e99ff", fill: "#3e99ff",
fontSize: "2.5rem", fontSize: "2.5rem",
fontFamily: "Lato", fontFamily: "Lato",
textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)", textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)",
}; };
export const intensityLightStyle = { export const intensityLightStyle = {
fill: "#3e99ff", fill: "#3e99ff",
fontSize: "1.2rem", fontSize: "1.2rem",
fontFamily: "Lato", fontFamily: "Lato",
textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)", textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)",
}; };
export const nameStyle = { export const nameStyle = {
fontSize : "1rem", fontSize: "1rem",
position: "absolute", position: "absolute",
top: "50%", top: "50%",
left: "50%", left: "50%",
transform: "translateX(-50%)", transform: "translateX(-50%)",
color : "black" color: "black",
}; };

View file

@ -1,19 +1,27 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import styled from 'styled-components'; import styled from "styled-components";
import {Button, Dropdown, Form, Icon, Image, Input, Modal} from "semantic-ui-react"; import {
Button,
Dropdown,
Form,
Icon,
Image,
Input,
Modal,
} from "semantic-ui-react";
const StyledDiv = styled.div` const StyledDiv = styled.div`
background-color : #ff4050; background-color: #ff4050;
padding : 3rem; padding: 3rem;
width: 10rem; width: 10rem;
height: 10rem; height: 10rem;
border-radius : 100%; border-radius: 100%;
border : none; border: none;
position : relative; position: relative;
box-shadow: 3px 2px 10px 5px #ccc; box-shadow: 3px 2px 10px 5px #ccc;
transition : all .3s ease-out; transition: all 0.3s ease-out;
:hover{ :hover {
background-color : #ff2436; background-color: #ff2436;
} }
`; `;
@ -22,15 +30,18 @@ export default class NewDevice extends Component {
super(props); super(props);
this.state = { this.state = {
step: 1, step: 1,
openModal : false openModal: false,
}; };
this.baseState = this.state this.baseState = this.state;
this.createDevice = this.createDevice.bind(this); this.createDevice = this.createDevice.bind(this);
} }
handleOpen = () => {this.setState({openModal : true})}; handleOpen = () => {
handleClose = () => {this.setState({openModal : false})}; this.setState({ openModal: true });
};
handleClose = () => {
this.setState({ openModal: false });
};
resetState = () => { resetState = () => {
this.setState(this.baseState); this.setState(this.baseState);
@ -38,92 +49,97 @@ export default class NewDevice extends Component {
}; };
nextStep = () => { nextStep = () => {
this.setState((prevState) => ({step: prevState.step + 1})); this.setState((prevState) => ({ step: prevState.step + 1 }));
}; };
previousStep = () => { previousStep = () => {
this.setState((prevState) => ({step: prevState.step - 1})); this.setState((prevState) => ({ step: prevState.step - 1 }));
}; };
setTypeOfDevice = (e, d) => { setTypeOfDevice = (e, d) => {
if (d.value === "dimmableLight"){ if (d.value === "dimmableLight") {
this.setState({typeOfDevice: d.value, this.setState({ typeOfDevice: d.value, intensity: 0 });
intensity: 0,}); } else {
} else { this.setState({ typeOfDevice: d.value });
this.setState({typeOfDevice: d.value,}); }
}
}; };
setDeviceName = (e, d) => { setDeviceName = (e, d) => {
this.setState({deviceName: d.value}); this.setState({ deviceName: d.value });
}; };
setTypeOfSensor = (e, d) => { setTypeOfSensor = (e, d) => {
this.setState({typeOfSensor: d.value}); this.setState({ typeOfSensor: d.value });
}; };
setLightsDimmerSwitch = (e, d) => { setLightsDimmerSwitch = (e, d) => {
this.setState({lightsAttached : d.value}); this.setState({ lightsAttached: d.value });
}; };
createDevice() { createDevice() {
// Connect to the backend and create device here. // Connect to the backend and create device here.
const data = { const data = {
params: { params: {
"name": this.state.deviceName, name: this.state.deviceName,
}, },
device: this.state.typeOfDevice device: this.state.typeOfDevice,
};
} switch (this.state.typeOfDevice) {
switch(this.state.typeOfDevice) {
case "dimmableLight": case "dimmableLight":
data.params["intensity"] = 1; data.params["intensity"] = 1;
break; break;
default: case "sensor":
data.params["sensor"] = this.state.typeOfSensor;
data.params["value"] = 0;
break;
case "switch":
data.params["lights"] = this.state.lightsAttached;
break;
default:
break; break;
} }
console.log(data);
this.props.addDevice(data); this.props.addDevice(data);
this.resetState(); this.resetState();
}; }
render() { render() {
const deviceOptions = [ const deviceOptions = [
{ {
key: 'light', key: "light",
text: 'Normal Light', text: "Normal Light",
value: 'regularLight', value: "regularLight",
image: {avatar: true, src: '/img/lightOn.svg'}, image: { avatar: true, src: "/img/lightOn.svg" },
}, },
{ {
key: 'intensity-light', key: "intensity-light",
text: 'Intensity Light', text: "Intensity Light",
value: 'dimmableLight', value: "dimmableLight",
image: {avatar: true, src: '/img/intensity-light.svg'}, image: { avatar: true, src: "/img/intensity-light.svg" },
}, },
{ {
key: 'smart-plug', key: "smart-plug",
text: 'Smart Plug', text: "Smart Plug",
value: 'smartPlug', value: "smartPlug",
image: {avatar: true, src: '/img/smart-plug.svg'}, image: { avatar: true, src: "/img/smart-plug.svg" },
}, },
{ {
key: 'sensor', key: "sensor",
text: 'Sensor', text: "Sensor",
value: 'sensor', value: "sensor",
image: {avatar: true, src: '/img/sensorOn.svg'}, image: { avatar: true, src: "/img/sensorOn.svg" },
}, },
{ {
key: 'switch', key: "switch",
text: 'Switch', text: "Switch",
value: 'switch', value: "switch",
image: {avatar: true, src: '/img/switchOn.svg'}, image: { avatar: true, src: "/img/switchOn.svg" },
}, },
{ {
key: 'dimmer', key: "dimmer",
text: 'Dimmer', text: "Dimmer",
value: 'dimmer', value: "buttonDimmer",
image: {avatar: true, src: '/img/dimmer.svg'}, image: { avatar: true, src: "/img/dimmer.svg" },
}, },
]; ];
const sensorOptions = [ const sensorOptions = [
@ -131,41 +147,39 @@ export default class NewDevice extends Component {
key: "temperature", key: "temperature",
text: "Temperature Sensor", text: "Temperature Sensor",
value: "TEMPERATURE", value: "TEMPERATURE",
image: {avatar: true, src: '/img/temperature-sensor.svg'}, image: { avatar: true, src: "/img/temperature-sensor.svg" },
}, },
{ {
key: "humidity", key: "humidity",
text: "Humidity Sensor", text: "Humidity Sensor",
value: "HUMIDITY", value: "HUMIDITY",
image: {avatar: true, src: '/img/humidity-sensor.svg'}, image: { avatar: true, src: "/img/humidity-sensor.svg" },
}, },
{ {
key: "light", key: "light",
text: "Light Sensor", text: "Light Sensor",
value: "LIGHT", value: "LIGHT",
image: {avatar: true, src: '/img/light-sensor.svg'}, image: { avatar: true, src: "/img/light-sensor.svg" },
}, },
{ {
key: "motion", key: "motion",
text: "Motion Sensor", text: "Motion Sensor",
value: "motionSensor", value: "motionSensor",
image: {avatar: true, src: '/img/sensorOn.svg'}, image: { avatar: true, src: "/img/sensorOn.svg" },
} },
]; ];
const availableLights = []; const availableLights = [];
this.props.devices.forEach(d => { this.props.devices.forEach((d) => {
availableLights.push( availableLights.push({
{ key: d.id,
key: d.id, text: d.name,
text: d.name, value: d.id,
value: d.id, });
}
)
}); });
const step1 = ( const step1 = (
<Dropdown <Dropdown
name="typeOfDevice" name="typeOfDevice"
placeholder='Select a Type of Device' placeholder="Select a Type of Device"
fluid fluid
selection selection
onChange={this.setTypeOfDevice} onChange={this.setTypeOfDevice}
@ -173,74 +187,114 @@ export default class NewDevice extends Component {
/> />
); );
const step2 = (typeOfDevice) => { const step2 = (typeOfDevice) => {
const deviceName = (<div> const deviceName = (
<Form.Field> <div>
<label>Device Name: </label> <Form.Field>
<Input fluid size={"large"} onChange={this.setDeviceName} focus placeholder='Device Name'/> <label>Device Name: </label>
</Form.Field> <Input
</div>); fluid
const sensorForm = (<Form.Field style={{marginTop : "1rem"}}> size={"large"}
onChange={this.setDeviceName}
focus
placeholder="Device Name"
/>
</Form.Field>
</div>
);
const sensorForm = (
<Form.Field style={{ marginTop: "1rem" }}>
<label>Type of Sensor: </label> <label>Type of Sensor: </label>
<Dropdown <Dropdown
name="typeOfDevice" name="typeOfDevice"
placeholder='Select a Type of Sensor' placeholder="Select a Type of Sensor"
fluid fluid
selection selection
onChange={this.setTypeOfSensor} onChange={this.setTypeOfSensor}
options={sensorOptions} options={sensorOptions}
/> />
</Form.Field>); </Form.Field>
const switchDimmerOptions = (<Form.Field style={{marginTop : "1rem"}}> );
<label>Select the Lights You Want to Attach: </label> const switchDimmerOptions = (
<Dropdown <Form.Field style={{ marginTop: "1rem" }}>
name="typeOfDevice" <label>Select the Lights You Want to Attach: </label>
placeholder='Select Lights' <Dropdown
fluid name="typeOfDevice"
multiple placeholder="Select Lights"
onChange={this.setLightsDimmerSwitch} fluid
options={availableLights} multiple
/> onChange={this.setLightsDimmerSwitch}
</Form.Field>); options={availableLights}
/>
</Form.Field>
);
return ( return (
<Form> <Form>
{deviceName} {deviceName}
{this.state.typeOfDevice === "sensor" ? (sensorForm) : ""} {this.state.typeOfDevice === "sensor" ? sensorForm : ""}
{this.state.typeOfDevice === "switch" || this.state.typeOfDevice === "dimmer" ? {this.state.typeOfDevice === "switch" ||
(switchDimmerOptions) : "" this.state.typeOfDevice === "dimmer"
} ? switchDimmerOptions
: ""}
</Form> </Form>
) );
}; };
const steps = [step1, step2()]; const steps = [step1, step2()];
return ( return (
<Modal closeIcon open={this.state.openModal} onClose={this.resetState} trigger={<StyledDiv onClick={this.handleOpen}> <Modal
<Image src="/img/add.svg" style={{filter: "invert()"}}/> closeIcon
</StyledDiv>} centered={true}> open={this.state.openModal}
onClose={this.resetState}
trigger={
<StyledDiv onClick={this.handleOpen}>
<Image src="/img/add.svg" style={{ filter: "invert()" }} />
</StyledDiv>
}
centered={true}
>
<Modal.Header>Add a New Device</Modal.Header> <Modal.Header>Add a New Device</Modal.Header>
<Modal.Content> <Modal.Content>{steps[this.state.step - 1]}</Modal.Content>
{steps[this.state.step -1]}
</Modal.Content>
<Modal.Actions> <Modal.Actions>
{this.state.step > 1 ? ( {this.state.step > 1 ? (
<Button onClick={this.previousStep} color="blue" icon labelPosition='left'> <Button
<Icon name='left arrow'/> onClick={this.previousStep}
color="blue"
icon
labelPosition="left"
>
<Icon name="left arrow" />
Back Back
</Button> </Button>
) : ""} ) : (
""
)}
{this.state.step < steps.length ? ( {this.state.step < steps.length ? (
<Button color="blue" onClick={this.nextStep} icon labelPosition='right'> <Button
color="blue"
onClick={this.nextStep}
icon
labelPosition="right"
>
Next Next
<Icon name='right arrow'/> <Icon name="right arrow" />
</Button> </Button>
) : ""} ) : (
""
)}
{this.state.step === steps.length ? ( {this.state.step === steps.length ? (
<Button onClick={this.createDevice} color="blue" icon labelPosition='right'> <Button
<Icon name='up arrow'/> onClick={this.createDevice}
color="blue"
icon
labelPosition="right"
>
<Icon name="up arrow" />
Finish Finish
</Button> </Button>
) : ""} ) : (
""
)}
</Modal.Actions> </Modal.Actions>
</Modal> </Modal>
) );
} }
} }

View file

@ -6,59 +6,110 @@
* For this story, make the sensors return a constant value with some small random error. * For this story, make the sensors return a constant value with some small random error.
*/ */
import React, {Component} from "react"; /*
import {CircularInput, CircularProgress, CircularTrack} from "react-circular-input";
import {errorStyle, sensorText, style, valueStyle} from "./SensorStyle"; OPTIONAL STATE
error: 2.4
<text style={errorStyle} x={100} y={100} textAnchor="middle" dy="0.6em" fontWeight="bold">
&#177;{this.state.error}
</text>
errorStyle,
*/
import React, { Component } from "react";
import {
CircularInput,
CircularProgress,
CircularTrack,
} from "react-circular-input";
import { sensorText, style, valueStyle } from "./SensorStyle";
import Settings from "./DeviceSettings"; import Settings from "./DeviceSettings";
import {StyledDiv} from "./styleComponents"; import { StyledDiv } from "./styleComponents";
import { call } from "../../../client_server";
export default class Sensor extends Component { export default class Sensor extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
turnedOn: false, turnedOn: false,
value: 20, value: 0,
error: 2.4
}; };
this.units = "ºC" this.units = "";
this.stateCallback = (e) => this.setState(Object.assign(this.state, e));
call.socketSubscribe(this.props.device.id, this.stateCallback);
}
componentWillUnmount() {
call.socketUnsubscribe(this.props.device.id, this.stateCallback);
} }
setName = () => { setName = () => {
if (this.props.device.name.length > 15) { if (this.props.device.name.length > 15) {
return this.props.device.name.slice(0, 12) + "..." return this.props.device.name.slice(0, 12) + "...";
} }
return this.props.device.name; return this.props.device.name;
}; };
componentDidMount() { componentDidMount() {
switch (this.props.device.sensor) {
case "TEMPERATURE":
this.units = "ºC";
break;
case "HUMIDITY":
this.units = "%";
break;
case "LIGHT":
this.units = "lm";
break;
default:
this.units = "";
}
this.setState({
value: this.props.device.value,
});
} }
render() { render() {
return ( return (
<StyledDiv> <StyledDiv>
<Settings <Settings
deviceId={this.props.device.id} deviceId={this.props.device.id}
edit={this.props.edit} edit={this.props.edit}
onChangeData={(id, newSettings) => this.props.onChangeData(id, newSettings)}/> onChangeData={(id, newSettings) =>
this.props.onChangeData(id, newSettings)
}
/>
<CircularInput <CircularInput value={this.state.value / 100} style={style}>
value={this.state.value / 100} <CircularTrack />
style={style} <CircularProgress />
> <text
<CircularTrack/> style={valueStyle}
<CircularProgress/> x={100}
<text style={valueStyle} x={100} y={80} textAnchor="middle" dy="0.3em" fontWeight="bold"> y={80}
{Math.round(this.state.value)}{this.units} textAnchor="middle"
dy="0.3em"
fontWeight="bold"
>
{Math.round(this.state.value)}
{this.units}
</text> </text>
<text style={errorStyle} x={100} y={100} textAnchor="middle" dy="0.6em" fontWeight="bold"> <text
&#177;{this.state.error} style={sensorText}
</text> x={100}
<text style={sensorText} x={100} y={150} textAnchor="middle" dy="0.3em" fontWeight="bold"> y={150}
textAnchor="middle"
dy="0.3em"
fontWeight="bold"
>
{this.setName()} {this.setName()}
</text> </text>
</CircularInput> </CircularInput>
</StyledDiv> </StyledDiv>
) );
} }
} }

View file

@ -1,23 +1,28 @@
export const style = {width: "10rem", height: "10rem", position: "absolute", top: "0", left: "0"}; export const style = {
width: "10rem",
export const sensorText = { height: "10rem",
fill: "#3e99ff", position: "absolute",
fontSize: "1.2rem", top: "0",
fontFamily: "Lato", left: "0",
textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)",
}
export const valueStyle = {
fill: "#3e99ff",
fontSize: "2.5rem",
fontFamily: "Lato",
textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)",
}; };
export const sensorText = {
fill: "#3e99ff",
fontSize: "1.2rem",
fontFamily: "Lato",
textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)",
};
export const valueStyle = {
fill: "#3e99ff",
fontSize: "2.5rem",
fontFamily: "Lato",
textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)",
};
export const errorStyle = { export const errorStyle = {
fill: "#ff4050", fill: "#ff4050",
fontSize: "1.5rem", fontSize: "1.5rem",
fontFamily: "Lato", fontFamily: "Lato",
textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)", textShadow: "1px 1px 0.5px rgba(0, 0, 0, .2)",
} };

View file

@ -1,56 +1,73 @@
import React, {Component, useState} from 'react'; import React, { Component, useState } from "react";
import {Button, Checkbox, Form, Icon, Header, Modal} from "semantic-ui-react"; import { Button, Checkbox, Form, Icon, Header, Modal } from "semantic-ui-react";
const DeleteModal = (props) => ( const DeleteModal = (props) => (
<Modal trigger={<Button color='red'>Remove</Button>} closeIcon> <Modal trigger={<Button color="red">Remove</Button>} closeIcon>
<Header icon='archive' content='Are you sure ?' /> <Header icon="archive" content="Are you sure ?" />
<Modal.Actions> <Modal.Actions>
<Button color='red'> <Button color="red">
<Icon name='remove' /> No <Icon name="remove" /> No
</Button> </Button>
<Button onClick={() => props.removeDevice()} color='green'> <Button onClick={() => props.removeDevice()} color="green">
<Icon name='checkmark' /> Yes <Icon name="checkmark" /> Yes
</Button> </Button>
</Modal.Actions> </Modal.Actions>
</Modal> </Modal>
) );
const SettingsForm = (props) => { const SettingsForm = (props) => {
const handleInputChange = (e) => {
const handleInputChange = e => { const { name, value } = e.target;
const {name, value} = e.target; setValues({ ...values, [name]: value });
setValues({...values, [name]: value})
}; };
const handleCheckboxChange = (e,d) => { const handleCheckboxChange = (e, d) => {
const {name, checked} = d; const { name, checked } = d;
setValues({...values, [name]: checked}) setValues({ ...values, [name]: checked });
}; };
const [values, setValues] = useState({name: ''}); const [values, setValues] = useState({ name: "" });
return ( return (
<Form> <Form>
<Form.Field> <Form.Field>
<label>New Name: </label> <label>New Name: </label>
<input autoComplete="off" name="name" onChange={handleInputChange} value={values.name} placeholder='Device name'/> <input
autoComplete="off"
name="name"
onChange={handleInputChange}
value={values.name}
placeholder="Device name"
/>
</Form.Field> </Form.Field>
{props.type === "smart-plug" ? ( {props.type === "smart-plug" ? (
<Form.Field> <Form.Field>
<Checkbox slider name={"reset"} onClick={handleCheckboxChange} label='Reset Energy Consumption'/> <Checkbox
slider
name={"reset"}
onClick={handleCheckboxChange}
label="Reset Energy Consumption"
/>
</Form.Field> </Form.Field>
) : ""} ) : (
""
)}
<Form.Field> <Form.Field>
<DeleteModal removeDevice={() => props.removeDevice(values)} /> <DeleteModal removeDevice={() => props.removeDevice(values)} />
</Form.Field> </Form.Field>
<Button onClick={() => props.saveFunction(values)} color="blue" type='submit'>Save</Button> <Button
onClick={() => props.saveFunction(values)}
color="blue"
type="submit"
>
Save
</Button>
</Form> </Form>
) );
} };
export default class SettingsModal extends Component { export default class SettingsModal extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -59,7 +76,7 @@ export default class SettingsModal extends Component {
} }
handleClose = () => { handleClose = () => {
this.setState({open: false}); this.setState({ open: false });
}; };
saveSettings = (device) => { saveSettings = (device) => {
@ -72,19 +89,23 @@ export default class SettingsModal extends Component {
this.props.openModal(); this.props.openModal();
}; };
render() { render() {
const SettingsModal = () => ( const SettingsModal = () => (
<Modal open={true} onOpen={this.props.openModal} onClose={this.props.openModal}> <Modal
open={true}
onOpen={this.props.openModal}
onClose={this.props.openModal}
>
<Modal.Header>Settings of {this.props.device.name}</Modal.Header> <Modal.Header>Settings of {this.props.device.name}</Modal.Header>
<Modal.Content> <Modal.Content>
<SettingsForm type={this.props.device.type} removeDevice={this.props.removeDevice} saveFunction={this.saveSettings}/> <SettingsForm
type={this.props.device.type}
removeDevice={this.props.removeDevice}
saveFunction={this.saveSettings}
/>
</Modal.Content> </Modal.Content>
</Modal> </Modal>
); );
return ( return <SettingsModal />;
<SettingsModal/>
)
} }
} }

View file

@ -4,48 +4,61 @@
The smart plug also stores the total energy consumed while the plug is active, in terms of kilowatt-hours 2(kWh) . The smart plug also stores the total energy consumed while the plug is active, in terms of kilowatt-hours 2(kWh) .
The user can reset this value. The user can reset this value.
**/ **/
import React, {Component} from 'react'; import React, { Component } from "react";
import {StyledDiv} from "./styleComponents"; import { StyledDiv } from "./styleComponents";
import Settings from "./DeviceSettings"; import Settings from "./DeviceSettings";
import {Image} from "semantic-ui-react"; import { Image } from "semantic-ui-react";
import {energyConsumedStyle, imageStyle, nameStyle} from "./SmartPlugStyle"; import { energyConsumedStyle, imageStyle, nameStyle } from "./SmartPlugStyle";
import { call } from "../../../client_server";
export default class SmartPlug extends Component { export default class SmartPlug extends Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state = { this.state = {
turnedOn: false, turnedOn: false,
energyConsumed : 0 // kWh energyConsumed: 0, // kWh
};
this.iconOn = "/img/smart-plug.svg";
this.iconOff = "/img/smart-plug-off.svg"
}
onClickDevice = () => {
this.setState((prevState) => ({turnedOn: !prevState.turnedOn}));
}; };
this.iconOn = "/img/smart-plug.svg";
this.iconOff = "/img/smart-plug-off.svg";
}
getIcon = () => { onClickDevice = () => {
if(this.state.turnedOn){ this.props.device.on = !this.state.turnedOn;
return this.iconOn; call.deviceUpdate(this.props.device, "smartPlug").then((res) => {
} if (res.status === 200) {
return this.iconOff; this.setState((prevState) => ({ turnedOn: !prevState.turnedOn }));
}; }
});
};
componentDidMount() { getIcon = () => {
if (this.state.turnedOn) {
return this.iconOn;
} }
return this.iconOff;
};
render(){ componentDidMount() {
return ( this.setState({
<StyledDiv onClick={this.props.edit.mode ? () => {} : this.onClickDevice}> turnedOn: this.props.device.on,
<Settings energyConsumed: this.props.device.totalConsumption,
deviceId={this.props.device.id} });
edit={this.props.edit} }
onChangeData={(id, newSettings) => this.props.onChangeData(id, newSettings)}/>
<Image src={this.getIcon()} style={imageStyle}/> render() {
<h4 style={energyConsumedStyle}>{this.state.energyConsumed} KWh</h4> return (
<h5 style={nameStyle}>{this.props.device.name}</h5> <StyledDiv onClick={this.props.edit.mode ? () => {} : this.onClickDevice}>
</StyledDiv> <Settings
) deviceId={this.props.device.id}
} edit={this.props.edit}
onChangeData={(id, newSettings) =>
this.props.onChangeData(id, newSettings)
}
/>
<Image src={this.getIcon()} style={imageStyle} />
<h4 style={energyConsumedStyle}>{this.state.energyConsumed} KWh</h4>
<h5 style={nameStyle}>{this.props.device.name}</h5>
</StyledDiv>
);
}
} }

View file

@ -1,27 +1,26 @@
export const energyConsumedStyle = { export const energyConsumedStyle = {
color : "black", color: "black",
fontSize : "1.3rem", fontSize: "1.3rem",
position: "absolute", position: "absolute",
top: "30%", top: "30%",
left: "50%", left: "50%",
transform: "translateX(-50%)" transform: "translateX(-50%)",
}; };
export const imageStyle = { export const imageStyle = {
width: "3.5rem", width: "3.5rem",
height: "auto", height: "auto",
position: "absolute", position: "absolute",
top: "10%", top: "10%",
left: "50%", left: "50%",
transform: "translateX(-50%)", transform: "translateX(-50%)",
filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))" filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))",
}; };
export const nameStyle = { export const nameStyle = {
color : "black", color: "black",
position: "absolute", position: "absolute",
top: "50%", top: "50%",
left: "50%", left: "50%",
transform: "translateX(-50%)" transform: "translateX(-50%)",
}; };

View file

@ -5,48 +5,69 @@
* The user can change the state of a switch through the SmartHut interface. * The user can change the state of a switch through the SmartHut interface.
*/ */
import React, {Component} from 'react'; import React, { Component } from "react";
import {StyledDiv} from "./styleComponents"; import { StyledDiv } from "./styleComponents";
import Settings from "./DeviceSettings"; import Settings from "./DeviceSettings";
import {Image} from "semantic-ui-react"; import { Image } from "semantic-ui-react";
import {imageStyle, nameStyle} from "./SwitchStyle"; import { imageStyle, nameStyle } from "./SwitchStyle";
import { call } from "../../../client_server";
export default class Switch extends Component { export default class Switch extends Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state = { this.state = {
turnedOn: false, turnedOn: false,
pointingLights : [] pointingLights: [],
}; };
this.iconOn = "/img/switchOn.svg"; this.iconOn = "/img/switchOn.svg";
this.iconOff = "/img/switchOff.svg"; this.iconOff = "/img/switchOff.svg";
} }
onClickDevice = () => { onClickDevice = () => {
this.setState((prevState) => ({turnedOn: !prevState.turnedOn})); this.props.device.on = !this.state.turnedOn;
let state = "";
if (this.props.device.on) {
state = "ON";
} else {
state = "OFF";
}
let data = {
type: state,
id: this.props.device.id,
};
call.deviceUpdate(data, "switch/operate").then((res) => {
if (res.status === 200) {
this.setState((prevState) => ({ turnedOn: !prevState.turnedOn }));
}
});
}; };
getIcon = () => { getIcon = () => {
if(this.state.turnedOn){ if (this.state.turnedOn) {
return this.iconOn; return this.iconOn;
} }
return this.iconOff; return this.iconOff;
}; };
componentDidMount() { componentDidMount() {
this.setState({
turnedOn: this.props.device.on,
});
} }
render(){ render() {
return ( return (
<StyledDiv onClick={this.props.edit.mode ? () => {} : this.onClickDevice}> <StyledDiv onClick={this.props.edit.mode ? () => {} : this.onClickDevice}>
<Settings <Settings
deviceId={this.props.device.id} deviceId={this.props.device.id}
edit={this.props.edit} edit={this.props.edit}
onChangeData={(id, newSettings) => this.props.onChangeData(id, newSettings)}/> onChangeData={(id, newSettings) =>
<Image src={this.getIcon()} style={imageStyle}/> this.props.onChangeData(id, newSettings)
}
/>
<Image src={this.getIcon()} style={imageStyle} />
<h5 style={nameStyle}>{this.props.device.name}</h5> <h5 style={nameStyle}>{this.props.device.name}</h5>
</StyledDiv> </StyledDiv>
) );
} }
} }

View file

@ -5,13 +5,13 @@ export const imageStyle = {
top: "15%", top: "15%",
left: "50%", left: "50%",
transform: "translateX(-50%)", transform: "translateX(-50%)",
filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))" filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))",
}; };
export const nameStyle = { export const nameStyle = {
color : "black", color: "black",
position: "absolute", position: "absolute",
top: "45%", top: "45%",
left: "50%", left: "50%",
transform: "translateX(-50%)" transform: "translateX(-50%)",
}; };

View file

@ -1,18 +1,24 @@
export const LightDevice = { export const LightDevice = {
img : "/img/lightOff.svg", img: "/img/lightOff.svg",
imgClick : "/img/lightOn.svg" imgClick: "/img/lightOn.svg",
}; };
export const SmartPlugDevice = { export const SmartPlugDevice = {
img : "/img/smart-plug.svg", img: "/img/smart-plug.svg",
imgClick : "/img/smart-plug-off.svg" imgClick: "/img/smart-plug-off.svg",
}; };
export const TemperatureSensor = { export const TemperatureSensor = {
type : "temperature_sensor", type: "temperature_sensor",
img : "", img: "",
imgClick : "", imgClick: "",
units: "ºC", units: "ºC",
}; };
export const deviceList = ["Light", "Dimmer", "Switcher", "Smart Plug", "Sensor"]; export const deviceList = [
"Light",
"Dimmer",
"Switcher",
"Smart Plug",
"Sensor",
];

View file

@ -1,5 +1,5 @@
export const DEVICE_NAME_MAX_LENGTH = 15; export const DEVICE_NAME_MAX_LENGTH = 15;
export function checkMaxLength(name){ export function checkMaxLength(name) {
return !(name.length > DEVICE_NAME_MAX_LENGTH); return !(name.length > DEVICE_NAME_MAX_LENGTH);
} }

View file

@ -1,20 +1,20 @@
import styled from "styled-components"; import styled from "styled-components";
export const editButtonStyle = { export const editButtonStyle = {
position : "absolute", position: "absolute",
top: "0", top: "0",
right : "0", right: "0",
backgroundColor : "#3e99ff", backgroundColor: "#3e99ff",
borderRadius : "0 0 0 20px", borderRadius: "0 0 0 20px",
padding : ".4rem 1.2rem", padding: ".4rem 1.2rem",
outline : "none", outline: "none",
color : "white", color: "white",
fontFamily : "Lato", fontFamily: "Lato",
textTransform : "uppercase" textTransform: "uppercase",
}; };
export const panelStyle = { export const panelStyle = {
position : "relative", position: "relative",
backgroundColor: "#fafafa", backgroundColor: "#fafafa",
height: "100vh", height: "100vh",
width: "auto", width: "auto",
@ -22,26 +22,26 @@ export const panelStyle = {
}; };
export const editModeStyle = { export const editModeStyle = {
position : "absolute", position: "absolute",
top: "15%", top: "15%",
right: "0", right: "0",
width : "1.5rem", width: "1.5rem",
height : "1.5rem", height: "1.5rem",
backgroundColor : "black", backgroundColor: "black",
borderRadius: "100%", borderRadius: "100%",
zIndex : "1000", zIndex: "1000",
cursor : "pointer", cursor: "pointer",
}; };
export const editModeIconStyle = { export const editModeIconStyle = {
position : "absolute", position: "absolute",
top: "50%", top: "50%",
left: "50%", left: "50%",
transform : "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
width: "0.75rem", width: "0.75rem",
height : "0.75rem", height: "0.75rem",
borderRadius : "20%", borderRadius: "20%",
zIndex : "101" zIndex: "101",
}; };
export const iconStyle = { export const iconStyle = {
@ -51,50 +51,49 @@ export const iconStyle = {
top: "20%", top: "20%",
left: "50%", left: "50%",
transform: "translateX(-50%)", transform: "translateX(-50%)",
filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))" filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))",
}; };
export const nameStyle = { export const nameStyle = {
position: "absolute", position: "absolute",
top: "50%", top: "50%",
left: "50%", left: "50%",
transform: "translateX(-50%)" transform: "translateX(-50%)",
}; };
export const formStyle = { export const formStyle = {
position : "absolute", position: "absolute",
zIndex: "1000", zIndex: "1000",
width : "80rem", width: "80rem",
height : "10rem", height: "10rem",
padding : "1rem", padding: "1rem",
margin : "1rem", margin: "1rem",
borderRadius : "10%", borderRadius: "10%",
boxShadow : "1px 1px 5px 2px #5d5d5d", boxShadow: "1px 1px 5px 2px #5d5d5d",
backgroundColor: "#3e99ff", backgroundColor: "#3e99ff",
}; };
export const addDeviceFormStyle = { export const addDeviceFormStyle = {
maxWidth : "400px", maxWidth: "400px",
background : "#3e99ff", background: "#3e99ff",
paddingRight : "5rem", paddingRight: "5rem",
}; };
export const StyledDiv = styled.div` export const StyledDiv = styled.div`
background-color : white; background-color: white;
padding : 3rem; padding: 3rem;
width: 10rem; width: 10rem;
height: 10rem; height: 10rem;
border-radius : 100%; border-radius: 100%;
border : none; border: none;
position : relative; position: relative;
box-shadow: 3px 2px 10px 5px #ccc; box-shadow: 3px 2px 10px 5px #ccc;
transition : all .3s ease-out; transition: all 0.3s ease-out;
text-align : center; text-align: center;
:hover{ :hover {
background-color : #f2f2f2; background-color: #f2f2f2;
} }
:active{ :active {
transform : translate(0.3px, 0.8px); transform: translate(0.3px, 0.8px);
box-shadow: 0.5px 0.5px 7px 3.5px #ccc; box-shadow: 0.5px 0.5px 7px 3.5px #ccc;
} }
`; `;

View file

@ -1,22 +1,30 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import { Button, Header, Modal, Form, Input, Icon, Responsive, Image } from 'semantic-ui-react'; import {
Button,
Header,
Modal,
Form,
Input,
Icon,
Responsive,
Image
} from "semantic-ui-react";
import SelectIcons from "./SelectIcons"; import SelectIcons from "./SelectIcons";
const NO_IMAGE="https://react.semantic-ui.com/images/wireframe/image.png"; const NO_IMAGE="https://react.semantic-ui.com/images/wireframe/image.png";
export default class ModalWindow extends Component { export default class ModalWindow extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
console.table(this.props); console.table(this.props);
this.state = { this.state = {
id : "", id: "",
selectedIcon: "", selectedIcon: "",
name: "", name: this.props.type === "new" ? "" : this.props.idRoom.name,
img: this.props.type === "new" ? null : this.props.idRoom.image, img: this.props.type === "new" ? null : this.props.idRoom.image,
openModal: false openModal: false,
}; };
this.fileInputRef = React.createRef(); this.fileInputRef = React.createRef();
@ -27,47 +35,49 @@ console.table(this.props);
addRoomModal = (e) => { addRoomModal = (e) => {
let data = { let data = {
"icon" : this.state.selectedIcon, icon: this.state.selectedIcon,
"name" : this.state.name, name: this.state.name,
"image" : this.state.img image: this.state.img,
} };
this.props.addRoom(data); this.props.addRoom(data);
this.closeModal(); this.closeModal();
} };
modifyRoomModal = (e) => { modifyRoomModal = (e) => {
let data = { let data = {
"icon" : this.state.selectedIcon === "" ? this.props.idRoom.icon : this.state.selectedIcon , icon:
"name" : this.state.name === ""? this.props.idRoom.name : this.state.name, this.state.selectedIcon === ""
"image" : this.state.img ? this.props.idRoom.icon
} : this.state.selectedIcon,
name: this.state.name === "" ? this.props.idRoom.name : this.state.name,
image: this.state.img,
};
this.props.updateRoom(data); this.props.updateRoom(data);
this.closeModal(); this.closeModal();
} };
deleteRoom = (e) => { deleteRoom = (e) => {
this.props.deleteRoom(); this.props.deleteRoom();
this.closeModal(); this.closeModal();
} };
changeSomething = (event) => { changeSomething = (event) => {
let nam = event.target.name;
let val = event.target.value;
this.setState({ [nam]: val });
};
let nam = event.target.name; closeModal = (e) => {
let val = event.target.value; this.setState({ openModal: false });
this.setState({[nam]: val}); this.updateIcon("home");
} };
closeModal = (e) => { openModal = (e) => {
this.setState({openModal:false}); this.setState({ openModal: true });
this.updateIcon('home'); };
}
openModal = (e) => {
this.setState({openModal:true})
}
updateIcon(e) { updateIcon(e) {
this.setState({selectedIcon : e}) this.setState({ selectedIcon: e });
} }
getBase64(file, callback) { getBase64(file, callback) {
@ -83,20 +93,29 @@ console.table(this.props);
render(){ render(){
const spaceDiv = { const spaceDiv = {
background: '#f4f4f4', background: "#f4f4f4",
padding: '10px 10px', padding: "10px 10px",
margin: '10px 0px' margin: "10px 0px",
} };
return (
return ( <div>
<div> <Responsive minWidth={768}>
<Responsive minWidth={768} > {this.props.type === "new" ? (
{this.props.type === "new" ? <Button icon labelPosition="left" inverted onClick={this.openModal}>
<Button icon labelPosition='left' inverted onClick={this.openModal}> <Icon name="plus" size="small" />
<Icon name='plus' size='small'/>
ADD ROOM ADD ROOM
</Button> </Button>
) : (
<Icon name="pencil" size="small" onClick={this.openModal} />
)}
</Responsive>
<Responsive maxWidth={768}>
{this.props.type === "new" ? (
<Button icon fluid labelPosition="left" onClick={this.openModal}>
<Icon name="plus" size="small" />
ADD ROOM
</Button>)
: :
<Icon name='pencil' size='small' onClick={this.openModal} /> <Icon name='pencil' size='small' onClick={this.openModal} />
} }
@ -124,19 +143,24 @@ console.table(this.props);
<Form> <Form>
<p>Insert the name of the room:</p> <p>Insert the name of the room:</p>
<Form.Field> <Form.Field>
<Input label='Room name' placeholder='Room Name' name="name" type='text' onChange={this.changeSomething} <Input
value={this.props.type === "new" && this.props.idRoom !== -1 ? null : this.props.idRoom.name }/> label='Room name'
placeholder='Room Name'
name="name"
type='text'
onChange={this.changeSomething}
value={this.state.name}/>
</Form.Field> </Form.Field>
<p>Insert an image of the room:</p> <p>Insert an image of the room:</p>
<Form.Field> <Form.Field>
<Image src={this.state.img == null ? NO_IMAGE : this.state.img} <Image
size='small' src={this.state.img == null ? NO_IMAGE : this.state.img}
onClick={() => this.fileInputRef.current.click()}/> size='small'
onClick={() => this.fileInputRef.current.click()}/>
<input ref={this.fileInputRef} hidden label='Room image' type='file' name="img" accept="image/png, image/jpeg" <input ref={this.fileInputRef} hidden label='Room image' type='file' name="img" accept="image/png, image/jpeg"
onChange={this.getBase64.bind(this)} onChange={this.getBase64.bind(this)}/>
value={this.props.type === "new" && this.props.idRoom !== -1 ? null : this.props.idRoom.images }/>
</Form.Field> </Form.Field>
</Form> </Form>

View file

@ -1,15 +1,11 @@
import React from 'react'; import React from "react";
import ReactDOM from 'react-dom'; import ReactDOM from "react-dom";
import App from './App'; import App from "./App";
import * as serviceWorker from './serviceWorker'; import * as serviceWorker from "./serviceWorker";
//React Router //React Router
//import { BrowserRouter, Route, Switch } from "react-router-dom"; //import { BrowserRouter, Route, Switch } from "react-router-dom";
const index = ( const index = <App />;
<App />
);
ReactDOM.render( ReactDOM.render(index, document.getElementById("root"));
index
, document.getElementById('root'));
serviceWorker.unregister(); serviceWorker.unregister();

View file

@ -11,9 +11,9 @@
// opt-in, read https://bit.ly/CRA-PWA // opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean( const isLocalhost = Boolean(
window.location.hostname === 'localhost' || window.location.hostname === "localhost" ||
// [::1] is the IPv6 localhost address. // [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' || window.location.hostname === "[::1]" ||
// 127.0.0.0/8 are considered localhost for IPv4. // 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match( window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
@ -21,7 +21,7 @@ const isLocalhost = Boolean(
); );
export function register(config) { export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
// The URL constructor is available in all browsers that support SW. // The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) { if (publicUrl.origin !== window.location.origin) {
@ -31,7 +31,7 @@ export function register(config) {
return; return;
} }
window.addEventListener('load', () => { window.addEventListener("load", () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) { if (isLocalhost) {
@ -42,8 +42,8 @@ export function register(config) {
// service worker/PWA documentation. // service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => { navigator.serviceWorker.ready.then(() => {
console.log( console.log(
'This web app is being served cache-first by a service ' + "This web app is being served cache-first by a service " +
'worker. To learn more, visit https://bit.ly/CRA-PWA' "worker. To learn more, visit https://bit.ly/CRA-PWA"
); );
}); });
} else { } else {
@ -57,21 +57,21 @@ export function register(config) {
function registerValidSW(swUrl, config) { function registerValidSW(swUrl, config) {
navigator.serviceWorker navigator.serviceWorker
.register(swUrl) .register(swUrl)
.then(registration => { .then((registration) => {
registration.onupdatefound = () => { registration.onupdatefound = () => {
const installingWorker = registration.installing; const installingWorker = registration.installing;
if (installingWorker == null) { if (installingWorker == null) {
return; return;
} }
installingWorker.onstatechange = () => { installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') { if (installingWorker.state === "installed") {
if (navigator.serviceWorker.controller) { if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched, // At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older // but the previous service worker will still serve the older
// content until all client tabs are closed. // content until all client tabs are closed.
console.log( console.log(
'New content is available and will be used when all ' + "New content is available and will be used when all " +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.' "tabs for this page are closed. See https://bit.ly/CRA-PWA."
); );
// Execute callback // Execute callback
@ -82,7 +82,7 @@ function registerValidSW(swUrl, config) {
// At this point, everything has been precached. // At this point, everything has been precached.
// It's the perfect time to display a // It's the perfect time to display a
// "Content is cached for offline use." message. // "Content is cached for offline use." message.
console.log('Content is cached for offline use.'); console.log("Content is cached for offline use.");
// Execute callback // Execute callback
if (config && config.onSuccess) { if (config && config.onSuccess) {
@ -93,25 +93,25 @@ function registerValidSW(swUrl, config) {
}; };
}; };
}) })
.catch(error => { .catch((error) => {
console.error('Error during service worker registration:', error); console.error("Error during service worker registration:", error);
}); });
} }
function checkValidServiceWorker(swUrl, config) { function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page. // Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, { fetch(swUrl, {
headers: { 'Service-Worker': 'script' } headers: { "Service-Worker": "script" },
}) })
.then(response => { .then((response) => {
// Ensure service worker exists, and that we really are getting a JS file. // Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type'); const contentType = response.headers.get("content-type");
if ( if (
response.status === 404 || response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1) (contentType != null && contentType.indexOf("javascript") === -1)
) { ) {
// No service worker found. Probably a different app. Reload the page. // No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => { navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => { registration.unregister().then(() => {
window.location.reload(); window.location.reload();
}); });
@ -123,18 +123,18 @@ function checkValidServiceWorker(swUrl, config) {
}) })
.catch(() => { .catch(() => {
console.log( console.log(
'No internet connection found. App is running in offline mode.' "No internet connection found. App is running in offline mode."
); );
}); });
} }
export function unregister() { export function unregister() {
if ('serviceWorker' in navigator) { if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready navigator.serviceWorker.ready
.then(registration => { .then((registration) => {
registration.unregister(); registration.unregister();
}) })
.catch(error => { .catch((error) => {
console.error(error.message); console.error(error.message);
}); });
} }

View file

@ -2,4 +2,4 @@
// allows you to do things like: // allows you to do things like:
// expect(element).toHaveTextContent(/react/i) // expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom // learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect'; import "@testing-library/jest-dom/extend-expect";

View file

@ -1,100 +1,79 @@
import React, { Component } from "react"; import React, { Component } from "react";
import HomeNavbar from "./../components/HomeNavbar"; import HomeNavbar from "./../components/HomeNavbar";
import { import { Image, Divider, Message, Grid } from "semantic-ui-react";
Image,
Divider,
Message,
Grid
} from "semantic-ui-react";
class Paragraph extends Component { class Paragraph extends Component {
state = { visible: true } state = { visible: true };
handleDismiss = () => { handleDismiss = () => {
this.setState({ visible: false }) this.setState({ visible: false });
setTimeout(() => { setTimeout(() => {
this.setState({ visible: true }) this.setState({ visible: true });
}, 2000) }, 2000);
} };
render() { render() {
if (this.state.visible) { if (this.state.visible) {
return (
<Message
onDismiss={this.handleDismiss}
header='Link has been sent!'
content='An e-mail has been sent your address, please follow the
instruction to create a new password'
/>
)
}
return ( return (
<p> <Message
<br /> onDismiss={this.handleDismiss}
<i>The message will return in 2s</i> header="Link has been sent!"
<br /> content="An e-mail has been sent your address, please follow the
<br /> instruction to create a new password"
</p> />
) );
} }
return (
<p>
<br />
<i>The message will return in 2s</i>
<br />
<br />
</p>
);
} }
}
const MessageReg = () => (
const MessageReg = () => ( <Grid>
<Grid>
<HomeNavbar /> <HomeNavbar />
<Divider /> <Divider />
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}> <Grid.Row height={3}>
</Grid.Row> <Grid.Column width={6}></Grid.Column>
<Grid.Row height={3}> <Grid.Column width={10}>
</Grid.Row> <Image src="title5.png" />
<Grid.Row height={3}> </Grid.Column>
</Grid.Row> <Grid.Column width={3}></Grid.Column>
<Grid.Row height={3}> </Grid.Row>
<Grid.Column width={6}> <Grid.Row height={3}></Grid.Row>
</Grid.Column> <Grid.Row height={3}></Grid.Row>
<Grid.Column width={10}> <Grid.Column width={3}></Grid.Column>
<Image src='title5.png' />
</Grid.Column>
<Grid.Column width={3}>
</Grid.Column>
</Grid.Row>
<Grid.Row height={3}>
</Grid.Row>
<Grid.Row height={3}>
</Grid.Row>
<Grid.Column width={3}>
</Grid.Column>
<Grid.Column width={4}> <Grid.Column width={4}>
<Image src='./img/logo.png' /> <Image src="./img/logo.png" />
</Grid.Column> </Grid.Column>
<Grid.Column width={6}> <Grid.Column width={6}>
<Paragraph /> <Paragraph />
</Grid.Column>
<Grid.Column width={4}>
</Grid.Column> </Grid.Column>
<Grid.Column width={4}></Grid.Column>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}> <Grid.Row height={3}>
</Grid.Row> <Grid.Column width={3}></Grid.Column>
<Grid.Row height={3}> <Grid.Column width={10}>
</Grid.Row> <Divider />
<Grid.Row height={3}> </Grid.Column>
<Grid.Column width={3}> <Grid.Column width={3}></Grid.Column>
</Grid.Column> </Grid.Row>
<Grid.Column width={10}> </Grid>
<Divider /> );
</Grid.Column>
<Grid.Column width={3}>
</Grid.Column>
</Grid.Row>
</Grid>
)
export default class ConfirmForgotPasswrod extends React.Component { export default class ConfirmForgotPasswrod extends React.Component {
render () { render() {
return ( return <MessageReg />;
<MessageReg />
)
} }
} }

View file

@ -1,100 +1,79 @@
import React, { Component } from "react"; import React, { Component } from "react";
import HomeNavbar from "./../components/HomeNavbar"; import HomeNavbar from "./../components/HomeNavbar";
import { import { Image, Divider, Message, Grid } from "semantic-ui-react";
Image,
Divider,
Message,
Grid
} from "semantic-ui-react";
class Paragraph extends Component { class Paragraph extends Component {
state = { visible: true } state = { visible: true };
handleDismiss = () => { handleDismiss = () => {
this.setState({ visible: false }) this.setState({ visible: false });
setTimeout(() => { setTimeout(() => {
this.setState({ visible: true }) this.setState({ visible: true });
}, 2000) }, 2000);
} };
render() { render() {
if (this.state.visible) { if (this.state.visible) {
return (
<Message
onDismiss={this.handleDismiss}
header='Congratulation!'
content='An e-mail has been sent your address, please confirm
your registration by following the enclosed link'
/>
)
}
return ( return (
<p> <Message
<br /> onDismiss={this.handleDismiss}
<i>The message will return in 2s</i> header="Congratulation!"
<br /> content="An e-mail has been sent your address, please confirm
<br /> your registration by following the enclosed link"
</p> />
) );
} }
return (
<p>
<br />
<i>The message will return in 2s</i>
<br />
<br />
</p>
);
} }
}
const MessageReg = () => (
const MessageReg = () => ( <Grid>
<Grid>
<HomeNavbar /> <HomeNavbar />
<Divider /> <Divider />
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}> <Grid.Row height={3}>
</Grid.Row> <Grid.Column width={6}></Grid.Column>
<Grid.Row height={3}> <Grid.Column width={10}>
</Grid.Row> <Image src="title5.png" />
<Grid.Row height={3}> </Grid.Column>
</Grid.Row> <Grid.Column width={3}></Grid.Column>
<Grid.Row height={3}> </Grid.Row>
<Grid.Column width={6}> <Grid.Row height={3}></Grid.Row>
</Grid.Column> <Grid.Row height={3}></Grid.Row>
<Grid.Column width={10}> <Grid.Column width={3}></Grid.Column>
<Image src='title5.png' />
</Grid.Column>
<Grid.Column width={3}>
</Grid.Column>
</Grid.Row>
<Grid.Row height={3}>
</Grid.Row>
<Grid.Row height={3}>
</Grid.Row>
<Grid.Column width={3}>
</Grid.Column>
<Grid.Column width={4}> <Grid.Column width={4}>
<Image src='./img/logo.png' /> <Image src="./img/logo.png" />
</Grid.Column> </Grid.Column>
<Grid.Column width={6}> <Grid.Column width={6}>
<Paragraph /> <Paragraph />
</Grid.Column>
<Grid.Column width={4}>
</Grid.Column> </Grid.Column>
<Grid.Column width={4}></Grid.Column>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}> <Grid.Row height={3}>
</Grid.Row> <Grid.Column width={3}></Grid.Column>
<Grid.Row height={3}> <Grid.Column width={10}>
</Grid.Row> <Divider />
<Grid.Row height={3}> </Grid.Column>
<Grid.Column width={3}> <Grid.Column width={3}></Grid.Column>
</Grid.Column> </Grid.Row>
<Grid.Column width={10}> </Grid>
<Divider /> );
</Grid.Column>
<Grid.Column width={3}>
</Grid.Column>
</Grid.Row>
</Grid>
)
export default class ConfirmRegistration extends React.Component { export default class ConfirmRegistration extends React.Component {
render () { render() {
return ( return <MessageReg />;
<MessageReg />
)
} }
} }

View file

@ -1,10 +1,10 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import DevicePanel from "../components/dashboard/DevicePanel"; import DevicePanel from "../components/dashboard/DevicePanel";
import Navbar from './Navbar' import Navbar from "./Navbar";
import MyHeader from '../components/HeaderController' import MyHeader from "../components/HeaderController";
import { call } from '../client_server'; import { call } from "../client_server";
import { Grid, Responsive } from 'semantic-ui-react' import { Grid, Responsive } from "semantic-ui-react";
/* /*
rooms -> actual rooms rooms -> actual rooms
activeItem -> the current room in view activeItem -> the current room in view
@ -14,7 +14,7 @@ import { Grid, Responsive } from 'semantic-ui-react'
id of Home is -1 id of Home is -1
*/ */
export default class Dashboard extends Component{ export default class Dashboard extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -33,40 +33,43 @@ export default class Dashboard extends Component{
getDevices() { getDevices() {
if (this.state.activeItem === -1) { if (this.state.activeItem === -1) {
call.getAllDevices() call
.then(res => { .getAllDevices()
if ( res.status === 200) { .then((res) => {
this.setState({ if (res.status === 200) {
devices: res.data console.log(res.data);
}); this.setState({
} devices: res.data,
}).catch(err => {
console.log(err);
}); });
}
})
.catch((err) => {
console.log(err);
});
} else { } else {
call.getAllDevicesByRoom(this.state.activeItem) call
.then(res => { .getAllDevicesByRoom(this.state.activeItem)
if (res.status === 200) { .then((res) => {
this.setState({ if (res.status === 200) {
devices: res.data this.setState({
}); devices: res.data,
}
}).catch(err => {
}); });
}
})
.catch((err) => {});
} }
} }
getRooms() { getRooms() {
call.getAllRooms(this.props.tkn) call
.then(res => { .getAllRooms(this.props.tkn)
this.setState({ .then((res) => {
rooms: res.data this.setState({
rooms: res.data,
});
}) })
}).catch(err => { .catch((err) => {});
}
});
}
componentDidMount() { componentDidMount() {
this.getRooms(); this.getRooms();
@ -74,69 +77,77 @@ getRooms() {
} }
addRoom(data) { addRoom(data) {
call.createRoom(data) call
.then(res => { .createRoom(data)
.then((res) => {
if (res.status === 200 && res.data) { if (res.status === 200 && res.data) {
this.getRooms(); this.getRooms();
} }
}).catch(err => { })
.catch((err) => {
console.log(err); console.log(err);
}); });
}; }
deleteRoom() { deleteRoom() {
let data = { let data = {
id : this.state.activeItem id: this.state.activeItem,
} };
call.deleteRoom(data) call
.then(res => { .deleteRoom(data)
.then((res) => {
//remove room in state.rooms //remove room in state.rooms
this.getRooms(); this.getRooms();
}).catch(err => { })
.catch((err) => {
console.log(err); console.log(err);
}); });
} }
updateRoom(data) { updateRoom(data) {
console.log(data) data.id = this.state.activeItem;
call.updateRoom(data) call
.then(res => { .updateRoom(data)
.then((res) => {
if (res.status === 200 && res.data) { if (res.status === 200 && res.data) {
this.getRooms(); this.getRooms();
this.forceUpdate(); this.forceUpdate();
} }
}).catch(err => {
}) })
.catch((err) => {});
} }
handleItemClick(id) { handleItemClick(id) {
// el -> obj of name and id // el -> obj of name and id
//da fare richiesta get della room e settare activeItem //da fare richiesta get della room e settare activeItem
this.setState({ this.setState({
activeItem: id activeItem: id,
}); });
if ( id === -1) { if (id === -1) {
call.getAllDevices(this.props.tkn) call
.then(res => { .getAllDevices(this.props.tkn)
if ( res.status === 200) { .then((res) => {
if (res.status === 200) {
this.setState({ this.setState({
devices: res.data devices: res.data,
}); });
} }
}).catch(err => { })
.catch((err) => {
console.log(err); console.log(err);
}); });
} else { } else {
call.getAllDevicesByRoom(id, this.props.tkn) call
.then(res => { .getAllDevicesByRoom(id, this.props.tkn)
.then((res) => {
if (res.status === 200) { if (res.status === 200) {
this.setState({ this.setState({
devices: res.data devices: res.data,
}); });
this.forceUpdate(); this.forceUpdate();
} }
}).catch(err => { })
.catch((err) => {
console.log(err); console.log(err);
}); });
} }
@ -144,59 +155,79 @@ getRooms() {
addDevice(data) { addDevice(data) {
data.params["roomId"] = this.state.activeItem; data.params["roomId"] = this.state.activeItem;
call.devicePost(data, this.props.tkn) call
.then(res => { .devicePost(data, this.props.tkn)
this.setState(state => ({ .then((res) => {
devices: state.devices.concat([res.data]) this.setState((state) => ({
})); devices: state.devices.concat([res.data]),
return this.state.devices; }));
}).catch(err => { return this.state.devices;
})
}); .catch((err) => {});
} }
render() {
render () { return (
return( <div style={{ height: "110vh", background: "#1b1c1d" }}>
<div style={{height : "110vh", background: '#1b1c1d'}}> <Responsive minWidth={768}>
<Responsive minWidth={768} > <Grid>
<Grid > <Grid.Row color="black">
<Grid.Row color='black'>
<Grid.Column> <Grid.Column>
<MyHeader logout={this.props.logout} /> <MyHeader logout={this.props.logout} />
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
<Grid.Row color='black'> <Grid.Row color="black">
<Grid.Column width={3}> <Grid.Column width={3}>
<Navbar addRoom={this.addRoom} updateRoom={this.updateRoom} deleteRoom={this.deleteRoom} rooms={this.state.rooms} handleItemClick={this.handleItemClick}/> <Navbar
</Grid.Column> addRoom={this.addRoom}
updateRoom={this.updateRoom}
deleteRoom={this.deleteRoom}
rooms={this.state.rooms}
handleItemClick={this.handleItemClick}
/>
</Grid.Column>
<Grid.Column width={13}> <Grid.Column width={13}>
<DevicePanel tkn={this.props.tkn} activeItem={this.state.activeItem} addDevice={this.addDevice} devices={this.state.devices} /> <DevicePanel
</Grid.Column> tkn={this.props.tkn}
</Grid.Row> activeItem={this.state.activeItem}
addDevice={this.addDevice}
devices={this.state.devices}
/>
</Grid.Column>
</Grid.Row>
</Grid> </Grid>
</Responsive> </Responsive>
<Responsive maxWidth={768} > <Responsive maxWidth={768}>
<Grid inverted> <Grid inverted>
<Grid.Row color='black'> <Grid.Row color="black">
<Grid.Column> <Grid.Column>
<MyHeader logout={this.props.logout} /> <MyHeader logout={this.props.logout} />
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
<Grid.Row color='black'> <Grid.Row color="black">
<Grid.Column color='black'> <Grid.Column color="black">
<Navbar addRoom={this.addRoom} deleteRoom={this.deleteRoom} rooms={this.state.rooms} handleItemClick={this.handleItemClick}/> <Navbar
</Grid.Column> addRoom={this.addRoom}
</Grid.Row> deleteRoom={this.deleteRoom}
<Grid.Row > rooms={this.state.rooms}
<Grid.Column > handleItemClick={this.handleItemClick}
<DevicePanel tkn={this.props.tkn} activeItem={this.state.activeItem} addDevice={this.addDevice} devices={this.state.devices} /> />
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> <Grid.Row>
<Grid.Column>
<DevicePanel
tkn={this.props.tkn}
activeItem={this.state.activeItem}
addDevice={this.addDevice}
devices={this.state.devices}
/>
</Grid.Column>
</Grid.Row>
</Grid>
</Responsive> </Responsive>
</div> </div>
) );
} }
} }

View file

@ -1,22 +1,17 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import {Button } from 'semantic-ui-react'; import { Button } from "semantic-ui-react";
export default class Dashboard extends Component { export default class Dashboard extends Component {
handleLogOut = (e) => {
console.log(this.props);
this.props.logout();
};
handleLogOut = (e) => { render() {
console.log(this.props); return (
this.props.logout(); <Button circular style={{ margin: "2em" }} onClick={this.handleLogOut}>
}; Go Home{" "}
</Button>
render() { );
return ( }
<Button }
circular
style={{margin: "2em"}}
onClick={this.handleLogOut}
>
Go Home </Button>
)
}
}

View file

@ -1,102 +1,122 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import {Button, Form, Grid, Header, Image, Icon, Message} from 'semantic-ui-react'; import {
import { call } from '../client_server'; Button,
Form,
Grid,
Header,
Image,
Icon,
Message,
} from "semantic-ui-react";
import { call } from "../client_server";
import { Redirect } from "react-router-dom"; import { Redirect } from "react-router-dom";
export default class ChangePass extends Component {
constructor(props) {
super(props);
this.state = {
password: "",
error: {
state: false,
message: "",
},
};
this.handleChangePassword = this.handleChangePassword.bind(this);
}
export default class ChangePass extends Component { onChangeHandler = (event) => {
constructor(props) { let nam = event.target.name;
super(props); let val = event.target.value;
this.state = { this.setState({ [nam]: val });
password: "", };
error: {
state: false, checkpassword = (e) => {
message: "", if (e.target.value !== this.state.password) {
} this.setState({
} error: {
this.handleChangePassword = this.handleChangePassword.bind(this); state: true,
message: "Passwords do not match.",
},
});
} }
};
onChangeHandler = (event) => { handleChangePassword = (e) => {
let nam = event.target.name; const params = {
let val = event.target.value; confirmationToken: this.props.query.token,
this.setState({[nam]: val}); password: this.state.password,
}; };
call
checkpassword = (e) => { .resetPassword(params)
if (e.target.value !== this.state.password) { .then((res) => {
this.setState({error: { if (res.status !== 200) {
state : true, this.setState({ error: { state: true, message: "Errore" } });
message : "Passwords do not match.", } else {
}}); return <Redirect to="/" />;
} }
}; // else set a message that an email has been sent
})
.catch((err) => {
console.log(err);
});
};
handleChangePassword = (e) => { render() {
const params = { return (
"confirmationToken" : this.props.query.token , <React.Fragment>
"password" : this.state.password <Button circular style={{ margin: "2em" }} href="/">
} <Icon name="arrow alternate circle left" />
call.resetPassword(params) Go Home{" "}
.then(res => { </Button>
if (res.status !== 200){ <Grid
this.setState({ error: { state: true, textAlign="center"
message: "Errore"}}); style={{ height: "70vh" }}
} else { verticalAlign="middle"
return <Redirect to="/" /> >
} <Grid.Column style={{ maxWidth: 450 }}>
// else set a message that an email has been sent <Header as="h2" color="blue" textAlign="center">
}).catch(err => { <Image src="img/logo.png" /> Reset Password
console.log(err); </Header>
}); <Form
}; size="large"
style={{ marginTop: "2em" }}
render() { error={this.state.error.state}
return (
<React.Fragment>
<Button
circular
style={{margin: "2em"}}
href="/"
> >
<Icon name='arrow alternate circle left'/> <Message
Go Home </Button> error
<Grid textAlign='center' style={{height: '70vh'}} verticalAlign='middle'> header="Change Password Error"
<Grid.Column style={{maxWidth: 450}}> content={this.state.error.message}
<Header as='h2' color='blue' textAlign='center'> />
<Image src='img/logo.png'/> Reset Password <Form.Input
</Header> icon="address card outline"
<Form size='large' style={{marginTop : "2em"}} error={this.state.error.state}> iconPosition="left"
<Message placeholder="Reset your password"
error name="password"
header='Change Password Error' type="password"
content= {this.state.error.message} onChange={this.onChangeHandler}
/> required
<Form.Input />
icon='address card outline' <Form.Input
iconPosition='left' icon="address card outline"
placeholder='Reset your password' iconPosition="left"
name="password" placeholder="Confirm Password"
type='password' name="confirm-password"
onChange={this.onChangeHandler} type="password"
required onChange={this.checkpassword}
/> required
<Form.Input />
icon='address card outline' <Button
iconPosition='left' color="blue"
placeholder='Confirm Password' fluid
name="confirm-password" size="large"
type='password' onClick={this.handleChangePassword}
onChange={this.checkpassword} >
required Confirm password
/> </Button>
<Button color='blue' fluid size='large' onClick={this.handleChangePassword}> </Form>
Confirm password </Grid.Column>
</Button> </Grid>
</Form> </React.Fragment>
</Grid.Column> );
</Grid> }
</React.Fragment> }
)
}
}

View file

@ -1,90 +1,108 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import {Button, Form, Grid, Header, Image, Icon, Message} from 'semantic-ui-react'; import {
import {Redirect } from "react-router-dom"; Button,
import { call } from '../client_server'; Form,
Grid,
Header,
Image,
Icon,
Message,
} from "semantic-ui-react";
import { Redirect } from "react-router-dom";
import { call } from "../client_server";
export default class ForgotPass extends Component {
constructor(props) {
super(props);
this.state = {
user: "",
error: {
state: false,
message: "",
},
success: false,
};
}
export default class ForgotPass extends Component { onChangeHandler = (event) => {
constructor(props) { let nam = event.target.name;
super(props); let val = event.target.value;
this.state = { this.setState({ [nam]: val });
user: "", };
error: {
state: false, handleSendEmail = (e) => {
message: "", e.preventDefault();
}, const params = {
success: false, email: this.state.user,
};
call
.initResetPassword(params)
.then((res) => {
console.log(res);
if (res.status === 200) {
this.setState({ success: true });
} }
if (res.status === "Errore") {
this.setState({ error: { state: true, message: "Errore" } });
}
//set a message that an email has been sent
})
.catch((err) => {
console.log(err);
});
};
render() {
if (this.state.success) {
return <Redirect to="sent-email" />;
} }
return (
onChangeHandler = (event) => { <React.Fragment>
let nam = event.target.name; <Button circular style={{ margin: "2em" }} href="/">
let val = event.target.value; <Icon name="arrow alternate circle left" />
this.setState({[nam]: val}); Go Home{" "}
}; </Button>
<Grid
handleSendEmail = (e) => { textAlign="center"
e.preventDefault(); style={{ height: "70vh" }}
const params = { verticalAlign="middle"
"email" : this.state.user, >
} <Grid.Column style={{ maxWidth: 450 }}>
<Header as="h2" color="blue" textAlign="center">
call.initResetPassword(params) <Image src="img/logo.png" /> Reset Password
.then(res => { </Header>
console.log(res); <Form
if (res.status === 200) { size="large"
this.setState({success : true}); style={{ marginTop: "2em" }}
} error={this.state.error.state}
if (res.status === "Errore") {
this.setState({ error: { state: true,
message: "Errore"}});
}
//set a message that an email has been sent
}).catch(err => {
console.log(err);
});
};
render() {
if (this.state.success) {
return <Redirect to="sent-email" />
}
return (
<React.Fragment>
<Button
circular
style={{margin: "2em"}}
href="/"
> >
<Icon name='arrow alternate circle left'/> <Message
Go Home </Button> error
<Grid textAlign='center' style={{height: '70vh'}} verticalAlign='middle'> header="Send E-mail Error"
<Grid.Column style={{maxWidth: 450}}> content={this.state.error.message}
<Header as='h2' color='blue' textAlign='center'> />
<Image src='img/logo.png'/> Reset Password <Form.Input
</Header> icon="address card outline"
<Form size='large' style={{marginTop : "2em"}} error={this.state.error.state}> iconPosition="left"
<Message placeholder="Username or E-mail"
error name="user"
header='Send E-mail Error' type="text"
content= {this.state.error.message} onChange={this.onChangeHandler}
/> required
<Form.Input />
icon='address card outline' <Button
iconPosition='left' color="blue"
placeholder='Username or E-mail' fluid
name="user" size="large"
type='text' onClick={this.handleSendEmail}
onChange={this.onChangeHandler} >
required Send E-mail
/> </Button>
<Button color='blue' fluid size='large' onClick={this.handleSendEmail}> </Form>
Send E-mail </Grid.Column>
</Button> </Grid>
</Form> </React.Fragment>
</Grid.Column> );
</Grid> }
</React.Fragment> }
)
}
}

View file

@ -11,97 +11,81 @@ import {
Header, Header,
Divider, Divider,
Message, Message,
Grid Grid,
} from "semantic-ui-react"; } from "semantic-ui-react";
class Paragraph extends Component { class Paragraph extends Component {
state = { visible: true } state = { visible: true };
handleDismiss = () => { handleDismiss = () => {
this.setState({ visible: false }) this.setState({ visible: false });
setTimeout(() => { setTimeout(() => {
this.setState({ visible: true }) this.setState({ visible: true });
}, 2000) }, 2000);
} };
render() { render() {
if (this.state.visible) { if (this.state.visible) {
return (
<Message
onDismiss={this.handleDismiss}
header='Link has been sent!'
content='An e-mail has been sent your address, please follow the
instruction to create a new password'
/>
)
}
return ( return (
<p> <Message
<br /> onDismiss={this.handleDismiss}
<i>The message will return in 2s</i> header="Link has been sent!"
<br /> content="An e-mail has been sent your address, please follow the
<br /> instruction to create a new password"
</p> />
) );
} }
return (
<p>
<br />
<i>The message will return in 2s</i>
<br />
<br />
</p>
);
} }
}
const MessageReg = () => (
const MessageReg = () => ( <Grid>
<Grid>
<HomeNavbar /> <HomeNavbar />
<Divider /> <Divider />
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}> <Grid.Row height={3}>
</Grid.Row> <Grid.Column width={6}></Grid.Column>
<Grid.Row height={3}> <Grid.Column width={10}>
</Grid.Row> <Image src="title5.png" />
<Grid.Row height={3}> </Grid.Column>
</Grid.Row> <Grid.Column width={3}></Grid.Column>
<Grid.Row height={3}> </Grid.Row>
<Grid.Column width={6}> <Grid.Row height={3}></Grid.Row>
</Grid.Column> <Grid.Row height={3}></Grid.Row>
<Grid.Column width={10}> <Grid.Column width={3}></Grid.Column>
<Image src='title5.png' />
</Grid.Column>
<Grid.Column width={3}>
</Grid.Column>
</Grid.Row>
<Grid.Row height={3}>
</Grid.Row>
<Grid.Row height={3}>
</Grid.Row>
<Grid.Column width={3}>
</Grid.Column>
<Grid.Column width={4}> <Grid.Column width={4}>
<Image src='./img/logo.png' /> <Image src="./img/logo.png" />
</Grid.Column> </Grid.Column>
<Grid.Column width={6}> <Grid.Column width={6}>
<Paragraph /> <Paragraph />
</Grid.Column>
<Grid.Column width={4}>
</Grid.Column> </Grid.Column>
<Grid.Column width={4}></Grid.Column>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}></Grid.Row>
<Grid.Row height={3}> <Grid.Row height={3}>
</Grid.Row> <Grid.Column width={3}></Grid.Column>
<Grid.Row height={3}> <Grid.Column width={10}>
</Grid.Row> <Divider />
<Grid.Row height={3}> </Grid.Column>
<Grid.Column width={3}> <Grid.Column width={3}></Grid.Column>
</Grid.Column> </Grid.Row>
<Grid.Column width={10}> </Grid>
<Divider /> );
</Grid.Column>
<Grid.Column width={3}>
</Grid.Column>
</Grid.Row>
</Grid>
)
export default class ForgotPasswrod extends React.Component { export default class ForgotPasswrod extends React.Component {
render () { render() {
return ( return <MessageReg />;
<MessageReg />
)
} }
} }

View file

@ -1,110 +1,127 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import { Grid, Button, Segment, Responsive, Image} from 'semantic-ui-react'; import { Grid, Button, Segment, Responsive, Image } from "semantic-ui-react";
import {Link } from "react-router-dom"; import { Link } from "react-router-dom";
import MyHeader from '../components/HeaderController' import MyHeader from "../components/HeaderController";
export default class FourOhFour extends Component {
export default class FourOhFour extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
const meme = ['1.jpeg', '2.jpeg', '3.png', '4.jpeg', '5.jpeg', '6.jpg', '7.jpg', const meme = [
'8.jpg', '9.jpeg', '10.jpg', '11.jpeg', '12.gif', '13.gif', '14.gif']; "1.jpeg",
"2.jpeg",
"3.png",
"4.jpeg",
"5.jpeg",
"6.jpg",
"7.jpg",
"8.jpg",
"9.jpeg",
"10.jpg",
"11.jpeg",
"12.gif",
"13.gif",
"14.gif",
];
var arrayNum = Math.floor(Math.random() * 13) + 1; var arrayNum = Math.floor(Math.random() * 13) + 1;
var path = 'img/room_404_meme/' + meme[arrayNum]; var path = "img/room_404_meme/" + meme[arrayNum];
this.state = {meme : path}; this.state = { meme: path };
} }
render() { render() {
return (
return ( <Segment.Group>
<Segment.Group> <Responsive as={Segment} minWidth={768}>
<Responsive as={Segment} minWidth={768}> <div style={{ height: "110vh", background: "#1b1c1d" }}>
<div style={{height : "110vh", background: '#1b1c1d'}}> <Grid>
<Grid > <Grid.Row color="black">
<Grid.Row color='black'>
<Grid.Column>
<MyHeader logout={this.props.logout} />
</Grid.Column>
</Grid.Row>
<Grid.Row color='black'>
<Grid.Column width={16}>
<Segment inverted color='red'>
<Grid>
<Grid.Row>
<Grid.Column textAlign='center'>
<h1>404 Page Not Found</h1>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column width={8}>
<Image centered src={this.state.meme} size='medium' />
</Grid.Column>
<Grid.Column width={8}>
<p>
Hey what are you doing here?
Looks like you are lost, this room does not exist. Maybe you were looking for
the kitchen, or the garage, or the bedroom, or your love room... so don't
wait here and let's go back to our main room! ...or refresh this page
some times...
</p>
<Button fluid inverted color='white'>
<Link style={{color: 'black'}} to="/">Let's go back to our main room!</Link>
</Button>
</Grid.Column>
</Grid.Row>
</Grid>
</Segment>
</Grid.Column>
</Grid.Row>
</Grid>
</div>
</Responsive>
<Responsive as={Segment} maxWidth={768}>
<div style={{background: '#1b1c1d'}}>
<Grid >
<Grid.Row color='black'>
<Grid.Column> <Grid.Column>
<MyHeader logout={this.props.logout} /> <MyHeader logout={this.props.logout} />
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
<Grid.Row color='black'> <Grid.Row color="black">
<Grid.Column width={16}> <Grid.Column width={16}>
<Segment inverted color='red'> <Segment inverted color="red">
<Grid> <Grid>
<Grid.Row> <Grid.Row>
<Grid.Column textAlign='center'> <Grid.Column textAlign="center">
<h1>404 Page Not Found</h1> <h1>404 Page Not Found</h1>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
<Grid.Row> <Grid.Row>
<Grid.Column width={16}> <Grid.Column width={8}>
<Image centered src={this.state.meme} size='medium' /> <Image centered src={this.state.meme} size="medium" />
</Grid.Column> </Grid.Column>
</Grid.Row> <Grid.Column width={8}>
<Grid.Row>
<Grid.Column width={16}>
<p> <p>
Hey what are you doing here? Hey what are you doing here? Looks like you are
Looks like you are lost, this room does not exist. Maybe you were looking for lost, this room does not exist. Maybe you were
the kitchen, or the garage, or the bedroom, or your love room... so don't looking for the kitchen, or the garage, or the
wait here and let's go back to our main room! ...or refresh this page bedroom, or your love room... so don't wait here and
some times... let's go back to our main room! ...or refresh this
page some times...
</p> </p>
<Button fluid inverted color='white'> <Button fluid inverted color="white">
<Link style={{color: 'black'}} to="/">Let's go back to our main room!</Link> <Link style={{ color: "black" }} to="/">
Let's go back to our main room!
</Link>
</Button> </Button>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>
</Segment> </Segment>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>
</div> </div>
</Responsive> </Responsive>
</Segment.Group>
) <Responsive as={Segment} maxWidth={768}>
} <div style={{ background: "#1b1c1d" }}>
<Grid>
<Grid.Row color="black">
<Grid.Column>
<MyHeader logout={this.props.logout} />
</Grid.Column>
</Grid.Row>
<Grid.Row color="black">
<Grid.Column width={16}>
<Segment inverted color="red">
<Grid>
<Grid.Row>
<Grid.Column textAlign="center">
<h1>404 Page Not Found</h1>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column width={16}>
<Image centered src={this.state.meme} size="medium" />
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column width={16}>
<p>
Hey what are you doing here? Looks like you are
lost, this room does not exist. Maybe you were
looking for the kitchen, or the garage, or the
bedroom, or your love room... so don't wait here and
let's go back to our main room! ...or refresh this
page some times...
</p>
<Button fluid inverted color="white">
<Link style={{ color: "black" }} to="/">
Let's go back to our main room!
</Link>
</Button>
</Grid.Column>
</Grid.Row>
</Grid>
</Segment>
</Grid.Column>
</Grid.Row>
</Grid>
</div>
</Responsive>
</Segment.Group>
);
}
} }

View file

@ -1,271 +1,270 @@
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import React, { Component } from 'react'; import React, { Component } from "react";
import HomeNavbar from './../components/HomeNavbar'; import HomeNavbar from "./../components/HomeNavbar";
import { import {
Button, Button,
Container, Container,
Grid, Grid,
Header, Header,
Icon, Icon,
Image, Image,
List, List,
Menu, Menu,
Responsive, Responsive,
Segment, Segment,
Sidebar, Sidebar,
Visibility, Visibility,
} from 'semantic-ui-react'; } from "semantic-ui-react";
// Heads up! // Heads up!
// We using React Static to prerender our docs with server side rendering, this is a quite simple solution. // We using React Static to prerender our docs with server side rendering, this is a quite simple solution.
// For more advanced usage please check Responsive docs under the "Usage" section. // For more advanced usage please check Responsive docs under the "Usage" section.
const getWidth = () => { const getWidth = () => {
const isSSR = typeof window === 'undefined'; const isSSR = typeof window === "undefined";
return isSSR ? Responsive.onlyTablet.minWidth : window.innerWidth; return isSSR ? Responsive.onlyTablet.minWidth : window.innerWidth;
} };
/* eslint-disable react/no-multi-comp */ /* eslint-disable react/no-multi-comp */
/* Heads up! HomepageHeading uses inline styling, however it's not the best practice. Use CSS or styled components for /* Heads up! HomepageHeading uses inline styling, however it's not the best practice. Use CSS or styled components for
* such things. * such things.
*/ */
const HomepageHeading = ({ mobile }) => ( const HomepageHeading = ({ mobile }) => (
<Container text> <Container text>
<Header <Header
as='h1' as="h1"
content='SmartHut' content="SmartHut"
inverted inverted
style={{ style={{
fontSize: mobile ? '2em' : '4em', fontSize: mobile ? "2em" : "4em",
fontWeight: 'normal', fontWeight: "normal",
marginBottom: 0, marginBottom: 0,
marginTop: mobile ? '1.5em' : '3em', marginTop: mobile ? "1.5em" : "3em",
}} }}
/> />
<Header <Header
as='h2' as="h2"
content='Keep your Home fully Connected' content="Keep your Home fully Connected"
inverted inverted
style={{ style={{
fontSize: mobile ? '1.5em' : '1.7em', fontSize: mobile ? "1.5em" : "1.7em",
fontWeight: 'normal', fontWeight: "normal",
marginTop: mobile ? '0.5em' : '1.5em', marginTop: mobile ? "0.5em" : "1.5em",
}} }}
/> />
<Button size='huge' color="orange" href="/signup"> <Button size="huge" color="orange" href="/signup">
Get Started Get Started
<Icon name='right arrow' /> <Icon name="right arrow" />
</Button> </Button>
</Container> </Container>
) );
HomepageHeading.propTypes = { HomepageHeading.propTypes = {
mobile: PropTypes.bool, mobile: PropTypes.bool,
} };
class DesktopContainer extends Component { class DesktopContainer extends Component {
state = {}; state = {};
hideFixedMenu = () => this.setState({ fixed: false }) hideFixedMenu = () => this.setState({ fixed: false });
showFixedMenu = () => this.setState({ fixed: true }) showFixedMenu = () => this.setState({ fixed: true });
render() { render() {
const { children } = this.props const { children } = this.props;
return ( return (
<Responsive getWidth={getWidth} minWidth={Responsive.onlyTablet.minWidth}> <Responsive getWidth={getWidth} minWidth={Responsive.onlyTablet.minWidth}>
<Visibility <Visibility
once={false} once={false}
onBottomPassed={this.showFixedMenu} onBottomPassed={this.showFixedMenu}
onBottomPassedReverse={this.hideFixedMenu} onBottomPassedReverse={this.hideFixedMenu}
> >
<Segment <Segment
basic basic
textAlign='center' textAlign="center"
style={{ style={{
minHeight: 700, minHeight: 700,
padding: '1em 0em', padding: "1em 0em",
background: ` linear-gradient(to bottom, rgba(0, 46, 200, 0.51), rgba(0, 0, 0, 0.51)), url("img/header.jpg")`, background: ` linear-gradient(to bottom, rgba(0, 46, 200, 0.51), rgba(0, 0, 0, 0.51)), url("img/header.jpg")`,
backgroundSize: "cover", backgroundSize: "cover",
}} }}
vertical vertical
> >
<HomeNavbar /> <HomeNavbar />
<HomepageHeading /> <HomepageHeading />
</Segment> </Segment>
</Visibility> </Visibility>
{children} {children}
</Responsive> </Responsive>
) );
} }
} }
DesktopContainer.propTypes = { DesktopContainer.propTypes = {
children: PropTypes.node, children: PropTypes.node,
} };
class MobileContainer extends Component { class MobileContainer extends Component {
state = {} state = {};
handleSidebarHide = () => this.setState({ sidebarOpened: false }) handleSidebarHide = () => this.setState({ sidebarOpened: false });
handleToggle = () => this.setState({ sidebarOpened: true }) handleToggle = () => this.setState({ sidebarOpened: true });
render() { render() {
const { children } = this.props; const { children } = this.props;
const { sidebarOpened } = this.state; const { sidebarOpened } = this.state;
return ( return (
<Responsive <Responsive
as={Sidebar.Pushable} as={Sidebar.Pushable}
getWidth={getWidth} getWidth={getWidth}
maxWidth={Responsive.onlyMobile.maxWidth} maxWidth={Responsive.onlyMobile.maxWidth}
> >
<Sidebar <Sidebar
as={Menu} as={Menu}
animation='push' animation="push"
inverted inverted
onHide={this.handleSidebarHide} onHide={this.handleSidebarHide}
vertical vertical
visible={sidebarOpened} visible={sidebarOpened}
> >
<Menu.Item as='a' active> <Menu.Item as="a" active>
Home Home
</Menu.Item> </Menu.Item>
<Menu.Item as='a'>Log in</Menu.Item> <Menu.Item as="a">Log in</Menu.Item>
<Menu.Item as='a'>Sign Up</Menu.Item> <Menu.Item as="a">Sign Up</Menu.Item>
</Sidebar> </Sidebar>
<Sidebar.Pusher dimmed={sidebarOpened}> <Sidebar.Pusher dimmed={sidebarOpened}>
<Segment <Segment
inverted inverted
textAlign='center' textAlign="center"
style={{ minHeight: 350, padding: '1em 0em' }} style={{ minHeight: 350, padding: "1em 0em" }}
vertical vertical
> >
<Container> <Container>
<Menu inverted pointing secondary size='large'> <Menu inverted pointing secondary size="large">
<Menu.Item onClick={this.handleToggle}> <Menu.Item onClick={this.handleToggle}>
<Icon name='sidebar' /> <Icon name="sidebar" />
</Menu.Item> </Menu.Item>
<Menu.Item position='right'> <Menu.Item position="right">
<Button as='a' inverted> <Button as="a" inverted>
Log in Log in
</Button> </Button>
<Button as='a' inverted style={{ marginLeft: '0.5em' }}> <Button as="a" inverted style={{ marginLeft: "0.5em" }}>
Sign Up Sign Up
</Button> </Button>
</Menu.Item> </Menu.Item>
</Menu> </Menu>
</Container> </Container>
<HomepageHeading mobile /> <HomepageHeading mobile />
</Segment> </Segment>
{children} {children}
</Sidebar.Pusher> </Sidebar.Pusher>
</Responsive> </Responsive>
) );
} }
} }
MobileContainer.propTypes = { MobileContainer.propTypes = {
children: PropTypes.node, children: PropTypes.node,
} };
const ResponsiveContainer = ({ children }) => ( const ResponsiveContainer = ({ children }) => (
<div> <div>
<DesktopContainer>{children}</DesktopContainer> <DesktopContainer>{children}</DesktopContainer>
<MobileContainer>{children}</MobileContainer> <MobileContainer>{children}</MobileContainer>
</div> </div>
) );
ResponsiveContainer.propTypes = { ResponsiveContainer.propTypes = {
children: PropTypes.node, children: PropTypes.node,
} };
const Home = () => ( const Home = () => (
<ResponsiveContainer> <ResponsiveContainer>
<Segment style={{ padding: '8em 0em' }} vertical> <Segment style={{ padding: "8em 0em" }} vertical>
<Grid container stackable verticalAlign='middle'> <Grid container stackable verticalAlign="middle">
<Grid.Row> <Grid.Row>
<Grid.Column width={8}> <Grid.Column width={8}>
<Header as='h3' style={{ fontSize: '2em' }}> <Header as="h3" style={{ fontSize: "2em" }}>
We help you keep your home connected We help you keep your home connected
</Header> </Header>
<p style={{ fontSize: '1.33em' }}> <p style={{ fontSize: "1.33em" }}>
In a few steps your home will be fully connected with SmartHut. In a few steps your home will be fully connected with SmartHut.
</p> </p>
<Header as='h3' style={{ fontSize: '2em' }}> <Header as="h3" style={{ fontSize: "2em" }}>
Choose between a wide range of devices Choose between a wide range of devices
</Header> </Header>
<p style={{ fontSize: '1.33em' }}> <p style={{ fontSize: "1.33em" }}>
SmartHut is a leading worldwide company in technology innovation. SmartHut is a leading worldwide company in technology innovation.
Explore our website to find the best devices for each room of your home! Explore our website to find the best devices for each room of your
</p> home!
</Grid.Column> </p>
<Grid.Column floated='right' width={6}> </Grid.Column>
<Image bordered rounded size='large' src='/img/banner.jpg' /> <Grid.Column floated="right" width={6}>
</Grid.Column> <Image bordered rounded size="large" src="/img/banner.jpg" />
</Grid.Row> </Grid.Column>
<Grid.Row> </Grid.Row>
<Grid.Column textAlign='center'> <Grid.Row>
<Button size='huge'>Check It Out</Button> <Grid.Column textAlign="center">
</Grid.Column> <Button size="huge">Check It Out</Button>
</Grid.Row> </Grid.Column>
</Grid> </Grid.Row>
</Segment> </Grid>
</Segment>
<Segment style={{ padding: '8em 0em' }} vertical> <Segment style={{ padding: "8em 0em" }} vertical>
<Container text> <Container text>
<Header as='h3' style={{ fontSize: '2em' }}> <Header as="h3" style={{ fontSize: "2em" }}>
Have you ever dreamt about a smart home? Have you ever dreamt about a smart home?
</Header> </Header>
<p style={{ fontSize: '1.33em' }}> <p style={{ fontSize: "1.33em" }}>
Let us carrying you into the future. With SmartHut, being at home Let us carrying you into the future. With SmartHut, being at home will
will be a refreshing experience. With just a few clicks, you will be be a refreshing experience. With just a few clicks, you will be able
able the set the illumination of your entire place. the set the illumination of your entire place. Follow the intelligent
Follow the intelligent light, follow SmartHut. light, follow SmartHut.
</p> </p>
<Button as='a' size='large'> <Button as="a" size="large">
Read More Read More
</Button> </Button>
</Container> </Container>
</Segment> </Segment>
<Segment inverted vertical style={{ padding: '5em 0em' }}> <Segment inverted vertical style={{ padding: "5em 0em" }}>
<Container> <Container>
<Grid divided inverted stackable> <Grid divided inverted stackable>
<Grid.Row> <Grid.Row>
<Grid.Column width={3}> <Grid.Column width={3}>
<Header inverted as='h4' content='About' /> <Header inverted as="h4" content="About" />
<List link inverted> <List link inverted>
<List.Item as='a'>Sitemap</List.Item> <List.Item as="a">Sitemap</List.Item>
<List.Item as='a'>Contact Us</List.Item> <List.Item as="a">Contact Us</List.Item>
<List.Item as='a'>Religious Ceremonies</List.Item> <List.Item as="a">Religious Ceremonies</List.Item>
<List.Item as='a'>Gazebo Plans</List.Item> <List.Item as="a">Gazebo Plans</List.Item>
</List> </List>
</Grid.Column> </Grid.Column>
<Grid.Column width={3}> <Grid.Column width={3}>
<Header inverted as='h4' content='Services' /> <Header inverted as="h4" content="Services" />
<List link inverted> <List link inverted>
<List.Item as='a'>Banana Pre-Order</List.Item> <List.Item as="a">Banana Pre-Order</List.Item>
<List.Item as='a'>DNA FAQ</List.Item> <List.Item as="a">DNA FAQ</List.Item>
<List.Item as='a'>How To Access</List.Item> <List.Item as="a">How To Access</List.Item>
<List.Item as='a'>Favorite X-Men</List.Item> <List.Item as="a">Favorite X-Men</List.Item>
</List> </List>
</Grid.Column> </Grid.Column>
<Grid.Column width={7}> <Grid.Column width={7}>
<Header as='h4' inverted> <Header as="h4" inverted>
SmartHut SmartHut
</Header> </Header>
<p> <p>Keep your Home connected.</p>
Keep your Home connected. </Grid.Column>
</p> </Grid.Row>
</Grid.Column> </Grid>
</Grid.Row> </Container>
</Grid> </Segment>
</Container> </ResponsiveContainer>
</Segment> );
</ResponsiveContainer>
)
export default Home; export default Home;

View file

@ -1,22 +1,17 @@
import React, { Component } from "react"; import React, { Component } from "react";
import HomeNavbar from "./../components/HomeNavbar"; import HomeNavbar from "./../components/HomeNavbar";
import { import { Container, Header, Divider, Grid } from "semantic-ui-react";
Container,
Header,
Divider,
Grid
} from "semantic-ui-react";
const ContainerExampleAlignment = () => ( const ContainerExampleAlignment = () => (
<div> <div>
<HomeNavbar /> <HomeNavbar />
<Container textAlign='justified'> <Container textAlign="justified">
<Header as="h1"> Instructions Page </Header> <Header as="h1"> Instructions Page </Header>
<Grid> <Grid>
<Grid.Row height={15}></Grid.Row> <Grid.Row height={15}></Grid.Row>
</Grid> </Grid>
</Container> </Container>
<Container textAlign='justified'> <Container textAlign="justified">
<b>First Step</b> <b>First Step</b>
<Divider /> <Divider />
<p> <p>
@ -36,74 +31,71 @@ const ContainerExampleAlignment = () => (
</p> </p>
<Divider /> <Divider />
</Container> </Container>
<Container textAlign='justified'> <Container textAlign="justified">
<b>Second Step</b> <b>Second Step</b>
<Divider /> <Divider />
<p> <p>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
ligula eget dolor. Aenean massa strong. Cum sociis natoque penatibus et ligula eget dolor. Aenean massa strong. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis,
ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
Nullam dictum felis eu pede link mollis pretium. Integer tincidunt. Cras Nullam dictum felis eu pede link mollis pretium. Integer tincidunt. Cras
dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend
tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac,
enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean
imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper
ultricies nisi. ultricies nisi.
</p> </p>
<Divider /> <Divider />
</Container> </Container>
<Container textAlign='justified'> <Container textAlign="justified">
<b>Third Step</b> <b>Third Step</b>
<Divider /> <Divider />
<p> <p>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
ligula eget dolor. Aenean massa strong. Cum sociis natoque penatibus et ligula eget dolor. Aenean massa strong. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis,
ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
Nullam dictum felis eu pede link mollis pretium. Integer tincidunt. Cras Nullam dictum felis eu pede link mollis pretium. Integer tincidunt. Cras
dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend
tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac,
enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean
imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper
ultricies nisi. ultricies nisi.
</p> </p>
<Divider /> <Divider />
</Container> </Container>
<Container textAlign='justified'> <Container textAlign="justified">
<b>Last Step</b> <b>Last Step</b>
<Divider /> <Divider />
<p> <p>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
ligula eget dolor. Aenean massa strong. Cum sociis natoque penatibus et ligula eget dolor. Aenean massa strong. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis,
ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
Nullam dictum felis eu pede link mollis pretium. Integer tincidunt. Cras Nullam dictum felis eu pede link mollis pretium. Integer tincidunt. Cras
dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend
tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac,
enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean
imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper
ultricies nisi. ultricies nisi.
</p> </p>
<Divider /> <Divider />
</Container> </Container>
</div> </div>
) );
export default class Insturction extends Component {
export default class Insturction extends Component{ render() {
render() { return <ContainerExampleAlignment />;
return( }
<ContainerExampleAlignment /> }
)
}
}

View file

@ -1,101 +1,130 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import {Button, Form, Grid, Header, Image, Message, Icon, Checkbox, Input} from 'semantic-ui-react'; import {
Button,
Form,
Grid,
Header,
Image,
Message,
Icon,
Checkbox,
Input,
} from "semantic-ui-react";
export default class Login extends Component { export default class Login extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
user: "", user: "",
password : "", password: "",
fireRedirect: false, fireRedirect: false,
error : { state : false, error: { state: false, message: "" },
message: ""},
}; };
} }
handleLogin = (e) => { handleLogin = (e) => {
e.preventDefault(); e.preventDefault();
const params = { const params = {
"usernameOrEmail": this.state.user, usernameOrEmail: this.state.user,
"password": this.state.password, password: this.state.password,
}; };
this.props.auth({ this.props
user: this.state.user, .auth({
params : params, user: this.state.user,
}).then(res => { params: params,
if (res.status === 200) { })
.then((res) => {
} else { if (res.status === 200) {
this.setState({error: { state: true, } else {
message: "Errore"}}); this.setState({ error: { state: true, message: "Errore" } });
} }
}).catch(err => { })
console.log(err); .catch((err) => {
}); console.log(err);
});
}; };
onChangeHandler = (event) => { onChangeHandler = (event) => {
let nam = event.target.name; let nam = event.target.name;
let val = event.target.value; let val = event.target.value;
this.setState({[nam]: val}); this.setState({ [nam]: val });
}; };
toggle = () => this.setState((prevState) => ({ rememberme: !prevState.rememberme })); toggle = () =>
this.setState((prevState) => ({ rememberme: !prevState.rememberme }));
render() { render() {
return ( return (
<React.Fragment> <React.Fragment>
<Button <Button circular style={{ margin: "2em" }} href="/">
circular <Icon name="arrow alternate circle left" />
style={{margin: "2em"}}
href="/"
>
<Icon name='arrow alternate circle left'/>
Go Home Go Home
</Button> </Button>
<Grid textAlign='center' style={{height: '70vh'}} verticalAlign='middle'> <Grid
<Grid.Column style={{maxWidth: 450}}> textAlign="center"
<Header as='h2' color='blue' textAlign='center'> style={{ height: "70vh" }}
<Image src='img/logo.png'/> Log-in to SmartHut verticalAlign="middle"
>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as="h2" color="blue" textAlign="center">
<Image src="img/logo.png" /> Log-in to SmartHut
</Header> </Header>
<Form size='large' style={{marginTop : "2em"}} error={this.state.error.state}> <Form
<Message size="large"
error style={{ marginTop: "2em" }}
header='Login Error' error={this.state.error.state}
content= {this.state.error.message} >
/> <Message
<Form.Input error
control={Input} header="Login Error"
type="text" content={this.state.error.message}
icon='user' />
name="user" <Form.Input
iconPosition='left' control={Input}
placeholder='Username or E-mail' type="text"
onChange={this.onChangeHandler} icon="user"
/> name="user"
<Form.Input iconPosition="left"
icon='lock' placeholder="Username or E-mail"
iconPosition='left' onChange={this.onChangeHandler}
placeholder='Password' />
name="password" <Form.Input
type='password' icon="lock"
onChange={this.onChangeHandler} iconPosition="left"
/> placeholder="Password"
<Checkbox type="checkbox" name="rememberme" onClick={this.toggle} label='Remember me' style={{margin: "1.5em 0", float : "left"}}/> name="password"
type="password"
onChange={this.onChangeHandler}
/>
<Checkbox
type="checkbox"
name="rememberme"
onClick={this.toggle}
label="Remember me"
style={{ margin: "1.5em 0", float: "left" }}
/>
<Button color='blue' fluid size='large' onClick={this.handleLogin}> <Button
Login color="blue"
fluid
size="large"
onClick={this.handleLogin}
>
Login
</Button> </Button>
</Form> </Form>
<Message> <Message>
<p><a href="/forgot-password">Forgot Password?</a></p> <p>
<p>New to us? <a href='/signup'> Sign Up</a></p> <a href="/forgot-password">Forgot Password?</a>
</p>
<p>
New to us? <a href="/signup"> Sign Up</a>
</p>
</Message> </Message>
</Grid.Column> </Grid.Column>
</Grid> </Grid>
</React.Fragment> </React.Fragment>
) );
} }
} }

View file

@ -1,23 +1,30 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import { Menu, Grid, Icon, Responsive, Segment, Dropdown } from "semantic-ui-react"; import {
import {editButtonStyle} from "../components/dashboard/devices/styleComponents"; Menu,
Grid,
Icon,
Responsive,
Segment,
Dropdown,
} from "semantic-ui-react";
import { editButtonStyle } from "../components/dashboard/devices/styleComponents";
import ModalWindow from "../components/modalform"; import ModalWindow from "../components/modalform";
class Navbar extends Component { class Navbar extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
activeItemName: 'Home', activeItemName: "Home",
activeItem: -1, activeItem: -1,
edited: "", edited: "",
editMode : false editMode: false,
} };
} }
editModeController = (e) => this.setState((prevState) => ({ editMode: !prevState.editMode })); editModeController = (e) =>
this.setState((prevState) => ({ editMode: !prevState.editMode }));
handleClick = (e, {id, name}) => { handleClick = (e, { id, name }) => {
console.log(id);
let obj = undefined; let obj = undefined;
this.props.rooms.forEach((e) => { this.props.rooms.forEach((e) => {
if (e.id === id) { if (e.id === id) {
@ -26,162 +33,161 @@ class Navbar extends Component {
}); });
this.setState({ this.setState({
activeItem: id, activeItem: id,
activeRoom: obj, activeRoom: obj,
activeItemName: name activeItemName: name,
}); });
this.props.handleItemClick(id) this.props.handleItemClick(id);
} };
render(){ render() {
//const { activeItem } = this.state //const { activeItem } = this.state
return ( return (
<div style={{background: '#1b1c1d'}}> <div style={{ background: "#1b1c1d!important" }}>
<Segment.Group> <Segment.Group>
<Responsive as={Segment} minWidth={768}> <Responsive as={Segment} minWidth={768}>
<Grid> <Grid>
<Grid.Row color='black'> <Grid.Row color="black">
<button style={editButtonStyle} onClick={this.editModeController}>Edit</button> <button
</Grid.Row> style={editButtonStyle}
<Grid.Row color='black'> onClick={this.editModeController}
>
Edit
</button>
</Grid.Row>
<Grid.Row color="black">
<Menu inverted fluid vertical> <Menu inverted fluid vertical>
<Menu.Item <Menu.Item
key={-1} key={-1}
id={-1} id={-1}
name='Home' name="Home"
active={this.state.activeItem === -1} active={this.state.activeItem === -1}
onClick={this.handleClick} onClick={this.handleClick}
> >
<Grid> <Grid>
<Grid.Row> <Grid.Row>
<Grid.Column> <Grid.Column>
<Icon name="home" size="small"/> <Icon name="home" size="small" />
</Grid.Column> </Grid.Column>
<Grid.Column> <Grid.Column>HOME</Grid.Column>
HOME </Grid.Row>
</Grid.Column> </Grid>
</Grid.Row> </Menu.Item>
</Grid>
</ Menu.Item> {this.props.rooms
? this.props.rooms.map((e, i) => {
{this.props.rooms ? return (
this.props.rooms.map((e, i) => { <Menu.Item
return ( id={e.id}
<Menu.Item key={i}
id={e.id} name={e.name}
key={i} active={this.state.activeItem === e.id}
name={e.name} onClick={this.handleClick}
active={this.state.activeItem === e.id} >
onClick={this.handleClick} <Grid>
> <Grid.Row>
<Grid> <Grid.Column>
<Grid.Row> <Icon name={e.icon} size="small" />
<Grid.Column> </Grid.Column>
<Icon name={e.icon} size="small"/> <Grid.Column width={8}>{e.name}</Grid.Column>
</Grid.Column> <Grid.Column floated="right">
<Grid.Column width={8}> {this.state.editMode ? (
{e.name} <ModalWindow
</Grid.Column> type="modify"
<Grid.Column floated="right"> idRoom={e}
{this.state.editMode ? updateRoom={this.props.updateRoom}
<ModalWindow type="modify" idRoom={e} updateRoom={this.props.updateRoom} deleteRoom={this.props.deleteRoom}/> deleteRoom={this.props.deleteRoom}
: null />
} ) : null}
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>
</ Menu.Item> </Menu.Item>
) );
}) : null })
} : null}
<Menu.Item <Menu.Item
name='newM' name="newM"
active={this.state.activeItem === 'newM'} active={this.state.activeItem === "newM"}
> >
<Grid>
<Grid.Row centered name="new">
<ModalWindow type="new" addRoom={this.props.addRoom} />
</Grid.Row>
</Grid>
</Menu.Item>
</Menu>
</Grid.Row>
</Grid>
</Responsive>
<Grid> <Responsive as={Segment} maxWidth={768}>
<Grid.Row centered name='new'> <Menu inverted>
<ModalWindow type="new" addRoom={this.props.addRoom}/> <Dropdown item fluid text={this.state.activeItemName}>
</Grid.Row> <Dropdown.Menu>
</Grid> <Dropdown.Item
key={-1}
id={-1}
name="Home"
active={this.state.activeItem === "Home"}
onClick={this.handleClick}
>
<Grid>
<Grid.Row>
<Grid.Column>
<Icon name="home" size="small" />
</Grid.Column>
<Grid.Column>Home</Grid.Column>
</Grid.Row>
</Grid>
</Dropdown.Item>
</ Menu.Item> {this.props.rooms
</Menu> ? this.props.rooms.map((e, i) => {
</Grid.Row> return (
</Grid> <Dropdown.Item
</Responsive> id={e.id}
key={i}
<Responsive as={Segment} maxWidth={768}> name={e.name}
<Menu inverted> active={this.state.activeItem === e.id}
<Dropdown item fluid text={this.state.activeItemName}> onClick={this.handleClick}
<Dropdown.Menu> >
<Grid>
<Dropdown.Item <Grid.Row>
key={-1} <Grid.Column width={1}>
name='Home' <Icon name={e.icon} size="small" />
active={this.state.activeItem === 'Home'} </Grid.Column>
onClick={this.handleClick}> <Grid.Column>{e.name}</Grid.Column>
<Grid> </Grid.Row>
<Grid.Row> </Grid>
<Grid.Column> </Dropdown.Item>
<Icon name="home" size="small"/> );
</Grid.Column> })
<Grid.Column> : null}
Home </Dropdown.Menu>
</Grid.Column> </Dropdown>
</Grid.Row> </Menu>
</Grid> <Grid inverted>
</Dropdown.Item> <Grid.Row>
<Grid.Column width={8}>
{this.props.rooms ? <ModalWindow type="new" addRoom={this.props.addRoom} />
this.props.rooms.map((e, i) => { </Grid.Column>
return ( {this.state.activeItem !== -1 ? (
<Dropdown.Item
id={e.id}
key={i}
name={e.name}
active={this.state.activeItem === e.id}
onClick={this.handleClick}
>
<Grid>
<Grid.Row>
<Grid.Column width={1}>
<Icon name={e.icon} size="small"/>
</Grid.Column>
<Grid.Column>
{e.name}
</Grid.Column>
</Grid.Row>
</Grid>
</ Dropdown.Item>
)
}) : null
}
</Dropdown.Menu>
</Dropdown>
</Menu>
{
this.state.activeItem !== -1 ?
<Grid>
<Grid.Row>
<Grid.Column width={8}> <Grid.Column width={8}>
<ModalWindow type="new" idRoom={this.state.activeItem === -1? -1 : this.state.activeRoom} updateRoom={this.props.updateRoom} deleteRoom={this.props.deleteRoom}/> <ModalWindow
type="modify"
idRoom={this.state.activeRoom}
updateRoom={this.props.updateRoom}
deleteRoom={this.props.deleteRoom}
/>
</Grid.Column> </Grid.Column>
<Grid.Column width={8}> ) : null}
<ModalWindow type="modify" idRoom={this.state.activeItem === -1? -1 : this.state.activeRoom} updateRoom={this.props.updateRoom} deleteRoom={this.props.deleteRoom}/> </Grid.Row>
</Grid.Column> </Grid>
</Grid.Row> </Responsive>
</Grid> </Segment.Group>
: </div>
null
}
</Responsive>
</Segment.Group>
</div>
); );
} }
} }

View file

@ -1,40 +1,49 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import {Button, Form, Grid, Header, Image, Icon, Input, Message} from 'semantic-ui-react'; import {
import {Redirect } from "react-router-dom"; Button,
import { call } from '../client_server'; Form,
Grid,
Header,
Image,
Icon,
Input,
Message,
} from "semantic-ui-react";
import { Redirect } from "react-router-dom";
import { call } from "../client_server";
export default class Signup extends Component{ export default class Signup extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
completeName: "", completeName: "",
username: "", username: "",
email: "", email: "",
password : "", password: "",
error : { state : false, error: { state: false, message: "" },
message: ""}, success: false,
success : false,
}; };
} }
handleRegistration = (e) => { handleRegistration = (e) => {
e.preventDefault(); e.preventDefault();
const params = { const params = {
"email": this.state.email, email: this.state.email,
"name": this.state.completeName, name: this.state.completeName,
"password": this.state.password, password: this.state.password,
"username": this.state.username, username: this.state.username,
}; };
call.register(params) call
.then(res => { .register(params)
if (res.status === 200 && res.data){ .then((res) => {
this.setState({success: true}); if (res.status === 200 && res.data) {
this.setState({ success: true });
} else { } else {
this.setState({error: { state: true, this.setState({ error: { state: true, message: "Errore" } });
message: "Errore"}});
} }
}).catch(err => { })
.catch((err) => {
//console.log(err); //console.log(err);
}); });
}; };
@ -42,82 +51,92 @@ export default class Signup extends Component{
onChangeHandler = (event) => { onChangeHandler = (event) => {
let nam = event.target.name; let nam = event.target.name;
let val = event.target.value; let val = event.target.value;
this.setState({[nam]: val}); this.setState({ [nam]: val });
}; };
render() { render() {
if (this.state.success) { if (this.state.success) {
return <Redirect to="sent-email-reg" /> return <Redirect to="sent-email-reg" />;
} }
return ( return (
<React.Fragment> <React.Fragment>
<Button <Button circular style={{ margin: "2em" }} href="/">
circular <Icon name="arrow alternate circle left" />
style={{margin: "2em"}} Go Home{" "}
href="/" </Button>
<Grid
textAlign="center"
style={{ height: "70vh" }}
verticalAlign="middle"
> >
<Icon name='arrow alternate circle left'/> <Grid.Column style={{ maxWidth: 450 }}>
Go Home </Button> <Header as="h2" color="blue" textAlign="center">
<Grid textAlign='center' style={{height: '70vh'}} verticalAlign='middle'> <Image src="img/logo.png" /> Sign-up to SmartHut
<Grid.Column style={{maxWidth: 450}}>
<Header as='h2' color='blue' textAlign='center'>
<Image src='img/logo.png'/> Sign-up to SmartHut
</Header> </Header>
<Form size='large' style={{marginTop : "2em"}} error={this.state.error.state}> <Form
<Message size="large"
error style={{ marginTop: "2em" }}
header='Singup Error' error={this.state.error.state}
content= {this.state.error.message} >
/> <Message
error
header="Singup Error"
content={this.state.error.message}
/>
<Form.Input <Form.Input
icon='address card outline' icon="address card outline"
iconPosition='left' iconPosition="left"
placeholder='First Name and Last Name' placeholder="First Name and Last Name"
name="completeName" name="completeName"
type='text' type="text"
onChange={this.onChangeHandler} onChange={this.onChangeHandler}
required required
/> />
<Form.Input <Form.Input
icon='user' icon="user"
iconPosition='left' iconPosition="left"
placeholder='Username' placeholder="Username"
name="username" name="username"
type='text' type="text"
onChange={this.onChangeHandler} onChange={this.onChangeHandler}
required required
/> />
<Form.Input <Form.Input
control={Input} control={Input}
type="name" type="name"
icon='envelope outline' icon="envelope outline"
name="email" name="email"
iconPosition='left' iconPosition="left"
placeholder='E-mail' placeholder="E-mail"
onChange={this.onChangeHandler} onChange={this.onChangeHandler}
/*error={{ /*error={{
content: 'Please enter a valid email address', content: 'Please enter a valid email address',
pointing: 'below', pointing: 'below',
}}*/ }}*/
required required
/> />
<Form.Input <Form.Input
icon='lock' icon="lock"
iconPosition='left' iconPosition="left"
placeholder='Password (at least 8 characters)' placeholder="Password (at least 8 characters)"
name="password" name="password"
type='password' type="password"
onChange={this.onChangeHandler} onChange={this.onChangeHandler}
minLength={6} minLength={6}
required required
/> />
<Button color='blue' fluid size='large' onClick={this.handleRegistration}> <Button
Register color="blue"
fluid
size="large"
onClick={this.handleRegistration}
>
Register
</Button> </Button>
</Form> </Form>
</Grid.Column> </Grid.Column>
</Grid> </Grid>
</React.Fragment> </React.Fragment>
) );
} }
} }

View file

@ -3,9 +3,7 @@ import React from "react";
import HeaderController from "./../components/HeaderController"; import HeaderController from "./../components/HeaderController";
export default class TestHeaderController extends React.Component { export default class TestHeaderController extends React.Component {
render () { render() {
return ( return <HeaderController />;
<HeaderController/>
)
} }
} }

View file

@ -8421,6 +8421,11 @@ prepend-http@^1.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
prettier@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.1.tgz#3f00ac71263be34684b2b2c8d7e7f63737592dac"
integrity sha512-piXGBcY1zoFOG0MvHpNE5reAGseLmaCRifQ/fmfF49BcYkInEs/naD/unxGNAeOKFA5+JxVrPyMvMlpzcd20UA==
pretty-bytes@^5.1.0: pretty-bytes@^5.1.0:
version "5.3.0" version "5.3.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
@ -8710,6 +8715,13 @@ react-dev-utils@^10.2.0:
strip-ansi "6.0.0" strip-ansi "6.0.0"
text-table "0.2.0" text-table "0.2.0"
react-device-detect@^1.11.14:
version "1.11.14"
resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-1.11.14.tgz#02ba2398e2ce81fb0eaed3e62a9ad713ab3870a7"
integrity sha512-WSjch241xI+rXHVtJaSYxNUT2WAykzfJgMI2Hg9xjNNTlIZdJu/fmWf4iedNH7qzFq+JaJ6fDJu3mrKFLerKBw==
dependencies:
ua-parser-js "^0.7.20"
react-dom@^16.12.0: react-dom@^16.12.0:
version "16.12.0" version "16.12.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11"
@ -10363,7 +10375,7 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
ua-parser-js@^0.7.18: ua-parser-js@^0.7.18, ua-parser-js@^0.7.20:
version "0.7.21" version "0.7.21"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ== integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==