Files
hitstar/src/server-deno/public/js/ui.js
2026-01-04 12:14:53 +01:00

269 lines
7.3 KiB
JavaScript

import {
$answerResult,
$copyRoomCode,
$createRoom,
$guessArtist,
$guessTitle,
$joinRoom,
$lobby,
$nameDisplay,
$nameLobby,
$nextBtn,
$pauseBtn,
$placeBtn,
$readyChk,
$room,
$roomCode,
$roomId,
$slotSelect,
$startGame,
$leaveRoom,
$playBtn,
$volumeSlider,
$saveName,
} from "./dom.js";
import { state } from "./state.js";
import { initAudioUI, stopAudioPlayback } from "./audio.js";
import { sendMsg } from "./ws.js";
import { showToast, wire } from "./utils.js";
export function wireUi() {
initAudioUI();
// --- Name autosave helpers
let nameDebounce;
const SAVE_DEBOUNCE_MS = 800;
// Button was removed; no state management needed.
function saveNameIfChanged(raw) {
const name = (raw || "").trim();
if (!name) return;
try {
const prev = localStorage.getItem("playerName") || "";
if (prev === name) return; // no-op
localStorage.setItem("playerName", name);
if ($nameDisplay) $nameDisplay.textContent = name;
sendMsg({ type: "set_name", name });
showToast("Name gespeichert!");
} catch {
// best-effort
}
}
// Manual save button
if ($saveName) {
wire($saveName, "click", () => {
if (nameDebounce) {
clearTimeout(nameDebounce);
nameDebounce = null;
}
const val = ($nameLobby?.value || "").trim();
if (!val) {
showToast("⚠️ Bitte gib einen Namen ein!");
return;
}
const prev = localStorage.getItem("playerName") || "";
if (prev === val) {
showToast("✓ Name bereits gespeichert!");
return;
}
saveNameIfChanged(val);
});
}
// Autosave on input with debounce
if ($nameLobby) {
wire($nameLobby, "input", () => {
if (nameDebounce) clearTimeout(nameDebounce);
const val = ($nameLobby.value || "").trim();
if (!val) return;
nameDebounce = setTimeout(() => {
saveNameIfChanged($nameLobby.value);
nameDebounce = null;
}, SAVE_DEBOUNCE_MS);
});
// Save immediately on blur
wire($nameLobby, "blur", () => {
if (nameDebounce) {
clearTimeout(nameDebounce);
nameDebounce = null;
}
const val = ($nameLobby.value || "").trim();
if (val) saveNameIfChanged(val);
});
// Save on Enter
wire($nameLobby, "keydown", (e) => {
if (e.key === "Enter") {
e.preventDefault();
if (nameDebounce) {
clearTimeout(nameDebounce);
nameDebounce = null;
}
const val = ($nameLobby.value || "").trim();
if (val) saveNameIfChanged(val);
}
});
}
// Auto-uppercase room code input for better UX
if ($roomCode) {
wire($roomCode, "input", () => {
const pos = $roomCode.selectionStart;
$roomCode.value = $roomCode.value.toUpperCase();
$roomCode.setSelectionRange(pos, pos);
});
}
wire($createRoom, "click", () => sendMsg({ type: "create_room" }));
wire($joinRoom, "click", () => {
const code = $roomCode.value.trim().toUpperCase();
if (code) sendMsg({ type: "join_room", roomId: code });
});
wire($leaveRoom, "click", () => {
sendMsg({ type: "leave_room" });
try {
localStorage.removeItem("playerId");
localStorage.removeItem("sessionId");
localStorage.removeItem("dashboardHintSeen");
localStorage.removeItem("lastRoomId");
} catch { }
stopAudioPlayback();
state.room = null;
if ($nameLobby) {
try {
const storedName = localStorage.getItem("playerName") || "";
$nameLobby.value = storedName;
} catch {
$nameLobby.value = "";
}
}
if ($nameDisplay) $nameDisplay.textContent = "";
if ($readyChk) {
try {
$readyChk.checked = false;
} catch { }
}
$lobby.classList.remove("hidden");
$room.classList.add("hidden");
});
wire($startGame, "click", () => {
// Validate playlist selection before starting
if (!state.room?.state?.playlist) {
showToast("⚠️ Bitte wähle zuerst eine Playlist aus!");
return;
}
sendMsg({ type: "start_game" });
});
wire($readyChk, "change", (e) => {
const val = !!e.target.checked;
state.pendingReady = val;
sendMsg({ type: "ready", ready: val });
});
// Playlist selection
const $playlistSelect = document.getElementById("playlistSelect");
if ($playlistSelect) {
wire($playlistSelect, "change", (e) => {
const playlistId = e.target.value;
sendMsg({ type: "select_playlist", playlist: playlistId });
});
}
// Goal/score selection
const $goalSelect = document.getElementById("goalSelect");
if ($goalSelect) {
wire($goalSelect, "change", (e) => {
const goal = parseInt(e.target.value, 10);
sendMsg({ type: "set_goal", goal });
});
}
wire($placeBtn, "click", () => {
const slot = parseInt($slotSelect.value, 10);
sendMsg({ type: "place_guess", slot });
});
wire($playBtn, "click", () => sendMsg({ type: "resume_play" }));
wire($pauseBtn, "click", () => sendMsg({ type: "pause" }));
wire($nextBtn, "click", () => sendMsg({ type: "skip_track" }));
// Volume slider is now handled in audio.js initAudioUI()
if ($copyRoomCode) {
$copyRoomCode.style.display = "inline-block";
wire($copyRoomCode, "click", () => {
if (state.room?.id) {
navigator.clipboard.writeText(state.room.id).then(() => {
$copyRoomCode.textContent = "✔️";
showToast("Code kopiert!");
setTimeout(() => {
$copyRoomCode.textContent = "📋";
}, 1200);
});
}
});
}
if ($roomId) {
wire($roomId, "click", () => {
if (state.room?.id) {
navigator.clipboard.writeText(state.room.id).then(() => {
$roomId.title = "Kopiert!";
showToast("Code kopiert!");
setTimeout(() => {
$roomId.title = "Klicken zum Kopieren";
}, 1200);
});
}
});
$roomId.style.cursor = "pointer";
}
const form = document.getElementById("answerForm");
if (form) {
form.addEventListener("submit", (e) => {
e.preventDefault();
const title = ($guessTitle?.value || "").trim();
const artist = ($guessArtist?.value || "").trim();
if (!title || !artist) {
if ($answerResult) {
$answerResult.textContent = "Bitte Titel und Künstler eingeben";
$answerResult.className = "mt-1 text-sm text-amber-600";
}
return;
}
sendMsg({ type: "submit_answer", guess: { title, artist } });
});
}
// Dashboard one-time hint
const dashboard = document.getElementById("dashboard");
const dashboardHint = document.getElementById("dashboardHint");
if (dashboard && dashboardHint) {
try {
const seen = localStorage.getItem("dashboardHintSeen");
if (!seen) {
dashboardHint.classList.remove("hidden");
const hide = () => {
dashboardHint.classList.add("hidden");
try {
localStorage.setItem("dashboardHintSeen", "1");
} catch { }
dashboard.removeEventListener("toggle", hide);
dashboard.removeEventListener("click", hide);
};
dashboard.addEventListener("toggle", hide);
dashboard.addEventListener("click", hide, { once: true });
setTimeout(() => {
if (!localStorage.getItem("dashboardHintSeen")) hide();
}, 6000);
}
} catch { }
}
}