WIP on redux conversion for devices
This commit is contained in:
parent
eead3694e6
commit
69a6cbae6d
16 changed files with 232 additions and 395 deletions
|
@ -4,87 +4,32 @@ import React, { Component } from "react";
|
|||
import { Grid } from "semantic-ui-react";
|
||||
import { editButtonStyle, panelStyle } from "./devices/styleComponents";
|
||||
import { checkMaxLength, DEVICE_NAME_MAX_LENGTH } from "./devices/constants";
|
||||
import DeviceType from "./devices/DeviceTypeController";
|
||||
import Device from "./devices/Device";
|
||||
import NewDevice from "./devices/NewDevice";
|
||||
import SettingsModal from "./devices/SettingsModal";
|
||||
import { connect } from "react-redux";
|
||||
import { RemoteService } from "../../remote";
|
||||
|
||||
class DevicePanel extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
editMode: false,
|
||||
};
|
||||
|
||||
this.addDevice = this.addDevice.bind(this);
|
||||
this.toggleEditMode = this.toggleEditMode.bind(this);
|
||||
this.getDevices();
|
||||
}
|
||||
|
||||
toggleEditMode(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);
|
||||
|
||||
for (let prop in this.props.devices[deviceId]) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
};*/
|
||||
|
||||
getDevices() {
|
||||
this.props.fetchDevices().then();
|
||||
this.props
|
||||
.fetchDevices()
|
||||
.catch((err) => console.error(`error fetching devices:`, err));
|
||||
}
|
||||
|
||||
render() {
|
||||
const edit = {
|
||||
mode: this.state.editMode,
|
||||
openModal: this.openModal,
|
||||
};
|
||||
|
||||
/*var backGroundImg =
|
||||
this.props.activeItem === -1 ? "" : this.props.room.image;*/
|
||||
const ds = this.state.devices ? this.state.devices : this.props.devices;
|
||||
|
||||
return (
|
||||
<div style={panelStyle}>
|
||||
<button style={editButtonStyle} onClick={this.editModeController}>
|
||||
Edit
|
||||
</button>
|
||||
<Grid doubling columns={4} divided="vertically">
|
||||
{this.state.openSettingsModal ? (
|
||||
<SettingsModal
|
||||
openModal={this.openModal}
|
||||
device={ds.filter((d) => d.id === this.state.settingsDeviceId)[0]}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{this.props.devices.map((e, i) => {
|
||||
return (
|
||||
<Grid.Column key={i}>
|
||||
<DeviceType type={e.kind} device={e} edit={edit} />
|
||||
<Device id={e.id} />
|
||||
</Grid.Column>
|
||||
);
|
||||
})}
|
||||
|
@ -110,7 +55,7 @@ const mapStateToProps = (state, _) => ({
|
|||
}
|
||||
},
|
||||
get isActiveRoomHome() {
|
||||
return this.props.activeRoom === -1;
|
||||
return state.active.activeRoom === -1;
|
||||
},
|
||||
activeRoom: state.active.activeRoom,
|
||||
});
|
||||
|
|
75
smart-hut/src/components/dashboard/devices/Device.js
Normal file
75
smart-hut/src/components/dashboard/devices/Device.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
import React from "react";
|
||||
import Light from "./Light";
|
||||
import SmartPlug from "./SmartPlug";
|
||||
import Sensor from "./Sensor";
|
||||
import { ButtonDimmer, KnobDimmer } from "./Dimmer";
|
||||
import Switcher from "./Switch";
|
||||
import { Segment } from "semantic-ui-react";
|
||||
import { RemoteService } from "../../../remote";
|
||||
import { connect } from "react-redux";
|
||||
import DeviceSettingsModal from "./DeviceSettingsModal";
|
||||
|
||||
class Device extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.modalRef = React.createRef();
|
||||
this.edit = this.edit.bind(this);
|
||||
this.resetSmartPlug = this.resetSmartPlug.bind(this);
|
||||
}
|
||||
|
||||
edit() {
|
||||
console.log("editing device with id=" + this.props.id);
|
||||
this.modalRef.current.openModal();
|
||||
}
|
||||
|
||||
resetSmartPlug() {
|
||||
this.props
|
||||
.resetSmartPlug(this.props.id)
|
||||
.catch((err) => console.error(`Smart plug reset error`, err));
|
||||
}
|
||||
|
||||
renderDeviceComponent() {
|
||||
switch (this.props.device.kind) {
|
||||
case "regularLight":
|
||||
return <Light id={this.props.id} />;
|
||||
case "sensor":
|
||||
return <Sensor id={this.props.id} />;
|
||||
case "motionSensor":
|
||||
return <Sensor id={this.props.id} />;
|
||||
case "buttonDimmer":
|
||||
return <ButtonDimmer id={this.props.id} />;
|
||||
case "knobDimmer":
|
||||
return <KnobDimmer id={this.props.id} />;
|
||||
case "smartPlug":
|
||||
return <SmartPlug id={this.props.id} />;
|
||||
case "switch":
|
||||
return <Switcher id={this.props.id} />;
|
||||
case "dimmableLight":
|
||||
return <Light id={this.props.id} />;
|
||||
default:
|
||||
throw new Error("Device type unknown");
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Segment>
|
||||
{this.renderDeviceComponent()}
|
||||
<h3>{this.props.device.name}</h3>
|
||||
<button onClick={this.edit}>Edit</button>
|
||||
{this.props.device.type === "smartPlug" ? (
|
||||
<button onClick={this.resetSmartPlug}></button>
|
||||
) : null}
|
||||
|
||||
<DeviceSettingsModal ref={this.modalRef} id={this.props.id} />
|
||||
</Segment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
device: state.devices[ownProps.id],
|
||||
});
|
||||
const DeviceContainer = connect(mapStateToProps, RemoteService)(Device);
|
||||
export default DeviceContainer;
|
|
@ -1,26 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import { editModeIconStyle, editModeStyle } from "./styleComponents";
|
||||
|
||||
export default class Settings extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
displayForm: true,
|
||||
};
|
||||
}
|
||||
|
||||
displayForm = () => {
|
||||
this.setState((prevState) => ({ displayForm: !prevState.displayForm }));
|
||||
};
|
||||
|
||||
render() {
|
||||
const view = (
|
||||
<div onClick={() => this.props.edit.openModal(this.props.deviceId)}>
|
||||
<span style={editModeStyle}>
|
||||
<img src="/img/settings.svg" alt="" style={editModeIconStyle} />
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
return <React.Fragment>{this.props.edit.mode ? view : ""}</React.Fragment>;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
import React, { Component, useState } from "react";
|
||||
import { Button, Checkbox, Form, Icon, Header, Modal } from "semantic-ui-react";
|
||||
import { Button, Form, Icon, Header, Modal } from "semantic-ui-react";
|
||||
import { connect } from "react-redux";
|
||||
import { RemoteService } from "../../../remote";
|
||||
|
||||
const DeleteModal = (props) => (
|
||||
<Modal trigger={<Button color="red">Remove</Button>} closeIcon>
|
||||
|
@ -21,11 +23,6 @@ const SettingsForm = (props) => {
|
|||
setValues({ ...values, [name]: value });
|
||||
};
|
||||
|
||||
const handleCheckboxChange = (e, d) => {
|
||||
const { name, checked } = d;
|
||||
setValues({ ...values, [name]: checked });
|
||||
};
|
||||
|
||||
const [values, setValues] = useState({ name: "" });
|
||||
|
||||
return (
|
||||
|
@ -41,18 +38,6 @@ const SettingsForm = (props) => {
|
|||
/>
|
||||
</Form.Field>
|
||||
|
||||
{props.type === "smart-plug" ? (
|
||||
<Form.Field>
|
||||
<Checkbox
|
||||
slider
|
||||
name={"reset"}
|
||||
onClick={handleCheckboxChange}
|
||||
label="Reset Energy Consumption"
|
||||
/>
|
||||
</Form.Field>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Form.Field>
|
||||
<DeleteModal removeDevice={() => props.removeDevice(values)} />
|
||||
</Form.Field>
|
||||
|
@ -67,41 +52,56 @@ const SettingsForm = (props) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default class SettingsModal extends Component {
|
||||
class DeviceSettingsModal extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
open: true,
|
||||
open: false,
|
||||
};
|
||||
|
||||
this.updateDevice = this.updateDevice.bind(this);
|
||||
this.deleteDevice = this.deleteDevice.bind(this);
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ open: false });
|
||||
};
|
||||
openModal() {
|
||||
this.setState({ open: true });
|
||||
}
|
||||
|
||||
saveSettings = (device) => {
|
||||
// TODO Here there should be all the connections to save the data in the backend
|
||||
console.log("SAVED: ", device);
|
||||
if (device.name.length > 0) {
|
||||
this.props.updateDevice(device);
|
||||
}
|
||||
updateDevice(values) {
|
||||
if (values.name.length === 0) return;
|
||||
this.props
|
||||
.saveDevice({ ...this.props.device, name: values.name })
|
||||
.then(() => this.setState({ open: false }))
|
||||
.catch((err) =>
|
||||
console.error(
|
||||
`settings modal for device ${this.props.id} deletion error`,
|
||||
err
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
this.props.openModal();
|
||||
};
|
||||
deleteDevice() {
|
||||
// closing is not needed (and actually harmful due to memory leaks)
|
||||
// since this component will be deleted anyways
|
||||
this.props
|
||||
.deleteDevice(this.props.device)
|
||||
.catch((err) =>
|
||||
console.error(
|
||||
`settings modal for device ${this.props.id} deletion error`,
|
||||
err
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const SettingsModal = () => (
|
||||
<Modal
|
||||
open={true}
|
||||
onOpen={this.props.openModal}
|
||||
onClose={this.props.openModal}
|
||||
>
|
||||
<Modal open={this.state.open}>
|
||||
<Modal.Header>Settings of {this.props.device.name}</Modal.Header>
|
||||
<Modal.Content>
|
||||
<SettingsForm
|
||||
type={this.props.device.type}
|
||||
removeDevice={this.props.removeDevice}
|
||||
saveFunction={this.saveSettings}
|
||||
removeDevice={this.deleteDevice}
|
||||
saveFunction={this.updateDevice}
|
||||
/>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
|
@ -109,3 +109,14 @@ export default class SettingsModal extends Component {
|
|||
return <SettingsModal />;
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
device: state.devices[ownProps.id],
|
||||
});
|
||||
const DeviceSettingsModalContainer = connect(
|
||||
mapStateToProps,
|
||||
RemoteService,
|
||||
null,
|
||||
{ forwardRef: true }
|
||||
)(DeviceSettingsModal);
|
||||
export default DeviceSettingsModalContainer;
|
|
@ -1,87 +0,0 @@
|
|||
import React from "react";
|
||||
import Light from "./Light";
|
||||
import SmartPlug from "./SmartPlug";
|
||||
import Sensor from "./Sensor";
|
||||
import { ButtonDimmer, KnobDimmer } from "./Dimmer";
|
||||
import Switcher from "./Switch";
|
||||
|
||||
const DeviceType = (props) => {
|
||||
switch (props.type) {
|
||||
case "regularLight":
|
||||
return (
|
||||
<Light
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
case "sensor":
|
||||
return (
|
||||
<Sensor
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
case "motionSensor":
|
||||
return (
|
||||
<Sensor
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
case "buttonDimmer":
|
||||
return (
|
||||
<ButtonDimmer
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
case "knobDimmer":
|
||||
return (
|
||||
<KnobDimmer
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
case "smartPlug":
|
||||
return (
|
||||
<SmartPlug
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
case "switch":
|
||||
return (
|
||||
<Switcher
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
case "dimmableLight":
|
||||
return (
|
||||
<Light
|
||||
updateDev={props.updateDeviceUi}
|
||||
onChangeData={props.changeDeviceData}
|
||||
device={props.device}
|
||||
edit={props.edit}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
export default DeviceType;
|
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* Users can add sensors in their rooms.
|
||||
* Sensors typically measure physical quantities in a room.
|
||||
* You must support temperature sensors, humidity sensors, light sensors (which measure luminosity1).
|
||||
* Sensors have an internal state that cannot be changed by the user.
|
||||
* 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";
|
||||
import { StyledDiv } from "./styleComponents";
|
||||
import Settings from "./DeviceSettings";
|
||||
import { Image } from "semantic-ui-react";
|
||||
import { imageStyle, nameStyle } from "./DigitalSensorStyle";
|
||||
|
||||
export default class DigitalSensor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
value: false, // This value is a boolean, was this type of sensor returns presence/absence
|
||||
};
|
||||
|
||||
this.iconOn = "/img/sensorOn.svg";
|
||||
this.iconOff = "/img/sensorOff.svg";
|
||||
}
|
||||
|
||||
setName = () => {
|
||||
if (this.props.device.name.length > 15) {
|
||||
return this.props.device.name.slice(0, 12) + "...";
|
||||
}
|
||||
return this.props.device.name;
|
||||
};
|
||||
|
||||
getIcon = () => {
|
||||
if (this.state.value) {
|
||||
return this.iconOn;
|
||||
}
|
||||
return this.iconOff;
|
||||
};
|
||||
|
||||
componentDidMount() {}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<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} />
|
||||
<h5 style={nameStyle}>{this.props.device.name}</h5>
|
||||
</StyledDiv>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
export const imageStyle = {
|
||||
width: "3.5rem",
|
||||
height: "auto",
|
||||
position: "absolute",
|
||||
top: "20%",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
filter: "drop-shadow( 1px 1px 0.5px rgba(0, 0, 0, .25))",
|
||||
};
|
||||
|
||||
export const nameStyle = {
|
||||
color: "black",
|
||||
position: "absolute",
|
||||
top: "40%",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
};
|
|
@ -19,7 +19,6 @@ import {
|
|||
PlusPanel,
|
||||
ThumbText,
|
||||
} from "./styleComponents";
|
||||
import Settings from "./DeviceSettings";
|
||||
import {
|
||||
CircularThumbStyle,
|
||||
KnobDimmerStyle,
|
||||
|
@ -28,10 +27,11 @@ import {
|
|||
knobIcon,
|
||||
knobContainer,
|
||||
} from "./DimmerStyle";
|
||||
|
||||
import { RemoteService } from "../../../remote";
|
||||
import { connect } from "react-redux";
|
||||
import { call } from "../../../client_server";
|
||||
|
||||
export class ButtonDimmer extends Component {
|
||||
export class ButtonDimmerComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
|
@ -63,13 +63,6 @@ export class ButtonDimmer extends Component {
|
|||
render() {
|
||||
return (
|
||||
<ButtonDimmerContainer>
|
||||
<Settings
|
||||
deviceId={this.props.device.id}
|
||||
edit={this.props.edit}
|
||||
onChangeData={(id, newSettings) =>
|
||||
this.props.onChangeData(id, newSettings)
|
||||
}
|
||||
/>
|
||||
<img alt="icon" src="/img/buttonDimmer.svg" />
|
||||
<span className="knob">
|
||||
{this.props.device.name} ({this.props.device.id})
|
||||
|
@ -85,7 +78,7 @@ export class ButtonDimmer extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export class KnobDimmer extends Component {
|
||||
export class KnobDimmerComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -118,13 +111,6 @@ export class KnobDimmer extends Component {
|
|||
render() {
|
||||
return (
|
||||
<div style={knobContainer}>
|
||||
<Settings
|
||||
deviceId={this.props.device.id}
|
||||
edit={this.props.edit}
|
||||
onChangeData={(id, newSettings) =>
|
||||
this.props.onChangeData(id, newSettings)
|
||||
}
|
||||
/>
|
||||
<CircularInput
|
||||
style={KnobDimmerStyle}
|
||||
value={+(Math.round(this.state.value / 100 + "e+2") + "e-2")}
|
||||
|
@ -151,3 +137,11 @@ export class KnobDimmer extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
device: state.devices[ownProps.id],
|
||||
});
|
||||
const conn = connect(mapStateToProps, RemoteService);
|
||||
|
||||
export const KnobDimmer = conn(KnobDimmerComponent);
|
||||
export const ButtonDimmer = conn(ButtonDimmerComponent);
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
BottomPanel,
|
||||
ThumbText,
|
||||
} from "./styleComponents";
|
||||
import Settings from "./DeviceSettings";
|
||||
import { Image } from "semantic-ui-react";
|
||||
import {
|
||||
CircularInput,
|
||||
|
@ -32,8 +31,10 @@ import {
|
|||
knobIcon,
|
||||
} from "./LightStyle";
|
||||
import { call } from "../../../client_server";
|
||||
import { RemoteService } from "../../../remote";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
export default class Light extends Component {
|
||||
class Light extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -52,7 +53,7 @@ export default class Light extends Component {
|
|||
);
|
||||
};
|
||||
|
||||
call.socketSubscribe(this.props.device.id, this.stateCallback);
|
||||
// call.socketSubscribe(this.props.device.id, this.stateCallback);
|
||||
}
|
||||
|
||||
onClickDevice = () => {
|
||||
|
@ -91,13 +92,6 @@ export default class Light extends Component {
|
|||
render() {
|
||||
const intensityLightView = (
|
||||
<div style={LightDimmerContainer}>
|
||||
<Settings
|
||||
deviceId={this.props.device.id}
|
||||
edit={this.props.edit}
|
||||
onChangeData={(id, newSettings) =>
|
||||
this.props.onChangeData(id, newSettings)
|
||||
}
|
||||
/>
|
||||
<CircularInput
|
||||
style={LightDimmerStyle}
|
||||
value={+(Math.round(this.intensity / 100 + "e+2") + "e-2")}
|
||||
|
@ -128,14 +122,7 @@ export default class Light extends Component {
|
|||
|
||||
const normalLightView = (
|
||||
<StyledDiv>
|
||||
<Settings
|
||||
deviceId={this.props.device.id}
|
||||
edit={this.props.edit}
|
||||
onChangeData={(id, newSettings) =>
|
||||
this.props.onChangeData(id, newSettings)
|
||||
}
|
||||
/>
|
||||
<div onClick={this.props.edit.mode ? () => {} : this.onClickDevice}>
|
||||
<div onClick={this.onClickDevice}>
|
||||
<Image src={this.getIcon()} style={iconStyle} />
|
||||
<BottomPanel style={{ backgroundColor: "#ffa41b" }}>
|
||||
<h5 style={nameStyle}>
|
||||
|
@ -155,3 +142,9 @@ export default class Light extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
device: state.devices[ownProps.id],
|
||||
});
|
||||
const LightContainer = connect(mapStateToProps, RemoteService)(Light);
|
||||
export default LightContainer;
|
||||
|
|
|
@ -35,11 +35,12 @@ import {
|
|||
humiditySensorColors,
|
||||
iconSensorStyle,
|
||||
} from "./SensorStyle";
|
||||
import Settings from "./DeviceSettings";
|
||||
import { call } from "../../../client_server";
|
||||
import { Image } from "semantic-ui-react";
|
||||
import { RemoteService } from "../../../remote";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
export default class Sensor extends Component {
|
||||
class Sensor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -131,13 +132,6 @@ export default class Sensor extends Component {
|
|||
|
||||
return (
|
||||
<div style={container}>
|
||||
<Settings
|
||||
deviceId={this.props.device.id}
|
||||
edit={this.props.edit}
|
||||
onChangeData={(id, newSettings) =>
|
||||
this.props.onChangeData(id, newSettings)
|
||||
}
|
||||
/>
|
||||
{this.state.motion ? (
|
||||
<MotionSensor />
|
||||
) : (
|
||||
|
@ -185,3 +179,9 @@ export default class Sensor extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
device: state.devices[ownProps.id],
|
||||
});
|
||||
const SensorContainer = connect(mapStateToProps, RemoteService)(Sensor);
|
||||
export default SensorContainer;
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
editModeIconStyle,
|
||||
editModeStyleLeft,
|
||||
} from "./styleComponents";
|
||||
import Settings from "./DeviceSettings";
|
||||
import { Image } from "semantic-ui-react";
|
||||
import {
|
||||
energyConsumedStyle,
|
||||
|
@ -20,8 +19,10 @@ import {
|
|||
nameStyle,
|
||||
} from "./SmartPlugStyle";
|
||||
import { call } from "../../../client_server";
|
||||
import { RemoteService } from "../../../remote";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
export default class SmartPlug extends Component {
|
||||
class SmartPlug extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -81,21 +82,7 @@ export default class SmartPlug extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<StyledDiv onClick={this.props.edit.mode ? () => {} : this.onClickDevice}>
|
||||
<Settings
|
||||
deviceId={this.props.device.id}
|
||||
edit={this.props.edit}
|
||||
onChangeData={(id, newSettings) =>
|
||||
this.props.onChangeData(id, newSettings)
|
||||
}
|
||||
/>
|
||||
{this.props.edit.mode ? (
|
||||
<span style={editModeStyleLeft} onClick={this.resetSmartPlug}>
|
||||
<img src="/img/refresh.svg" alt="" style={editModeIconStyle} />
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<StyledDiv onClick={this.onClickDevice}>
|
||||
<Image src={this.getIcon()} style={imageStyle} />
|
||||
<span style={nameStyle}>
|
||||
{this.props.device.name} ({this.props.device.id})
|
||||
|
@ -115,3 +102,9 @@ export default class SmartPlug extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
device: state.devices[ownProps.id],
|
||||
});
|
||||
const SmartPlugContainer = connect(mapStateToProps, RemoteService)(SmartPlug);
|
||||
export default SmartPlugContainer;
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
|
||||
import React, { Component } from "react";
|
||||
import { BottomPanel, StyledDiv } from "./styleComponents";
|
||||
import Settings from "./DeviceSettings";
|
||||
import { Image } from "semantic-ui-react";
|
||||
import { imageStyle, nameStyle, turnedOnStyle } from "./SwitchStyle";
|
||||
import { call } from "../../../client_server";
|
||||
import { RemoteService } from "../../../remote";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
export default class Switch extends Component {
|
||||
class Switch extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -57,15 +58,7 @@ export default class Switch extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<StyledDiv onClick={this.props.edit.mode ? () => {} : this.onClickDevice}>
|
||||
<Settings
|
||||
deviceId={this.props.device.id}
|
||||
edit={this.props.edit}
|
||||
onChangeData={(id, newSettings) =>
|
||||
this.props.onChangeData(id, newSettings)
|
||||
}
|
||||
/>
|
||||
|
||||
<StyledDiv onClick={this.onClickDevice}>
|
||||
<Image src={this.getIcon()} style={imageStyle} />
|
||||
<span style={nameStyle}>
|
||||
{this.props.device.name} ({this.props.device.id})
|
||||
|
@ -86,3 +79,9 @@ export default class Switch extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
device: state.devices[ownProps.id],
|
||||
});
|
||||
const SwitchContainer = connect(mapStateToProps, RemoteService)(Switch);
|
||||
export default SwitchContainer;
|
||||
|
|
|
@ -60,7 +60,7 @@ const Endpoint = {
|
|||
Authorization: `Bearer ${Endpoint.token}`,
|
||||
},
|
||||
}).then((res) => {
|
||||
if (!res.data) {
|
||||
if (!res.data && method != "delete") {
|
||||
console.error("Response body is empty");
|
||||
return null;
|
||||
} else {
|
||||
|
@ -294,7 +294,7 @@ export const RemoteService = {
|
|||
}
|
||||
|
||||
return Endpoint[data.id ? "put" : "post"](url, {}, data)
|
||||
.then((res) => void dispatch(actions.deviceUpdate(res.data)))
|
||||
.then((res) => void dispatch(actions.deviceSave(res.data)))
|
||||
.catch((err) => {
|
||||
console.warn("Update device: ", data, "error: ", err);
|
||||
throw new RemoteError(["Network error"]);
|
||||
|
@ -396,7 +396,7 @@ export const RemoteService = {
|
|||
*/
|
||||
deleteRoom: (roomId) => {
|
||||
return (dispatch) => {
|
||||
Endpoint.delete(`/room/${roomId}`)
|
||||
return Endpoint.delete(`/room/${roomId}`)
|
||||
.then((_) => dispatch(actions.roomDelete(roomId)))
|
||||
.catch((err) => {
|
||||
console.warn("Room deletion error", err);
|
||||
|
@ -407,14 +407,14 @@ export const RemoteService = {
|
|||
|
||||
/**
|
||||
* Deletes a device
|
||||
* @param {Number} deviceId the id of the device to delete
|
||||
* @param {Device} device the device to delete
|
||||
* @returns {Promise<Undefined, RemoteError>} promise that resolves to void and rejects
|
||||
* with user-fiendly errors as a RemoteError
|
||||
*/
|
||||
deleteDevice: (deviceId) => {
|
||||
deleteDevice: (device) => {
|
||||
return (dispatch) => {
|
||||
Endpoint.delete(`/device/${deviceId}`)
|
||||
.then((_) => dispatch(actions.deviceDelete(deviceId)))
|
||||
return Endpoint.delete(`/${device.kind}/${device.id}`)
|
||||
.then((_) => dispatch(actions.deviceDelete(device.id)))
|
||||
.catch((err) => {
|
||||
console.warn("Device deletion error", err);
|
||||
throw new RemoteError(["Network error"]);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { createStore, applyMiddleware } from "redux";
|
||||
import thunk from "redux-thunk";
|
||||
import actions from "./storeActions";
|
||||
import action from "./storeActions";
|
||||
import update from "immutability-helper";
|
||||
|
||||
function reducer(previousState, action) {
|
||||
let newState;
|
||||
const createOrUpdateRoom = (room) => {
|
||||
if (!(room.id in newState.rooms)) {
|
||||
if (!newState.rooms[room.id]) {
|
||||
newState = update(newState, {
|
||||
rooms: { [room.id]: { devices: { $set: new Set() } } },
|
||||
rooms: { [room.id]: { $set: { ...room, devices: new Set() } } },
|
||||
});
|
||||
} else {
|
||||
newState = update(newState, {
|
||||
|
@ -78,7 +78,7 @@ function reducer(previousState, action) {
|
|||
rooms: {},
|
||||
};
|
||||
|
||||
for (const room of newState.rooms) {
|
||||
for (const room of Object.values(previousState.rooms)) {
|
||||
change.rooms[room.id].devices = { $set: new Set() };
|
||||
}
|
||||
}
|
||||
|
@ -109,9 +109,14 @@ function reducer(previousState, action) {
|
|||
case "ROOM_SAVE":
|
||||
createOrUpdateRoom(action.room);
|
||||
break;
|
||||
case "DEVICE_SAVE":
|
||||
newState = update(previousState, {
|
||||
devices: { [action.device.id]: { $set: action.device } },
|
||||
});
|
||||
break;
|
||||
case "ROOM_DELETE":
|
||||
if (!(actions.roomId in previousState.rooms)) {
|
||||
console.warn(`Room to delete ${actions.roomId} does not exist`);
|
||||
if (!(action.roomId in previousState.rooms)) {
|
||||
console.warn(`Room to delete ${action.roomId} does not exist`);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -124,23 +129,28 @@ function reducer(previousState, action) {
|
|||
change.devices.$unset.push(id);
|
||||
}
|
||||
|
||||
change.rooms = { $unset: actions.roomId };
|
||||
change.rooms = { $unset: [action.roomId] };
|
||||
newState = update(previousState, change);
|
||||
break;
|
||||
case "DEVICE_DELETE":
|
||||
if (!(actions.deviceId in previousState.devices)) {
|
||||
console.warn(`Device to delete ${actions.deviceId} does not exist`);
|
||||
if (!(action.deviceId in previousState.devices)) {
|
||||
console.warn(`Device to delete ${action.deviceId} does not exist`);
|
||||
break;
|
||||
}
|
||||
|
||||
newState = update(previousState, {
|
||||
devices: { $unset: actions.deviceId },
|
||||
rooms: {
|
||||
[previousState.devices[actions.deviceId].roomId]: {
|
||||
devices: { $remove: actions.deviceId },
|
||||
change = {
|
||||
devices: { $unset: [action.deviceId] },
|
||||
};
|
||||
|
||||
if (previousState.rooms[previousState.devices[action.deviceId].roomId]) {
|
||||
change.rooms = {
|
||||
[previousState.devices[action.deviceId].roomId]: {
|
||||
devices: { $remove: [action.deviceId] },
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
newState = update(previousState, change);
|
||||
break;
|
||||
case "LOGOUT":
|
||||
newState = update(initState, {});
|
||||
|
@ -149,7 +159,7 @@ function reducer(previousState, action) {
|
|||
newState = update(previousState, {
|
||||
active: {
|
||||
activeRoom: {
|
||||
$set: actions.activeRoom,
|
||||
$set: action.activeRoom,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -17,12 +17,20 @@ const actions = {
|
|||
type: "ROOM_SAVE",
|
||||
room,
|
||||
}),
|
||||
deviceSave: (device) => ({
|
||||
type: "DEVICE_SAVE",
|
||||
device,
|
||||
}),
|
||||
devicesUpdate: (roomId, devices, partial = false) => ({
|
||||
type: "DEVICES_UPDATE",
|
||||
roomId,
|
||||
devices,
|
||||
partial,
|
||||
}),
|
||||
roomsUpdate: (rooms) => ({
|
||||
type: "ROOMS_UPDATE",
|
||||
rooms,
|
||||
}),
|
||||
roomDelete: (roomId) => ({
|
||||
type: "ROOM_DELETE",
|
||||
roomId,
|
||||
|
|
|
@ -185,11 +185,13 @@ class Navbar extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setActiveRoom: (activeRoom) =>
|
||||
dispatch(appActions.setActiveRoom(activeRoom)),
|
||||
};
|
||||
const setActiveRoom = (dispatch) => {
|
||||
return (activeRoom) => dispatch(appActions.setActiveRoom(activeRoom));
|
||||
};
|
||||
const NavbarContainer = connect(mapDispatchToProps, RemoteService)(Navbar);
|
||||
|
||||
const mapStateToProps = (state, _) => ({ rooms: state.rooms });
|
||||
const NavbarContainer = connect(mapStateToProps, {
|
||||
...RemoteService,
|
||||
setActiveRoom,
|
||||
})(Navbar);
|
||||
export default NavbarContainer;
|
||||
|
|
Loading…
Reference in a new issue