Took 5 hours 14 minutes
This commit is contained in:
Tobias Hopp 2022-11-21 12:13:30 +01:00
parent a4ac8d083b
commit a722caf2d4
17 changed files with 421 additions and 106 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
/dist/ /dist/
/.idea/ /.idea/
/node_modules /node_modules

View File

@ -0,0 +1,9 @@
#containers_volume {
min-width: 10%;
max-width: 10%;
display: inline-block;
}
#containers_volumeSlider {
width: 45%;
}

View File

@ -102,9 +102,9 @@ label {
.input { .input {
padding: 6px; padding: 6px;
font-size: 1.1em; font-size: 1.1em;
margin-left: 1%; margin-left: 1%;
margin-right: 1%; margin-right: 1%;
margin-bottom: 2%;
border: 0; border: 0;
border-radius: 3px; border-radius: 3px;
} }

View File

@ -1,10 +1,18 @@
#menu { #menu {
padding-left: 5%; padding-left: 5%;
padding-right: 5%; padding-right: 5%;
padding-top: 1%; padding-top: 10%;
display: grid; display: grid;
grid-template-columns: repeat(2, calc(90% / 2)); grid-template-columns: repeat(2, calc(100% / 2));
grid-template-rows: repeat(2, calc(90% / 2)); grid-template-rows: repeat(2, calc(95% / 2));
grid-gap: 2% 2%; grid-gap: 2% 2%;
color: white; color: white;
}
#menu > button {
grid-row: span 1;
grid-column: span 1;
font-size: 1.8em;
height: 50%;
} }

View File

@ -2,13 +2,19 @@
@import url("/stylesheets/fonts.css"); @import url("/stylesheets/fonts.css");
@import url("/stylesheets/inputs.css"); @import url("/stylesheets/inputs.css");
@import url("/stylesheets/modal.css"); @import url("/stylesheets/modal.css");
@import url("/stylesheets/menu.css");
@import url("/stylesheets/main.css"); @import url("/stylesheets/main.css");
@import url("/stylesheets/setup.css"); @import url("/stylesheets/setup.css");
@import url("/stylesheets/containers.css");
:root { :root {
/*cursor: none !important;*/ /*cursor: none !important;*/
} }
ul {
list-style: circle;
}
html * { html * {
/*cursor: none !important*/ /*cursor: none !important*/

5
src/RequestType.ts Normal file
View File

@ -0,0 +1,5 @@
export enum RequestType {
CONTAINERS = "CONTAINERS",
INGREDIENTS = "INGREDIENTS",
STATS = "STATS",
}

View File

@ -2,8 +2,10 @@ export enum WebSocketEvent {
STATUS= "STATUS", STATUS= "STATUS",
DRINKS = "DRINKS", DRINKS = "DRINKS",
CONTAINERS = "CONTAINERS", CONTAINERS = "CONTAINERS",
CONTAINER_UPDATE = "CONTAINER_UPDATE",
CONFIG = "CONFIG", CONFIG = "CONFIG",
TARE = "TARE", TARE = "TARE",
SETUP = "SETUP", SETUP = "SETUP",
REQUEST = "REQUEST" REQUEST = "REQUEST",
RESPONSE = "RESPONSE"
} }

View File

@ -3,6 +3,11 @@ import {WebSocketEvent} from "./WebSocketEvent";
import {iTender} from "./iTender"; import {iTender} from "./iTender";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
import Container from "./database/Container"; import Container from "./database/Container";
import Job from "./database/Job";
import Drink from "./database/Drink";
import {IDrink} from "./database/IDrink";
import Ingredient from "./database/Ingredient";
import {RequestType} from "./RequestType";
export class WebSocketHandler { export class WebSocketHandler {
private static _ws: WebSocket; private static _ws: WebSocket;
@ -28,6 +33,11 @@ export class WebSocketHandler {
}); });
} }
public static answerRequest(type: RequestType, content: any) {
WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.RESPONSE, false, {type: type, content: content}));
}
public static sendStatus() { public static sendStatus() {
return new Promise(resolve => { return new Promise(resolve => {
let payload = new WebSocketPayload(WebSocketEvent.STATUS, false, {status: iTender.status}); let payload = new WebSocketPayload(WebSocketEvent.STATUS, false, {status: iTender.status});
@ -39,12 +49,52 @@ export class WebSocketHandler {
return new Promise(resolve => { return new Promise(resolve => {
let payload = new WebSocketPayload(WebSocketEvent.CONFIG, false, Settings.json); let payload = new WebSocketPayload(WebSocketEvent.CONFIG, false, Settings.json);
WebSocketHandler.send(payload).then(resolve); WebSocketHandler.send(payload).then(resolve);
}) });
}
static sendStats() {
return new Promise(async resolve => {
let counts: IDrink[] = [];
for (let drink of (await Drink.find())) {
// @ts-ignore
drink.count = (await Job.countDocuments({drink: drink}));
counts.push(drink)
}
counts.sort((a: IDrink, b: IDrink) => {
// @ts-ignore
if (a.count < b.count)
return -1;
// @ts-ignore
else if (a.count > b.count)
return 1;
else
return 0;
});
let stats = {
"drinks_finished": (await Job.countDocuments({successful: true})),
"drink_most": counts[0].name,
"count_ingredients": (await Ingredient.countDocuments()),
"count_cocktails": (await Drink.countDocuments())
};
let payload = new WebSocketPayload(WebSocketEvent.RESPONSE, false, {
type: RequestType.STATS,
content: stats
});
WebSocketHandler.send(payload).then(resolve);
});
} }
static sendContainers() { static sendContainers() {
return new Promise(async resolve => { return new Promise(async resolve => {
let payload = new WebSocketPayload(WebSocketEvent.CONTAINERS, false, ( await Container.find() )); let payload = new WebSocketPayload(WebSocketEvent.CONTAINERS, false, (await Container.find()));
WebSocketHandler.send(payload).then(resolve);
})
}
static sendDrinks() {
return new Promise(async resolve => {
let payload = new WebSocketPayload(WebSocketEvent.DRINKS, false, iTender.drinks);
WebSocketHandler.send(payload).then(resolve); WebSocketHandler.send(payload).then(resolve);
}) })
} }

View File

@ -125,9 +125,9 @@ export class iTender {
} }
log("Drinks refreshed!"); log("Drinks refreshed!");
await WebSocketHandler.sendDrinks();
resolve(); resolve();
this.setStatus(iTenderStatus.READY);
}); });
} }

View File

@ -6,7 +6,6 @@ import Ingredient from "./database/Ingredient";
import {iTender} from "./iTender"; import {iTender} from "./iTender";
import {iTenderStatus} from "./iTenderStatus"; import {iTenderStatus} from "./iTenderStatus";
import {Utils} from "./Utils"; import {Utils} from "./Utils";
import Container from "./database/Container";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
const log = debug("itender:server"); const log = debug("itender:server");
@ -43,7 +42,7 @@ const wsApp = new WebsocketApp();
await init(); await init();
setInterval(refresh, 1000 * 60 * 10); setInterval(refresh, 1000 * 60);
iTender.setStatus(iTenderStatus.READY); iTender.setStatus(iTenderStatus.READY);
}, 1000); }, 1000);
} }

View File

@ -7,6 +7,8 @@ import {WebSocketEvent} from "../../WebSocketEvent";
import Container from "../../database/Container"; import Container from "../../database/Container";
import {SensorType} from "../../SensorType"; import {SensorType} from "../../SensorType";
import {Settings} from "../../Settings"; import {Settings} from "../../Settings";
import Ingredient from "../../database/Ingredient";
import {RequestType} from "../../RequestType";
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
@ -26,6 +28,8 @@ router.ws('/', async (ws, req, next) => {
await WebSocketHandler.sendRunningConfig(); await WebSocketHandler.sendRunningConfig();
await WebSocketHandler.sendContainers(); await WebSocketHandler.sendContainers();
await WebSocketHandler.sendStatus(); await WebSocketHandler.sendStatus();
await WebSocketHandler.sendDrinks();
ws.on('message', async (raw, bool) => { ws.on('message', async (raw, bool) => {
@ -36,6 +40,8 @@ router.ws('/', async (ws, req, next) => {
return; return;
} }
log(msg);
switch (msg.event) { switch (msg.event) {
case WebSocketEvent.TARE: { case WebSocketEvent.TARE: {
if (msg.data["state"] == true) { if (msg.data["state"] == true) {
@ -66,6 +72,26 @@ router.ws('/', async (ws, req, next) => {
break; break;
} }
case WebSocketEvent.CONTAINER_UPDATE: {
let container = await Container.findById(msg.data["container"]);
if (!container) break;
let ingredient;
if (msg.data["ingredient"] != null) {
ingredient = await Ingredient.findById(msg.data["ingredient"]);
if (!ingredient)
ingredient = undefined;
}
container.volume = parseInt(msg.data["volume"]);
container.content = ingredient;
await container.save();
await iTender.refreshDrinks();
break;
}
case WebSocketEvent.CONFIG: { case WebSocketEvent.CONFIG: {
// ToDo // ToDo
console.log("New Settings:", msg.data); console.log("New Settings:", msg.data);
@ -85,10 +111,34 @@ router.ws('/', async (ws, req, next) => {
if (Settings.setupDone) { if (Settings.setupDone) {
iTender.setStatus(iTenderStatus.READY); iTender.setStatus(iTenderStatus.READY);
await WebSocketHandler.sendRunningConfig(); await WebSocketHandler.sendRunningConfig();
} }
} }
await WebSocketHandler.sendContainers(); await WebSocketHandler.sendContainers();
break;
}
case WebSocketEvent.REQUEST: {
switch (msg.data["type"] as RequestType) {
case RequestType.STATS: {
await WebSocketHandler.sendStats();
break;
}
case RequestType.CONTAINERS: {
WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Container.find().sort({"slot": 1})));
break;
}
case RequestType.INGREDIENTS: {
WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Ingredient.find().sort({"name": 1})));
break;
}
}
break;
}
default: {
log("WebSocketHandler does not know how to handle " + msg.event + " Event");
} }
} }
}); });

142
src/web/Containers.ts Normal file
View File

@ -0,0 +1,142 @@
import {Modal} from "./Modal";
import {WebWebSocketHandler} from "./WebWebSocketHandler";
import {IContainer} from "../database/IContainer";
import {IIngredient} from "../database/IIngredient";
import {ButtonType} from "./ButtonType";
import {RequestType} from "../RequestType";
import {WebSocketPayload} from "../WebSocketPayload";
import {WebSocketEvent} from "../WebSocketEvent";
export class Containers {
static openMenu() {
let modal = new Modal("containers", "Behälter aktualisieren");
let txt = document.createElement("p");
txt.innerText = "Zu aktualisierenden Behälter wählen";
modal.addContent(txt);
modal.addContent(document.createElement("br"));
let form = document.createElement("div");
modal.addContent(form);
let btnSave = document.createElement("button");
btnSave.innerText = "Speichern";
btnSave.classList.add("btn", "btn-primary")
btnSave.disabled = true;
let containerVolumes: Record<any, number> = {};
let volume = document.createElement("span");
volume.innerText = "";
volume.id = "containers_volume";
let volumeSlider = document.createElement("input");
volumeSlider.type = "range";
volumeSlider.step = "10";
volumeSlider.style.visibility = "hidden";
volumeSlider.id = "containers_volumeSlider"
function onChange() {
volume.innerText = volumeSlider.value + " ml ";
txt.innerText = "Speichern zum abschließen"
}
volumeSlider.oninput = onChange;
volumeSlider.onchange = onChange;
let nonSelect = document.createElement("option");
nonSelect.value = "-1";
nonSelect.innerText = "Bitte wählen";
nonSelect.disabled = true;
let selectIngredient = document.createElement("select");
selectIngredient.style.visibility = "hidden";
selectIngredient.classList.add("input");
selectIngredient.onchange = () => {
if (selectIngredient.value == "null") {
volumeSlider.value = "0";
volumeSlider.disabled = true;
} else {
volumeSlider.disabled = false;
}
volumeSlider.style.visibility = "visible";
volume.innerText = volumeSlider.value + " ml ";
if (selectContainer.value && selectIngredient.value)
btnSave.disabled = false;
txt.innerText = "Menge des Inhalts mittels Slider einstellen";
}
selectIngredient.append(nonSelect.cloneNode(true));
selectIngredient.selectedIndex = 0;
let noIngredient = document.createElement("option");
noIngredient.value = "null";
noIngredient.innerText = "Kein Inhalt";
selectIngredient.append(noIngredient);
let selectContainer = document.createElement("select");
selectContainer.classList.add("input");
selectContainer.onchange = () => {
selectIngredient.style.visibility = "visible";
volumeSlider.max = String(containerVolumes[selectContainer.value]);
volumeSlider.min = String(0);
volumeSlider.value = String(containerVolumes[selectContainer.value] / 2);
txt.innerText = "Ingredient des Behälters auswählen";
}
selectContainer.append(nonSelect.cloneNode(true));
selectContainer.selectedIndex = 0;
WebWebSocketHandler.request(RequestType.CONTAINERS).then((payload) => {
for (let container of (payload.data["content"] as IContainer[])) {
containerVolumes[container._id] = container.volume;
let option = document.createElement("option");
option.value = container._id;
option.innerText = "Behälter Slot " + container.slot + "[" + (container.content && container.content.name ? container.content.name : "Kein Inhalt") + "]";
selectContainer.append(option);
}
});
WebWebSocketHandler.request(RequestType.INGREDIENTS).then((payload) => {
for (let ingredient of (payload.data["content"] as IIngredient[])) {
let option = document.createElement("option");
option.value = ingredient._id;
option.innerText = ingredient.name;
selectIngredient.append(option);
}
});
form.append(selectContainer, document.createElement("br"), selectIngredient, document.createElement("br"), volume, volumeSlider);
modal.addContent(document.createElement("br"));
modal.addButton(ButtonType.PRIMARY, "Abbrechen", () => modal.close());
modal.addContent(btnSave);
btnSave.onclick = () => {
// Validation
if (selectIngredient.value == "-1" || selectContainer.value == "-1") {
return;
}
// If no ingredient, move slider to 0
if (selectIngredient.value == "null")
volumeSlider.value = "0";
let payload = new WebSocketPayload(WebSocketEvent.CONTAINER_UPDATE, false, {
container: selectContainer.value,
ingredient: (selectIngredient.value == "null") ? null : selectIngredient.value,
volume: volumeSlider.value
});
WebWebSocketHandler.send(payload).then(() => modal.close());
};
modal.open();
}
}

View File

@ -44,7 +44,8 @@ export class Modal {
this._loader = value; this._loader = value;
} }
public addButton(type: ButtonType, content: string, onclick: Function = () => {}): HTMLButtonElement { public addButton(type: ButtonType, content: string, onclick: Function = () => {
}): HTMLButtonElement {
let btn = document.createElement("button"); let btn = document.createElement("button");
btn.classList.add("btn", "btn-" + type); btn.classList.add("btn", "btn-" + type);
btn.onclick = () => onclick(btn); btn.onclick = () => onclick(btn);
@ -56,17 +57,19 @@ export class Modal {
} }
public open(): Promise<void> { public open(): Promise<void> {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
/* if (this._leftCentered) { /* if (this._leftCentered) {
this._content = "<div style='text-align: left; padding-left: 2%;'>" + this._content; this._content = "<div style='text-align: left; padding-left: 2%;'>" + this._content;
}*/ //todo }*/ //todo
/* if (this._loader) if (this._loader) {
this._content += "<br><div class=\"lds-ellipsis\">\n" + let div = document.createElement("div");
" <div></div><div></div><div></div><div></div>\n" + div.innerHTML = "<br><div class=\"lds-ellipsis\">\n" +
"</div>";*/ // todo " <div></div><div></div><div></div><div></div>\n" +
"</div>";
this._elements.push(div);
}
/*if (this._leftCentered) { /*if (this._leftCentered) {
this._content += "</div>"; this._content += "</div>";
@ -121,7 +124,7 @@ export class Modal {
} }
public close() : void { public close(): void {
Modal.close(this._id); Modal.close(this._id);
} }

View File

@ -7,6 +7,7 @@ import {WebSocketEvent} from "../WebSocketEvent";
import {WebWebSocketHandler} from "./WebWebSocketHandler"; import {WebWebSocketHandler} from "./WebWebSocketHandler";
import {IContainer} from "../database/IContainer"; import {IContainer} from "../database/IContainer";
import {SensorType} from "../SensorType"; import {SensorType} from "../SensorType";
import {RequestType} from "../RequestType";
export class Setup { export class Setup {
@ -200,7 +201,6 @@ Während der Einmessung müssen die Behälter einmal geleert und gefüllt werden
let ul; let ul;
tareModal.addButton(ButtonType.PRIMARY, "Starten", async () => { tareModal.addButton(ButtonType.PRIMARY, "Starten", async () => {
tareModal.close(); tareModal.close();
let payload = new WebSocketPayload(WebSocketEvent.TARE, false, {state: true});
let modal = new Modal("tare", "Einmessung"); let modal = new Modal("tare", "Einmessung");
@ -213,6 +213,8 @@ Die Gewichtssensoren werden beim Bestätigen austariert<br><br>Zum fortfahren Ta
ul = document.createElement("ul"); ul = document.createElement("ul");
modal.addContent(ul); modal.addContent(ul);
let tareInterval: NodeJS.Timer;
let btn = document.createElement("button"); let btn = document.createElement("button");
btn.classList.add("btn", "btn-primary"); btn.classList.add("btn", "btn-primary");
btn.innerText = "Tarieren"; btn.innerText = "Tarieren";
@ -227,30 +229,35 @@ Die Gewichtssensoren werden beim Bestätigen austariert.<br><br>Zum fortfahren T
btn.onclick = () => { btn.onclick = () => {
let payload = new WebSocketPayload(WebSocketEvent.TARE, false, {tare: 1}); let payload = new WebSocketPayload(WebSocketEvent.TARE, false, {tare: 1});
WebWebSocketHandler.send(payload); WebWebSocketHandler.send(payload);
btn.onclick = () => modal.close();
btn.onclick = () => {
modal.close();
clearInterval(tareInterval);
};
}; };
}; };
modal.addContent(btn); modal.addContent(btn);
await modal.open(); await modal.open();
await WebWebSocketHandler.send(payload);
tareInterval = setInterval(() => WebWebSocketHandler.request(RequestType.CONTAINERS).then((payload) => {
if (!ul) return;
ul.innerHTML = "";
let containers = payload.data as IContainer[];
for (let c of containers) {
if (c.sensorType == SensorType.NONE) continue;
let li = document.createElement("li");
li.innerText = `Behälter ${c.slot}: ${c.rawData.toFixed(3)} [${c.sensorType}]`;
ul.append(li);
}
}), 250);
}); });
tareModal.open(); tareModal.open();
WebWebSocketHandler.registerForEvent(WebSocketEvent.CONTAINERS, (payload: WebSocketPayload) => {
if (!ul) return;
ul.innerHTML = "";
let containers = payload.data as IContainer[];
for (let c of containers) {
if (c.sensorType == SensorType.NONE) continue;
let li = document.createElement("li");
li.innerText = `Behälter ${c.slot}: ${c.rawData.toFixed(3)} [${c.sensorType}]`;
ul.append(li);
}
});
} }
public static addSetupContainer() { public static addSetupContainer() {
@ -406,6 +413,41 @@ Die Gewichtssensoren werden beim Bestätigen austariert.<br><br>Zum fortfahren T
} }
public static onContainerUpdate(payload: WebSocketPayload) {
let containerDiv = document.getElementById("setupContainers") as HTMLDivElement;
containerDiv.innerHTML = "";
let containers = payload.data["content"] as IContainer[];
for (let c of containers) {
Setup.addSetupContainer();
}
let i = 0;
let list = containerDiv.getElementsByTagName("div");
for (let c of containers) {
let current = list[i] as HTMLDivElement;
let selects = current.getElementsByTagName("select");
(selects[0] as HTMLSelectElement).value = c.pumpPin.toString();
let type;
if (c.sensorType == SensorType.NONE)
type = "-1";
else if (c.sensorType == SensorType.ULTRASOUND)
type = "0";
else
type = "1";
(selects[1] as HTMLSelectElement).value = type;
(selects[2] as HTMLSelectElement).value = c.sensorPin1.toString();
(selects[3] as HTMLSelectElement).value = c.sensorPin2.toString();
(selects[4] as HTMLSelectElement).value = c.volume.toString();
let event = new Event('change', {bubbles: true});
selects[1].dispatchEvent(event);
i++;
}
}
public static checkContainers(): boolean { public static checkContainers(): boolean {
console.log("Checking containers...") console.log("Checking containers...")
let returner = true; let returner = true;

View File

@ -1,15 +1,12 @@
import {WebSocketPayload} from "../WebSocketPayload"; import {WebSocketPayload} from "../WebSocketPayload";
import {IDrink} from "../database/IDrink"; import {IDrink} from "../database/IDrink";
import {Pane} from "./Pane"; import {Pane} from "./Pane";
import {IContainer} from "../database/IContainer";
import {Setup} from "./Setup"; import {Setup} from "./Setup";
import {SensorType} from "../SensorType";
export class WebHandler { export class WebHandler {
static get currentPane(): Pane { static get currentPane(): Pane {
return this._currentPane; return this._currentPane;
} }
private static containers = [];
public static onDrinkUpdate(payload: WebSocketPayload) { public static onDrinkUpdate(payload: WebSocketPayload) {
if (!payload.data) return; if (!payload.data) return;
@ -18,6 +15,8 @@ export class WebHandler {
const main = document.getElementById("main"); const main = document.getElementById("main");
if (!main) return; if (!main) return;
console.log(drinks)
main.style.gridTemplateRows = `repeat(${Math.round(drinks.length / 3)}, calc(90%/2))`; main.style.gridTemplateRows = `repeat(${Math.round(drinks.length / 3)}, calc(90%/2))`;
main.innerHTML = ""; main.innerHTML = "";
@ -55,43 +54,7 @@ ${ingredients}`*/ //todo
// modal.open(); // modal.open();
//}; //};
//main.append(drinkEle); main.append(drinkEle);
}
}
public static onContainerUpdate(payload: WebSocketPayload) {
let containerDiv = document.getElementById("setupContainers") as HTMLDivElement;
containerDiv.innerHTML = "";
let containers = payload.data as IContainer[];
for (let c of containers) {
Setup.addSetupContainer();
}
let i = 0;
let list = containerDiv.getElementsByTagName("div");
for (let c of containers) {
let current = list[i] as HTMLDivElement;
let selects = current.getElementsByTagName("select");
(selects[0] as HTMLSelectElement).value = c.pumpPin.toString();
let type;
if (c.sensorType == SensorType.NONE)
type = "-1";
else if (c.sensorType == SensorType.ULTRASOUND)
type = "0";
else
type = "1";
(selects[1] as HTMLSelectElement).value = type;
(selects[2] as HTMLSelectElement).value = c.sensorPin1.toString();
(selects[3] as HTMLSelectElement).value = c.sensorPin2.toString();
(selects[4] as HTMLSelectElement).value = c.volume.toString();
let event = new Event('change', {bubbles: true});
selects[1].dispatchEvent(event);
i++;
} }
} }
@ -99,6 +62,7 @@ ${ingredients}`*/ //todo
private static _currentPane: Pane; private static _currentPane: Pane;
public static openPane(pane: Pane): void { public static openPane(pane: Pane): void {
const menuBtn = document.getElementById("menuBtn") as HTMLButtonElement;
let mainPanel = document.getElementById("main") as HTMLDivElement; let mainPanel = document.getElementById("main") as HTMLDivElement;
let setupPanel = document.getElementById("setup") as HTMLDivElement; let setupPanel = document.getElementById("setup") as HTMLDivElement;
let menuPanel = document.getElementById("menu") as HTMLDivElement; let menuPanel = document.getElementById("menu") as HTMLDivElement;
@ -112,6 +76,7 @@ ${ingredients}`*/ //todo
settingsPanel.classList.add("hiddenPane"); settingsPanel.classList.add("hiddenPane");
} }
switch (this._currentPane) { switch (this._currentPane) {
case Pane.MAIN: { case Pane.MAIN: {
mainPanel.classList.add("hiddenPane"); mainPanel.classList.add("hiddenPane");
@ -129,29 +94,36 @@ ${ingredients}`*/ //todo
settingsPanel.classList.add("hiddenPane"); settingsPanel.classList.add("hiddenPane");
break; break;
} }
case Pane.CONTAINERS: {
}
} }
menuBtn.innerText = "Menü";
let title = document.getElementById("title") as HTMLTitleElement; let title = document.getElementById("title") as HTMLTitleElement;
switch (pane) { switch (pane) {
case Pane.MAIN: { case Pane.MAIN: {
mainPanel.classList.remove("hiddenPane"); mainPanel.classList.remove("hiddenPane");
mainPanel.scrollTo({top: 0, behavior: "smooth"});
title.innerText = "iTender"; title.innerText = "iTender";
break; break;
} }
case Pane.MENU: { case Pane.MENU: {
menuPanel.classList.remove("hiddenPane"); menuPanel.classList.remove("hiddenPane");
title.innerText = "Menü"; title.innerText = "Menü";
menuBtn.innerText = "Start";
break; break;
} }
case Pane.SETUP: { case Pane.SETUP: {
setupPanel.classList.remove("hiddenPane"); setupPanel.classList.remove("hiddenPane");
title.innerText = "Setup"; title.innerText = "Setup";
setupPanel.scrollTo({top: 0, behavior: "smooth"});
break; break;
} }
case Pane.SETTINGS: { case Pane.SETTINGS: {
settingsPanel.classList.remove("hiddenPane"); settingsPanel.classList.remove("hiddenPane");
title.innerText = "Einstellungen"; title.innerText = "Einstellungen";
settingsPanel.scrollTo({top: 0, behavior: "smooth"})
break; break;
} }
} }

View File

@ -6,6 +6,7 @@ import {iTenderStatus} from "../iTenderStatus";
import {WebHandler} from "./WebHandler"; import {WebHandler} from "./WebHandler";
import {Setup} from "./Setup"; import {Setup} from "./Setup";
import {Pane} from "./Pane"; import {Pane} from "./Pane";
import {RequestType} from "../RequestType";
export class WebWebSocketHandler { export class WebWebSocketHandler {
private static socket: WebSocket; private static socket: WebSocket;
@ -14,12 +15,16 @@ export class WebWebSocketHandler {
private static eventRegister: { event: WebSocketEvent, fn: (payload: WebSocketPayload) => void }[] = []; private static eventRegister: { event: WebSocketEvent, fn: (payload: WebSocketPayload) => void }[] = [];
constructor() { constructor(resolver: (() => void)) {
WebWebSocketHandler.socket = new WebSocket(WebWebSocketHandler.url); WebWebSocketHandler.socket = new WebSocket(WebWebSocketHandler.url);
WebWebSocketHandler.socket.onopen = this.onOpen; WebWebSocketHandler.socket.onopen = (x) => {
resolver();
this.onOpen(x);
};
WebWebSocketHandler.socket.onclose = this.onClose; WebWebSocketHandler.socket.onclose = this.onClose;
WebWebSocketHandler.socket.onerror = this.onError; WebWebSocketHandler.socket.onerror = this.onError;
WebWebSocketHandler.socket.onmessage = this.onMessage; WebWebSocketHandler.socket.onmessage = this.onMessage;
} }
public static registerForEvent(event: WebSocketEvent, fn: (payload: WebSocketPayload) => void) { public static registerForEvent(event: WebSocketEvent, fn: (payload: WebSocketPayload) => void) {
@ -95,6 +100,7 @@ export class WebWebSocketHandler {
} }
} }
private onOpen(event) { private onOpen(event) {
console.log("[WS] Connected", event); console.log("[WS] Connected", event);
@ -171,6 +177,22 @@ export class WebWebSocketHandler {
//window.location.reload(); //window.location.reload();
} }
/**
* @return Promise<WebSocketPayload>
* @param type
*/
public static request(type: RequestType): Promise<WebSocketPayload> {
console.log("Request to " + type)
return new Promise(resolve => {
WebWebSocketHandler.registerForEvent(WebSocketEvent.RESPONSE, (payload) => {
if ((payload.data["type"] as RequestType) == type) {
resolve(payload);
}
});
WebWebSocketHandler.send(new WebSocketPayload(WebSocketEvent.REQUEST, false, {type: type}));
});
}
public static send(payload: WebSocketPayload): Promise<void> { public static send(payload: WebSocketPayload): Promise<void> {
console.log("[WS] Sending " + payload.event + " Event", payload); console.log("[WS] Sending " + payload.event + " Event", payload);
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {

View File

@ -5,13 +5,15 @@ import {Pane} from "./Pane";
import {WebSocketPayload} from "../WebSocketPayload"; import {WebSocketPayload} from "../WebSocketPayload";
import {WebSocketEvent} from "../WebSocketEvent"; import {WebSocketEvent} from "../WebSocketEvent";
import {ButtonType} from "./ButtonType"; import {ButtonType} from "./ButtonType";
import {Containers} from "./Containers";
import {Setup} from "./Setup";
import {RequestType} from "../RequestType";
const main = document.getElementById("main"); const main = document.getElementById("main");
const time = document.getElementById("right"); const time = document.getElementById("right");
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", async () => {
console.log("DOM Loaded"); console.log("DOM Loaded");
setupOnClickEvents();
WebHandler.openPane(Pane.NONE); WebHandler.openPane(Pane.NONE);
let modal = new Modal("start", "iTender"); let modal = new Modal("start", "iTender");
@ -20,7 +22,9 @@ document.addEventListener("DOMContentLoaded", () => {
modal.addContent(txt); modal.addContent(txt);
modal.loader = true; modal.loader = true;
//modal.open(); //modal.open();
connect(); await connect();
setupOnClickEvents();
setTimeout(load, 100); setTimeout(load, 100);
}); });
@ -33,10 +37,8 @@ function setupOnClickEvents() {
function doMenu() { function doMenu() {
if (WebHandler.currentPane != Pane.MENU) { if (WebHandler.currentPane != Pane.MENU) {
WebHandler.openPane(Pane.MENU); WebHandler.openPane(Pane.MENU);
menuBtn.innerText = "Start";
} else { } else {
WebHandler.openPane(Pane.MAIN); WebHandler.openPane(Pane.MAIN);
menuBtn.innerText = "Menü";
} }
} }
@ -46,7 +48,9 @@ function setupOnClickEvents() {
const menuContainersBtn = document.getElementById("menu_containers") as HTMLButtonElement; const menuContainersBtn = document.getElementById("menu_containers") as HTMLButtonElement;
const menuStatsBtn = document.getElementById("menu_stats") as HTMLButtonElement; const menuStatsBtn = document.getElementById("menu_stats") as HTMLButtonElement;
menuContainersBtn.onclick = () => WebHandler.openPane(Pane.CONTAINERS); menuContainersBtn.onclick = Containers.openMenu;
menuStatsBtn.onclick = async () => { menuStatsBtn.onclick = async () => {
let statsModal = new Modal("stats", "Statistiken"); let statsModal = new Modal("stats", "Statistiken");
@ -65,29 +69,25 @@ function setupOnClickEvents() {
statsModal.addContent(document.createElement("br")); statsModal.addContent(document.createElement("br"));
statsModal.addButton(ButtonType.PRIMARY, "Schließen", () => statsModal.close()); statsModal.addButton(ButtonType.PRIMARY, "Schließen", () => statsModal.close());
WebWebSocketHandler.registerForEvent(WebSocketEvent.REQUEST, (payload) => { WebWebSocketHandler.request(RequestType.STATS).then((payload) => {
if (payload.data["event"] == "stats") { let li = document.createElement("li");
let li = document.createElement("li"); li.innerText = "Cocktails ausgegeben: " + payload.data["content"]["drinks_finished"];
li.innerText = "Cocktails ausgegeben: " + payload.data["content"]["drinks_finished"]; list.append(li);
list.append(li);
li = document.createElement("li"); li = document.createElement("li");
li.innerText = "Häufigster Cocktail: " + payload.data["content"]["drink_most"]; li.innerText = "Häufigster Cocktail: " + payload.data["content"]["drink_most"];
list.append(li); list.append(li);
li = document.createElement("li"); li = document.createElement("li");
li.innerText = "Anzahl Ingredients: " + payload.data["content"]["count_ingredients"]; li.innerText = "Anzahl Ingredients: " + payload.data["content"]["count_ingredients"];
list.append(li); list.append(li);
li = document.createElement("li");
li.innerText = "Anzahl Cocktails: " + payload.data["content"]["count_cocktails"];
list.append(li);
li = document.createElement("li");
li.innerText = "Anzahl Cocktails: " + payload.data["content"]["count_cocktails"];
list.append(li);
}
}); });
let payload = new WebSocketPayload(WebSocketEvent.REQUEST, false, {type: "stats"});
await WebWebSocketHandler.send(payload);
await statsModal.open(); await statsModal.open();
}; };
@ -96,10 +96,12 @@ function setupOnClickEvents() {
menuSettingsBtn.onclick = () => WebHandler.openPane(Pane.SETTINGS); menuSettingsBtn.onclick = () => WebHandler.openPane(Pane.SETTINGS);
menuSetupBtn.onclick = () => { menuSetupBtn.onclick = () => {
let payload = new WebSocketPayload(WebSocketEvent.SETUP, false, true ); let payload = new WebSocketPayload(WebSocketEvent.SETUP, false, true);
WebWebSocketHandler.send(payload); WebWebSocketHandler.send(payload);
} }
WebWebSocketHandler.request(RequestType.CONTAINERS).then(Setup.onContainerUpdate);
} }
function load() { function load() {
@ -114,6 +116,9 @@ function load() {
let wsHandler; let wsHandler;
function connect() { function connect(): Promise<void> {
wsHandler = new WebWebSocketHandler(); return new Promise(resolve => {
wsHandler = new WebWebSocketHandler(resolve);
});
} }