From de5fb0d16ddde159a54ce7bb2af09eb4a87960c2 Mon Sep 17 00:00:00 2001 From: Stian Aune Date: Sun, 3 Mar 2019 21:14:30 +0100 Subject: [PATCH] Modal cleanup + light page. --- webui/package.json | 2 - webui/src/App.css | 4 + webui/src/App.js | 2 + webui/src/Components/Group.jsx | 2 +- webui/src/Components/Light.jsx | 39 ++++++---- .../src/Components/Misc/BrightnessSlider.jsx | 34 ++++++++ .../src/Components/Modals/BrightnessModal.jsx | 34 ++++++++ webui/src/Components/Modals/ColorModal.jsx | 26 +++++-- webui/src/Components/Pages/GroupPage.jsx | 2 +- webui/src/Components/Pages/IndexPage.jsx | 3 +- webui/src/Components/Pages/LightPage.jsx | 25 ++++++ webui/src/Helpers/fetcher.js | 17 ++++ webui/src/Helpers/groups.js | 6 -- webui/src/Helpers/lights.js | 78 ++++++++++++++----- webui/src/Hooks/auth.js | 1 - webui/src/Hooks/light.js | 2 +- 16 files changed, 225 insertions(+), 52 deletions(-) create mode 100644 webui/src/Components/Misc/BrightnessSlider.jsx create mode 100644 webui/src/Components/Modals/BrightnessModal.jsx create mode 100644 webui/src/Components/Pages/LightPage.jsx diff --git a/webui/package.json b/webui/package.json index 9b94c6e..89f3e6d 100644 --- a/webui/package.json +++ b/webui/package.json @@ -5,9 +5,7 @@ "dependencies": { "@jaames/iro": "^4.0.1", "bootstrap": "^4.2.1", - "rc-color-picker": "^1.2.6", "react": "^16.8.1", - "react-color": "^2.17.0", "react-dom": "^16.8.1", "react-router": "^4.3.1", "react-router-dom": "^4.3.1", diff --git a/webui/src/App.css b/webui/src/App.css index ae77d2f..b650816 100755 --- a/webui/src/App.css +++ b/webui/src/App.css @@ -13,4 +13,8 @@ a, button { .loading { margin: 2em 0; text-align: center; +} + +.on-switch { + text-align: center; } \ No newline at end of file diff --git a/webui/src/App.js b/webui/src/App.js index b589145..bf7c026 100755 --- a/webui/src/App.js +++ b/webui/src/App.js @@ -10,6 +10,7 @@ import useAuth from "./Hooks/auth"; import IndexPage from "./Components/Pages/IndexPage"; import GroupPage from "./Components/Pages/GroupPage"; import Loading from "./Components/Loading"; +import LightPage from "./Components/Pages/LightPage"; setGlobal({ "auth/login": false, @@ -37,6 +38,7 @@ export default function App() { {isChecked && isLoggedIn && ( <> + )} diff --git a/webui/src/Components/Group.jsx b/webui/src/Components/Group.jsx index 29fbc53..9ae2b2c 100644 --- a/webui/src/Components/Group.jsx +++ b/webui/src/Components/Group.jsx @@ -20,7 +20,7 @@ function Group({id, name}) { {" "} {" "} - + {id > 0 && } ); diff --git a/webui/src/Components/Light.jsx b/webui/src/Components/Light.jsx index 4a62603..a70d84f 100644 --- a/webui/src/Components/Light.jsx +++ b/webui/src/Components/Light.jsx @@ -1,33 +1,46 @@ import React, {useState} from "react"; -import {Badge, Col, ListGroupItem, Row} from "reactstrap"; -import {percentage} from "../Helpers/percentage"; +import {Badge, ButtonDropdown, Col, DropdownItem, DropdownMenu, DropdownToggle, ListGroupItem, Row} from "reactstrap"; import ColorModal from "./Modals/ColorModal"; import {changeColor} from "../Helpers/lights"; -function Light({id, name, color, brightness}) { - const pc = percentage(brightness, 255); - +function Light({id, name, on, color, brightness}) { const [modal, setModal] = useState(false); + const [dropDown, setDropDown] = useState(false); return ( - {name} + setDropDown(!dropDown)}> + + {name} + + + Flytt + Gi nytt navn + Glem + + - setModal(true)}> - {color.toUpperCase()} - + {on && ( + setModal(true)}> + {color.toUpperCase()} + + )} - {pc} + setModal(true)}> + {on ? brightness : "Av"} + {modal && ( - { - changeColor(id, newColor); + { + changeColor(id, newColor, newBrightness, newPower); setModal(false); }} onCancel={() => setModal(false)} diff --git a/webui/src/Components/Misc/BrightnessSlider.jsx b/webui/src/Components/Misc/BrightnessSlider.jsx new file mode 100644 index 0000000..ec88900 --- /dev/null +++ b/webui/src/Components/Misc/BrightnessSlider.jsx @@ -0,0 +1,34 @@ +import React, {useLayoutEffect} from "react"; +import {randId} from "../../Helpers/random"; +import iro from "@jaames/iro"; + +function BrightnessSlider({brightness, onChange}) { + const random = randId(); + + useLayoutEffect(() => { + console.log(brightness); + const colorPicker = new iro.ColorPicker("#color-picker-" + random, { + color: `rgb(${brightness}, ${brightness}, ${brightness})`, + layout: [ + { + component: iro.ui.Slider, + options: { + borderColor: '#888' + } + } + ], + }); + + colorPicker.on("input:end", color => { + onChange(color.rgb.r); + }) + }, []); + + return ( +
+ +
+ ); +} + +export default BrightnessSlider; diff --git a/webui/src/Components/Modals/BrightnessModal.jsx b/webui/src/Components/Modals/BrightnessModal.jsx new file mode 100644 index 0000000..46e6f87 --- /dev/null +++ b/webui/src/Components/Modals/BrightnessModal.jsx @@ -0,0 +1,34 @@ +import React, {useState} from "react"; +import {Button, CustomInput, FormGroup, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; +import BrightnessSlider from "../Misc/BrightnessSlider"; + +function BrightnessModal({bValue, pValue, onConfirm, onCancel}) { + const [brightness, setBrightness] = useState(bValue); + const [power, setPower] = useState(pValue); + + return ( + + Lysstyrke + + + + + + setPower(e.target.checked)}/> + + + + + {" "} + + + + ); +} + +export default BrightnessModal; diff --git a/webui/src/Components/Modals/ColorModal.jsx b/webui/src/Components/Modals/ColorModal.jsx index b016144..7945716 100644 --- a/webui/src/Components/Modals/ColorModal.jsx +++ b/webui/src/Components/Modals/ColorModal.jsx @@ -1,18 +1,34 @@ import React, {useState} from "react"; -import {Button, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; +import {Button, CustomInput, FormGroup, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; import ColorPicker from "../Misc/ColorPicker"; +import BrightnessSlider from "../Misc/BrightnessSlider"; -function ColorModal({value, onConfirm, onCancel}) { - const [color, setColor] = useState(value); +function ColorModal({cValue, bValue, pValue, onConfirm, onCancel}) { + const [color, setColor] = useState(cValue); + const [brightness, setBrightness] = useState(bValue); + const [power, setPower] = useState(pValue); return ( Fargevalg - + + + + + + + + setPower(e.target.checked)}/> + - + {" "} diff --git a/webui/src/Components/Pages/GroupPage.jsx b/webui/src/Components/Pages/GroupPage.jsx index 58b63d4..57841d0 100644 --- a/webui/src/Components/Pages/GroupPage.jsx +++ b/webui/src/Components/Pages/GroupPage.jsx @@ -1,5 +1,5 @@ import React from "react"; -import Groups from "./IndexPage"; +import Groups from "../Groups"; function GroupPage() { return ( diff --git a/webui/src/Components/Pages/IndexPage.jsx b/webui/src/Components/Pages/IndexPage.jsx index ada5b33..cfc415a 100644 --- a/webui/src/Components/Pages/IndexPage.jsx +++ b/webui/src/Components/Pages/IndexPage.jsx @@ -1,9 +1,8 @@ import React from "react"; -import Groups from "../Groups"; function IndexPage() { return ( - +
); } diff --git a/webui/src/Components/Pages/LightPage.jsx b/webui/src/Components/Pages/LightPage.jsx new file mode 100644 index 0000000..863ae8d --- /dev/null +++ b/webui/src/Components/Pages/LightPage.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import useLights from "../../Hooks/light"; +import Light from "../Light"; +import Loading from "../Loading"; +import {Card, CardBody, CardHeader} from "reactstrap"; + +function LightPage() { + const lights = useLights(); + if (lights === null) { + return ; + } + + return ( + + + Tilgjengelige lys + + + {lights.map(light => )} + + + ); +} + +export default LightPage; diff --git a/webui/src/Helpers/fetcher.js b/webui/src/Helpers/fetcher.js index 13c673c..5317603 100644 --- a/webui/src/Helpers/fetcher.js +++ b/webui/src/Helpers/fetcher.js @@ -60,3 +60,20 @@ export function fetchPost(url, data = {}) { body: JSON.stringify(data), }).then(authCheck); } + + +/** + * @param {string} url + * @param {object} data + * @returns {Promise} + */ +export function fetchPatch(url, data = {}) { + return fetch(formatUrl(url), { + method: "PATCH", + credentials: "include", + headers: { + "Content-Type": "application/json; charset=utf-8", + }, + body: JSON.stringify(data), + }).then(authCheck); +} diff --git a/webui/src/Helpers/groups.js b/webui/src/Helpers/groups.js index d9ff374..3981c3e 100644 --- a/webui/src/Helpers/groups.js +++ b/webui/src/Helpers/groups.js @@ -28,9 +28,6 @@ export function subscribeToGroup(groupId, callback) { fetchAll(); } - console.log("subscribed"); - console.dir(callbacks); - return callbackId; } @@ -38,9 +35,6 @@ export function unsubscribeFromGroup(callbackId) { const callback = callbacks.find(c => c !== null && c.callbackId === callbackId); const index = callbacks.indexOf(callback); callbacks[index] = null; - - console.log("unsubscribed"); - console.dir(callbacks); } function fetchAll() { diff --git a/webui/src/Helpers/lights.js b/webui/src/Helpers/lights.js index 62da455..90bddb5 100644 --- a/webui/src/Helpers/lights.js +++ b/webui/src/Helpers/lights.js @@ -1,6 +1,6 @@ import {randId} from "./random"; -import {notNullish, nullish} from "./null"; -import {fetchGet} from "./fetcher"; +import {nullish} from "./null"; +import {fetchGet, fetchPatch} from "./fetcher"; const localData = {}; const callbacks = []; @@ -11,19 +11,11 @@ export function subscribeToLight(lightId, callback) { callbacks.push({callbackId, lightId, callback}); if (lightId >= 0) { - if (notNullish(localData[lightId])) { - dispatch(localData[lightId]); - } + dispatch(); fetchOne(lightId); } else { - const list = []; - for (let key in localData) { - if (localData.hasOwnProperty(key) && notNullish(localData[key])) { - list.push(localData[key]); - } - } - dispatch(list); + dispatch(); fetchAll(); } @@ -35,22 +27,64 @@ export function unsubscribeFromLight(callbackId) { callbacks[index] = null; } -export function changeColor(lightId, newColor) { - console.dir(localData); - +export function changeColor(lightId, newColor, newBrightness, newPower) { const light = localData[lightId]; if (nullish(light)) { return; } - localData[lightId].color = newColor; - dispatch(Object.values(localData)); + const oldBrightness = light.brightness; + const oldPower = light.on; + const oldColor = light.color; + light.color = newColor; + light.brightness = newBrightness; + light.on = newPower; + dispatch(); + + fetchPatch(`/light/${lightId}`, { + color: newColor, + brightness: newBrightness, + on: newPower, + }).then(({data, error}) => { + if (error !== null) { + light.color = oldColor; + light.brightness = oldBrightness; + light.on = oldPower; + dispatch(); + return; + } - // TODO: Send request + localData[lightId] = data; + dispatch(); + }); } -export function changeBrightness(lightId, newBrightness) { +export function changeBrightness(lightId, newPower, newBrightness) { + const light = localData[lightId]; + if (nullish(light)) { + return; + } + + const oldBrightness = light.brightness; + const oldPower = light.on; + light.brightness = newBrightness; + light.on = newPower; + dispatch(); + + fetchPatch(`/light/${lightId}`, { + brightness: newBrightness, + on: newPower, + }).then(({data, error}) => { + if (error !== null) { + light.brightness = oldBrightness; + light.on = oldPower; + dispatch(); + return; + } + localData[lightId] = data; + dispatch(); + }); } function fetchAll() { @@ -87,7 +121,11 @@ function handleLight(light) { dispatch(light); } -function dispatch(data) { +function dispatch(data = null) { + if (data === null) { + data = Object.values(localData); + } + if (Array.isArray(data)) { callbacks .filter(c => c !== null) diff --git a/webui/src/Hooks/auth.js b/webui/src/Hooks/auth.js index d0364ca..3f2de6a 100644 --- a/webui/src/Hooks/auth.js +++ b/webui/src/Hooks/auth.js @@ -20,7 +20,6 @@ export default function useAuth() { fetchPost("/user/login", {username, password}).then(({data, error}) => { setIsChecked(true); - console.dir({data, error}); if (error !== null) { setIsLoggedIn(false); return; diff --git a/webui/src/Hooks/light.js b/webui/src/Hooks/light.js index 5ff5106..3956ef1 100644 --- a/webui/src/Hooks/light.js +++ b/webui/src/Hooks/light.js @@ -1,7 +1,7 @@ import {useEffect, useState} from "react"; import {subscribeToLight, unsubscribeFromLight} from "../Helpers/lights"; -export default function useLights({groupId = -1, id = -1}) { +export default function useLights({groupId = -1, id = -1} = {}) { const [light, setLight] = useState(null); function onChange(light) {