import { ApiService } from "./ApiService.js"; import { DialogManager } from "./DialogManager.js"; import { throttle, createStyledElement } from "./utils.js"; export class BarControlSystem { constructor() { this.settings = {}; this.websockets = {}; this.init(); } async init() { await this.loadSettings(); this.createControlPanel(); this.renderColorPickers(); } async loadSettings() { this.settings = await ApiService.loadSettings(); } createControlPanel() { const panel = createStyledElement("div", { position: "fixed", top: "10px", right: "10px", padding: "15px", border: "2px solid #333", borderRadius: "8px", backgroundColor: "#f0f0f0", zIndex: "1000", }); panel.id = "control-panel"; const title = createStyledElement( "h3", { margin: "0 0 10px 0", fontFamily: "Arial, sans-serif", }, { textContent: "Control Panel" }, ); const buttonStyles = { padding: "8px 12px", border: "none", borderRadius: "4px", cursor: "pointer", color: "white", }; const createButton = createStyledElement( "button", { ...buttonStyles, marginRight: "10px", backgroundColor: "#4CAF50", }, { textContent: "Create New Bar" }, ); const refreshButton = createStyledElement( "button", { ...buttonStyles, backgroundColor: "#2196F3", }, { textContent: "Refresh" }, ); createButton.onclick = () => this.showCreateDialog(); refreshButton.onclick = () => this.refresh(); panel.append(title, createButton, refreshButton); document.body.appendChild(panel); } showCreateDialog() { DialogManager.showCreateDialog((barData) => this.createBar(barData)); } async createBar(barData) { if (!barData.barId) { alert("Bar ID is required"); return; } try { await ApiService.createBar(barData); console.log(`Bar created: ${barData.barId}`); await this.refresh(); } catch (error) { console.error("Failed to create bar:", error); alert(error.message || "Failed to create bar"); } } async deleteBar(barId) { if (!confirm(`Are you sure you want to delete bar ${barId}?`)) { return; } try { await ApiService.deleteBar(barId); console.log(`Bar deleted: ${barId}`); await this.refresh(); } catch (error) { console.error("Failed to delete bar:", error); alert(error.message || "Failed to delete bar"); } } async refresh() { // Close existing websockets Object.values(this.websockets).forEach((ws) => { if (ws && ws.readyState === WebSocket.OPEN) { ws.close(); } }); // Remove existing color pickers Object.keys(this.settings).forEach((barId) => { const form = document.getElementById("color_form_" + barId); if (form) { form.remove(); } }); this.websockets = {}; await this.loadSettings(); this.renderColorPickers(); } renderColorPickers() { Object.keys(this.settings).forEach((barId) => { const config = this.settings[barId]; this.createColorPicker(barId, config); }); } makeDraggable(element, barId) { let isDragging = false; let startX, startY, initialX, initialY; element.addEventListener("mousedown", (e) => { if (e.target.tagName === "BUTTON") return; isDragging = true; startX = e.clientX; startY = e.clientY; const rect = element.getBoundingClientRect(); initialX = rect.left; initialY = rect.top; element.style.cursor = "move"; e.preventDefault(); }); document.addEventListener("mousemove", (e) => { if (!isDragging) return; const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; const newX = initialX + deltaX; const newY = initialY + deltaY; element.style.left = newX + "px"; element.style.top = newY + "px"; }); document.addEventListener("mouseup", () => { if (isDragging) { const rect = element.getBoundingClientRect(); ApiService.savePosition(barId, rect.left, rect.top); element.style.cursor = "default"; } isDragging = false; }); } createColorPicker(barId, config) { const ws = new WebSocket(config["url"]); this.websockets[barId] = ws; const form = createStyledElement("form", { position: "absolute", left: config["x"] + "px", top: config["y"] + "px", padding: "10px", border: "1px solid #ccc", borderRadius: "5px", backgroundColor: "white", }); form.id = "color_form_" + barId; const label = createStyledElement( "label", { display: "block", marginBottom: "5px", fontFamily: "Arial, sans-serif", fontSize: "14px", }, { htmlFor: "color_input_" + barId, textContent: barId, }, ); const colorInput = createStyledElement( "input", {}, { type: "color", id: "color_input_" + barId, name: barId, value: config["color"], }, ); const deleteButton = createStyledElement( "button", { position: "absolute", top: "2px", right: "2px", width: "20px", height: "20px", backgroundColor: "#f44336", color: "white", border: "none", borderRadius: "50%", cursor: "pointer", fontSize: "12px", lineHeight: "1", }, { type: "button", textContent: "×", }, ); deleteButton.onclick = () => this.deleteBar(barId); const throttledColorHandler = throttle((event) => { const color = event.target.value; console.log(`Color selected for ${barId}: ${color}`); ApiService.saveColor(barId, color); if (ws.readyState === WebSocket.OPEN) { const message = { color1: color }; ws.send(JSON.stringify(message)); } else { console.warn( `WebSocket not ready for ${barId}. ReadyState: ${ws.readyState}`, ); } }, 500); colorInput.addEventListener("input", throttledColorHandler); form.append(label, colorInput, deleteButton); document.body.appendChild(form); this.makeDraggable(form, barId); } }