Converting project to Redux store

This commit is contained in:
britea 2020-04-09 17:24:30 +02:00
parent bad5d04238
commit eead3694e6
5 changed files with 191 additions and 459 deletions

View file

@ -7,9 +7,10 @@ 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 { connect } from "react-redux";
import { RemoteService } from "../../remote";
export default class DevicePanel extends Component { class DevicePanel extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -17,10 +18,13 @@ export default class DevicePanel extends Component {
}; };
this.addDevice = this.addDevice.bind(this); this.addDevice = this.addDevice.bind(this);
this.toggleEditMode = this.toggleEditMode.bind(this);
this.getDevices();
} }
editModeController = (e) => toggleEditMode(e) {
this.setState((prevState) => ({ editMode: !prevState.editMode })); this.setState((prevState) => ({ editMode: !prevState.editMode }));
}
openModal = (settingsDeviceId) => { openModal = (settingsDeviceId) => {
this.setState((prevState) => ({ this.setState((prevState) => ({
@ -29,107 +33,30 @@ export default class DevicePanel extends Component {
})); }));
}; };
changeDeviceData = (deviceId, newSettings) => { /*changeDeviceData = (deviceId, newSettings) => {
console.log(newSettings.name, " <-- new name --> ", deviceId); console.log(newSettings.name, " <-- new name --> ", deviceId);
this.props.devices.map((device) => {
if (device.id === deviceId) { for (let prop in this.props.devices[deviceId]) {
for (let prop in newSettings) { if (prop === "name") {
if (device.hasOwnProperty(prop)) { if (checkMaxLength(newSettings[prop])) {
if (prop === "name") { device[prop] = newSettings[prop];
if (checkMaxLength(newSettings[prop])) { } else {
device[prop] = newSettings[prop]; alert(
} else { "Name must be less than " +
alert( DEVICE_NAME_MAX_LENGTH +
"Name must be less than " + " characters."
DEVICE_NAME_MAX_LENGTH + );
" characters."
);
}
} else {
device[prop] = newSettings[prop];
}
}
} }
} else {
device[prop] = newSettings[prop];
} }
return null;
});
this.forceUpdate();
};
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) { getDevices() {
const ds = await this.props.addDevice(data); this.props.fetchDevices().then();
this.setState({
devices: ds,
});
this.forceUpdate();
} }
updateDevice = (data) => {
const roomId = this.props.devices.filter(
(d) => d.id === this.state.settingsDeviceId
)[0].roomId;
data["id"] = this.state.settingsDeviceId;
data["roomId"] = roomId;
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,
@ -149,31 +76,21 @@ export default class DevicePanel extends Component {
{this.state.openSettingsModal ? ( {this.state.openSettingsModal ? (
<SettingsModal <SettingsModal
openModal={this.openModal} openModal={this.openModal}
updateDevice={this.updateDevice}
removeDevice={this.removeDevice}
device={ds.filter((d) => d.id === this.state.settingsDeviceId)[0]} device={ds.filter((d) => d.id === this.state.settingsDeviceId)[0]}
/> />
) : ( ) : (
"" ""
)} )}
{ds {this.props.devices.map((e, i) => {
? ds.map((e, i) => { return (
return ( <Grid.Column key={i}>
<Grid.Column key={i}> <DeviceType type={e.kind} device={e} edit={edit} />
<DeviceType </Grid.Column>
updateDev={this.props.updateDeviceUi} );
type={e.kind} })}
onChangeData={this.changeDeviceData} {!this.props.isActiveRoomHome ? (
device={e}
edit={edit}
/>
</Grid.Column>
);
})
: null}
{this.props.activeItem !== -1 ? (
<Grid.Column> <Grid.Column>
<NewDevice addDevice={this.addDevice} devices={ds} /> <NewDevice />
</Grid.Column> </Grid.Column>
) : null} ) : null}
</Grid> </Grid>
@ -181,3 +98,24 @@ export default class DevicePanel extends Component {
); );
} }
} }
const mapStateToProps = (state, _) => ({
get devices() {
if (state.active.activeRoom === -1) {
return Object.values(state.devices);
} else {
return state.rooms[state.active.activeRoom].devices.map(
(id) => state.devices[id]
);
}
},
get isActiveRoomHome() {
return this.props.activeRoom === -1;
},
activeRoom: state.active.activeRoom,
});
const DevicePanelContainer = connect(
mapStateToProps,
RemoteService
)(DevicePanel);
export default DevicePanelContainer;

View file

@ -143,12 +143,16 @@ function reducer(previousState, action) {
}); });
break; break;
case "LOGOUT": case "LOGOUT":
newState = { newState = update(initState, {});
login: { loggedIn: false, token: null }, break;
rooms: [], case "SET_ACTIVE_ROOM":
devices: [], newState = update(previousState, {
userInfo: null, active: {
}; activeRoom: {
$set: actions.activeRoom,
},
},
});
break; break;
default: default:
console.warn(`Action type ${action.type} unknown`, action); console.warn(`Action type ${action.type} unknown`, action);
@ -159,23 +163,33 @@ function reducer(previousState, action) {
return newState; return newState;
} }
const initState = {
errors: {},
active: {
activeRoom: -1,
},
login: {
loggedIn: false,
token: null,
},
userInfo: null,
/** @type {[integer]Room} */
rooms: {},
/** @type {[integer]Device} */
devices: {},
};
function createSmartHutStore() { function createSmartHutStore() {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
const exp = localStorage.getItem("exp"); const exp = localStorage.getItem("exp");
const initialState = { const initialState = update(initState, {
errors: {},
login: { login: {
token: token, token: { $set: token },
loggedIn: { $set: !!(token && exp > new Date().getTime()) },
}, },
userInfo: null, });
/** @type {[integer]Room} */
rooms: {},
/** @type {[integer]Device} */
devices: {},
};
initialState.login.loggedIn = !!(token && exp > new Date().getTime());
if (!initialState.login.loggedIn) { if (!initialState.login.loggedIn) {
localStorage.removeItem("token"); localStorage.removeItem("token");
localStorage.removeItem("exp"); localStorage.removeItem("exp");

View file

@ -33,4 +33,12 @@ const actions = {
}), }),
}; };
export const appActions = {
// -1 for home view
setActiveRoom: (activeRoom = -1) => ({
type: "SET_ACTIVE_ROOM",
activeRoom,
}),
};
export default actions; export default actions;

View file

@ -2,191 +2,9 @@ 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 { Grid, Responsive } from "semantic-ui-react"; import { Grid, Responsive } from "semantic-ui-react";
/*
rooms -> actual rooms
activeItem -> the current room in view
devices -> current device in current room view
id of Home is -1
*/
export default class Dashboard extends Component { export default class Dashboard extends Component {
constructor(props) {
super(props);
this.state = {
rooms: [],
activeItem: -1,
devices: [],
image: "",
tkn: this.props.tkn,
};
this.addRoom = this.addRoom.bind(this);
this.deleteRoom = this.deleteRoom.bind(this);
this.updateRoom = this.updateRoom.bind(this);
this.addDevice = this.addDevice.bind(this);
this.handleItemClick = this.handleItemClick.bind(this);
}
getDevices() {
if (this.state.activeItem === -1) {
call
.getAllDevices()
.then((res) => {
if (res.status === 200) {
//console.log(res.data);
this.setState({
devices: res.data,
});
}
})
.catch((err) => {
//console.log(err);
});
} else {
call
.getAllDevicesByRoom(this.state.activeItem)
.then((res) => {
if (res.status === 200) {
//console.log(res.data);
this.setState({
devices: res.data,
});
}
})
.catch((err) => {});
}
}
getRooms() {
call
.getAllRooms(this.props.tkn)
.then((res) => {
this.setState({
rooms: res.data,
});
})
.catch((err) => {});
}
componentDidMount() {
this.getRooms();
this.getDevices();
}
addRoom(data) {
call
.createRoom(data)
.then((res) => {
if (res.status === 200 && res.data) {
this.getRooms();
this.handleItemClick(-1);
}
})
.catch((err) => {
//console.log(err);
});
}
deleteRoom() {
let data = {
id: this.state.activeItem,
};
call
.deleteRoom(data)
.then((res) => {
//remove room in state.rooms
this.getRooms();
this.setState({
activeItem: -1,
});
this.handleItemClick(-1);
})
.catch((err) => {
//console.log(err);
});
}
updateRoom(data) {
data.id = this.state.activeItem;
call
.updateRoom(data)
.then((res) => {
if (res.status === 200 && res.data) {
this.getRooms();
this.forceUpdate();
}
})
.catch((err) => {});
}
handleItemClick(id) {
this.setState({
activeItem: id,
});
if (id === -1) {
call
.getAllDevices(this.props.tkn)
.then((res) => {
if (res.status === 200) {
this.setState({
devices: res.data,
});
}
})
.catch((err) => {
//console.log(err);
});
} else {
call
.getAllDevicesByRoom(id, this.props.tkn)
.then((res) => {
if (res.status === 200) {
this.setState({
devices: res.data,
});
this.forceUpdate();
}
})
.catch((err) => {
//console.log(err);
});
}
this.state.rooms.forEach((item) => {
if (item.id === id) {
this.setState({ room: item });
}
});
}
addDevice(data) {
data.params["roomId"] = this.state.activeItem;
call
.devicePost(data, this.props.tkn)
.then((res) => {
this.getDevices();
})
.catch((err) => {});
}
updateDeviceUi = (data) => {
let ds = this.state.devices;
ds.forEach((e) => {
if (e.id === data.id) {
e = data;
}
});
this.setState({
devices: ds,
});
return;
};
render() { render() {
return ( return (
<div style={{ height: "110vh", background: "#1b1c1d" }}> <div style={{ height: "110vh", background: "#1b1c1d" }}>
@ -194,29 +12,16 @@ export default class Dashboard extends Component {
<Grid> <Grid>
<Grid.Row color="black"> <Grid.Row color="black">
<Grid.Column> <Grid.Column>
<MyHeader logout={this.props.logout} /> <MyHeader />
</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 <Navbar />
activeItem={this.state.activeItem}
addRoom={this.addRoom}
updateRoom={this.updateRoom}
deleteRoom={this.deleteRoom}
rooms={this.state.rooms}
handleItemClick={this.handleItemClick}
/>
</Grid.Column> </Grid.Column>
<Grid.Column width={13}> <Grid.Column width={13}>
<DevicePanel <DevicePanel />
tkn={this.props.tkn}
activeItem={this.state.activeItem}
addDevice={this.addDevice}
devices={this.state.devices}
room={this.state.room}
/>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>
@ -225,32 +30,17 @@ export default class Dashboard extends Component {
<Grid inverted> <Grid inverted>
<Grid.Row color="black"> <Grid.Row color="black">
<Grid.Column> <Grid.Column>
<MyHeader logout={this.props.logout} /> <MyHeader />
</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 <Navbar />
activeItem={this.state.activeItem}
addRoom={this.addRoom}
updateRoom={this.updateRoom}
deleteRoom={this.deleteRoom}
rooms={this.state.rooms}
handleItemClick={this.handleItemClick}
/>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
<Grid.Row> <Grid.Row>
<Grid.Column> <Grid.Column>
<DevicePanel <DevicePanel />
img={this.state.image}
tkn={this.props.tkn}
activeItem={this.state.activeItem}
addDevice={this.addDevice}
devices={this.state.devices}
updateDev={this.updateDeviceUi}
room={this.state.room}
/>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>

View file

@ -9,45 +9,48 @@ import {
} from "semantic-ui-react"; } from "semantic-ui-react";
import { editButtonStyle } from "../components/dashboard/devices/styleComponents"; import { editButtonStyle } from "../components/dashboard/devices/styleComponents";
import ModalWindow from "../components/modalform"; import ModalWindow from "../components/modalform";
import { RemoteService } from "../remote";
import { connect } from "react-redux";
import { appActions } from "../storeActions";
class Navbar extends Component { class Navbar extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
activeItemName: "Home",
activeItem: -1,
edited: "",
editMode: false, editMode: false,
room: "",
}; };
this.roomRefs = {}; this.toggleEditMode = this.toggleEditMode.bind(this);
this.props.rooms.forEach((e) => { this.selectRoom = this.selectRoom.bind(this);
this.roomRefs[e.id] = React.createRef();
}); this.getRooms();
} }
componentDidMount() { getRooms() {
this.setState({ this.props.fetchAllRooms().catch(console.error);
activeItem: this.props.activeItem,
});
} }
editModeController = (e) => get activeItem() {
return this.props.activeRoom;
}
set activeItem(item) {
this.props.setActiveRoom(item);
}
get activeItemName() {
console.log(this.constructor);
if (this.props.activeRoom === -1) return "Home";
return this.props.rooms[this.props.activeRoom];
}
toggleEditMode(e) {
this.setState((prevState) => ({ editMode: !prevState.editMode })); this.setState((prevState) => ({ editMode: !prevState.editMode }));
}
handleClick = (e, { id, name }) => { selectRoom(e, { id }) {
const room = this.props.rooms.filter((d) => d.id === id)[0]; this.activeItem = id;
//console.log(room); }
this.setState({
activeItem: id,
activeItemName: name,
});
this.activeRoom = room;
//console.log(this.activeRoom);
this.forceUpdate();
this.props.handleItemClick(id);
};
render() { render() {
return ( return (
@ -55,7 +58,7 @@ class Navbar extends Component {
<Responsive minWidth={768}> <Responsive minWidth={768}>
<Grid> <Grid>
<Grid.Row color="black"> <Grid.Row color="black">
<button style={editButtonStyle} onClick={this.editModeController}> <button style={editButtonStyle} onClick={this.toggleEditMode}>
Edit Edit
</button> </button>
</Grid.Row> </Grid.Row>
@ -65,8 +68,8 @@ class Navbar extends Component {
key={-1} key={-1}
id={-1} id={-1}
name="Home" name="Home"
active={this.state.activeItem === -1} active={this.activeRoom === -1}
onClick={this.handleClick} onClick={this.selectRoom}
> >
<Grid> <Grid>
<Grid.Row> <Grid.Row>
@ -78,46 +81,36 @@ class Navbar extends Component {
</Grid> </Grid>
</Menu.Item> </Menu.Item>
{this.props.rooms {Object.values(this.props.rooms).map((e, i) => {
? this.props.rooms.map((e, i) => { return (
return ( <Menu.Item
<Menu.Item id={e.id}
id={e.id} key={i}
key={i} name={e.name}
name={e.name} active={this.activeRoom === e.id}
active={this.state.activeItem === e.id} onClick={this.selectRoom}
onClick={this.handleClick} >
> <Grid>
<Grid> <Grid.Row>
<Grid.Row> <Grid.Column>
<Grid.Column> <Icon name={e.icon} size="small" />
<Icon name={e.icon} size="small" /> </Grid.Column>
</Grid.Column> <Grid.Column width={8}>{e.name}</Grid.Column>
<Grid.Column width={8}>{e.name}</Grid.Column> <Grid.Column floated="right">
<Grid.Column floated="right"> {this.state.editMode ? (
{this.state.editMode ? ( <ModalWindow type="modify" idRoom={e.id} />
<ModalWindow ) : null}
type="modify" </Grid.Column>
idRoom={e} </Grid.Row>
updateRoom={this.props.updateRoom} </Grid>
deleteRoom={this.props.deleteRoom} </Menu.Item>
/> );
) : null} })}
</Grid.Column>
</Grid.Row>
</Grid>
</Menu.Item>
);
})
: null}
<Menu.Item <Menu.Item name="newM">
name="newM"
active={this.state.activeItem === "newM"}
>
<Grid> <Grid>
<Grid.Row centered name="new"> <Grid.Row centered name="new">
<ModalWindow type="new" addRoom={this.props.addRoom} /> <ModalWindow type="new" />
</Grid.Row> </Grid.Row>
</Grid> </Grid>
</Menu.Item> </Menu.Item>
@ -128,14 +121,14 @@ class Navbar extends Component {
<Responsive maxWidth={768}> <Responsive maxWidth={768}>
<Menu> <Menu>
<Dropdown item fluid text={this.state.activeItemName}> <Dropdown item fluid text={this.activeItemName}>
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item <Dropdown.Item
key={-1} key={-1}
id={-1} id={-1}
name="Home" name="Home"
active={this.state.activeItem === "Home"} active={this.activeRoom === -1}
onClick={this.handleClick} onClick={this.selectRoom}
> >
<Grid> <Grid>
<Grid.Row> <Grid.Row>
@ -147,56 +140,38 @@ class Navbar extends Component {
</Grid> </Grid>
</Dropdown.Item> </Dropdown.Item>
{this.props.rooms {Object.values(this.props.rooms).map((e, i) => {
? this.props.rooms.map((e, i) => { return (
if (!this.roomRefs[e.id]) <Dropdown.Item
this.roomRefs[e.id] = React.createRef(); id={e.id}
return ( key={i}
<Dropdown.Item name={e.name}
id={e.id} active={this.activeRoom === e.id}
key={i} onClick={this.selectRoom}
name={e.name} >
active={this.state.activeItem === e.id} <Grid>
onClick={this.handleClick} <Grid.Row>
> <Grid.Column width={1}>
<Grid> <Icon name={e.icon} size="small" />
<Grid.Row> </Grid.Column>
<Grid.Column width={1}> <Grid.Column>{e.name}</Grid.Column>
<Icon name={e.icon} size="small" /> </Grid.Row>
</Grid.Column> </Grid>
<Grid.Column>{e.name}</Grid.Column> <ModalWindow type="modify" nicolaStop={true} idRoom={e} />
</Grid.Row> </Dropdown.Item>
</Grid> );
<ModalWindow })}
ref={this.roomRefs[e.id]}
type="modify"
nicolaStop={true}
idRoom={e}
updateRoom={this.props.updateRoom}
deleteRoom={this.props.deleteRoom}
/>
</Dropdown.Item>
);
})
: null}
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
</Menu> </Menu>
<Grid inverted> <Grid inverted>
<Grid.Row> <Grid.Row>
<Grid.Column width={8}> <Grid.Column width={8}>
<ModalWindow type="new" addRoom={this.props.addRoom} /> <ModalWindow type="new" />
</Grid.Column> </Grid.Column>
{this.state.activeItem !== -1 ? ( {this.activeRoom !== -1 ? (
<Grid.Column width={8}> <Grid.Column width={8}>
<Button <Button icon fluid labelPosition="left">
icon
fluid
labelPosition="left"
onClick={() =>
this.roomRefs[this.state.activeItem].current.openModal()
}
>
<Icon name="pencil" size="small" /> <Icon name="pencil" size="small" />
EDIT ROOM EDIT ROOM
</Button> </Button>
@ -210,4 +185,11 @@ class Navbar extends Component {
} }
} }
export default Navbar; const mapDispatchToProps = (dispatch) => {
return {
setActiveRoom: (activeRoom) =>
dispatch(appActions.setActiveRoom(activeRoom)),
};
};
const NavbarContainer = connect(mapDispatchToProps, RemoteService)(Navbar);
export default NavbarContainer;