const traducciones = { es: { "nav.init": "Panel Atleta", logout: "Salir", role: "Atleta", "sim.title": "Cargando rutina...", "sim.play": "▶ Reproducir", "sim.pause": "⏸ Pausar", "sim.timeline": "Línea de Tiempo" }, en: { "nav.init": "Athlete Panel", logout: "Logout", role: "Athlete", "sim.title": "Loading routine...", "sim.play": "▶ Play", "sim.pause": "⏸ Pause", "sim.timeline": "Timeline" }, fr: { "nav.init": "Panneau Athlète", logout: "Se déconnecter", role: "Athlète", "sim.title": "Chargement de la routine...", "sim.play": "▶ Lecture", "sim.pause": "⏸ Pause", "sim.timeline": "Ligne du Temps" } }; let langActual = 'es'; function t(clave) { return traducciones[langActual]?.[clave] || clave; } function translateStatic() { const mapping = { 'nav.init': '[data-i18n="nav.init"]', 'logout': '[data-i18n="logout"]', 'sim.title': '#tituloRutina', 'sim.timeline': '[data-i18n="sim.timeline"]', 'sim.play': '#playPauseBtn', 'role': '[data-i18n="role"]' }; for (const [clave, selector] of Object.entries(mapping)) { const el = document.querySelector(selector); if (el) el.textContent = t(clave); } } document.getElementById('langSelector')?.addEventListener('change', async (e) => { langActual = e.target.value; translateStatic(); const userId = sessionStorage.getItem("userId"); if (userId) { await fetch(`/api/users/${userId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ language: langActual }) }); } }); document.addEventListener("DOMContentLoaded", async () => { const rutinaId = new URLSearchParams(window.location.search).get("routineId"); const formationIndex = parseInt(new URLSearchParams(window.location.search).get("formationIndex")); const userId = sessionStorage.getItem("userId"); if (userId) { try { const user = await fetch(`/api/users/${userId}`).then(res => res.json()); if (user?.language && traducciones[user.language]) { langActual = user.language; const selector = document.getElementById("langSelector"); if (selector) selector.value = langActual; } if (user?.name) { document.getElementById("nombreUsuarioHeader").textContent = user.name; } } catch (err) { console.error("❌ Error al obtener usuario:", err); } } translateStatic(); if (!rutinaId || isNaN(formationIndex)) { return alert("No se proporcionó ID de rutina o índice de formación."); } const tituloRutina = document.getElementById("tituloRutina"); const tipoRutina = document.getElementById("tipoRutina"); const modalidadRutina = document.getElementById("modalidadRutina"); const audioPlayer = document.getElementById("audioPlayer"); const playBtn = document.getElementById("playPauseBtn"); const timeline = document.getElementById("lineaTiempo"); const rutina = await fetch(`/api/rutinas/${rutinaId}`).then(res => res.json()); const modalidad = rutina.modalidad; tituloRutina.textContent = rutina.title || rutina.nombreCompetencia; tipoRutina.textContent = rutina.tipoCompetencia; modalidadRutina.textContent = modalidad; if (rutina.musicUrl) { audioPlayer.src = rutina.musicUrl; playBtn.textContent = t("sim.play"); playBtn.onclick = () => { if (audioPlayer.paused) { audioPlayer.play(); playBtn.textContent = t("sim.pause"); } else { audioPlayer.pause(); playBtn.textContent = t("sim.play"); } }; } else { playBtn.style.display = "none"; } const piscinaWidth = rutina.piscina?.width || 850; const piscinaHeight = rutina.piscina?.height || 400; const escalaX = 25 / piscinaWidth; const escalaY = 20 / piscinaHeight; function convertirAMetros(pxX, pxY) { return { metrosX: (pxX * escalaX).toFixed(2), metrosY: (pxY * escalaY).toFixed(2) }; } const stage = new Konva.Stage({ container: "piscina", width: piscinaWidth, height: piscinaHeight }); const layer = new Konva.Layer(); stage.add(layer); const divPiscina = document.getElementById("piscina"); divPiscina.style.width = `${piscinaWidth}px`; divPiscina.style.height = `${piscinaHeight}px`; divPiscina.style.background = "#d4f0ff"; document.getElementById("piscinaContainer").style.width = `${piscinaWidth + 20}px`; function dibujarCuadricula(layer, ancho, alto, tamano = 45) { for (let x = 0; x <= ancho; x += tamano) { layer.add(new Konva.Line({ points: [x, 0, x, alto], stroke: '#cceeff', strokeWidth: 1 })); } for (let y = 0; y <= alto; y += tamano) { layer.add(new Konva.Line({ points: [0, y, ancho, y], stroke: '#cceeff', strokeWidth: 1 })); } } dibujarCuadricula(layer, piscinaWidth, piscinaHeight); function dibujarAtleta(atleta) { const color = atleta.rol === 'volador' ? 'purple' : atleta.rol === 'pilar' ? 'blue' : 'red'; const metros = convertirAMetros(atleta.x, atleta.y); const circle = new Konva.Circle({ x: atleta.x, y: atleta.y, radius: 15, fill: color, stroke: 'white', strokeWidth: 2 }); const text = new Konva.Text({ x: atleta.x - 10, y: atleta.y - 7, text: atleta.idPersonalizado, fontSize: 14, fontStyle: 'bold', fill: 'white' }); const figuraText = new Konva.Text({ x: atleta.x - 30, y: atleta.y + 20, text: atleta.figura || '', fontSize: 11, fill: '#333', fontStyle: 'italic' }); const coordText = new Konva.Text({ x: atleta.x - 38, y: atleta.y + 34, text: `${metros.metrosX}m, ${metros.metrosY}m`, fontSize: 10, fill: '#666' }); layer.add(circle, text, figuraText, coordText); if (atleta.direccion) { const dir = new Konva.Line({ points: [atleta.direccion.x1, atleta.direccion.y1, atleta.direccion.x2, atleta.direccion.y2], stroke: 'black', strokeWidth: 2, dash: [4, 4] }); layer.add(dir); } layer.draw(); } const formaciones = await fetch(`/api/rutinas/${rutinaId}/formations`).then(res => res.json()); const formacion = formaciones[formationIndex]; if (!formacion) { alert("La formación solicitada no existe."); return; } formacion.atletas.forEach(dibujarAtleta); const block = document.createElement("button"); block.className = "btn btn-outline-primary btn-sm me-2 step"; block.textContent = `${formacion.nombreColoquial || `Formación ${formationIndex + 1}`} (${formacion.duracion || '?'}s)`; block.dataset.index = formationIndex; block.title = formacion.notasTacticas || ''; timeline.appendChild(block); });