Guest selection panel working

This commit is contained in:
Claudio Maggioni (maggicl) 2020-05-02 22:37:20 +02:00
parent a6fbd1a5d2
commit 9b2253b161
7 changed files with 166 additions and 161 deletions

View File

@ -1,43 +1,71 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { Button, Header, Modal, Icon, Responsive } from "semantic-ui-react"; import {
Button,
Header,
Modal,
Icon,
Form,
Responsive,
Dropdown,
} from "semantic-ui-react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { RemoteService } from "../remote"; import { RemoteService, Forms } from "../remote";
import { appActions } from "../storeActions"; import { appActions } from "../storeActions";
//import { update } from "immutability-helper"; //import { update } from "immutability-helper";
class HostModal extends Component { class HostModal extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = this.initialState; this.state = { guests: [], users: [] };
this.props
.fetchGuests()
.then(() => {
this.setState({
...this.state,
guests: this.props.guests.map((u) => u.id),
});
})
.catch(console.error);
Forms.fetchAllUsers()
.then((users) =>
this.setState({
...this.state,
users: users.map((u) => ({
key: u.id,
text: `@${u.username} (${u.name})`,
value: u.id,
})),
})
)
.catch(console.error);
this.saveGuestSettings = this.saveGuestSettings.bind(this);
this.closeModal = this.closeModal.bind(this);
this.openModal = this.openModal.bind(this);
this.setGuests = this.setGuests.bind(this);
this.saveGuestSettings = this.saveGuestSettings.bind(this); this.saveGuestSettings = this.saveGuestSettings.bind(this);
} }
get initialState() { setGuests(_, guests) {
return { this.setState({ guests: guests.value });
//INITIAL STATE HERE
};
} }
setInitialState() { closeModal() {
this.setState(this.initialState);
}
changeSomething = (event) => {
let nam = event.target.name;
let val = event.target.value;
this.setState({ [nam]: val });
};
closeModal = (e) => {
this.setState({ openModal: false }); this.setState({ openModal: false });
}; }
openModal = (e) => { openModal() {
this.setState({ openModal: true }); this.setState({ openModal: true });
}; }
saveGuestSettings() {} saveGuestSettings() {
this.props
.updateGuests(this.state.guests)
.then(this.closeModal)
.catch(console.error);
}
render() { render() {
return ( return (
@ -49,17 +77,10 @@ class HostModal extends Component {
</Button> </Button>
</Responsive> </Responsive>
<Responsive maxWidth={768}> <Responsive maxWidth={768}>
{this.type === "new" ? ( <Button icon fluid labelPosition="left" onClick={this.openModal}>
<Button icon fluid labelPosition="left" onClick={this.openModal}> <Icon name="plus" size="small" />
<Icon name="plus" size="small" /> Invitation settings
Invitation settings </Button>
</Button>
) : (
<Button icon fluid labelPosition="left" onClick={this.openModal}>
<Icon name="pencil" size="small" />
EDIT AUTOMATION
</Button>
)}
</Responsive> </Responsive>
<Modal closeIcon onClose={this.closeModal} open={this.state.openModal}> <Modal closeIcon onClose={this.closeModal} open={this.state.openModal}>
@ -68,6 +89,22 @@ class HostModal extends Component {
<marquee scrollamount="50"> <marquee scrollamount="50">
<h1>Spaghetti!</h1> <h1>Spaghetti!</h1>
</marquee> </marquee>
<Modal.Content>
<Form>
<Form.Field style={{ marginTop: "1rem" }}>
<label>Select which users are your guests: </label>
<Dropdown
name="guests"
placeholder="Select Guests"
fluid
multiple
onChange={this.setGuests}
options={this.state.users}
value={this.state.guests}
/>
</Form.Field>
</Form>
</Modal.Content>
</Modal.Content> </Modal.Content>
<Modal.Actions> <Modal.Actions>
<Button color="red" onClick={this.closeModal}> <Button color="red" onClick={this.closeModal}>
@ -88,8 +125,8 @@ const setActiveHost = (activeHost) => {
return (dispatch) => dispatch(appActions.setActiveHost(activeHost)); return (dispatch) => dispatch(appActions.setActiveHost(activeHost));
}; };
const mapStateToProps = (state, ownProps) => ({ const mapStateToProps = (state) => ({
hostss: ownProps.id ? state.hostss[ownProps.id] : null, guests: state.guests,
}); });
const HostModalContainer = connect( const HostModalContainer = connect(
mapStateToProps, mapStateToProps,

View File

@ -1,9 +1,7 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { RemoteService } from "../../remote"; import { RemoteService } from "../../remote";
import { Grid } from "semantic-ui-react"; import { Card, Segment, Header, Icon } from "semantic-ui-react";
import Device from "./devices/Device";
import NewSceneDevice from "./NewSceneDevice";
class HostsPanel extends Component { class HostsPanel extends Component {
constructor(props) { constructor(props) {
@ -12,32 +10,22 @@ class HostsPanel extends Component {
render() { render() {
return ( return (
<Grid doubling columns={2} divided="vertically"> <Card.Group centered style={{ paddingTop: "3rem" }}>
{!this.props.isActiveDefaultHost {this.props.isActiveDefaultHost && (
? Object.values(this.props.hostDevices).map((e, i) => { <Segment placeholder>
return ( <Header icon>
<Grid.Column key={i}> <Icon name="folder open" />
<Device tab={this.props.tab} id={e} /> Please select a host to visit on the left.
</Grid.Column> </Header>
); </Segment>
})
: null}
{!this.props.isActiveDefaultHost ? (
<Grid.Column>
<NewSceneDevice />
</Grid.Column>
) : (
<Grid.Column>
Welcome to the Host View, select a host to view their devices.
</Grid.Column>
)} )}
</Grid> </Card.Group>
); );
} }
} }
const mapStateToProps = (state, _) => ({ const mapStateToProps = (state, _) => ({
activeTab: state.active.activeTab, isActiveDefaultHost: state.active.activeHost === -1,
activeHost: state.active.activeHost, activeHost: state.active.activeHost,
hostDevices: state.hostDevices, hostDevices: state.hostDevices,
}); });

View File

@ -48,6 +48,7 @@ class NewSceneDevice extends Component {
handleOpen = () => { handleOpen = () => {
this.setState({ openModal: true }); this.setState({ openModal: true });
}; };
handleClose = () => { handleClose = () => {
this.setState({ openModal: false }); this.setState({ openModal: false });
}; };

View File

@ -351,10 +351,10 @@ export const RemoteService = {
* @returns {Promise<Undefined, RemoteError>} promise that resolves to void and rejects * @returns {Promise<Undefined, RemoteError>} promise that resolves to void and rejects
* with user-fiendly errors as a RemoteError * with user-fiendly errors as a RemoteError
*/ */
fetchAllHosts: () => { fetchHosts: () => {
return (dispatch) => { return (dispatch) => {
return Endpoint.get(`/user/hosts`) return Endpoint.get(`/user/hosts`)
.then((res) => void dispatch(actions.getHosts(res.data))) .then((res) => void dispatch(actions.hostsUpdate(res.data)))
.catch((err) => { .catch((err) => {
console.error(`Fetch hosts error`, err); console.error(`Fetch hosts error`, err);
throw new RemoteError(["Network error"]); throw new RemoteError(["Network error"]);
@ -363,17 +363,32 @@ export const RemoteService = {
}, },
/** /**
* Adds the current user as a guest to another user * Fetches all guests of a particular user.
* identified through a host id.
* @param {Number} hostId the host to add.
* @param {String} username the username of the guest to add.
* @returns {Promise<Undefined, RemoteError>} promise that resolves to void and rejects * @returns {Promise<Undefined, RemoteError>} promise that resolves to void and rejects
* with user-fiendly errors as a RemoteError * with user-fiendly errors as a RemoteError
*/ */
addUserAsGuest: (hostId, username) => { fetchGuests: () => {
return (dispatch) => { return (dispatch) => {
return Endpoint.post(`/user/guest`) return Endpoint.get(`/user/guests`)
.then((res) => void dispatch(actions.guestSave(res.data))) .then((res) => void dispatch(actions.guestsUpdate(res.data)))
.catch((err) => {
console.error(`Fetch guests error`, err);
throw new RemoteError(["Network error"]);
});
};
},
/**
* Adds the current user as a guest to another user
* identified through a user id.
* @param {Number[]} userId the users to add.
* @returns {Promise<Undefined, RemoteError>} promise that resolves to void and rejects
* with user-fiendly errors as a RemoteError
*/
updateGuests: (userIds) => {
return (dispatch) => {
return Endpoint.put(`/user/guests`, {}, { ids: userIds })
.then((res) => void dispatch(actions.guestsUpdate(res.data)))
.catch((err) => { .catch((err) => {
console.error(`Guest save error`, err); console.error(`Guest save error`, err);
throw new RemoteError(["Network Error"]); throw new RemoteError(["Network Error"]);
@ -828,6 +843,15 @@ for (const key in RemoteService) {
} }
export class Forms { export class Forms {
static fetchAllUsers() {
return Endpoint.get(`/user`)
.then((res) => res.data)
.catch((err) => {
console.error(`Fetch users error`, err);
throw new RemoteError(["Network error"]);
});
}
/** /**
* Attempts to create a new user from the given data. * Attempts to create a new user from the given data.
* This method does not update the global state, * This method does not update the global state,

View File

@ -433,47 +433,11 @@ function reducer(previousState, action) {
case "LOGOUT": case "LOGOUT":
newState = update(initState, {}); newState = update(initState, {});
break; break;
case "SET_ACTIVE_ROOM": case "SET_ACTIVE":
newState = update(previousState, { newState = update(previousState, {
active: { active: {
activeRoom: { [action.key]: {
$set: action.activeRoom, $set: action.value,
},
},
});
break;
case "SET_ACTIVE_TAB":
newState = update(previousState, {
active: {
activeTab: {
$set: action.activeTab,
},
},
});
break;
case "SET_ACTIVE_SCENE":
newState = update(previousState, {
active: {
activeScene: {
$set: action.activeScene,
},
},
});
break;
case "SET_ACTIVE_AUTOMATION":
newState = update(previousState, {
active: {
activeAutomation: {
$set: action.activeAutomation,
},
},
});
break;
case "SET_ACTIVE_HOST":
newState = update(previousState, {
active: {
activeHost: {
$set: action.activeHost,
}, },
}, },
}); });
@ -488,14 +452,10 @@ function reducer(previousState, action) {
devices, devices,
}); });
break; break;
case "HOSTS_UPDATE": case "HG_UPDATE":
change = { newState = update(previousState, {
hosts: {}, [action.key]: { $set: action.value },
}; });
for (const host of action.hosts) {
change.hosts[host.id] = { $set: host };
}
newState = update(previousState, change);
break; break;
default: default:
console.warn(`Action type ${action.type} unknown`, action); console.warn(`Action type ${action.type} unknown`, action);
@ -532,10 +492,10 @@ const initState = {
devices: {}, devices: {},
/** @type {[integer]SceneState} */ /** @type {[integer]SceneState} */
sceneStates: {}, sceneStates: {},
/** @type {[integer]Guest} */ /** @type {User[]} */
guests: {}, guests: [],
/** @type {[integer]Host} */ /** @type {User[]} */
hosts: {}, hosts: [],
/** @type {[integer]HostDevice} */ /** @type {[integer]HostDevice} */
hostDevices: {}, hostDevices: {},
}; };

View File

@ -91,54 +91,48 @@ const actions = {
type: "DEVICE_DELETE", type: "DEVICE_DELETE",
deviceId, deviceId,
}), }),
hostsUpdate: (hosts) => ({ hostsUpdate: (hosts) => ({
type: "HOSTS_UPDATE", type: "HG_UPDATE",
hosts, key: "hosts",
value: hosts,
}),
guestsUpdate: (hosts) => ({
type: "HG_UPDATE",
key: "guests",
value: hosts,
}), }),
getHostDevices: (host) => ({ getHostDevices: (host) => ({
type: "GET_HOST_DEVICES", type: "GET_HOST_DEVICES",
host, host,
}), }),
guestUpdate: (guests) => ({
guestSave: (guest) => ({ type: "HG_UPDATE",
type: "GUEST_SAVE", key: "guests",
guest, value: guests,
}),
guestUpdate: (guest) => ({
type: "GUEST_UPDATE",
guest,
}),
guestDelete: (guest) => ({
type: "GUEST_DELETE",
guest,
}), }),
}; };
export const appActions = { export const appActions = {
// -1 for home view // -1 for home view
setActiveRoom: (activeRoom = -1) => ({ setActiveRoom: (activeRoom = -1) => ({
type: "SET_ACTIVE_ROOM", type: "SET_ACTIVE",
activeRoom, key: "activeRoom",
value: activeRoom,
}), }),
setActiveTab: (activeTab) => ({ setActiveTab: (activeTab) => ({
type: "SET_ACTIVE_TAB", type: "SET_ACTIVE",
activeTab, key: "activeTab",
value: activeTab,
}), }),
setActiveScene: (activeScene = -1) => ({ setActiveScene: (activeScene = -1) => ({
type: "SET_ACTIVE_SCENE", type: "SET_ACTIVE",
activeScene, key: "activeScene",
value: activeScene,
}), }),
setActiveAutomations: (activeAutomation = -1) => ({ setActiveHost: (activeHost = -1) => ({
type: "SET_ACTIVE_AUTOMATION", type: "SET_ACTIVE",
activeAutomation, key: "activeHost",
}), value: activeHost,
setActiveHosts: (activeHost = -1) => ({
type: "SET_ACTIVE_HOST",
activeHost,
}), }),
}; };

View File

@ -20,28 +20,29 @@ class HostsNavbar extends Component {
}; };
this.getHosts(); this.getHosts();
this.selectHosts = this.selectHosts.bind(this);
} }
getHosts() { getHosts() {
this.props.fetchAllHosts().catch(console.error); this.props.fetchHosts().catch(console.error);
} }
get activeItemHost() { selectHosts(_, { id }) {
this.props.setActiveHost(id || -1);
}
get activeItem() {
return this.props.activeHost; return this.props.activeHost;
} }
set activeItemHost(item) {
this.props.setActiveHost(item);
}
get activeItemHostsName() { get activeItemHostsName() {
if (this.props.activeHost === -1) return "Home"; if (this.props.activeItem === -1) return "Home";
return this.props.hosts[this.props.activeHost].name; return this.props.hosts[this.props.activeHost].name;
} }
render() { render() {
return ( return (
<div style={{ background: "#1b1c1d!important", padding: "0 20px" }}> <div>
<Responsive minWidth={768}> <Responsive minWidth={768}>
<Grid style={{ margin: "1em -1em 0 1em" }}> <Grid style={{ margin: "1em -1em 0 1em" }}>
<Grid.Row> <Grid.Row>
@ -50,7 +51,7 @@ class HostsNavbar extends Component {
key={-1} key={-1}
id={null} id={null}
name="hosts" name="hosts"
active={this.activeItemHost === -1} active={this.activeItem === -1}
onClick={this.selectHosts} onClick={this.selectHosts}
> >
<strong>Hosts</strong> <strong>Hosts</strong>
@ -61,7 +62,7 @@ class HostsNavbar extends Component {
id={e.id} id={e.id}
key={i} key={i}
name={e.name} name={e.name}
active={this.activeItemHost === e.id} active={this.activeItem === e.id}
onClick={this.selectHosts} onClick={this.selectHosts}
> >
{e.name} {e.name}
@ -84,7 +85,7 @@ class HostsNavbar extends Component {
key={-1} key={-1}
id={null} id={null}
name="scene" name="scene"
active={this.activeItemHost === -1} active={this.activeItem === -1}
onClick={this.selectHosts} onClick={this.selectHosts}
> >
<strong>Hosts</strong> <strong>Hosts</strong>
@ -96,7 +97,7 @@ class HostsNavbar extends Component {
id={e.id} id={e.id}
key={i} key={i}
name={e.name} name={e.name}
active={this.activeItemHost === e.id} active={this.activeItem === e.id}
onClick={this.selectHosts} onClick={this.selectHosts}
> >
{e.name} {e.name}