Sync tool status across all clients

This commit is contained in:
2018-02-03 19:59:39 -07:00
parent a1c80c70cb
commit 0c59652222
6 changed files with 406 additions and 23 deletions

View File

@@ -4,29 +4,62 @@ import Category from './Category';
import Tool from './Tool';
import { Container, Dimmer, Dropdown, Header, Icon, Item, Loader, Menu, Segment, Input } from 'semantic-ui-react';
import { Link, Route } from 'react-router-dom';
import io from 'socket.io-client';
// Move to env var
const SERVER_URL = "http://localhost:8080";
class App extends Component {
constructor() {
super();
this.socket = io(SERVER_URL);
this.state = {
user: null,
toolData: null,
toolStatus: null,
connected: false,
};
}
componentDidMount() {
fetch('http://localhost:8080/api/tooldata')
fetch(SERVER_URL + '/api/tooldata')
.then(response => response.json())
.then(data => this.setState({ toolData: data }));
fetch('http://localhost:8080/api/user')
fetch(SERVER_URL + '/api/user')
.then(response => response.json())
.then(data => this.setState({ user: data }));
this.socket.on('toolStatus', toolStatus =>
this.setState({ toolStatus: toolStatus })
);
this.socket.on('connect', toolStatus =>
this.setState({ connected: true })
);
this.socket.on('disconnect', toolStatus =>
this.setState({ toolStatus: null, connected: false })
);
}
componentWillUnmount() {
this.socket.removeAllListeners();
}
requestInterlock = change => {
this.socket.emit('requestInterlock', {
username: this.state.user.username,
change: change,
});
}
render() {
const toolData = this.state.toolData;
const toolStatus = this.state.toolStatus;
const user = this.state.user;
const connected = this.state.connected;
return (
<div>
@@ -37,6 +70,9 @@ class App extends Component {
<Menu.Item as={Link} to='/'>
<Icon name='home' size='big' />
</Menu.Item>
<Menu.Item>
<Icon name='circle' color={connected ? 'green' : 'red'} />
</Menu.Item>
<Menu.Menu position='right'>
<Menu.Item position='right'>
<Input transparent inverted placeholder='Search...' icon='search' />
@@ -49,7 +85,7 @@ class App extends Component {
{toolData && user ?
<div>
<Route exact path='/' render={props =>
<Categories {...props} data={toolData} user={user} />
<Categories {...props} data={toolData} />
} />
<Route exact path='/:category' render={props =>
@@ -57,7 +93,12 @@ class App extends Component {
} />
<Route exact path='/:category/:id' render={props =>
<Tool {...props} data={toolData} user={user} />
<Tool {...props}
data={toolData}
user={user}
toolStatus={toolStatus}
requestInterlock={this.requestInterlock}
/>
} />
</div>
:

View File

@@ -8,7 +8,7 @@ class Category extends Component {
const user = this.props.user;
const match = this.props.match;
const category = data.categories.find((x) =>
const category = data.categories.find(x =>
x.slug === match.params.category
);

View File

@@ -3,19 +3,41 @@ import { Breadcrumb, Button, Container, Dropdown, Header, Icon, Image, Item, Lab
import { Link } from 'react-router-dom';
class Tool extends Component {
decodeStatus = status => {
if (status === null) {
return { msg: 'Unknown! Connection error?', canArm: false, canDisarm: false, };
} else if (!status.armed && !status.on) {
return { msg: 'Off', canArm: true, canDisarm: false, };
} else if (status.armed && !status.on) {
return { msg: 'Armed', canArm: false, canDisarm: true, };
} else if (status.armed && status.on) {
return { msg: 'On', canArm: false, canDisarm: true, };
} else if (!status.armed && status.on) {
return { msg: 'Error: Impossible state!', canArm: false, canDisarm: false, };
}
}
render() {
const data = this.props.data;
const user = this.props.user;
const match = this.props.match;
const toolStatus = this.props.toolStatus || [];
const requestInterlock = this.props.requestInterlock;
const category = data.categories.find((x) =>
const category = data.categories.find(x =>
x.slug === match.params.category
);
const tool = category.tools.find((x) =>
const tool = category.tools.find(x =>
x.id.toString() === match.params.id
);
const status = toolStatus.find(x =>
x.id.toString() === match.params.id
) || null;
const decodedStatus = this.decodeStatus(status);
console.log(decodedStatus);
const approved = user.authorizedTools.includes(tool.id);
return (
@@ -32,12 +54,18 @@ class Tool extends Component {
<Segment>
<Image src={tool.photo} size='medium' centered rounded />
<Segment textAlign='center' basic>
<p>Status: Off</p>
<p> Status: {decodedStatus.msg}</p>
<div>
<Button color='green' disabled={!approved}>
<Icon name='lightning' /> Arm
<Button color='green'
disabled={!approved || !decodedStatus.canArm}
onClick={() => requestInterlock({toolId: tool.id, action: 'arm',})}
>
<Icon name='lightning' /> Arm
</Button>
<Button color='red' disabled={!approved}>
<Button color='red'
disabled={!approved || !decodedStatus.canDisarm}
onClick={() => requestInterlock({toolId: tool.id, action: 'disarm',})}
>
<Icon name='stop' /> Disarm
</Button>
</div>