master
Nicole Collings 2019-09-17 22:49:49 -07:00
parent 646c7231c8
commit f01a0b8002
35 changed files with 865 additions and 206 deletions

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
Client/node_modules
Client/package-lock.json
Client/build
Server/node_modules
Server/package-lock.json
Server/build

View File

@ -8,10 +8,12 @@
"@types/node": "12.7.5",
"@types/react": "16.9.2",
"@types/react-dom": "16.9.0",
"@types/react-router-dom": "^4.3.5",
"@types/socket.io-client": "^1.4.32",
"node-sass": "^4.12.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-router-dom": "^5.0.1",
"react-scripts": "3.1.1",
"socket.io-client": "^2.2.0",
"typescript": "3.6.3"

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="#fff" d="M19.36,2.72L20.78,4.14L15.06,9.85C16.13,11.39 16.28,13.24 15.38,14.44L9.06,8.12C10.26,7.22 12.11,7.37 13.65,8.44L19.36,2.72M5.93,17.57C3.92,15.56 2.69,13.16 2.35,10.92L7.23,8.83L14.67,16.27L12.58,21.15C10.34,20.81 7.94,19.58 5.93,17.57Z" /></svg>

After

Width:  |  Height:  |  Size: 544 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path fill="#fff" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8 0-1.85.63-3.55 1.69-4.9L16.9 18.31C15.55 19.37 13.85 20 12 20zm6.31-3.1L7.1 5.69C8.45 4.63 10.15 4 12 4c4.42 0 8 3.58 8 8 0 1.85-.63 3.55-1.69 4.9z"/></svg>

After

Width:  |  Height:  |  Size: 389 B

View File

@ -1,8 +1,8 @@
.App {
.DeskApp {
color: #fff;
}
.App-header {
.DeskApp-header {
height: 64px;
background-color: #1c1c1c;
box-shadow: 0px 0px 24px 0px rgba(0, 0, 0, 0.4);
@ -20,7 +20,7 @@
}
}
.App-connectMessage {
.DeskApp-connectMessage {
font-family: "Montserrat";
font-weight: 400;
font-size: 28px;

View File

@ -1,20 +1,20 @@
import React from 'react';
import openSocket from 'socket.io-client';
import './App.scss';
import './DeskApp.scss';
import {PatientColumn} from "./PatientColumn";
import {PatientMenu, PatientMenuState} from "./PatientMenu";
import {DeskPatientColumn} from "./DeskPatientColumn";
import {DeskMenu, DeskMenuState} from "./DeskMenu";
import {BedProps} from "../share/BedProps";
import {SetState} from "../share/NetSetState";
interface State {
patients: BedProps[];
menu: PatientMenuState | null;
menu: DeskMenuState | null;
socket: SocketIOClient.Socket | null;
socketState: string;
}
export class App extends React.Component<{}, State> {
export class DeskApp extends React.Component<{}, State> {
constructor(props: {}) {
super(props);
@ -73,7 +73,7 @@ export class App extends React.Component<{}, State> {
this.setState({menu: {
ind: ind,
s: this.state.patients[elem].s,
elem: elem,
offsetX: offX,
offsetY: offY,
open: false
@ -86,8 +86,8 @@ export class App extends React.Component<{}, State> {
}, 16);
}
patientMenuStateChange(ind: number, state: SetState) {
this.state.socket!.emit('updatePatient', ind, state);
patientMenuStateChange(ind: number, state: SetState, arg?: any) {
this.state.socket!.emit('updatePatient', ind, state, arg);
this.patientMenuClose();
}
@ -101,22 +101,23 @@ export class App extends React.Component<{}, State> {
render() {
return (
<div className="App">
<div className="App-header">
<div className="DeskApp">
<div className="DeskApp-header">
<h1>Powell River General Hospital ER</h1>
</div>
{this.state.socket != null && <>
<PatientColumn patients={this.state.patients} onClick={this.patientCardClicked.bind(this)}/>
<DeskPatientColumn patients={this.state.patients} onClick={this.patientCardClicked.bind(this)}/>
{this.state.menu &&
<PatientMenu
<DeskMenu
state={this.state.menu}
s={this.state.patients[this.state.menu.elem].s}
onStateChange={this.patientMenuStateChange.bind(this, this.state.menu.ind)}
onClose={this.patientMenuClose.bind(this)}
/>
}
</>}
{this.state.socket == null &&
<h1 className="App-connectMessage">
<h1 className="DeskApp-connectMessage">
{this.state.socketState === "unconnected" ?
"Connecting..." :
this.state.socketState === "retrying" ?

View File

@ -1,6 +1,6 @@
@import "../vars";
.PatientMenu {
.DeskMenu {
width: 100%;
height: 100%;
display: block;
@ -9,18 +9,18 @@
color: #fff;
}
.PatientMenu.open {
.PatientMenu-mouseCatcher {
.DeskMenu.open {
.DeskMenu-mouseCatcher {
opacity: 1;
}
.PatientMenu-menuWrap {
.DeskMenu-menuWrap {
transform: scale(1);
opacity: 1;
}
}
.PatientMenu-mouseCatcher {
.DeskMenu-mouseCatcher {
width: 100%;
height: 100%;
display: block;
@ -32,7 +32,7 @@
transition: opacity 0.1s;
}
.PatientMenu-menuWrap {
.DeskMenu-menuWrap {
position: absolute;
display: block;
width: 250px;
@ -60,7 +60,7 @@
}
}
.PatientMenu-menuOption {
.DeskMenu-menuOption {
width: 100%;
height: auto;
position: relative;
@ -106,6 +106,17 @@
}
}
&.sub {
position: relative;
top: -4px;
opacity: 0.6;
padding: 4px 16px 8px 16px;
}
&.sub .checkbox {
opacity: 0.6;
}
& > p {
margin: 0;
display: inline-block;
@ -126,6 +137,27 @@
background-size: 20px 20px;
}
&.bloodwork::after {
@include icon;
background-image: url(/res/bloodwork.svg);
filter: grayscale(100%) brightness(500%);
opacity: 0.8;
}
&.imaging::after {
@include icon;
background-image: url(/res/imaging.svg);
filter: grayscale(100%) brightness(500%);
opacity: 0.8;
}
&.consult::after {
@include icon;
background-image: url(/res/consultation.svg);
filter: grayscale(100%) brightness(500%);
opacity: 0.8;
}
&.clipboard::after {
@include icon;
background-image: url(/res/clipboard.svg);
@ -136,11 +168,6 @@
background-image: url(/res/assign.svg);
}
// &.pending_discharge::after {
// @include icon;
// background-image: url(/res/pending_discharge.svg);
// }
&.discharge::after {
@include icon;
background-image: url(/res/pending_discharge.svg);
@ -150,5 +177,15 @@
@include icon;
background-image: url(/res/message-mono.svg);
}
&.disable::after {
@include icon;
background-image: url(/res/disabled.svg);
}
&.brush::after {
@include icon;
background-image: url(/res/broom.svg);
}
}
}

View File

@ -0,0 +1,157 @@
import React from "react";
import './DeskMenu.scss';
import {PatientState, OccupationState as OS, TaskState as TS} from "../share/BedProps"
import {SetState} from "../share/NetSetState";
export interface DeskMenuState {
ind: number,
elem: number,
offsetX: number,
offsetY: number,
open: boolean
}
interface Props {
state: DeskMenuState;
s: PatientState;
onStateChange: (state: SetState, arg?: any) => void;
onClose: () => void;
}
export class DeskMenu extends React.Component<Props, {}> {
render() {
let options;
if (this.props.s.occupation === OS.TO_CLEAN) {
options = (<>
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISCHARGE_PATIENT, false)}>
<p className='brush'>Mark Cleaned</p>
</div>
<hr />
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.MESSAGE)}>
<p className='message'>Message</p>
</div>
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISABLE, true)}>
<p className='disable'>Disable</p>
</div>
</>);
}
else if (this.props.s.occupation === OS.UNOCCUPIED) {
options = (<>
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.ASSIGN_PATIENT)}>
<p className='assign'>Assign Patient</p>
</div>
<hr />
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.MESSAGE)}>
<p className='message'>Message</p>
</div>
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISABLE, true)}>
<p className='disable'>Disable</p>
</div>
</>);
}
else if (this.props.s.occupation === OS.DISABLED) {
options = (<>
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISABLE, false)}>
<p className='assign'>Enable</p>
</div>
</>);
}
else {
options = (<>
{/*Send Bloodwork*/}
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_BLOODWORK, this.props.s.bloodwork !== TS.SENT)}>
{this.props.s.bloodwork === TS.SENT &&
<div className="checkbox checked"/>}
<p className={this.props.s.bloodwork !== TS.SENT ? "bloodwork" : ""}>
{(this.props.s.bloodwork === TS.SENT ? "Sent" : "Send") + " for Bloodwork"}</p>
</div>
{/*Return Bloodwork*/}
{this.props.s.bloodwork !== TS.NONE && <div className="DeskMenu-menuOption sub"
onClick={() => this.props.onStateChange(SetState.RECV_BLOODWORK, this.props.s.bloodwork !== TS.RETURNED)}>
{this.props.s.bloodwork === TS.RETURNED &&
<div className="checkbox checked"/>}
<p className={this.props.s.bloodwork !== TS.RETURNED ? "bloodwork" : ""}>Returned from Bloodwork</p>
</div>}
{/*Send Imaging*/}
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_IMAGING, this.props.s.imaging !== TS.SENT)}>
{this.props.s.imaging === TS.SENT &&
<div className="checkbox checked"/>}
<p className={this.props.s.imaging !== TS.SENT ? "imaging" : ""}>
{(this.props.s.imaging === TS.SENT ? "Sent" : "Send") + " for Imaging"}</p>
</div>
{/*Return Imaging*/}
{this.props.s.imaging !== TS.NONE && <div className="DeskMenu-menuOption sub"
onClick={() => this.props.onStateChange(SetState.RECV_IMAGING, this.props.s.imaging !== TS.RETURNED)}>
{this.props.s.imaging === TS.RETURNED &&
<div className="checkbox checked"/>}
<p className={this.props.s.imaging !== TS.RETURNED ? "imaging" : ""}>Returned from Imaging</p>
</div>}
{/*Send Consult*/}
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_CONSULT, this.props.s.consult !== TS.SENT)}>
{this.props.s.consult === TS.SENT &&
<div className="checkbox checked"/>}
<p className={this.props.s.consult !== TS.SENT ? "consult" : ""}>
{(this.props.s.consult === TS.SENT ? "Sent" : "Send") + " for Consult"}</p>
</div>
{/*Return Consult*/}
{this.props.s.consult !== TS.NONE && <div className="DeskMenu-menuOption sub"
onClick={() => this.props.onStateChange(SetState.RECV_CONSULT, this.props.s.consult !== TS.RETURNED)}>
{this.props.s.consult === TS.RETURNED &&
<div className="checkbox checked"/>}
<p className={this.props.s.consult !== TS.RETURNED ? "consult" : ""}>Returned from Consult</p>
</div>}
{/*Pending Discharge*/}
{(this.props.s.consult === TS.RETURNED || this.props.s.bloodwork === TS.RETURNED ||
this.props.s.imaging === TS.RETURNED || this.props.s.occupation === OS.PENDING_DISCHARGE) && <>
<hr />
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange((this.props.s.occupation === OS.PENDING_DISCHARGE) ?
SetState.ASSIGN_PATIENT : SetState.PATIENT_PENDING_DISCHARGE)}>
<div className={"checkbox " + (this.props.s.occupation === OS.PENDING_DISCHARGE ? "checked" : "")}/>
<p>Pending Discharge</p>
</div>
</>}
<hr />
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.MESSAGE)}>
<p className='message'>Message</p>
</div>
<div className="DeskMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISCHARGE_PATIENT, false)}>
<p className='discharge'>Discharge</p>
</div>
</>);
}
return (
<div className={"DeskMenu " + (this.props.state.open ? "open" : "")}>
<div className="DeskMenu-mouseCatcher" onClick={this.props.onClose}/>
<div className="DeskMenu-menuWrap" style={{left: this.props.state.offsetX, top: this.props.state.offsetY}}>
{options}
</div>
</div>
);
}
}

View File

@ -1,4 +1,4 @@
.PatientColumn {
.DeskPatientColumn {
display: block;
margin: 0 auto;
max-width: 965px;

View File

@ -1,5 +1,5 @@
import React from 'react';
import './PatientColumn.scss';
import './DeskPatientColumn.scss';
import {PatientCard} from "./PatientCard"
import {BedProps} from "../share/BedProps"
@ -9,10 +9,10 @@ interface Props {
onClick: (ind: number, e: React.MouseEvent) => void;
}
export class PatientColumn extends React.Component<Props, {}> {
export class DeskPatientColumn extends React.Component<Props, {}> {
render() {
return (
<div className="PatientColumn">
<div className="DeskPatientColumn">
{this.props.patients.map((patient, index) =>
<PatientCard
bedNum={patient.bedNum}

View File

@ -28,6 +28,14 @@
.PatientCard-statusText { opacity: 0.6; }
}
&.disabled {
background-color: #5c6f78;
background: linear-gradient(-20deg, #0e1a25, #202b31);
.PatientCard-topSegment { opacity: 0.5; }
.PatientCard-statusText { opacity: 0.3; }
}
&.satisfied {
background-color: #558b2f;
background: linear-gradient(-20deg, #1B5E20, #8BC34A);
@ -53,6 +61,13 @@
.PatientCard-statusText { font-weight: 700; }
}
&.to_clean {
background-color: #397fb5;
background: linear-gradient(-20deg, #044390, #50b1d6);
.PatientCard-statusText { font-weight: 700; }
}
}
.PatientCard-content {

View File

@ -12,6 +12,8 @@ interface Props {
export class PatientCard extends React.Component<Props, {}> {
render() {
let state = this.props.s.occupation === OS.UNOCCUPIED ? "unoccupied"
: this.props.s.occupation === OS.DISABLED ? "disabled"
: this.props.s.occupation === OS.TO_CLEAN ? "to_clean"
: this.props.s.message === true ? "message"
: this.props.s.occupation === OS.OCCUPIED ?
this.props.s.bloodwork !== TS.RETURNED &&
@ -22,10 +24,12 @@ export class PatientCard extends React.Component<Props, {}> {
: "message";
let properCase = state === "unoccupied" ? "Unoccupied"
: state === "disabled" ? "Disabled"
: state === "satisfied" ? "Satisfied"
: state === "pending_discharge" ? "Pending Discharge"
: state === "needs_attention" ? "Needs Attention"
: state === "message" ? "New Message"
: state === "to_clean" ? "Needs Cleaning"
: "Error"
return (

View File

@ -1,111 +0,0 @@
import React from "react";
import './PatientMenu.scss';
import {PatientState, OccupationState as OS, TaskState as TS} from "../share/BedProps"
import {SetState} from "../share/NetSetState";
export interface PatientMenuState {
ind: number,
s: PatientState,
offsetX: number,
offsetY: number,
open: boolean
}
interface Props {
state: PatientMenuState;
onStateChange: (state: SetState) => void;
onClose: () => void;
}
export class PatientMenu extends React.Component<Props, {}> {
render() {
let options;
if (this.props.state.s.occupation === OS.UNOCCUPIED) {
options = (<>
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.ASSIGN_PATIENT)}>
<p className='assign'>Assign Patient</p>
</div>
<hr />
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.MESSAGE)}>
<p className='message'>Message</p>
</div>
</>);
}
else {
options = (<>
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_BLOODWORK)}>
<div className={"checkbox " + (this.props.state.s.bloodwork === TS.SENT ? "checked" : "")}/>
<p>Sent for Bloodwork</p>
</div>
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_IMAGING)}>
<div className={"checkbox " + (this.props.state.s.imaging === TS.SENT ? "checked" : "")}/>
<p>Sent for Imaging</p>
</div>
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_CONSULT)}>
<div className={"checkbox " + (this.props.state.s.consult === TS.SENT ? "checked" : "")}/>
<p>Sent for Consult</p>
</div>
{(this.props.state.s.bloodwork === TS.SENT
||this.props.state.s.imaging === TS.SENT
||this.props.state.s.consult === TS.SENT) &&
<>
<hr />
{this.props.state.s.bloodwork === TS.SENT && <div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.RECV_BLOODWORK)}>
<div className="checkbox"/>
<p>Returned from Bloodwork</p>
</div>}
{this.props.state.s.imaging === TS.SENT && <div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.RECV_IMAGING)}>
<div className="checkbox"/>
<p>Returned from Imaging</p>
</div>}
{this.props.state.s.consult === TS.SENT && <div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.RECV_CONSULT)}>
<div className="checkbox"/>
<p>Returned from Consult</p>
</div>}
</>
}
<hr />
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.MESSAGE)}>
<p className='message'>Message</p>
</div>
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange((this.props.state.s.occupation === OS.PENDING_DISCHARGE) ? SetState.ASSIGN_PATIENT : SetState.PATIENT_PENDING_DISCHARGE)}>
<div className={"checkbox " + (this.props.state.s.occupation === OS.PENDING_DISCHARGE ? "checked" : "")}/>
<p>Pending Discharge</p>
</div>
<div className="PatientMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISCHARGE_PATIENT)}>
<p className='discharge'>Discharge</p>
</div>
</>);
}
return (
<div className={"PatientMenu " + (this.props.state.open ? "open" : "")}>
<div className="PatientMenu-mouseCatcher" onClick={this.props.onClose}/>
<div className="PatientMenu-menuWrap" style={{left: this.props.state.offsetX, top: this.props.state.offsetY}}>
{options}
</div>
</div>
);
}
}

View File

@ -0,0 +1,38 @@
.PhoneApp {
color: #fff;
height: 100vh;
padding-top: 64px;
padding-bottom: 0px;
overflow: auto;
}
.PhoneApp-header {
height: 64px;
background-color: #1c1c1c;
box-shadow: 0px 0px 24px 0px rgba(0, 0, 0, 0.4);
overflow: auto;
user-select: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 5;
& > h1 {
text-align: center;
font-family: "Montserrat", sans-serif;
font-weight: 500;
font-size: 22px;
margin-top: 19px;
margin-bottom: 0;
opacity: 0.7;
}
}
.Phone-connectMessage {
font-family: "Montserrat";
font-weight: 400;
font-size: 28px;
text-align: center;
margin-top: calc(50vh - 96px)
}

View File

@ -0,0 +1,114 @@
import React from 'react';
import openSocket from 'socket.io-client';
import './PhoneApp.scss';
import {PhonePatientColumn} from "./PhonePatientColumn";
import {PhoneMenu, PhoneMenuState} from "./PhoneMenu";
import {BedProps} from "../share/BedProps";
import {SetState} from "../share/NetSetState";
interface State {
patients: BedProps[];
menu: PhoneMenuState | null;
socket: SocketIOClient.Socket | null;
socketState: string;
}
export class PhoneApp extends React.Component<{}, State> {
constructor(props: {}) {
super(props);
this.state = {
socket: null,
socketState: "unconnected",
patients: [],
menu: null
}
const socket = openSocket('http://192.168.1.9:8000');
socket.on('connect', () => {
this.setState({socket: socket});
this.initSocket();
this.state.socket!.on('disconnect', () => {
this.setState({socket: null, socketState: "retrying"});
});
});
}
initSocket() {
this.state.socket!.emit('init');
this.state.socket!.on('state', (patients: BedProps[]) => {
this.setState({patients: patients});
});
}
patientCardClicked(ind: number, e: React.MouseEvent) {
let elem = -1;
for (let i = 0; i < this.state.patients.length; i++) {
if (this.state.patients[i].bedNum === ind) {
elem = i;
break;
}
}
if (elem === -1) return;
this.setState({menu: {
ind: ind,
elem: elem,
open: false
}});
setTimeout(() => {
let menu = Object.assign({}, this.state.menu);
menu.open = true;
this.setState({menu: menu});
}, 16);
}
patientMenuStateChange(ind: number, state: SetState, arg?: any) {
this.state.socket!.emit('updatePatient', ind, state, arg);
this.patientMenuClose();
}
patientMenuClose() {
let menu = Object.assign({}, this.state.menu);
menu.open = false;
this.setState({menu: menu});
setTimeout(() => this.setState({menu: null}), 100);
}
render() {
return (
<div className="PhoneApp">
<div className="PhoneApp-header">
<h1>PR Hospital ER</h1>
</div>
{this.state.socket != null && <>
<PhonePatientColumn patients={this.state.patients} onClick={this.patientCardClicked.bind(this)}/>
{this.state.menu &&
<PhoneMenu
state={this.state.menu}
s={this.state.patients[this.state.menu.elem].s}
onStateChange={this.patientMenuStateChange.bind(this, this.state.menu.ind)}
onClose={this.patientMenuClose.bind(this)}
/>
}
</>}
{this.state.socket == null &&
<h1 className="PhoneApp-connectMessage">
{this.state.socketState === "unconnected" ?
"Connecting..." :
this.state.socketState === "retrying" ?
"Disconnected. Attempting to reconnect." :
"Error state. Please try again later"
}
</h1>
}
</div>
);
}
}

View File

@ -0,0 +1,191 @@
@import "../vars";
.PhoneMenu {
width: 100%;
height: 100%;
display: block;
position: fixed;
top: 0; left: 0;
color: #fff;
}
.PhoneMenu.open {
.PhoneMenu-mouseCatcher {
opacity: 1;
}
.PhoneMenu-menuWrap {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
}
.PhoneMenu-mouseCatcher {
width: 100%;
height: 100%;
display: block;
position: absolute;
top: 0; left: 0;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0;
transition: opacity 0.1s;
}
.PhoneMenu-menuWrap {
position: absolute;
display: block;
width: 280px;
max-width: calc(100% - 32px);
height: auto;
padding: 8px 0px;
overflow: hidden;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
border-radius: 6px;
background-color: #222;
box-shadow: 0px 4px 32px 0px rgba(0,0,0,0.7);
user-select: none;
transition: opacity 0.1s, transform 0.1s;
hr {
width: calc(100% - 8px);
margin-left: 4px;
border: none;
border-bottom: 1px solid rgba(255,255,255,0.2);
}
}
.PhoneMenu-menuOption {
width: 100%;
height: auto;
position: relative;
padding: 16px 24px;
font-size: 18px;
transition: background-color 0.2s;
@include button;
&:hover {
background-color: rgba(255,255,255,0.05);
}
&:active {
background-color: rgba(255,255,255,0.1);
}
& > .checkbox {
width: 20px;
height: 20px;
background-color: transparent;
border: 2px solid rgba(255,255,255,0.7);
border-radius: 4px;
padding: 0;
top: 16px;
left: 18px;
position: absolute;
cursor: pointer;
&.checked {
border: 2px solid transparent;
background-color: rgba(255, 255, 255, 0.7);
&::after {
position: absolute;
content: " ";
display: block;
top: 1px;
left: 1px;
width: 14px;
height: 14px;
background-image: url('/res/check.svg');
background-size: 14px 14px;
opacity: 0.8;
}
}
}
&.sub {
position: relative;
top: -4px;
opacity: 0.6;
padding: 4px 16px 8px 16px;
}
&.sub .checkbox {
opacity: 0.6;
}
& > p {
margin: 0;
display: inline-block;
position: relative;
padding-left: 32px;
font-family: "Roboto", sans-serif;
font-weight: 400;
@mixin icon {
content: " ";
position: absolute;
opacity: 0.6;
top: -2px;
left: -8px;
width: 24px;
height: 24px;
background-size: 24px 24px;
}
&.bloodwork::after {
@include icon;
background-image: url(/res/bloodwork.svg);
filter: grayscale(100%) brightness(500%);
opacity: 0.8;
}
&.imaging::after {
@include icon;
background-image: url(/res/imaging.svg);
filter: grayscale(100%) brightness(500%);
opacity: 0.8;
}
&.consult::after {
@include icon;
background-image: url(/res/consultation.svg);
filter: grayscale(100%) brightness(500%);
opacity: 0.8;
}
&.clipboard::after {
@include icon;
background-image: url(/res/clipboard.svg);
}
&.assign::after {
@include icon;
background-image: url(/res/assign.svg);
}
&.discharge::after {
@include icon;
background-image: url(/res/pending_discharge.svg);
}
&.message::after {
@include icon;
background-image: url(/res/message-mono.svg);
}
&.disable::after {
@include icon;
background-image: url(/res/disabled.svg);
}
}
}

View File

@ -0,0 +1,132 @@
import React from "react";
import './PhoneMenu.scss';
import {PatientState, OccupationState as OS, TaskState as TS} from "../share/BedProps"
import {SetState} from "../share/NetSetState";
export interface PhoneMenuState {
ind: number,
elem: number;
open: boolean
}
interface Props {
state: PhoneMenuState;
s: PatientState;
onStateChange: (state: SetState, arg?: any) => void;
onClose: () => void;
}
export class PhoneMenu extends React.Component<Props, {}> {
render() {
let options;
if (this.props.s.occupation === OS.UNOCCUPIED || this.props.s.occupation === OS.TO_CLEAN) {
options = (<>
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.MESSAGE)}>
<p className='message'>Message</p>
</div>
</>);
}
else if (this.props.s.occupation === OS.DISABLED) {
options = (<>
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISABLE, false)}>
<p className='assign'>Enable</p>
</div>
</>);
}
else {
options = (<>
{( this.props.s.bloodwork === TS.RETURNED
|| this.props.s.imaging === TS.RETURNED
|| this.props.s.consult === TS.RETURNED) && <>
{/*Clear Bloodwork*/}
{this.props.s.bloodwork === TS.RETURNED && <div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.RECV_BLOODWORK, false)}>
<p className="bloodwork">Clear Bloodwork</p>
</div>}
{/*Clear Imaging*/}
{this.props.s.imaging === TS.RETURNED && <div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.RECV_IMAGING, false)}>
<p className="imaging">Clear Imaging</p>
</div>}
{/*Clear Consult*/}
{this.props.s.consult === TS.RETURNED && <div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.RECV_CONSULT, false)}>
<p className="consult">Clear Consult</p>
</div>}
<hr/>
</>}
{/*Send Bloodwork*/}
{this.props.s.bloodwork !== TS.RETURNED &&
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_BLOODWORK, this.props.s.bloodwork !== TS.SENT)}>
{this.props.s.bloodwork === TS.SENT && <div className="checkbox checked"/>}
<p className={this.props.s.bloodwork !== TS.SENT ? "bloodwork" : ""}>
{(this.props.s.bloodwork === TS.SENT ? "Sent" : "Send") + " for Bloodwork"}</p>
</div>
}
{/*Send Imaging*/}
{this.props.s.imaging !== TS.RETURNED &&
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_IMAGING, this.props.s.imaging !== TS.SENT)}>
{this.props.s.imaging === TS.SENT && <div className="checkbox checked"/>}
<p className={this.props.s.imaging !== TS.SENT ? "imaging" : ""}>
{(this.props.s.imaging === TS.SENT ? "Sent" : "Send") + " for Imaging"}</p>
</div>
}
{/*Send Consult*/}
{this.props.s.consult !== TS.RETURNED &&
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.SENT_CONSULT, this.props.s.consult !== TS.SENT)}>
{this.props.s.consult === TS.SENT && <div className="checkbox checked"/>}
<p className={this.props.s.consult !== TS.SENT ? "consult" : ""}>
{(this.props.s.consult === TS.SENT ? "Sent" : "Send") + " for Consult"}</p>
</div>
}
{( this.props.s.bloodwork !== TS.RETURNED
|| this.props.s.imaging !== TS.RETURNED
|| this.props.s.consult !== TS.RETURNED) && <hr/>}
{/*Pending Discharge*/}
{(this.props.s.consult === TS.RETURNED || this.props.s.bloodwork === TS.RETURNED ||
this.props.s.imaging === TS.RETURNED || this.props.s.occupation === OS.PENDING_DISCHARGE) && <>
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange((this.props.s.occupation === OS.PENDING_DISCHARGE) ?
SetState.ASSIGN_PATIENT : SetState.PATIENT_PENDING_DISCHARGE)}>
<div className={"checkbox " + (this.props.s.occupation === OS.PENDING_DISCHARGE ? "checked" : "")}/>
<p>Pending Discharge</p>
</div>
</>}
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.MESSAGE)}>
<p className='message'>Message</p>
</div>
<div className="PhoneMenu-menuOption"
onClick={() => this.props.onStateChange(SetState.DISCHARGE_PATIENT, true)}>
<p className='discharge'>Discharge</p>
</div>
</>);
}
return (
<div className={"PhoneMenu " + (this.props.state.open ? "open" : "")}>
<div className="PhoneMenu-mouseCatcher" onClick={this.props.onClose}/>
<div className="PhoneMenu-menuWrap">
{options}
</div>
</div>
);
}
}

View File

@ -0,0 +1,7 @@
.PhonePatientColumn {
display: block;
margin: 0 auto;
width: 100%;
max-width: 350px;
padding: 32px 8px 64px 8px;
}

View File

@ -0,0 +1,29 @@
import React from 'react';
import './PhonePatientColumn.scss';
import {PatientCard} from "./PatientCard"
import {BedProps} from "../share/BedProps"
import {OccupationState as OS} from "../share/BedProps"
interface Props {
patients: BedProps[];
onClick: (ind: number, e: React.MouseEvent) => void;
}
export class PhonePatientColumn extends React.Component<Props, {}> {
render() {
return (
<div className="PhonePatientColumn">
{this.props.patients.map((patient, index) => {
if (patient.s.occupation !== OS.DISABLED) return (<PatientCard
bedNum={patient.bedNum}
key={patient.bedNum}
s={patient.s}
onClick={(e: React.MouseEvent) => this.props.onClick(patient.bedNum, e)}
/>);
return null;
})}
</div>
);
}
}

View File

@ -20,3 +20,13 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.Choice-wrap {
margin-top: 200px;
text-align: center;
& > p > a {
color: #fff;
font-size: 64px;
}
}

View File

@ -1,7 +1,23 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './index.scss';
import {App} from './components/App';
import {DeskApp} from './components/DeskApp';
import {PhoneApp} from './components/PhoneApp';
ReactDOM.render(<App/>, document.getElementById('root'));
class Choice extends React.Component {
render() {
return (<div className="Choice-wrap">
<p><Link to="/desk">Desktop</Link></p>
<p><Link to="/mobile">Mobile</Link></p>
</div>);
}
}
ReactDOM.render(
<Router>
<Route exact path="/" component={Choice} />
<Route exact path="/desk" component={DeskApp} />
<Route exact path="/mobile" component={PhoneApp} />
</Router>, document.getElementById('root'));

View File

@ -12,7 +12,9 @@ export enum TaskState {
export enum OccupationState {
UNOCCUPIED,
OCCUPIED,
PENDING_DISCHARGE
PENDING_DISCHARGE,
DISABLED,
TO_CLEAN,
}
export interface PatientState {

View File

@ -8,5 +8,6 @@ export enum SetState {
RECV_BLOODWORK,
RECV_IMAGING,
RECV_CONSULT,
MESSAGE
MESSAGE,
DISABLE
}

View File

@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
const BedProps_1 = require("./share/BedProps");
const NetSetState_1 = require("./share/NetSetState");
class ERFlow {
constructor() {
this.socket = null;
constructor(io) {
this.io = io;
this.patients = [];
for (let i = 0; i < 18; i++) {
for (let i = 0; i < 9; i++) {
this.patients.push({
bedNum: i + 1,
s: {
occupation: BedProps_1.OccupationState.UNOCCUPIED,
occupation: i % 6 == 0 ? BedProps_1.OccupationState.TO_CLEAN : BedProps_1.OccupationState.UNOCCUPIED,
consult: BedProps_1.TaskState.NONE,
bloodwork: BedProps_1.TaskState.NONE,
imaging: BedProps_1.TaskState.NONE,
@ -19,21 +19,14 @@ class ERFlow {
});
}
}
replaceSocket(socket) {
if (this.socket != null) {
this.socket.emit('ended');
this.socket.disconnect(true);
}
this.socket = socket;
this.socket.emit('started');
this.socket.on('updatePatient', this.updateState.bind(this));
addSocket(socket) {
socket.emit('started');
socket.on('updatePatient', this.updateState.bind(this));
this.sendState();
}
sendState() {
if (this.socket != null) {
console.log("Sending state.");
this.socket.emit('state', this.patients);
}
console.log("Sending state.");
this.io.emit('state', this.patients);
}
updateState(bedNum, state, arg) {
let bed = null;
@ -51,27 +44,27 @@ class ERFlow {
break;
}
case NetSetState_1.SetState.SENT_BLOODWORK: {
bed.s.bloodwork = BedProps_1.TaskState.SENT;
bed.s.bloodwork = arg ? BedProps_1.TaskState.SENT : BedProps_1.TaskState.NONE;
break;
}
case NetSetState_1.SetState.SENT_IMAGING: {
bed.s.imaging = BedProps_1.TaskState.SENT;
bed.s.imaging = arg ? BedProps_1.TaskState.SENT : BedProps_1.TaskState.NONE;
break;
}
case NetSetState_1.SetState.SENT_CONSULT: {
bed.s.consult = BedProps_1.TaskState.SENT;
bed.s.consult = arg ? BedProps_1.TaskState.SENT : BedProps_1.TaskState.NONE;
break;
}
case NetSetState_1.SetState.RECV_BLOODWORK: {
bed.s.bloodwork = BedProps_1.TaskState.RETURNED;
bed.s.bloodwork = arg ? BedProps_1.TaskState.RETURNED : BedProps_1.TaskState.NONE;
break;
}
case NetSetState_1.SetState.RECV_IMAGING: {
bed.s.imaging = BedProps_1.TaskState.RETURNED;
bed.s.imaging = arg ? BedProps_1.TaskState.RETURNED : BedProps_1.TaskState.NONE;
break;
}
case NetSetState_1.SetState.RECV_CONSULT: {
bed.s.consult = BedProps_1.TaskState.RETURNED;
bed.s.consult = arg ? BedProps_1.TaskState.RETURNED : BedProps_1.TaskState.NONE;
break;
}
case NetSetState_1.SetState.PATIENT_PENDING_DISCHARGE: {
@ -79,7 +72,7 @@ class ERFlow {
break;
}
case NetSetState_1.SetState.DISCHARGE_PATIENT: {
bed.s.occupation = BedProps_1.OccupationState.UNOCCUPIED;
bed.s.occupation = arg ? BedProps_1.OccupationState.TO_CLEAN : BedProps_1.OccupationState.UNOCCUPIED;
bed.s.bloodwork = BedProps_1.TaskState.NONE;
bed.s.imaging = BedProps_1.TaskState.NONE;
bed.s.consult = BedProps_1.TaskState.NONE;
@ -87,6 +80,15 @@ class ERFlow {
}
case NetSetState_1.SetState.MESSAGE: {
bed.s.message = true;
break;
}
case NetSetState_1.SetState.DISABLE: {
bed.s.occupation = arg ? BedProps_1.OccupationState.DISABLED : BedProps_1.OccupationState.UNOCCUPIED;
bed.s.bloodwork = BedProps_1.TaskState.NONE;
bed.s.imaging = BedProps_1.TaskState.NONE;
bed.s.consult = BedProps_1.TaskState.NONE;
bed.s.message = false;
break;
}
}
this.sendState();

View File

@ -1 +1 @@
{"version":3,"file":"ERFlow.js","sourceRoot":"","sources":["../src/ERFlow.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"ERFlow.js","sourceRoot":"","sources":["../src/ERFlow.ts"],"names":[],"mappings":"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"}

View File

@ -8,13 +8,13 @@ const app = express();
let http = require("http").Server(app);
let io = require("socket.io")(http);
// Create ERFlow Object
const flow = new ERFlow_1.ERFlow();
const flow = new ERFlow_1.ERFlow(io);
// Start Webserver and listen for connections.
let server = http.listen(port, () => {
console.log(`Listening On ${port}.`);
});
io.on('connection', (client) => {
console.log(`${client.id} connected.`);
flow.replaceSocket(client);
flow.addSocket(client);
});
//# sourceMappingURL=Main.js.map

View File

@ -1 +1 @@
{"version":3,"file":"Main.js","sourceRoot":"","sources":["../src/Main.ts"],"names":[],"mappings":";;AAAA,mCAAmC;AAEnC,qCAAgC;AAEhC,uBAAuB;AAEvB,MAAM,IAAI,GAAG,IAAI,CAAC;AAElB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,IAAI,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACvC,IAAI,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;AAEpC,uBAAuB;AAEvB,MAAM,IAAI,GAAG,IAAI,eAAM,EAAE,CAAC;AAE1B,8CAA8C;AAE9C,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACnC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAA;AACrC,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAiB,EAAE,EAAE;IACzC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;IACvC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC"}
{"version":3,"file":"Main.js","sourceRoot":"","sources":["../src/Main.ts"],"names":[],"mappings":";;AAAA,mCAAmC;AAEnC,qCAAgC;AAEhC,uBAAuB;AAEvB,MAAM,IAAI,GAAG,IAAI,CAAC;AAElB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,IAAI,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACvC,IAAI,EAAE,GAAc,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;AAE/C,uBAAuB;AAEvB,MAAM,IAAI,GAAG,IAAI,eAAM,CAAC,EAAE,CAAC,CAAC;AAE5B,8CAA8C;AAE9C,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACnC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAA;AACrC,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAiB,EAAE,EAAE;IACzC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;IACvC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC,CAAC,CAAC"}

View File

@ -11,5 +11,7 @@ var OccupationState;
OccupationState[OccupationState["UNOCCUPIED"] = 0] = "UNOCCUPIED";
OccupationState[OccupationState["OCCUPIED"] = 1] = "OCCUPIED";
OccupationState[OccupationState["PENDING_DISCHARGE"] = 2] = "PENDING_DISCHARGE";
OccupationState[OccupationState["DISABLED"] = 3] = "DISABLED";
OccupationState[OccupationState["TO_CLEAN"] = 4] = "TO_CLEAN";
})(OccupationState = exports.OccupationState || (exports.OccupationState = {}));
//# sourceMappingURL=BedProps.js.map

View File

@ -1 +1 @@
{"version":3,"file":"BedProps.js","sourceRoot":"","sources":["../../src/share/BedProps.ts"],"names":[],"mappings":";;AAKA,IAAY,SAIX;AAJD,WAAY,SAAS;IACpB,yCAAI,CAAA;IACJ,iDAAQ,CAAA;IACR,yCAAI,CAAA;AACL,CAAC,EAJW,SAAS,GAAT,iBAAS,KAAT,iBAAS,QAIpB;AAED,IAAY,eAIX;AAJD,WAAY,eAAe;IAC1B,iEAAU,CAAA;IACV,6DAAQ,CAAA;IACR,+EAAiB,CAAA;AAClB,CAAC,EAJW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAI1B"}
{"version":3,"file":"BedProps.js","sourceRoot":"","sources":["../../src/share/BedProps.ts"],"names":[],"mappings":";;AAKA,IAAY,SAIX;AAJD,WAAY,SAAS;IACpB,yCAAI,CAAA;IACJ,iDAAQ,CAAA;IACR,yCAAI,CAAA;AACL,CAAC,EAJW,SAAS,GAAT,iBAAS,KAAT,iBAAS,QAIpB;AAED,IAAY,eAMX;AAND,WAAY,eAAe;IAC1B,iEAAU,CAAA;IACV,6DAAQ,CAAA;IACR,+EAAiB,CAAA;IACjB,6DAAQ,CAAA;IACR,6DAAQ,CAAA;AACT,CAAC,EANW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAM1B"}

View File

@ -12,5 +12,6 @@ var SetState;
SetState[SetState["RECV_IMAGING"] = 7] = "RECV_IMAGING";
SetState[SetState["RECV_CONSULT"] = 8] = "RECV_CONSULT";
SetState[SetState["MESSAGE"] = 9] = "MESSAGE";
SetState[SetState["DISABLE"] = 10] = "DISABLE";
})(SetState = exports.SetState || (exports.SetState = {}));
//# sourceMappingURL=NetSetState.js.map

View File

@ -1 +1 @@
{"version":3,"file":"NetSetState.js","sourceRoot":"","sources":["../../src/share/NetSetState.ts"],"names":[],"mappings":";;AAAA,IAAY,QAWX;AAXD,WAAY,QAAQ;IACnB,2DAAc,CAAA;IACd,iFAAyB,CAAA;IACzB,iEAAiB,CAAA;IACjB,2DAAc,CAAA;IACd,uDAAY,CAAA;IACZ,uDAAY,CAAA;IACZ,2DAAc,CAAA;IACd,uDAAY,CAAA;IACZ,uDAAY,CAAA;IACZ,6CAAO,CAAA;AACR,CAAC,EAXW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAWnB"}
{"version":3,"file":"NetSetState.js","sourceRoot":"","sources":["../../src/share/NetSetState.ts"],"names":[],"mappings":";;AAAA,IAAY,QAYX;AAZD,WAAY,QAAQ;IACnB,2DAAc,CAAA;IACd,iFAAyB,CAAA;IACzB,iEAAiB,CAAA;IACjB,2DAAc,CAAA;IACd,uDAAY,CAAA;IACZ,uDAAY,CAAA;IACZ,2DAAc,CAAA;IACd,uDAAY,CAAA;IACZ,uDAAY,CAAA;IACZ,6CAAO,CAAA;IACP,8CAAO,CAAA;AACR,CAAC,EAZW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAYnB"}

View File

@ -1,19 +1,19 @@
import {Socket} from "socket.io";
import {Socket, Server} from "socket.io";
import {BedProps, OccupationState as OS, TaskState as TS} from "./share/BedProps"
import {SetState} from "./share/NetSetState";
export class ERFlow {
socket: Socket | null = null;
patients: BedProps[];
constructor() {
io: Server;
constructor(io: Server) {
this.io = io;
this.patients = [];
for (let i = 0; i < 18; i++) {
for (let i = 0; i < 9; i++) {
this.patients.push({
bedNum: i + 1,
s: {
occupation: OS.UNOCCUPIED,
occupation: i % 6 == 0 ? OS.TO_CLEAN : OS.UNOCCUPIED,
consult: TS.NONE,
bloodwork: TS.NONE,
imaging: TS.NONE,
@ -23,22 +23,15 @@ export class ERFlow {
}
}
replaceSocket(socket: Socket) {
if (this.socket != null) {
this.socket.emit('ended');
this.socket.disconnect(true);
}
this.socket = socket;
this.socket.emit('started');
this.socket.on('updatePatient', this.updateState.bind(this));
addSocket(socket: Socket) {
socket.emit('started');
socket.on('updatePatient', this.updateState.bind(this));
this.sendState();
}
sendState() {
if (this.socket != null) {
console.log("Sending state.");
this.socket.emit('state', this.patients);
}
console.log("Sending state.");
this.io.emit('state', this.patients);
}
updateState(bedNum: number, state: SetState, arg?: any) {
@ -59,27 +52,27 @@ export class ERFlow {
break;
}
case SetState.SENT_BLOODWORK: {
bed.s.bloodwork = TS.SENT;
bed.s.bloodwork = (arg as boolean) ? TS.SENT : TS.NONE;
break;
}
case SetState.SENT_IMAGING: {
bed.s.imaging = TS.SENT;
bed.s.imaging = (arg as boolean) ? TS.SENT : TS.NONE;
break;
}
case SetState.SENT_CONSULT: {
bed.s.consult = TS.SENT;
bed.s.consult = (arg as boolean) ? TS.SENT : TS.NONE;
break;
}
case SetState.RECV_BLOODWORK: {
bed.s.bloodwork = TS.RETURNED;
bed.s.bloodwork = (arg as boolean) ? TS.RETURNED : TS.NONE;
break;
}
case SetState.RECV_IMAGING: {
bed.s.imaging = TS.RETURNED;
bed.s.imaging = (arg as boolean) ? TS.RETURNED : TS.NONE;
break;
}
case SetState.RECV_CONSULT: {
bed.s.consult = TS.RETURNED;
bed.s.consult = (arg as boolean) ? TS.RETURNED : TS.NONE;
break;
}
case SetState.PATIENT_PENDING_DISCHARGE: {
@ -87,7 +80,7 @@ export class ERFlow {
break;
}
case SetState.DISCHARGE_PATIENT: {
bed.s.occupation = OS.UNOCCUPIED;
bed.s.occupation = (arg as boolean) ? OS.TO_CLEAN : OS.UNOCCUPIED;
bed.s.bloodwork = TS.NONE;
bed.s.imaging = TS.NONE;
bed.s.consult = TS.NONE;
@ -95,6 +88,15 @@ export class ERFlow {
}
case SetState.MESSAGE: {
bed.s.message = true;
break;
}
case SetState.DISABLE: {
bed.s.occupation = (arg as boolean) ? OS.DISABLED : OS.UNOCCUPIED;
bed.s.bloodwork = TS.NONE;
bed.s.imaging = TS.NONE;
bed.s.consult = TS.NONE;
bed.s.message = false;
break;
}
}

View File

@ -8,11 +8,11 @@ const port = 8000;
const app = express();
let http = require("http").Server(app);
let io = require("socket.io")(http);
let io: IO.Server = require("socket.io")(http);
// Create ERFlow Object
const flow = new ERFlow();
const flow = new ERFlow(io);
// Start Webserver and listen for connections.
@ -22,5 +22,5 @@ let server = http.listen(port, () => {
io.on('connection', (client: IO.Socket) => {
console.log(`${client.id} connected.`);
flow.replaceSocket(client);
flow.addSocket(client);
});

View File

@ -12,7 +12,9 @@ export enum TaskState {
export enum OccupationState {
UNOCCUPIED,
OCCUPIED,
PENDING_DISCHARGE
PENDING_DISCHARGE,
DISABLED,
TO_CLEAN,
}
export interface PatientState {

View File

@ -8,5 +8,6 @@ export enum SetState {
RECV_BLOODWORK,
RECV_IMAGING,
RECV_CONSULT,
MESSAGE
MESSAGE,
DISABLE
}