// ==== FRONTEND app.js ==== // Service-Liste const services = [ { id: "abc", name: "Control GamePad", url: "https://tccontrol.server.schooltech.ch/" }, { id: "xyz", name: "Guacamole", url: "https://rp5guac.server.schooltech.ch/" }, { id: "sim", name: "Simulation", url: "https://tcSimulation.server.schooltech.ch/" }, { id: "video", name: "Video", url: "https://robotVideo.server.schooltech.ch/" }, { id: "homing", name: "Homing", url:"https://robotHoming.server.schooltech.ch/"}, { id: "base", name:"RobotBase", url:"https://robotBase.server.schooltech.ch/"}, { id: "ellbow", name:"RobotEllbow", url:"https://robotEllbow.server.schooltech.ch/"}, { id: "hand", name:"RobotHand", url:"https://robotHand.server.schooltech.ch/"}, { id: "driver", name:"RobotDriver", url:"https://robotdriver.server.schooltech.ch/"}, { id: "code", name:"VSCode", url:"https://robotVSCode.server.schooltech.ch/"} ]; // DOM-Elemente const iframe = document.getElementById("service-frame"); const loginModal = document.getElementById("login-modal"); const loginBtn = document.getElementById("login-btn"); const loginSubmit = document.getElementById("login-submit"); const loginMsg = document.getElementById("login-msg"); const nav = document.getElementById("services"); const estopBtn = document.getElementById("emergency-stop"); const usernameInput = document.getElementById("username"); const passwordInput = document.getElementById("password"); let loggedIn = false; let armedPollInterval = null; // =========================== // Login anzeigen // =========================== function switchToLogin() { loginBtn.textContent = "Login"; loginBtn.onclick = () => { loginModal.style.display = "block"; }; } // =========================== // Logout anzeigen // =========================== function switchToLogout() { loginBtn.textContent = "Logout"; loginBtn.onclick = async () => { try { await fetch("/api/logout", { method: "POST" }); } catch (e) { console.warn("Logout request failed:", e); } performLocalLogout(); }; } // =========================== // Lokales Logout // =========================== function performLocalLogout() { loggedIn = false; stopArmedPolling(); estopBtn.style.display = "none"; iframe.src = ""; iframe.style.display = "none"; nav.innerHTML = ""; loginModal.style.display = "block"; switchToLogin(); } // =========================== // Armed-Status prüfen // =========================== const POWER_STATUS_URL = 'https://robotdriver.server.schooltech.ch/api/power-status'; const ESTOP_URL = 'https://robotdriver.server.schooltech.ch/api/emergency-stop'; async function updateArmedStatus() { console.log('[armed-check] GET', POWER_STATUS_URL); try { const r = await fetch(POWER_STATUS_URL); if (r.ok) { const data = await r.json(); console.log('[armed-check] response:', data); estopBtn.style.display = data.armed ? "block" : "none"; } else { console.warn('[armed-check] HTTP', r.status, '– Button versteckt'); estopBtn.style.display = "none"; } } catch (e) { console.error('[armed-check] Fehler bei', POWER_STATUS_URL, '–', e.message); estopBtn.style.display = "none"; } } function startArmedPolling() { updateArmedStatus(); armedPollInterval = setInterval(updateArmedStatus, 5000); } function stopArmedPolling() { if (armedPollInterval) { clearInterval(armedPollInterval); armedPollInterval = null; } } // =========================== // Emergency Stop // =========================== estopBtn.addEventListener("click", async () => { console.log('[estop] POST', ESTOP_URL); try { const r = await fetch(ESTOP_URL, { method: 'POST' }); console.log('[estop] response HTTP', r.status); } catch (e) { console.error('[estop] Fehler bei', ESTOP_URL, '–', e.message); } }); // =========================== // Login-Logik // =========================== async function doLogin() { const user = usernameInput.value; const pass = passwordInput.value; try { const res = await fetch("/api/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ user, pass }) }); if (res.ok) { loggedIn = true; loginModal.style.display = "none"; loginMsg.textContent = ""; setupServiceButtons(); switchToLogout(); startArmedPolling(); } else { loginMsg.textContent = "Login fehlgeschlagen"; } } catch (e) { loginMsg.textContent = "Fehler: " + e.message; } } loginSubmit.onclick = doLogin; // Enter-Taste Login [usernameInput, passwordInput].forEach(input => { input.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); doLogin(); } }); }); // =========================== // Buttons erzeugen // =========================== function setupServiceButtons() { nav.innerHTML = ""; services.forEach(svc => { console.log("Service " + svc.name + " wird als Button angefuegt"); const btn = document.createElement("button"); btn.textContent = svc.name; btn.onclick = async () => { try { await fetch('/api/event', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ event: 'open', service: svc.id, url: svc.url }) }); } catch(e) { console.error('Event log failed', e); } document.querySelectorAll("nav button").forEach(b => b.classList.remove("active")); btn.classList.add("active"); openService(svc); }; nav.appendChild(btn); }); } // =========================== // Service öffnen // =========================== function openService(svc) { iframe.src = svc.url; iframe.style.display = "block"; window.scrollTo(0,0); } // =========================== // Session Status beim Laden prüfen // =========================== (async function checkStatus() { try { const r = await fetch('/api/status'); if (r.ok) { loggedIn = true; setupServiceButtons(); switchToLogout(); startArmedPolling(); } else { switchToLogin(); } } catch (e) { switchToLogin(); } })();