summaryrefslogtreecommitdiff
path: root/frontend/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/main.js')
-rw-r--r--frontend/main.js393
1 files changed, 373 insertions, 20 deletions
diff --git a/frontend/main.js b/frontend/main.js
index 51041fe..cfacc86 100644
--- a/frontend/main.js
+++ b/frontend/main.js
@@ -1,23 +1,376 @@
-const btn = document.getElementById("notbtn")
-btn.addEventListener("click", () => requestPermission())
-function requestPermission() {
- console.log("Requesting permission...");
- OneSignal.Notifications.requestPermission();
+// --- begin, important constants
+const data = {
+ duration: 1, // will be multiplied by 30
+ machine_id: "",
}
-document.cookie = "session_key=0"
+const API_URL = "https://backend.laundryweb.altafcreator.com"
-const data = {
- duration: 2,
- block: 1,
- machine: 2,
-}
-
-//fetch("http://localhost:8000/start", {
-// credentials: "include",
-// method: "POST",
-// headers: {
-// "Content-Type": "application/json"
-// },
-// body: JSON.stringify(data)
-//});
+const PUBLIC_VAPID_KEY = "BCvVfKfWBtHKtzdakJfhYy604yTn0_FgZxy2sNtxcQm6YyC3qdzBBuCJLbVcG6pmbz_CZLa0I44Z-b5UVBbegGw"
+
+// --- REGISTER SERVICE WORKERS
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register('/sw.js', {
+ scope: '/',
+ });
+}
+
+// --- subscribe
+async function subscribe() {
+ if (!('serviceWorker' in navigator)) {
+ alert("err: no service worker");
+ return;
+ }
+
+ console.log(await Notification.requestPermission());
+
+ const registration = await navigator.serviceWorker.ready;
+
+ try {
+ const subscription = await registration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: urlBase64ToUint8Array(PUBLIC_VAPID_KEY),
+ });
+
+ console.log(subscription);
+
+ console.log("sw regis pass, write to db");
+
+ const db_reply = await fetch(`${API_URL}/notifsubscribe`, {
+ method: 'POST',
+ credentials: "include",
+ body: JSON.stringify(subscription),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+
+ console.log(db_reply)
+
+ return db_reply.ok;
+ } catch (e) {
+ console.log("ERR in regis, ", e);
+ return false;
+ }
+
+}
+
+/// copied from somewhere
+const urlBase64ToUint8Array = (base64String) => {
+ const padding = '='.repeat((4 - base64String.length % 4) % 4);
+ const base64 = (base64String + padding)
+ .replace(/\-/g, '+')
+ .replace(/_/g, '/');
+
+ const rawData = window.atob(base64);
+ const outputArray = new Uint8Array(rawData.length);
+
+ for (let i = 0; i < rawData.length; ++i) {
+ outputArray[i] = rawData.charCodeAt(i);
+ }
+ return outputArray;
+};
+
+// --- check machine status
+// returns a 2d array representing machines
+// []: root array
+// []: block
+// enum: machine status
+async function checkMachineStatus() {
+ const response = await fetch(`${API_URL}/status`, {
+ method: "POST",
+ credentials: "include",
+ });
+ return await response.json();
+}
+
+// --- timer duration
+const minField = document.getElementById("min-field");
+const decBtn = document.getElementById("decTime");
+function increaseTime() {
+ data.duration += 1;
+ minField.innerText = (30 * data.duration).toString() + " minutes";
+ decBtn.disabled = false;
+}
+
+function decreaseTime() {
+ data.duration -= 1;
+ data.duration = Math.max(data.duration, 1);
+ if (data.duration == 1) {
+ decBtn.disabled = true;
+ }
+ minField.innerText = (30 * data.duration).toString() + " minutes";
+}
+
+// --- starting a timer
+async function start() {
+ fetch(`${API_URL}/start`, {
+ credentials: "include",
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(data)
+ }).then(response => response.text())
+ .then(data => {
+ console.log(data);
+ if (data == "all good bro timer started") {
+ window.location.href = "/timer/";
+ }
+ cookieStore.delete("last_used_url");
+ });
+}
+
+// --- information loading + cookie setting (from server)
+async function information(urlParam = null) {
+ const urlCookie = await cookieStore.get("last_used_url");
+
+ const response = await fetch(`${API_URL}/info`, {
+ credentials: "include",
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({ "machine_id": urlParam ? urlParam : "" }),
+ });
+
+ const json = await response.json();
+
+ if (json["block"]) {
+ document.getElementById("logo-id").innerText = "H" + json["block"];
+ } else {
+ document.getElementById("logo-id").innerText = "H?";
+ }
+
+ return Promise.resolve(json);
+}
+
+
+// ------ page specific -----
+// wait WHY THE FUCK ARE THESE HERE THEN?
+
+// ---- machine status page
+
+const STATUS_INTERVAL = 30
+
+// --- machines visual
+async function startUpdateMachines() {
+ const urlParams = new URLSearchParams(window.location.search);
+
+ await information(urlParams.get("machine"));
+ console.log("info done")
+
+ updateMachines();
+
+ while (true) {
+ await delay(STATUS_INTERVAL * 1000);
+
+ await updateMachines();
+ }
+}
+
+async function updateMachines() {
+ // less disgusting.
+ const types = ["dryer", "washer"];
+ const ns = [1, 2];
+
+ const machineImgs = [];
+ const machineTxts = [];
+ const machineDetailImgs = [];
+ const machineDetailTitles = [];
+ const machineDetailDescs = [];
+
+ for (const n of ns) {
+ for (const t of types) {
+ machineImgs.push(document.getElementById(`${t}${n}-img`));
+ machineTxts.push(document.getElementById(`${t}${n}-span`));
+ machineDetailImgs.push(document.getElementById(`detail-${t[0]}${n}-img`));
+ machineDetailTitles.push(document.getElementById(`detail-${t[0]}${n}-title`));
+ machineDetailDescs.push(document.getElementById(`detail-${t[0]}${n}-desc`));
+ }
+ }
+
+ console.log(machineDetailImgs);
+ console.log(machineDetailTitles);
+ console.log(machineDetailDescs);
+
+ const status = await checkMachineStatus();
+ console.log(status);
+
+ for (let i = 0; i < status[0].length; i++) {
+ if (status[0][i] == "RUNNING") {
+ if ((i + 1) % 2 == 0) {
+ machineImgs[i].src = "/assets/img/washer_on.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/washer_on.png";
+ if (machineDetailImgs[0]) machineDetailDescs[i].innerHTML = "Timing might differ due to heavy load or excess suds."
+ } else {
+ machineImgs[i].src = "/assets/img/dryer_on.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/dryer_on.png";
+ if (machineDetailImgs[0]) machineDetailTitles[i].innerHTML = "Idle"
+ }
+ const now = Date.now();
+ const end = Date.parse(status[2][i]);
+ const minsLeft = Math.ceil((end - now) / 60000).toString();
+ machineTxts[i].innerHTML = minsLeft + " min(s) left";
+ if (machineDetailImgs[0]) machineDetailTitles[i].innerHTML = minsLeft + " minute(s) left"
+ } else if (status[0][i] == "OUTOFSERVICE") {
+ if ((i + 1) % 2 == 0) {
+ machineImgs[i].src = "/assets/img/washer_down.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/washer_down.png";
+ } else {
+ machineImgs[i].src = "/assets/img/dryer_down.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/dryer_down.png";
+ }
+ machineTxts[i].innerHTML = "Down"
+ if (machineDetailImgs[0]) machineDetailTitles[i].innerHTML = "Out of Service"
+ if (machineDetailImgs[0]) machineDetailDescs[i].innerHTML = "This machine is currently out of service, and is unavailable to use."
+ } else if (status[0][i] == "FINISHED") {
+ if ((i + 1) % 2 == 0) {
+ machineImgs[i].src = "/assets/img/washer_clothes.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/washer_clothes.png";
+ } else {
+ machineImgs[i].src = "/assets/img/dryer_clothes.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/dryer_clothes.png";
+ }
+ machineTxts[i].innerHTML = "Idle"
+ if (machineDetailImgs[0]) machineDetailTitles[i].innerHTML = "Idle"
+ if (machineDetailImgs[0]) machineDetailDescs[i].innerHTML = "Clothes may not be collected yet."
+ } else {
+ if ((i + 1) % 2 == 0) {
+ machineImgs[i].src = "/assets/img/washer_off.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/washer_off.png";
+ } else {
+ machineImgs[i].src = "/assets/img/dryer_off.png";
+ if (machineDetailImgs[0]) machineDetailImgs[i].src = "/assets/img/dryer_off.png";
+ }
+ if (machineDetailImgs[0]) machineDetailTitles[i].innerHTML = "Idle"
+ if (machineDetailImgs[0]) machineDetailDescs[i].innerHTML = ""
+ machineTxts[i].innerHTML = "Idle"
+ }
+ }
+
+ console.log("done");
+}
+
+// --- current timers
+async function startLoadTimers() {
+ information();
+
+ const timersData = await fetchTimers();
+
+ if (timersData[0] != 200) {
+ console.error(timersData[0].toString() + " from backend: " + timersData[1]);
+ return;
+ }
+
+ const timers = timersData[1];
+
+ const container = document.getElementById("timer-container")
+ if (timers.length > 0) container.innerHTML = '';
+
+ const textList = []
+ const progList = []
+ const startTimestamps = []
+ const endTimestamps = []
+
+ for (let i = 0; i < timers.length; i++) {
+ container.innerHTML += `
+ <div class="section-container no-pad" id="timer-${timers[i]["id"]}">
+ <h1>Timer #${(i + 1).toString()}</h1>
+ <div class="machine-container">
+ <div class="txtcol-dryer ${timers[i]["machine"] == 1 ? "machine-selected" : ""}">
+ <span>Dryer 1</span>
+ <img src="/assets/img/dryer_${timers[i]["machine"] == 1 ? "on" : "off"}.png" alt="">
+ </div>
+ <div class="txtcol-washer ${timers[i]["machine"] == 2 ? "machine-selected" : ""}">
+ <span>Washer 1</span>
+ <img src="/assets/img/washer_${timers[i]["machine"] == 2 ? "on" : "off"}.png" alt="">
+ </div>
+ <div class="txtcol-dryer ${timers[i]["machine"] == 3 ? "machine-selected" : ""}">
+ <span>Dryer 2</span>
+ <img src="/assets/img/dryer_${timers[i]["machine"] == 3 ? "on" : "off"}.png" alt="">
+ </div>
+ <div class="txtcol-washer ${timers[i]["machine"] == 4 ? "machine-selected" : ""}">
+ <span>Washer 2</span>
+ <img src="/assets/img/washer_${timers[i]["machine"] == 4 ? "on" : "off"}.png" alt="">
+ </div>
+ </div>
+ <div class="timer-container">
+ <span id="timer-txt-${i}">15:00</span>
+ <div class="prog-container">
+ <div class="prog" id="timer-prog-${i}"></div>
+ </div>
+ </div>
+ <button class="button bg-1" disabled id="timer-btn-${i}">I have collected my laundry!</button>
+ </div>
+ `
+
+ textList.push(`timer-txt-${i}`);
+ progList.push(`timer-prog-${i}`);
+ endTimestamps.push(Date.parse(timers[i]["end_time"]));
+ startTimestamps.push(Date.parse(timers[i]["start_time"]));
+ }
+
+ for (let i = 0; i < timers.length; i++) { // html rebuilds everytime innerHTML is modified
+ document.getElementById(`timer-btn-${i}`).addEventListener("click", function () {
+ finishLaundryTimer(timers[i]["id"]);
+ });
+ console.log("added!");
+ }
+
+ console.log(textList);
+ console.log(progList);
+ console.log(endTimestamps);
+ console.log(startTimestamps);
+
+ while (true) {
+ for (let i = 0; i < textList.length; i++) {
+ const text = document.getElementById(textList[i]);
+ text.innerText = "";
+ const timeRemaining = Math.max(Math.round((endTimestamps[i] - Date.now()) / 1000), 0);
+ const hours = Math.floor(timeRemaining / 3600);
+ const minutes = Math.floor(timeRemaining / 60) % 60;
+ const seconds = timeRemaining % 60;
+ if (hours > 0) text.innerText += hours.toString().padStart(2, '0') + ':';
+ text.innerText += minutes.toString().padStart(2, '0') + ':';
+ text.innerText += seconds.toString().padStart(2, '0');
+
+ const prog = document.getElementById(progList[i]);
+ const totalTime = endTimestamps[0] - startTimestamps[0];
+ prog.style.width = ((timeRemaining / (totalTime / 1000)) * 100).toString() + "%";
+
+ if (timeRemaining <= 0) {
+ document.getElementById(`timer-btn-${i}`).disabled = false;
+ }
+ }
+ await delay(1000);
+ }
+}
+
+async function fetchTimers() {
+ const response = await fetch(`${API_URL}/laundry`, {
+ method: "POST",
+ credentials: "include",
+ });
+ return [response.status, await response.json()];
+}
+
+// --- finish / collect timer / laundry
+async function finishLaundryTimer(timerId) {
+ console.log("finishing timer! w/ id "+timerId.toString());
+ const response = await fetch(`${API_URL}/finish`, {
+ method: "POST",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify({id: timerId}),
+ });
+ if (await response.text() == "laundry finished") {
+ window.location.reload();
+ }
+}
+
+const delay = (durationMs) => {
+ return new Promise(resolve => setTimeout(resolve, durationMs));
+}