correciones atleta
This commit is contained in:
parent
db12eda039
commit
c0a40b82f2
|
@ -1,64 +1,65 @@
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
const atletaId = sessionStorage.getItem("userId");
|
const atletaId = sessionStorage.getItem("userId");
|
||||||
|
const contenedor = document.getElementById("rutinas-list");
|
||||||
|
|
||||||
if (!atletaId) {
|
if (!atletaId) {
|
||||||
document.getElementById("rutinas-list").innerHTML =
|
contenedor.innerHTML = "<p>No se encontró tu sesión. Inicia sesión nuevamente.</p>";
|
||||||
"<p>No se encontró tu sesión. Inicia sesión nuevamente.</p>";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(`/api/rutinas/atleta/${atletaId}`)
|
try {
|
||||||
.then(res => {
|
const res = await fetch(`/api/rutinas/atleta/${atletaId}/formaciones`);
|
||||||
if (!res.ok) {
|
if (!res.ok) throw new Error("Error al obtener formaciones del atleta");
|
||||||
throw new Error("Error al obtener rutinas");
|
|
||||||
}
|
const formaciones = await res.json();
|
||||||
return res.json();
|
if (formaciones.length === 0) {
|
||||||
})
|
contenedor.innerHTML = "<p>No estás asignado a ninguna formación aún.</p>";
|
||||||
.then(rutinas => {
|
return;
|
||||||
const contenedor = document.getElementById("rutinas-list");
|
}
|
||||||
if (rutinas.length === 0) {
|
|
||||||
contenedor.innerHTML = "<p>No tienes rutinas asignadas todavía.</p>";
|
formaciones.forEach(f => {
|
||||||
return;
|
const card = document.createElement("div");
|
||||||
}
|
card.className = "card text-start my-3 shadow-sm";
|
||||||
rutinas.forEach(rutina => {
|
|
||||||
const card = document.createElement("div");
|
card.innerHTML = `
|
||||||
card.className = "card my-3";
|
<div class="card-body">
|
||||||
card.innerHTML = `
|
<h5 class="card-title text-primary fw-bold">${f.rutinaNombre || "Rutina sin nombre"}</h5>
|
||||||
<div class="card-body">
|
<h6 class="card-subtitle mb-2 text-muted">Formación: ${f.nombreColoquial || "(sin nombre)"}</h6>
|
||||||
<h5 class="card-title">${rutina.title}</h5>
|
<p class="card-text small mb-1">
|
||||||
<p class="card-text">${rutina.nombreCompetencia || "Sin descripción"}</p>
|
<strong>Duración:</strong> ${f.duracion || "?"}s<br>
|
||||||
<button class="btn btn-success" onclick="verRutina('${rutina._id}')">Ver rutina</button>
|
<strong>Notas:</strong> ${f.notasTacticas || "Sin notas"}<br>
|
||||||
</div>
|
<strong>Rol:</strong> ${f.atleta.rol || "N/A"} |
|
||||||
`;
|
<strong>ID:</strong> ${f.atleta.idPersonalizado || "N/A"} |
|
||||||
contenedor.appendChild(card);
|
<strong>Figura:</strong> ${f.atleta.figura || "—"}
|
||||||
});
|
</p>
|
||||||
})
|
<button class="btn btn-sm btn-outline-success" onclick="verSimulador('${f.rutinaId}', ${f.index})">
|
||||||
.catch(err => {
|
Ver simulación
|
||||||
console.error(err);
|
</button>
|
||||||
document.getElementById("rutinas-list").innerHTML =
|
</div>
|
||||||
"<p>Error al cargar tus rutinas.</p>";
|
`;
|
||||||
|
contenedor.appendChild(card);
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("❌ Error al obtener formaciones:", err);
|
||||||
|
contenedor.innerHTML = "<p>Error al cargar tus asignaciones.</p>";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function verRutina(id) {
|
function verSimulador(rutinaId, index) {
|
||||||
window.location.href = `simulador.html?routineId=${id}`;
|
window.location.href = `simulador.html?routineId=${rutinaId}&formationIndex=${index}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
alert("Sesión cerrada");
|
alert("Sesión cerrada");
|
||||||
window.location.href = "../index.html";
|
window.location.href = "../index.html";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mostrar nombre del usuario logueado en el header
|
// Mostrar nombre de usuario
|
||||||
window.addEventListener('DOMContentLoaded', async () => {
|
window.addEventListener("DOMContentLoaded", async () => {
|
||||||
const userId = sessionStorage.getItem("userId");
|
const userId = sessionStorage.getItem("userId");
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) return;
|
||||||
alert("Sesión expirada, inicia sesión de nuevo.");
|
|
||||||
window.location.href = "index.html";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/users/${userId}`);
|
const res = await fetch(`/api/users/${userId}`);
|
||||||
|
@ -66,9 +67,8 @@ window.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
if (user?.name) {
|
if (user?.name) {
|
||||||
document.getElementById("nombreUsuarioHeader").textContent = user.name;
|
document.getElementById("nombreUsuarioHeader").textContent = user.name;
|
||||||
document.getElementById("nombreUsuarioDropdown").textContent = "Coach " + user.name;
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("❌ Error al obtener datos del usuario:", err);
|
console.error("❌ Error al obtener usuario:", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -298,15 +298,32 @@ tipoPiscinaSelect.addEventListener('change', async () => {
|
||||||
|
|
||||||
circle.on('dblclick', () => {
|
circle.on('dblclick', () => {
|
||||||
const i = formacionActual.findIndex(a => a.idPersonalizado === atleta.idPersonalizado);
|
const i = formacionActual.findIndex(a => a.idPersonalizado === atleta.idPersonalizado);
|
||||||
const html = `
|
const html = `
|
||||||
<div class="p-2" style="min-width:200px;">
|
<div class="p-2" style="min-width:200px;">
|
||||||
<h6 class="mb-1">${atleta.figura || 'Sin figura'}</h6>
|
<h6 class="mb-1">${atleta.figura || 'Sin figura'}</h6>
|
||||||
<button class="btn btn-sm btn-outline-primary w-100 mb-2" onclick="activarModoDireccion(${i})">➤ Añadir Dirección</button>
|
<button class="btn btn-sm btn-outline-primary w-100 mb-2" onclick="activarModoDireccion(${i})">➤ Añadir Dirección</button>
|
||||||
<button class="btn btn-sm btn-outline-secondary w-100" onclick="alert('Función editar aún no implementada')">✏ Editar/Eliminar</button>
|
<button class="btn btn-sm btn-outline-danger w-100 mb-2" onclick="eliminarDireccion(${i})">❌ Eliminar Dirección</button>
|
||||||
</div>
|
|
||||||
`;
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
showPopover(circle.x(), circle.y(), html);
|
showPopover(circle.x(), circle.y(), html);
|
||||||
});
|
});
|
||||||
|
window.eliminarDireccion = function(index) {
|
||||||
|
const atleta = formacionActual[index];
|
||||||
|
if (!atleta) return;
|
||||||
|
|
||||||
|
atleta.direccion = null;
|
||||||
|
|
||||||
|
const visual = atletasKonva[atleta.idPersonalizado];
|
||||||
|
if (visual?.flecha) {
|
||||||
|
visual.flecha.destroy();
|
||||||
|
visual.flecha = null;
|
||||||
|
layer.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('popoverAtleta')?.remove();
|
||||||
|
};
|
||||||
|
|
||||||
circle.on('dragend', () => {
|
circle.on('dragend', () => {
|
||||||
const newX = circle.x();
|
const newX = circle.x();
|
||||||
|
@ -644,6 +661,40 @@ formaciones.forEach((f, i) => {
|
||||||
alert('Selecciona una formación desde la línea de tiempo primero.');
|
alert('Selecciona una formación desde la línea de tiempo primero.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const btnEliminarFormacion = document.getElementById('btnEliminarFormacion');
|
||||||
|
|
||||||
|
btnEliminarFormacion.addEventListener('click', async () => {
|
||||||
|
if (indexSeleccionado === null || !formaciones[indexSeleccionado]) {
|
||||||
|
return alert('Selecciona una formación primero');
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirm = await Swal.fire({
|
||||||
|
title: '¿Eliminar formación?',
|
||||||
|
text: 'Esta acción no se puede deshacer',
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Sí, eliminar',
|
||||||
|
cancelButtonText: 'Cancelar'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirm.isConfirmed) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/rutinas/${rutinaId}/formations/${indexSeleccionado}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
Swal.fire('Eliminada', 'La formación ha sido eliminada.', 'success');
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
Swal.fire('Error', 'No se pudo eliminar la formación.', 'error');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
Swal.fire('Error', 'Ocurrió un error de red.', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
document.addEventListener("DOMContentLoaded", async () => {
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
const rutinaId = new URLSearchParams(window.location.search).get("routineId");
|
const rutinaId = new URLSearchParams(window.location.search).get("routineId");
|
||||||
if (!rutinaId) return alert("No se proporcionó ID de rutina.");
|
const formationIndex = parseInt(new URLSearchParams(window.location.search).get("formationIndex"));
|
||||||
|
|
||||||
|
if (!rutinaId || isNaN(formationIndex)) {
|
||||||
|
return alert("No se proporcionó ID de rutina o índice de formación.");
|
||||||
|
}
|
||||||
|
|
||||||
const tituloRutina = document.getElementById("tituloRutina");
|
const tituloRutina = document.getElementById("tituloRutina");
|
||||||
const tipoRutina = document.getElementById("tipoRutina");
|
const tipoRutina = document.getElementById("tipoRutina");
|
||||||
const modalidadRutina = document.getElementById("modalidadRutina");
|
const modalidadRutina = document.getElementById("modalidadRutina");
|
||||||
const audioPlayer = document.getElementById("audioPlayer");
|
const audioPlayer = document.getElementById("audioPlayer");
|
||||||
|
const playBtn = document.getElementById("playPauseBtn");
|
||||||
const timeline = document.getElementById("lineaTiempo");
|
const timeline = document.getElementById("lineaTiempo");
|
||||||
|
|
||||||
const rutina = await fetch(`/api/rutinas/${rutinaId}`).then(res => res.json());
|
const rutina = await fetch(`/api/rutinas/${rutinaId}`).then(res => res.json());
|
||||||
|
@ -14,8 +19,20 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||||
tituloRutina.textContent = rutina.title || rutina.nombreCompetencia;
|
tituloRutina.textContent = rutina.title || rutina.nombreCompetencia;
|
||||||
tipoRutina.textContent = rutina.tipoCompetencia;
|
tipoRutina.textContent = rutina.tipoCompetencia;
|
||||||
modalidadRutina.textContent = modalidad;
|
modalidadRutina.textContent = modalidad;
|
||||||
|
|
||||||
if (rutina.musicUrl) {
|
if (rutina.musicUrl) {
|
||||||
audioPlayer.src = rutina.musicUrl;
|
audioPlayer.src = rutina.musicUrl;
|
||||||
|
playBtn.onclick = () => {
|
||||||
|
if (audioPlayer.paused) {
|
||||||
|
audioPlayer.play();
|
||||||
|
playBtn.textContent = "⏸ Pausar";
|
||||||
|
} else {
|
||||||
|
audioPlayer.pause();
|
||||||
|
playBtn.textContent = "▶ Reproducir";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
playBtn.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
const piscinaWidth = rutina.piscina?.width || 850;
|
const piscinaWidth = rutina.piscina?.width || 850;
|
||||||
|
@ -41,6 +58,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||||
const divPiscina = document.getElementById("piscina");
|
const divPiscina = document.getElementById("piscina");
|
||||||
divPiscina.style.width = `${piscinaWidth}px`;
|
divPiscina.style.width = `${piscinaWidth}px`;
|
||||||
divPiscina.style.height = `${piscinaHeight}px`;
|
divPiscina.style.height = `${piscinaHeight}px`;
|
||||||
|
divPiscina.style.background = "#d4f0ff"; // Azul claro
|
||||||
document.getElementById("piscinaContainer").style.width = `${piscinaWidth + 20}px`;
|
document.getElementById("piscinaContainer").style.width = `${piscinaWidth + 20}px`;
|
||||||
|
|
||||||
function dibujarCuadricula(layer, ancho, alto, tamano = 45) {
|
function dibujarCuadricula(layer, ancho, alto, tamano = 45) {
|
||||||
|
@ -79,38 +97,38 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||||
x: atleta.x - 10,
|
x: atleta.x - 10,
|
||||||
y: atleta.y - 7,
|
y: atleta.y - 7,
|
||||||
text: atleta.idPersonalizado,
|
text: atleta.idPersonalizado,
|
||||||
fontSize: 12,
|
fontSize: 14,
|
||||||
|
fontStyle: 'bold',
|
||||||
fill: 'white'
|
fill: 'white'
|
||||||
});
|
});
|
||||||
|
|
||||||
const figuraText = new Konva.Text({
|
const figuraText = new Konva.Text({
|
||||||
x: atleta.x - 25,
|
x: atleta.x - 30,
|
||||||
y: atleta.y + 18,
|
y: atleta.y + 20,
|
||||||
text: atleta.figura || '',
|
text: atleta.figura || '',
|
||||||
fontSize: 10,
|
fontSize: 11,
|
||||||
fill: '#333',
|
fill: '#333',
|
||||||
fontStyle: 'italic'
|
fontStyle: 'italic'
|
||||||
});
|
});
|
||||||
|
|
||||||
const coordText = new Konva.Text({
|
const coordText = new Konva.Text({
|
||||||
x: atleta.x - 35,
|
x: atleta.x - 38,
|
||||||
y: atleta.y + 30,
|
y: atleta.y + 34,
|
||||||
text: `${metros.metrosX}m, ${metros.metrosY}m`,
|
text: `${metros.metrosX}m, ${metros.metrosY}m`,
|
||||||
fontSize: 9,
|
fontSize: 10,
|
||||||
fill: '#666'
|
fill: '#666'
|
||||||
});
|
});
|
||||||
|
|
||||||
layer.add(circle);
|
layer.add(circle, text, figuraText, coordText);
|
||||||
layer.add(text);
|
|
||||||
layer.add(figuraText);
|
|
||||||
layer.add(coordText);
|
|
||||||
|
|
||||||
if (atleta.direccion) {
|
if (atleta.direccion) {
|
||||||
const dir = new Konva.Line({
|
const dir = new Konva.Line({
|
||||||
points: [atleta.direccion.x1, atleta.direccion.y1, atleta.direccion.x2, atleta.direccion.y2],
|
points: [atleta.direccion.x1, atleta.direccion.y1, atleta.direccion.x2, atleta.direccion.y2],
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
dash: [4, 4]
|
dash: [4, 4],
|
||||||
|
pointerLength: 10,
|
||||||
|
pointerWidth: 10
|
||||||
});
|
});
|
||||||
layer.add(dir);
|
layer.add(dir);
|
||||||
}
|
}
|
||||||
|
@ -119,27 +137,21 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const formaciones = await fetch(`/api/rutinas/${rutinaId}/formations`).then(res => res.json());
|
const formaciones = await fetch(`/api/rutinas/${rutinaId}/formations`).then(res => res.json());
|
||||||
|
const formacion = formaciones[formationIndex];
|
||||||
|
|
||||||
if (Array.isArray(formaciones)) {
|
if (!formacion) {
|
||||||
formaciones.forEach((f, i) => {
|
alert("La formación solicitada no existe.");
|
||||||
const block = document.createElement("button");
|
return;
|
||||||
block.className = "btn btn-outline-primary btn-sm me-2 step";
|
|
||||||
block.textContent = `${f.nombreColoquial || `Formación ${i + 1}`} (${f.duracion || '?'}s)`;
|
|
||||||
block.dataset.index = i;
|
|
||||||
block.title = f.notasTacticas || '';
|
|
||||||
timeline.appendChild(block);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timeline.addEventListener("click", (e) => {
|
// Pintar solo esta formación
|
||||||
if (!e.target.classList.contains("step")) return;
|
formacion.atletas.forEach(dibujarAtleta);
|
||||||
|
|
||||||
const index = parseInt(e.target.dataset.index);
|
// Mostrar título visual
|
||||||
const formacion = formaciones[index];
|
const block = document.createElement("button");
|
||||||
if (!formacion) return;
|
block.className = "btn btn-outline-primary btn-sm me-2 step";
|
||||||
|
block.textContent = `${formacion.nombreColoquial || `Formación ${formationIndex + 1}`} (${formacion.duracion || '?'}s)`;
|
||||||
layer.destroyChildren();
|
block.dataset.index = formationIndex;
|
||||||
dibujarCuadricula(layer, stage.width(), stage.height());
|
block.title = formacion.notasTacticas || '';
|
||||||
formacion.atletas.forEach(a => dibujarAtleta(a));
|
timeline.appendChild(block);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -81,39 +81,41 @@
|
||||||
<button id="btnAgregarAtleta" class="btn btn-primary mt-auto">Añadir Atleta</button>
|
<button id="btnAgregarAtleta" class="btn btn-primary mt-auto">Añadir Atleta</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-lg-8 d-flex flex-column gap-3">
|
||||||
|
<div class="card p-4">
|
||||||
|
<h5 class="fw-semibold mb-3 text-primary">Piscina</h5>
|
||||||
|
|
||||||
<div class="col-lg-8 d-flex flex-column gap-3">
|
<div class="mb-3">
|
||||||
<div class="card p-4">
|
<label for="tipoPiscina" class="form-label">Tipo de piscina</label>
|
||||||
<h5 class="fw-semibold mb-3 text-primary">Piscina</h5>
|
<select id="tipoPiscina" class="form-select form-select-sm w-100" style="max-width: 280px;">
|
||||||
|
<option value="olimpica">Olímpica (50m x 25m)</option>
|
||||||
|
<option value="semiolimpica">Semiolímpica (25m x 12.5m)</option>
|
||||||
|
<option value="fosa">Fosa/Poza (20m x 20m)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div id="piscinaContainer" class="border rounded p-2 mb-4" style="width: 100%; height: auto;">
|
||||||
<label for="tipoPiscina" class="form-label">Tipo de piscina</label>
|
<div id="piscina"></div>
|
||||||
<select id="tipoPiscina" class="form-select form-select-sm w-100" style="max-width: 280px;">
|
</div>
|
||||||
<option value="olimpica">Olímpica (50m x 25m)</option>
|
|
||||||
<option value="semiolimpica">Semiolímpica (25m x 12.5m)</option>
|
|
||||||
<option value="fosa">Fosa/Poza (20m x 20m)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="piscinaContainer" class="border rounded p-2 mb-4" style="width: 100%; height: auto;">
|
<div class="d-flex align-items-center gap-2 flex-wrap mb-3">
|
||||||
<div id="piscina"></div>
|
<button id="btnEditarFormacion" class="btn btn-outline-secondary btn-sm">✏ Editar formación</button>
|
||||||
</div>
|
<button id="btnEliminarFormacion" class="btn btn-outline-danger btn-sm">🗑 Eliminar Formación</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-3">
|
<label class="form-label fw-semibold">Línea de Tiempo</label>
|
||||||
<button id="btnEditarFormacion" class="btn btn-outline-secondary btn-sm">Editar formación</button>
|
<div id="lineaTiempo" class="timeline-placeholder d-flex flex-wrap gap-2 mb-3"></div>
|
||||||
<div class="flex-grow-1">
|
|
||||||
<div id="waveform" style="height: 80px;"></div>
|
|
||||||
<div class="text-end">
|
|
||||||
<button id="playPauseBtn" class="btn btn-outline-primary btn-sm">Reproducir</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label class="form-label fw-semibold mt-3">Línea de Tiempo</label>
|
<!-- Reproductor abajo -->
|
||||||
<div id="lineaTiempo" class="timeline-placeholder d-flex flex-wrap gap-2"></div>
|
<div class="mb-3">
|
||||||
</div>
|
<div id="waveform" style="height: 80px;"></div>
|
||||||
|
<div class="text-end mt-2">
|
||||||
|
<button id="playPauseBtn" class="btn btn-outline-primary btn-sm">▶ Reproducir</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="card p-4 mt-4">
|
<div class="card p-4 mt-4">
|
||||||
<h5 class="fw-semibold mb-3 text-primary">Datos de Formación</h5>
|
<h5 class="fw-semibold mb-3 text-primary">Datos de Formación</h5>
|
||||||
|
|
|
@ -49,18 +49,24 @@
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
<h2 id="tituloRutina" class="text-center text-primary mb-3">Cargando rutina...</h2>
|
<h2 id="tituloRutina" class="text-center text-primary mb-3">Cargando rutina...</h2>
|
||||||
<p class="text-center"><span id="tipoRutina" class="badge bg-info"></span> | <span id="modalidadRutina" class="badge bg-secondary"></span></p>
|
<p class="text-center">
|
||||||
|
<span id="tipoRutina" class="badge bg-info"></span> |
|
||||||
|
<span id="modalidadRutina" class="badge bg-secondary"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
<audio id="audioPlayer" controls class="d-block mx-auto mb-4"></audio>
|
<audio id="audioPlayer" controls class="d-block mx-auto mb-2"></audio>
|
||||||
|
<div class="text-center">
|
||||||
|
<button id="playPauseBtn" class="btn btn-sm btn-outline-success">▶ Reproducir</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="piscinaContainer" class="mx-auto mb-4">
|
<div id="piscinaContainer" class="mx-auto mb-4">
|
||||||
<div id="piscina" class="border bg-white" style="margin: 0 auto;"></div>
|
<div id="piscina" class="border" style="margin: 0 auto; background: #d4f0ff;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-3">Línea de Tiempo</h5>
|
||||||
|
<div id="lineaTiempo" class="d-flex flex-wrap gap-2"></div>
|
||||||
|
|
||||||
<h5 class="mt-3">Línea de Tiempo</h5>
|
|
||||||
<div id="lineaTiempo" class="d-flex flex-wrap gap-2"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/konva@8.3.12/konva.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/konva@8.3.12/konva.min.js"></script>
|
||||||
|
|
|
@ -258,11 +258,97 @@ router.get('/atleta/:id', async (req, res) => {
|
||||||
const rutinas = await Routine.find({ participantes: atletaId })
|
const rutinas = await Routine.find({ participantes: atletaId })
|
||||||
.populate('participantes', 'name')
|
.populate('participantes', 'name')
|
||||||
.populate('formaciones.atletas.atletaId', 'name');
|
.populate('formaciones.atletas.atletaId', 'name');
|
||||||
res.json(rutinas);
|
|
||||||
|
// Filtrar solo rutinas donde realmente aparece en alguna formación
|
||||||
|
const filtradas = rutinas.filter(rutina =>
|
||||||
|
rutina.formaciones.some(f =>
|
||||||
|
f.atletas.some(a => a.atletaId?.toString() === atletaId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
res.json(filtradas);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
res.status(500).json({ mensaje: "Error al obtener rutinas del atleta" });
|
res.status(500).json({ mensaje: "Error al obtener rutinas del atleta" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// DELETE eliminar una formación específica por índice
|
||||||
|
router.delete('/:id/formations/:index', async (req, res) => {
|
||||||
|
const { id, index } = req.params;
|
||||||
|
|
||||||
|
if (!mongoose.Types.ObjectId.isValid(id)) {
|
||||||
|
return res.status(400).json({ message: 'ID de rutina inválido' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const i = parseInt(index);
|
||||||
|
if (isNaN(i) || i < 0) {
|
||||||
|
return res.status(400).json({ message: 'Índice de formación inválido' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rutina = await Routine.findById(id);
|
||||||
|
if (!rutina) {
|
||||||
|
return res.status(404).json({ message: 'Rutina no encontrada' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= rutina.formaciones.length) {
|
||||||
|
return res.status(400).json({ message: 'Índice fuera de rango' });
|
||||||
|
}
|
||||||
|
|
||||||
|
rutina.formaciones.splice(i, 1);
|
||||||
|
await rutina.save();
|
||||||
|
|
||||||
|
const nuevosParticipantes = new Set();
|
||||||
|
rutina.formaciones.forEach(f => {
|
||||||
|
f.atletas.forEach(a => {
|
||||||
|
if (a.atletaId) nuevosParticipantes.add(a.atletaId.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
rutina.participantes = [...nuevosParticipantes];
|
||||||
|
|
||||||
|
res.status(200).json({ message: 'Formación eliminada exitosamente' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error al eliminar formación:', error);
|
||||||
|
res.status(500).json({ message: 'Error del servidor', error });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
router.get('/atleta/:id/formaciones', async (req, res) => {
|
||||||
|
const atletaId = req.params.id;
|
||||||
|
try {
|
||||||
|
const rutinas = await Routine.find({ participantes: atletaId });
|
||||||
|
|
||||||
|
const resultado = [];
|
||||||
|
|
||||||
|
for (const rutina of rutinas) {
|
||||||
|
const formacionesAtleta = rutina.formaciones
|
||||||
|
.map((f, i) => {
|
||||||
|
const match = f.atletas.find(a => a.atletaId?.toString() === atletaId);
|
||||||
|
return match
|
||||||
|
? {
|
||||||
|
rutinaId: rutina._id,
|
||||||
|
rutinaNombre: rutina.title || rutina.nombreCompetencia,
|
||||||
|
index: i,
|
||||||
|
nombreColoquial: f.nombreColoquial,
|
||||||
|
notasTacticas: f.notasTacticas,
|
||||||
|
duracion: f.duracion,
|
||||||
|
atleta: match
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
if (formacionesAtleta.length > 0) {
|
||||||
|
resultado.push(...formacionesAtleta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(resultado);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).json({ mensaje: "Error al obtener formaciones del atleta" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
Loading…
Reference in New Issue