diff --git a/smart-hut/src/components/dashboard/Automations.css b/smart-hut/src/components/dashboard/Automations.css index 69299e3..0042cba 100644 --- a/smart-hut/src/components/dashboard/Automations.css +++ b/smart-hut/src/components/dashboard/Automations.css @@ -5,3 +5,14 @@ .list-index { font-size: 1.5rem; } + +.remove-icon { + display: inline !important; + margin-left: 1rem !important; +} + +.trigger-item { + display: flex !important; + justify-content: center !important; + align-items: center !important; +} diff --git a/smart-hut/src/components/dashboard/AutomationsPanel.js b/smart-hut/src/components/dashboard/AutomationsPanel.js index 297a5f0..4e8ca37 100644 --- a/smart-hut/src/components/dashboard/AutomationsPanel.js +++ b/smart-hut/src/components/dashboard/AutomationsPanel.js @@ -1,7 +1,8 @@ -import React, { Component, useState } from "react"; -import { connect } from "react-redux"; -import { RemoteService } from "../../remote"; +import React, {Component, useState, useEffect} from "react"; +import {connect} from "react-redux"; +import {RemoteService} from "../../remote"; import "./Automations.css"; + import { Segment, Grid, @@ -15,40 +16,64 @@ import { Divider, Checkbox, Menu, - Label, + Label } from "semantic-ui-react"; -const options = [ - { key: "equal", text: "=", value: "equal" }, +const operands = [ + {key: "EQUAL", text: "=", value: "EQUAL"}, { - key: "greater-than-or-equal", + key: "GREATER_EQUAL", text: "\u2265", - value: "greater-than-or-equal", + value: "GREATER_EQUAL", }, { - key: "greater-than", + key: "GREATER", text: ">", - value: "greater-than", + value: "GREATER", }, { - key: "less-than-or-equal", + key: "LESS_EQUAL", text: "\u2264", - value: "less-than-or-equal", + value: "LESS_EQUAL", }, { - key: "less-than", + key: "LESS", text: "<", - value: "less-than", + value: "LESS", }, ]; +const deviceStateOptions = [ + {key: "off", text: "off", value: false}, + {key: "on", text: "on", value: true}, +]; + const CreateTrigger = (props) => { - const devices = [ - { key: "Light-1", text: "Light-1", value: "Light-1" }, - { key: "Light-2", text: "Light-2", value: "Light-2" }, - { key: "SmartPlug-1", text: "SmartPlug-1", value: "SmartPlug-1" }, - { key: "SmartPlug-2", text: "SmartPlug-2", value: "SmartPlug-2" }, - ]; + const [activeOperand, setActiveOperand] = useState(true); + const admitedDevices = ["sensor", "regularLight", "dimmableLight"]; // TODO Complete this list + const deviceList = props.devices + .map((device) => { + return { + key: device.id, + text: device.name, + value: device.id, + kind: device.kind, + }; + }) + .filter((e) => admitedDevices.includes(e.kind)); + + const onChange = (e, val) => { + props.inputChange(val); + if ( + props.devices + .filter((d) => d.id === val.value)[0] + .hasOwnProperty("on") + ) { + setActiveOperand(false); + } else { + setActiveOperand(true); + } + }; return ( @@ -57,32 +82,52 @@ const CreateTrigger = (props) => { props.inputChange(val)} + onChange={onChange} name="device" search selection - options={devices} + options={deviceList} placeholder="Device" /> - - - props.inputChange(val)} - name="operand" - compact - selection - options={options} - /> - - - props.inputChange(val)} - name="value" - type="number" - placeholder="Value" - /> - + {activeOperand ? ( + + + + props.inputChange(val) + } + name="operand" + compact + selection + options={operands} + /> + + + + props.inputChange(val) + } + name="value" + type="number" + placeholder="Value" + /> + + + ) : ( + + + props.inputChange(val) + } + placeholder="State" + name="value" + compact + selection + options={deviceStateOptions} + /> + + )} @@ -91,16 +136,31 @@ const CreateTrigger = (props) => { }; const SceneItem = (props) => { + let position = props.order.indexOf(props.scene.id); return ( - + + props.orderScenes( + props.scene.id, + val.checked + ) + } + checked={position + 1 > 0} + /> -

{props.sceneName}

+

{props.scene.name}

+
+ +

+ {position !== -1 ? "# " + (position + 1) : ""} +

@@ -109,37 +169,59 @@ const SceneItem = (props) => { ); }; -const Trigger = ({ trigger }) => { - console.log(trigger); - const { device, operand, value } = trigger; - const symbol = options.filter((opt) => opt.key === operand)[0].text; +const Trigger = ({deviceName, trigger, onRemove, index}) => { + const {device, operand, value} = trigger; + let symbol; + if (operand) { + symbol = operands.filter((opt) => opt.key === operand)[0].text; + } return ( - + - {device} - {symbol} - {value} + {deviceName} + {operand ? {symbol} : ""} + {value ? "on" : "off"} + onRemove(device, index)} + className="remove-icon" + name="remove" + /> ); }; -const Automation = (props) => { +const CreateAutomation = (props) => { const [triggerList, setTrigger] = useState([]); - const [newTrigger, setNewTrigger] = useState({ - device: null, - operand: null, - value: null, - }); - const scenes = ["scene-1", "scene-2", "scene-3"]; - const automationName = "Automation Name"; + const [order, setOrder] = useState([]); + const [stateScenes, setScenes] = useState(props.scenes); + const [automationName, setautomationName] = useState("New Automation"); + const [editName, setEditName] = useState(false); + const [newTrigger, setNewTrigger] = useState({}); - const checkNewTrigger = (trigger) => { - if (!trigger.device || !trigger.operand || !trigger.value) { - return { - result: false, - message: "There are missing fields", - }; + useEffect(() => { + setScenes(props.scenes); + }, [props]); + + const _checkNewTrigger = (trigger) => { + const auxDevice = props.devices.filter( + (d) => d.id === trigger.device + )[0]; + if (auxDevice && auxDevice.hasOwnProperty("on")) { + if (!trigger.device || !trigger.value == null) { + return { + result: false, + message: "There are missing fields!", + }; + } + } else { + if (!trigger.device || !trigger.operand || !trigger.value) { + return { + result: false, + message: "There are missing fields", + }; + } } const result = !triggerList.some( (t) => t.device === trigger.device && t.operand === trigger.operand @@ -152,43 +234,135 @@ const Automation = (props) => { }; }; const addTrigger = () => { - const { result, message } = checkNewTrigger(newTrigger); + const {result, message} = _checkNewTrigger(newTrigger); + const auxTrigger = newTrigger; if (result) { - setTrigger((prevList) => [...prevList, newTrigger]); + if ( + props.devices + .filter((d) => d.id === newTrigger.device)[0] + .hasOwnProperty("on") + ) { + delete auxTrigger.operand; + } + setTrigger((prevList) => [...prevList, auxTrigger]); } else { alert(message); } }; - const onInputChange = (val) => { - setNewTrigger({ ...newTrigger, [val.name]: val.value }); + const removeTrigger = (trigger) => { + // TODO When this is connected to the backend each trigger will have an id which can be used to remove it }; + // This gets triggered when the devices dropdown changes the value. + const onInputChange = (val) => { + setNewTrigger({...newTrigger, [val.name]: val.value}); + }; + const onChangeName = (e, val) => setautomationName(val.value); + + const orderScenes = (id, checked) => { + if (checked) { + setOrder((prevList) => [...prevList, id]); + } else { + setOrder((prevList) => prevList.filter((e) => e !== id)); + } + }; + const searchScenes = (e, {value}) => { + if (value.length > 0) { + setScenes((prevScenes) => { + return stateScenes.filter((e) => { + console.log(e.name.includes(value)); + return e.name.includes(value); + }); + }); + } else { + setScenes(props.scenes); + } + }; + + const _generateKey = (trigger) => { + if (trigger.hasOwnProperty("operand")) { + return trigger.device + trigger.operand + trigger.value; + } + return trigger.device + trigger.value; + }; + + const checkBeforeSave = () => { + if (automationName.length <= 0) { + alert("Give a name to the automation"); + return false; + } + if (triggerList.length <= 0) { + alert("You have to create a trigger"); + return false; + } + if (order.length <= 0) { + alert("You need at least one active scene"); + return false; + } + return true; + } + + const saveAutomation = () => { + console.log("trigger list: ", triggerList); + //if(checkBeforeSave()){ + const automation = { + name: automationName + } + props.save({automation, triggerList, order}); + //} + } + return ( -
- {automationName} +
+ {editName ? ( + + ) : ( + automationName + )}
@@ -229,11 +408,11 @@ const Automation = (props) => { - - + + - + @@ -241,17 +420,99 @@ const Automation = (props) => { ); }; +const Automation = ({automation, devices}) => { + const {triggers, scenes} = automation; + const getOperator = (operand) => operands.filter(o => o.key == operand)[0].text; + + return ( + +
+ {automation.name} +
+