diff --git a/.mailmap b/.mailmap index 3b149aa..3886c55 100644 --- a/.mailmap +++ b/.mailmap @@ -1 +1,8 @@ -Claudio Maggioni Claudio Maggioni +Claudio Maggioni Claudio Maggioni (maggicl) +Claudio Maggioni Claudio Maggioni (maggicl) +Filippo Cesana FilippoCesana +Filippo Cesana Fil Cesana +Andrea Brites Marto britea +Christian Capeáns Pérez christiancp +Tommaso Rodolfo Masera tommi27 + diff --git a/smart-hut/public/img/curtains-icon.png b/smart-hut/public/img/curtains-icon.png new file mode 100644 index 0000000..2772356 Binary files /dev/null and b/smart-hut/public/img/curtains-icon.png differ diff --git a/smart-hut/public/img/thermostat-icon.png b/smart-hut/public/img/thermostat-icon.png new file mode 100644 index 0000000..9f64146 Binary files /dev/null and b/smart-hut/public/img/thermostat-icon.png differ diff --git a/smart-hut/src/components/HeaderController.js b/smart-hut/src/components/HeaderController.js index 1d84c6b..f67edfe 100644 --- a/smart-hut/src/components/HeaderController.js +++ b/smart-hut/src/components/HeaderController.js @@ -1,5 +1,12 @@ import React from "react"; -import { Grid, Divider, Button, Label, Responsive } from "semantic-ui-react"; +import { + Grid, + Divider, + Button, + Label, + Responsive, + Checkbox, +} from "semantic-ui-react"; import { Segment, Image } from "semantic-ui-react"; import { RemoteService } from "../remote"; import { withRouter } from "react-router-dom"; @@ -35,13 +42,23 @@ export class MyHeader extends React.Component { .catch((err) => console.error("MyHeader fetch user info error", err)); } + setCameraEnabled(val) { + let enabled = { + cameraEnabled: val, + }; + this.props + .userPermissions(enabled) + .then(() => this.getInfo()) + .catch((err) => console.error("Camera enabled", err)); + } + render() { return (
- + @@ -51,7 +68,7 @@ export class MyHeader extends React.Component { - + } + checked={this.props.cameraEnabled} + toggle + onChange={(e, val) => this.setCameraEnabled(val.checked)} + /> + @@ -82,6 +108,15 @@ export class MyHeader extends React.Component { + + Share cameras} + checked={this.props.cameraEnabled} + toggle + onChange={(e, val) => this.setCameraEnabled(val.checked)} + /> + @@ -94,6 +129,7 @@ export class MyHeader extends React.Component { const mapStateToProps = (state, _) => ({ username: state.userInfo && state.userInfo.username ? state.userInfo.username : "", + cameraEnabled: state.userInfo ? state.userInfo.cameraEnabled : false, }); const LoginContainer = connect( mapStateToProps, diff --git a/smart-hut/src/components/HostModal.js b/smart-hut/src/components/HostModal.js index 789c484..cd03809 100644 --- a/smart-hut/src/components/HostModal.js +++ b/smart-hut/src/components/HostModal.js @@ -11,7 +11,6 @@ import { import { connect } from "react-redux"; import { RemoteService, Forms } from "../remote"; import { appActions } from "../storeActions"; -//import { update } from "immutability-helper"; class HostModal extends Component { constructor(props) { @@ -32,11 +31,13 @@ class HostModal extends Component { .then((users) => this.setState({ ...this.state, - users: users.map((u) => ({ - key: u.id, - text: `@${u.username} (${u.name})`, - value: u.id, - })), + users: users + .filter((u) => u.id !== this.props.currentUserId) + .map((u) => ({ + key: u.id, + text: `@${u.username} (${u.name})`, + value: u.id, + })), }) ) .catch(console.error); @@ -86,25 +87,20 @@ class HostModal extends Component {
Select guests
- -

Spaghetti!

-
- -
- - - - -
-
+
+ + + + +
{this.type === "modify" ? ( +
+ Delete Room + +
+ ) : null} diff --git a/smart-hut/src/components/SceneModal.js b/smart-hut/src/components/SceneModal.js index be03283..8b935cc 100644 --- a/smart-hut/src/components/SceneModal.js +++ b/smart-hut/src/components/SceneModal.js @@ -8,6 +8,8 @@ import { Form, Input, Dropdown, + Checkbox, + Segment, } from "semantic-ui-react"; import SelectIcons from "./SelectIcons"; import { connect } from "react-redux"; @@ -23,6 +25,7 @@ class SceneModal extends Component { this.modifySceneModal = this.modifySceneModal.bind(this); this.deleteScene = this.deleteScene.bind(this); this.updateIcon = this.updateIcon.bind(this); + this.setGuestAccessEnabled = this.setGuestAccessEnabled.bind(this); this.setCopyFrom = this.setCopyFrom.bind(this); } @@ -41,6 +44,8 @@ class SceneModal extends Component { selectedIcon: "home", scenes: this.scenes, copyFrom: null, + guestAccessEnabled: + this.type === "new" ? null : this.props.scene.guestAccessEnabled, }; } @@ -79,7 +84,9 @@ class SceneModal extends Component { let data = { name: this.state.name, icon: this.state.selectedIcon, + guestAccessEnabled: this.state.guestAccessEnabled, }; + console.log(data); this.props .saveScene(data, this.props.id) @@ -104,21 +111,26 @@ class SceneModal extends Component { }; closeModal = (e) => { - this.setState({ openModal: false }); + this.setState({ ...this.state, openModal: false }); }; openModal = (e) => { - this.setState({ openModal: true }); + this.setState({ ...this.state, openModal: true }); }; updateIcon(e) { - this.setState({ selectedIcon: e }); + this.setState({ ...this.state, selectedIcon: e }); } setCopyFrom(_, copyFrom) { this.setState({ ...this.state, copyFrom: copyFrom.value }); } + setGuestAccessEnabled(val) { + console.log(this.state, val); + this.setState({ ...this.state, guestAccessEnabled: val }); + } + render() { const spaceDiv = { background: "#f4f4f4", @@ -210,6 +222,20 @@ class SceneModal extends Component { /> )} + {this.type === "modify" ? ( + + + + this.setGuestAccessEnabled(val.checked) + } + /> + + + ) : null} {this.type === "modify" ? ( diff --git a/smart-hut/src/components/dashboard/DevicePanel.js b/smart-hut/src/components/dashboard/DevicePanel.js index 73196df..f55ee11 100644 --- a/smart-hut/src/components/dashboard/DevicePanel.js +++ b/smart-hut/src/components/dashboard/DevicePanel.js @@ -1,7 +1,7 @@ // vim: set ts=2 sw=2 et tw=80: import React, { Component } from "react"; -import { Segment, Card } from "semantic-ui-react"; +import { Segment, Card, Header, Icon } from "semantic-ui-react"; import Device from "./devices/Device"; import NewDevice from "./devices/NewDevice"; import { connect } from "react-redux"; @@ -25,16 +25,31 @@ class DevicePanel extends Component { render() { return ( - {this.props.devices.map((e, i) => { - return ; - })} - {!this.props.isActiveRoomHome ? ( - - - - - - ) : null} + {this.props.numbeOfRooms > 0 ? ( + + {this.props.devices.map((e, i) => { + return ; + })} + {!this.props.isActiveRoomHome ? ( + + + + + + ) : null} + + ) : ( + +
+ + Please create a room on the left, and then add devices to the + same. +
+
+ )}
); } @@ -55,6 +70,9 @@ const mapStateToProps = (state, _) => ({ return state.active.activeRoom === -1; }, activeRoom: state.active.activeRoom, + get numbeOfRooms() { + return Object.keys(state.rooms).length; + }, }); const DevicePanelContainer = connect( mapStateToProps, diff --git a/smart-hut/src/components/dashboard/HostsPanel.js b/smart-hut/src/components/dashboard/HostsPanel.js index ca63068..5a6d380 100644 --- a/smart-hut/src/components/dashboard/HostsPanel.js +++ b/smart-hut/src/components/dashboard/HostsPanel.js @@ -1,7 +1,7 @@ import React, { Component } from "react"; import { connect } from "react-redux"; import { RemoteService } from "../../remote"; -import { Card, Segment, Header, Icon } from "semantic-ui-react"; +import { Card, Segment, Header, Icon, Button } from "semantic-ui-react"; import Device from "../../components/dashboard/devices/Device"; class HostsPanel extends Component { @@ -12,31 +12,64 @@ class HostsPanel extends Component { ) { this.props.fetchDevices(null, this.props.activeHost).catch(console.error); this.props.fetchAllRooms(this.props.activeHost).catch(console.error); + this.props.fetchAllScenes(this.props.activeHost).catch(console.error); } } render() { - return ( - - {this.props.isActiveDefaultHost && ( + if (this.props.isActiveDefaultHost) { + return ( +
- + Please select a host to visit on the left.
- )} - {this.props.hostDeviceIds.map((id) => { - return ( - - ); - })} -
+
+ ); + } + + return ( + +
+ Scenes +
+ + {this.props.hostScenes.map((scene) => ( + + +
+ {scene.name} +
+
+ +
+ +
+
+
+ ))} +
+
+ Devices +
+ + {this.props.hostDeviceIds.map((id) => { + return ( + + ); + })} + +
); } } @@ -44,6 +77,7 @@ class HostsPanel extends Component { const mapStateToProps = (state, _) => ({ isActiveDefaultHost: state.active.activeHost === -1, activeHost: state.active.activeHost, + hostScenes: state.hostScenes[state.active.activeHost] || [], hostDevices: state.hostDevices, hostDeviceIds: Object.keys(state.hostDevices[state.active.activeHost] || {}), }); diff --git a/smart-hut/src/components/dashboard/ScenesPanel.js b/smart-hut/src/components/dashboard/ScenesPanel.js index a9b2210..2be4cd1 100644 --- a/smart-hut/src/components/dashboard/ScenesPanel.js +++ b/smart-hut/src/components/dashboard/ScenesPanel.js @@ -44,7 +44,10 @@ class ScenesPanel extends Component { ) : (
- + Please select a scene on the left or add a new one.
diff --git a/smart-hut/src/components/dashboard/devices/Curtains.css b/smart-hut/src/components/dashboard/devices/Curtains.css index 5d1939b..c4ec319 100644 --- a/smart-hut/src/components/dashboard/devices/Curtains.css +++ b/smart-hut/src/components/dashboard/devices/Curtains.css @@ -4,10 +4,6 @@ box-sizing: border-box; } -body { - overflow-y: hidden; -} - .container.curtain-container { position: relative; margin-top: 10%; diff --git a/smart-hut/src/components/dashboard/devices/DeviceSettingsModal.js b/smart-hut/src/components/dashboard/devices/DeviceSettingsModal.js index 83773c8..c6b9408 100644 --- a/smart-hut/src/components/dashboard/devices/DeviceSettingsModal.js +++ b/smart-hut/src/components/dashboard/devices/DeviceSettingsModal.js @@ -1,13 +1,5 @@ import React, { Component, useState } from "react"; -import { - Button, - Form, - Icon, - Header, - Modal, - Input, - Checkbox, -} from "semantic-ui-react"; +import { Button, Form, Icon, Header, Modal, Input } from "semantic-ui-react"; import { connect } from "react-redux"; import { RemoteService } from "../../../remote"; diff --git a/smart-hut/src/components/dashboard/devices/NewDevice.js b/smart-hut/src/components/dashboard/devices/NewDevice.js index e5c99b4..965ccc0 100644 --- a/smart-hut/src/components/dashboard/devices/NewDevice.js +++ b/smart-hut/src/components/dashboard/devices/NewDevice.js @@ -141,6 +141,11 @@ class NewDevice extends Component { case "buttonDimmer": case "knobDimmer": outputs = this.state.lightsAttached; + if (this.state.lightsAttached === undefined || + this.state.lightsAttached.length === 0) { + alert("No lights attached to this switch! Please, add a light a first."); + return; + } break; default: break; @@ -160,8 +165,12 @@ class NewDevice extends Component { render() { const deviceOptions = [ //stuff - { key: "thermostat", text: "Thermostat", value: "thermostat", image: {} }, - { key: "curtains", text: "Curtain", value: "curtains", image: {} }, + { key: "thermostat", text: "Thermostat", value: "thermostat", + image: {avatar: true, src: "/img/thermostat-icon.png"} + }, + { key: "curtains", text: "Curtain", value: "curtains", + image: {avatar: true, src: "/img/curtains-icon.png"} + }, //stuff ends { key: "light", diff --git a/smart-hut/src/components/dashboard/devices/Thermostats.js b/smart-hut/src/components/dashboard/devices/Thermostats.js index 9ec24ff..fcab8a6 100644 --- a/smart-hut/src/components/dashboard/devices/Thermostats.js +++ b/smart-hut/src/components/dashboard/devices/Thermostats.js @@ -164,7 +164,10 @@ class Thermostats extends Component { const mapStateToProps2 = (state, ownProps) => ({ ...mapStateToProps(state, ownProps), get tempSensorsInRoom() { - const deviceIds = state.rooms[state.devices[ownProps.id].roomId].devices; + if (state.active.activeTab !== "Devices") return false; + const room = state.rooms[state.devices[ownProps.id].roomId]; + if (!room) return false; + const deviceIds = room.devices; const devices = [...deviceIds].map((id) => state.devices[id]); const sensors = devices.filter( (d) => d.kind === "sensor" && d.sensor === "TEMPERATURE" diff --git a/smart-hut/src/components/dashboard/devices/Videocam.js b/smart-hut/src/components/dashboard/devices/Videocam.js index de77219..409d467 100644 --- a/smart-hut/src/components/dashboard/devices/Videocam.js +++ b/smart-hut/src/components/dashboard/devices/Videocam.js @@ -31,7 +31,7 @@ class Videocam extends Component { setOnOff(onOff) { const turn = onOff; - if (this.props.tab === "Devices") { + if (this.props.tab === "Devices" || this.props.tab === "Hosts") { this.props .saveDevice({ ...this.props.device, on: turn }) .then((res) => @@ -70,12 +70,16 @@ class Videocam extends Component { /> + + + this.setOnOff(val.checked)} + /> + + - this.setOnOff(val.checked)} - /> ); diff --git a/smart-hut/src/remote.js b/smart-hut/src/remote.js index 666910b..f0cfcea 100644 --- a/smart-hut/src/remote.js +++ b/smart-hut/src/remote.js @@ -242,6 +242,20 @@ export const RemoteService = { }); }, + /** + * Fetches user information via REST calls, if it is logged in + * @returns {Promise} promise that resolves to void and rejects + * with user-fiendly errors as a RemoteError + */ + userPermissions: (data) => { + return (dispatch) => { + return Endpoint.put("/user/permissions", {}, data).catch((err) => { + console.warn("Fetch user info error", err); + throw new RemoteError(["Network error"]); + }); + }; + }, + /** * Fetches user information via REST calls, if it is logged in * @returns {Promise} promise that resolves to void and rejects @@ -290,10 +304,17 @@ export const RemoteService = { * @returns {Promise} promise that resolves to void and rejects * with user-fiendly errors as a RemoteError */ - fetchAllScenes: () => { + fetchAllScenes: (hostId = null) => { return (dispatch) => { - return Endpoint.get("/scene") - .then((res) => void dispatch(actions.scenesUpdate(res.data))) + return Endpoint.get("/scene", hostId ? { hostId } : {}) + .then( + (res) => + void dispatch( + !hostId + ? actions.scenesUpdate(res.data) + : actions.hostScenesUpdate(hostId, res.data) + ) + ) .catch((err) => { console.error("Fetch all scenes error", err); throw new RemoteError(["Network error"]); @@ -458,6 +479,7 @@ export const RemoteService = { data = { name: data.name, icon: data.icon, + guestAccessEnabled: sceneId ? data.guestAccessEnabled : false, }; return (sceneId diff --git a/smart-hut/src/store.js b/smart-hut/src/store.js index 1ade73b..f256839 100644 --- a/smart-hut/src/store.js +++ b/smart-hut/src/store.js @@ -120,6 +120,15 @@ function reducer(previousState, action) { createOrUpdateScene(scene); } break; + case "HOST_SCENES_UPDATE": + change = { + hostScenes: { + [action.hostId]: { $set: action.scenes }, // stored as array + }, + }; + + newState = update(previousState, change); + break; case "STATES_UPDATE": //console.log(action.sceneStates); change = null; @@ -576,6 +585,7 @@ const initState = { rooms: {}, /** @type {[integer]Scene} */ scenes: {}, + hostScenes: {}, /** @type {[integer]Automation} */ automations: {}, /** @type {[integer]Device} */ diff --git a/smart-hut/src/storeActions.js b/smart-hut/src/storeActions.js index 64c2a52..218f4b9 100644 --- a/smart-hut/src/storeActions.js +++ b/smart-hut/src/storeActions.js @@ -102,6 +102,11 @@ const actions = { type: "SCENES_UPDATE", scenes, }), + hostScenesUpdate: (hostId, scenes) => ({ + type: "HOST_SCENES_UPDATE", + hostId, + scenes, + }), deviceDelete: (deviceId) => ({ type: "DEVICE_DELETE", deviceId, diff --git a/smart-hut/src/views/Dashboard.js b/smart-hut/src/views/Dashboard.js index 18d0ef0..b79bf6f 100644 --- a/smart-hut/src/views/Dashboard.js +++ b/smart-hut/src/views/Dashboard.js @@ -94,12 +94,12 @@ class Dashboard extends Component {
- + - + ( - + The Shell diff --git a/smart-hut/src/views/Signup.js b/smart-hut/src/views/Signup.js index 5ad8af5..c0de088 100644 --- a/smart-hut/src/views/Signup.js +++ b/smart-hut/src/views/Signup.js @@ -116,7 +116,7 @@ export default class Signup extends Component {