17 Commits

Author SHA1 Message Date
dbvictor2002 7ae1b14e6e Subir archivos a "js" 2026-09-29 13:19:26 +02:00
dbvictor2002 e64761400d Subir archivos a "css" 2026-09-29 13:18:57 +02:00
dbvictor2002 00e1c04868 Subir archivos a "controladores" 2026-09-29 13:18:33 +02:00
dbvictor2002 8e1ccc6718 Subir archivos a "/" 2026-09-29 13:18:16 +02:00
jorge 3cc0dfb122 Corregido cambiar avatar en cabecera 2026-09-28 13:29:57 +02:00
jorge 4efb831b7a Reparado inicio y registro de momento 2026-09-28 13:13:05 +02:00
jorge 22f38f924f Merge branch 'pruebasJorge' 2026-09-28 12:37:07 +02:00
jorge 01aa2643f6 Actualizando a 12:24 2026-09-28 12:23:45 +02:00
jorge 07c1f79474 Merge branch 'main' of https://git.desarrolloalcala.com/jorge/triviagmatico 2026-09-28 10:28:26 +02:00
jorge 54b6b0d67b Changes to cabecera & sala 2026-09-28 10:09:26 +02:00
profesor 57e3dfc444 grafico E-R, no afecta en nada 2026-09-28 10:04:35 +02:00
Isaac 8c7958ad96 Merge branch 'main' of https://git.desarrolloalcala.com/jorge/triviagmatico 2026-09-28 09:43:03 +02:00
Isaac bf2361ad43 crear pregunta (y select de categorias) 2026-09-28 09:42:58 +02:00
jorge 03715d621e Corregida ruta jquery en buscadorSala 2026-09-28 09:03:36 +02:00
Isaac 6da20872c6 arreglado crear sala 2026-09-28 08:50:54 +02:00
Isaac 26a46c29e8 Funcionalidad de crear Sala.
Crear ClaseEquipoxPartida.php
Modificar controladorPartida.php
2026-09-25 14:11:29 +02:00
jorge 4e345fa01d Ranking 2026-09-25 13:53:22 +02:00
21 changed files with 1664 additions and 3710 deletions
+58 -156
View File
@@ -4,200 +4,102 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Trivial - Lobby</title> <title>Trivial - Lobby</title>
<link rel="icon" type="image/svg+xml" href="img/favicon/favicon.svg"> <link rel="icon" type="image/svg+xml" href="img/favicon/favicon.svg">
<link <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet">
<link rel="stylesheet" href="css/index.css"> <link rel="stylesheet" href="css/index.css">
<link rel="stylesheet" href="css/buscadorSala.css"> <link rel="stylesheet" href="css/buscadorSala.css">
</head> </head>
<body> <body>
<?php <?php include_once("cabecera.php"); ?>
include_once("cabecera.php");
?>
<main class="container py-5"> <main class="container py-4">
<div id="contenedorCrearSala" class="text-center mb-5">
<button
type="button"
class="btn btn-play-kahoot btn-crear-sala"
data-bs-toggle="modal"
data-bs-target="#modalCrearSala">
<span>+</span>
Crear sala
</button>
<!-- Botón Volver -->
<div class="mb-4">
<a href="index.php" class="btn btn-outline-secondary d-inline-flex align-items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8"/>
</svg>
Volver al Inicio
</a>
</div> </div>
<div <!-- Botón Crear Sala -->
id="contenedorSalas" <div id="contenedorCrearSala" class="text-center mb-5">
class="row justify-content-center g-4"> <button type="button" class="btn btn-play-kahoot btn-crear-sala" data-bs-toggle="modal" data-bs-target="#modalCrearSala">
<span>+</span> Crear sala
<div </button>
id="cargandoSalas" </div>
class="col-12 text-center">
<div
class="spinner-border text-primary"
role="status">
<span class="visually-hidden">
Cargando...
</span>
<!-- Contenedor Principal de Salas -->
<div id="contenedorSalas" class="row justify-content-center g-4">
<div id="cargandoSalas" class="col-12 text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Cargando...</span>
</div> </div>
<p class="mt-3 text-muted">Cargando salas...</p>
<p class="mt-3 text-muted">
Cargando salas...
</p>
</div> </div>
</div> </div>
</main> </main>
<!-- Modal Crear Sala --> <!-- Modal Crear Sala -->
<div <div class="modal fade" id="modalCrearSala" tabindex="-1" aria-labelledby="modalCrearSalaLabel" aria-hidden="true">
class="modal fade"
id="modalCrearSala"
tabindex="-1"
aria-labelledby="modalCrearSalaLabel"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered"> <div class="modal-dialog modal-dialog-centered">
<div class="modal-content modal-kahoot"> <div class="modal-content modal-kahoot">
<div class="modal-header modal-kahoot-header"> <div class="modal-header modal-kahoot-header">
<h5 class="modal-title" id="modalCrearSalaLabel">Crear sala</h5>
<h5 <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Cerrar"></button>
class="modal-title"
id="modalCrearSalaLabel">
Crear sala
</h5>
<button
type="button"
class="btn-close btn-close-white"
data-bs-dismiss="modal"
aria-label="Cerrar">
</button>
</div> </div>
<div class="modal-body p-4"> <div class="modal-body p-4">
<div class="mb-3"> <div class="mb-3">
<label for="nombreSala" class="form-label">Nombre de la sala</label>
<label <input type="text" id="nombreSala" class="form-control input-kahoot" name="nombreSala" placeholder="Ej. Noche de Trivial" maxlength="100">
for="nombreSala"
class="form-label">
Nombre de la sala
</label>
<input
type="text"
id="nombreSala"
class="form-control input-kahoot"
name="nombreSala"
placeholder="Ej. Noche de Trivial"
maxlength="100">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="nombreEquipo1" class="form-label">Nombre del equipo 1</label>
<label <input type="text" id="nombreEquipo1" name="nombreEquipo1" class="form-control input-kahoot" placeholder="Ej. Los cerebritos" maxlength="50">
for="nombreEquipo1"
class="form-label">
Nombre del equipo 1
</label>
<input
type="text"
id="nombreEquipo1"
name="nombreEquipo1"
class="form-control input-kahoot"
placeholder="Ej. Los cerebritos"
maxlength="50">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="nombreEquipo2" class="form-label">Nombre del equipo 2</label>
<label <input type="text" id="nombreEquipo2" name="nombreEquipo2" class="form-control input-kahoot" placeholder="Ej. Los campeones" maxlength="50">
for="nombreEquipo2"
class="form-label">
Nombre del equipo 2
</label>
<input
type="text"
id="nombreEquipo2"
name="nombreEquipo2"
class="form-control input-kahoot"
placeholder="Ej. Los campeones"
maxlength="50">
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button <button type="button" class="btn btn-kahoot-login" id="btnCrearSala">Crear sala</button>
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal">
Cancelar
</button>
<button
type="button"
class="btn btn-kahoot-login"
id="btnCrearSala">
Crear sala
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!--MODAL ABANDONAR SALA -->
<!-- Modal Confirmar Abandonar Sala -->
<div class="modal fade" id="modalAbandonarSala" tabindex="-1" aria-labelledby="modalAbandonarSalaLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content modal-kahoot text-center p-3">
<div class="modal-body">
<div class="mb-3 fs-1">⚠️</div>
<h4 class="modal-title mb-2 fw-bold text-white" id="modalAbandonarSalaLabel">¿Abandonar la sala?</h4>
<p class="text-white-50">Si sales de la sala, perderás tu lugar en el equipo.</p>
</div>
<div class="modal-footer justify-content-center border-0 gap-2">
<button type="button" class="btn btn-secondary px-4 py-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="btnConfirmarAbandonar" class="btn btn-danger px-4 py-2">
Sí, salir
</button>
</div>
</div>
</div>
</div>
<script <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"> <script src="js/jquery-4.0.0.min.js"></script>
</script>
<script src="js/jquery/jquery.min.js"></script>
<script src="js/buscadorSala.js"></script> <script src="js/buscadorSala.js"></script>
</body> </body>
</html>
</html>
+10 -55
View File
@@ -1,13 +1,3 @@
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Comprobación de sesión
$isLoggedIn = isset($_SESSION['idUsuario']) && !empty($_SESSION['idUsuario']);
$username = $isLoggedIn ? $_SESSION['nombreUsuario'] : '';
?>
<!-- Bootstrap 5 CSS --> <!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- FontAwesome para iconos --> <!-- FontAwesome para iconos -->
@@ -17,7 +7,6 @@ $username = $isLoggedIn ? $_SESSION['nombreUsuario'] : '';
<link rel="stylesheet" href="css/index.css"> <link rel="stylesheet" href="css/index.css">
<script src="js/jquery-4.0.0.min.js"></script> <script src="js/jquery-4.0.0.min.js"></script>
<nav class="navbar navbar-expand-lg navbar-kahoot py-3 mb-4"> <nav class="navbar navbar-expand-lg navbar-kahoot py-3 mb-4">
<div class="container"> <div class="container">
<a class="navbar-brand" href="index.php"> <a class="navbar-brand" href="index.php">
@@ -32,44 +21,8 @@ $username = $isLoggedIn ? $_SESSION['nombreUsuario'] : '';
<div class="collapse navbar-collapse" id="navbarContent"> <div class="collapse navbar-collapse" id="navbarContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0"></ul> <ul class="navbar-nav me-auto mb-2 mb-lg-0"></ul>
<div class="d-flex align-items-center gap-3"> <!-- Contenedor dinámico cargado por js/cabecera.js -->
<?php if ($isLoggedIn): ?> <div class="d-flex align-items-center gap-3" id="contenedorUsuarioCabecera">
<!-- Menú desplegable cuando la sesión está iniciada -->
<div class="dropdown">
<button class="btn user-dropdown-btn dropdown-toggle d-flex align-items-center gap-2"
type="button"
id="userDropdown"
data-bs-toggle="dropdown"
aria-expanded="false">
<i class="fa-solid fa-circle-user fa-lg text-warning"></i>
<span><?= htmlspecialchars($username) ?></span>
</button>
<ul class="dropdown-menu dropdown-menu-end user-dropdown-menu" aria-labelledby="userDropdown">
<li>
<a class="dropdown-item d-flex align-items-center gap-2" href="perfil.php">
<i class="fa-solid fa-user text-primary"></i> Perfil
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item logout-item d-flex align-items-center gap-2" href="#" id="botonCerrarSesion">
<i class="fa-solid fa-right-from-bracket"></i> Cerrar Sesión
</a>
</li>
</ul>
</div>
<?php else: ?>
<!-- Botones que abren los modales cuando NO hay sesión iniciada -->
<button type="button" class="btn btn-kahoot-login rounded-pill px-4" data-bs-toggle="modal" data-bs-target="#modalLogin">
<i class="fa-solid fa-right-to-bracket me-1"></i> Iniciar Sesión
</button>
<button type="button" class="btn btn-kahoot-register rounded-pill px-4" data-bs-toggle="modal" data-bs-target="#modalRegistro">
<i class="fa-solid fa-user-plus me-1"></i> Registrarse
</button>
<?php endif; ?>
</div> </div>
</div> </div>
</div> </div>
@@ -95,11 +48,6 @@ $username = $isLoggedIn ? $_SESSION['nombreUsuario'] : '';
<input type="password" class="form-control border-dark" id="loginPassword" name="contrasena" placeholder="Contraseña" required> <input type="password" class="form-control border-dark" id="loginPassword" name="contrasena" placeholder="Contraseña" required>
<label for="loginPassword">Contraseña</label> <label for="loginPassword">Contraseña</label>
</div> </div>
<div class="form-check">
<input class="form-check-input" id="recordar" name="recordar" type="checkbox" />
<label for="recordar" class="small">Recuérdeme durante 10 días</label>
</div>
<input type="hidden" name="orden" value="validar">
</form> </form>
<div id="errorLogin" class="text-danger fw-bold mt-2"></div> <div id="errorLogin" class="text-danger fw-bold mt-2"></div>
</div> </div>
@@ -139,7 +87,14 @@ $username = $isLoggedIn ? $_SESSION['nombreUsuario'] : '';
<input type="password" class="form-control border-dark" id="regPasswordConfirm" name="contrasenaConfirm" placeholder="Confirmar contraseña" required> <input type="password" class="form-control border-dark" id="regPasswordConfirm" name="contrasenaConfirm" placeholder="Confirmar contraseña" required>
<label for="regPasswordConfirm">Confirmar contraseña</label> <label for="regPasswordConfirm">Confirmar contraseña</label>
</div> </div>
<input type="hidden" name="orden" value="registrar">
<!-- Checkbox Recuérdame -->
<div class="form-check mb-3">
<input class="form-check-input border-dark" type="checkbox" value="" id="recuerdameCheck">
<label class="form-check-label fw-semibold" for="recuerdameCheck">
Recuérdame en 10 días
</label>
</div>
</form> </form>
<div id="errorRegistro" class="text-danger fw-bold mt-2"></div> <div id="errorRegistro" class="text-danger fw-bold mt-2"></div>
</div> </div>
+26
View File
@@ -118,4 +118,30 @@ class EquipoxUsuario
} }
} }
public static function salirDeSala($idUsuario)
{
$conexion = conexionBD();
if (is_array($conexion)) {
return $conexion;
}
try {
$sql = "DELETE FROM equipoxusuario WHERE idUsuario = :idUsuario";
$consulta = $conexion->prepare($sql);
$consulta->bindParam(':idUsuario', $idUsuario, PDO::PARAM_INT);
$consulta->execute();
return [
'exito' => true,
'mensaje' => 'Usuario eliminado de la sala correctamente.'
];
} catch (PDOException $error) {
return [
'error' => 'Ocurrió un error al salir de la sala.',
'error_tecnico' => $error->getMessage()
];
}
}
} }
+33
View File
@@ -383,4 +383,37 @@ class Usuario
]; ];
} }
} }
public static function obtenerRanking($limite = 10) {
try {
$conexion = conexionBD();
if (is_array($conexion)) {
return [];
}
$sql = "SELECT
idUsuario,
nombreUsuario,
avatar,
aciertos,
victorias,
derrotas,
CASE
WHEN (victorias + derrotas) > 0
THEN ROUND((victorias / (victorias + derrotas)) * 100, 0)
ELSE 0
END AS porcentajeVictoria
FROM usuario
ORDER BY victorias DESC, aciertos DESC
LIMIT " . (int)$limite;
$stmt = $conexion->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
return [];
}
}
} }
@@ -75,4 +75,16 @@ switch ($_POST['orden']) {
break; break;
case 'salirDeSala':
if (!isset($_SESSION['idUsuario'])) {
echo json_encode(['error' => 'Usuario no autenticado']);
exit;
}
$idUsuario = $_SESSION['idUsuario'];
$respuesta = EquipoxUsuario::salirDeSala($idUsuario);
echo json_encode($respuesta);
break;
} }
+106 -6
View File
@@ -3,6 +3,7 @@
session_start(); session_start();
require_once '../clases/ClasePregunta.php'; require_once '../clases/ClasePregunta.php';
require_once '../clases/ClaseRespuesta.php';
switch ($_POST['orden']) { switch ($_POST['orden']) {
@@ -11,18 +12,118 @@ switch ($_POST['orden']) {
$idCategoria = intval($_POST['idCategoria'] ?? 0); $idCategoria = intval($_POST['idCategoria'] ?? 0);
$nombrePregunta = trim($_POST['nombrePregunta'] ?? ''); $nombrePregunta = trim($_POST['nombrePregunta'] ?? '');
if ($idCategoria <= 0 || $nombrePregunta == '') { $respuestaCorrecta = trim($_POST['respuestaCorrecta'] ?? '');
echo json_encode(['error' => 'La categoría y el texto de la pregunta son obligatorios']); $respuestaIncorrecta1 = trim($_POST['respuestaIncorrecta1'] ?? '');
$respuestaIncorrecta2 = trim($_POST['respuestaIncorrecta2'] ?? '');
$respuestaIncorrecta3 = trim($_POST['respuestaIncorrecta3'] ?? '');
// Comprobamos los datos
if (
$idCategoria <= 0 ||
$nombrePregunta === '' ||
$respuestaCorrecta === '' ||
$respuestaIncorrecta1 === '' ||
$respuestaIncorrecta2 === '' ||
$respuestaIncorrecta3 === ''
) {
echo json_encode([
'error' => 'La categoría, la pregunta y todas las respuestas son obligatorias.'
]);
break; break;
} }
$pregunta = new Pregunta($idCategoria, $nombrePregunta);
$resultado = $pregunta->guardar();
echo json_encode($resultado); /*
* ==========================================
* 1. CREAMOS LA PREGUNTA
* ==========================================
*/
$pregunta = new Pregunta(
$idCategoria,
$nombrePregunta
);
$resultadoPregunta = $pregunta->guardar();
if (isset($resultadoPregunta['error'])) {
echo json_encode($resultadoPregunta);
break;
}
// Obtenemos el ID de la pregunta creada
$idPregunta = (int)$resultadoPregunta['exito_tecnico'];
/*
* ==========================================
* 2. CREAMOS LAS RESPUESTAS
* ==========================================
*/
$respuestas = [
[
'texto' => $respuestaCorrecta,
'correcta' => 1
],
[
'texto' => $respuestaIncorrecta1,
'correcta' => 0
],
[
'texto' => $respuestaIncorrecta2,
'correcta' => 0
],
[
'texto' => $respuestaIncorrecta3,
'correcta' => 0
]
];
foreach ($respuestas as $respuesta) {
$objRespuesta = new Respuesta(
null,
$idPregunta,
$respuesta['texto'],
$respuesta['correcta']
);
$resultadoRespuesta = $objRespuesta->insertar();
if (isset($resultadoRespuesta['error'])) {
echo json_encode($resultadoRespuesta);
break 2;
}
}
/*
* ==========================================
* 3. TODO CORRECTO
* ==========================================
*/
echo json_encode([
'exito' => 'Pregunta creada correctamente.',
'idPregunta' => $idPregunta
]);
break; break;
case 'obtenerPreguntasPorCategoria': case 'obtenerPreguntasPorCategoria':
$idCategoria = intval($_POST['idCategoria'] ?? 0); $idCategoria = intval($_POST['idCategoria'] ?? 0);
@@ -49,5 +150,4 @@ switch ($_POST['orden']) {
echo json_encode($listado); echo json_encode($listado);
break; break;
} }
+166
View File
@@ -0,0 +1,166 @@
<?php
session_start();
require_once $_SERVER['DOCUMENT_ROOT'] . '/triviagmatico/includes/conexionBD.php';
header('Content-Type: application/json; charset=utf-8');
if (!isset($_SESSION['idUsuario'])) {
echo json_encode(['error' => 'Sesión no iniciada']);
exit;
}
$idPartida = intval($_POST['idPartida'] ?? 0);
$orden = $_POST['orden'] ?? '';
if ($idPartida <= 0) {
echo json_encode(['error' => 'Partida no válida']);
exit;
}
$conexion = conexionBD();
if (is_array($conexion)) {
echo json_encode($conexion);
exit;
}
switch ($orden) {
case 'comprobarEstado':
try {
// Contar jugadores totales apuntados en los equipos de esta partida
$stmt = $conexion->prepare("
SELECT COUNT(exu.idUsuario) AS total_jugadores
FROM equipoxpartida exp
INNER JOIN equipoxusuario exu ON exp.idEquipo = exu.idEquipo
WHERE exp.idPartida = :idPartida
");
$stmt->execute([':idPartida' => $idPartida]);
$totalJugadores = (int)$stmt->fetchColumn();
$preguntasTotalesEsperadas = $totalJugadores * 10;
// Contar respuestas dadas en la partida
$stmtRespuestas = $conexion->prepare("
SELECT COUNT(*)
FROM respuestaalmacenada ra
INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta
WHERE pxp.idPartida = :idPartida
");
$stmtRespuestas->execute([':idPartida' => $idPartida]);
$respuestasRespondidas = (int)$stmtRespuestas->fetchColumn();
$terminada = ($respuestasRespondidas >= $preguntasTotalesEsperadas && $preguntasTotalesEsperadas > 0);
// Cuando la partida finaliza, se actualizan los históricos
if ($terminada && !isset($_SESSION['partidas_procesadas'][$idPartida])) {
$conexion->beginTransaction();
// CÁLCULO DE VELOCIDAD PREGUNTA A PREGUNTA EN SESIÓN
if (!isset($_SESSION['primeros_en_acertar'][$idPartida])) {
$_SESSION['primeros_en_acertar'][$idPartida] = [];
}
// Vemos quién fue el primero
$stmtVelocidad = $conexion->prepare("
SELECT ra.idPartidaxPregunta, ra.idUsuario
FROM respuestaalmacenada ra
INNER JOIN respuesta r ON ra.idRespuesta = r.idRespuesta
INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta
WHERE pxp.idPartida = :idPartida AND r.correcta = 1
ORDER BY ra.idRespuestaAlmacenada ASC
");
$stmtVelocidad->execute([':idPartida' => $idPartida]);
$todosLosAciertos = $stmtVelocidad->fetchAll(PDO::FETCH_ASSOC);
foreach ($todosLosAciertos as $acierto) {
$idPxp = $acierto['idPartidaxPregunta'];
$idU = $acierto['idUsuario'];
if (!isset($_SESSION['primeros_en_acertar'][$idPartida][$idPxp])) {
$_SESSION['primeros_en_acertar'][$idPartida][$idPxp] = $idU;
}
}
// Actualizamos la base de datos
// Buscamos los aciertos de cada jugador en la partida actual
$stmtAciertos = $conexion->prepare("
SELECT ra.idUsuario, exu.idEquipo, COUNT(*) as aciertos_partida
FROM respuestaalmacenada ra
INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta
INNER JOIN respuesta r ON ra.idRespuesta = r.idRespuesta
INNER JOIN equipoxusuario exu ON ra.idUsuario = exu.idUsuario
WHERE pxp.idPartida = :idPartida AND r.correcta = 1
GROUP BY ra.idUsuario
");
$stmtAciertos->execute([':idPartida' => $idPartida]);
$jugadoresPartida = $stmtAciertos->fetchAll(PDO::FETCH_ASSOC);
$updateAciertosGlobales = $conexion->prepare("
UPDATE usuario
SET aciertos = aciertos + :nuevos_aciertos
WHERE idUsuario = :idUsuario
");
$puntosEquipos = [];
foreach ($jugadoresPartida as $jp) {
$idU = (int)$jp['idUsuario'];
$idE = (int)$jp['idEquipo'];
$nuevosAciertos = (int)$jp['aciertos_partida'];
// Sumamos los aciertos al perfil del usuario
$updateAciertos->execute([
':nuevos_aciertos' => $nuevosAciertos,
':idUsuario' => $idU
]);
if (!isset($puntosEquipos[$idE])) {
$puntosEquipos[$idE] = 0;
}
$puntosEquipos[$idE] += $nuevosAciertos;
}
// Determinamos qué equipo ha obtenido más aciertos en la partida
arsort($puntosEquipos);
$idEquipoGanador = key($puntosEquipos);
// Obtenemos todos los usuarios de la partida para asignar victorias/derrotas
$stmtMiembros = $conexion->prepare("
SELECT exu.idUsuario, exu.idEquipo
FROM equipoxpartida exp
INNER JOIN equipoxusuario exu ON exp.idEquipo = exu.idEquipo
WHERE exp.idPartida = :idPartida
");
$stmtMiembros->execute([':idPartida' => $idPartida]);
$todosLosMiembros = $stmtMiembros->fetchAll(PDO::FETCH_ASSOC);
$updateVictoria = $conexion->prepare("UPDATE usuario SET victorias = victorias + 1 WHERE idUsuario = :idUsuario");
$updateDerrota = $conexion->prepare("UPDATE usuario SET derrotas = derrotas + 1 WHERE idUsuario = :idUsuario");
foreach ($todosLosMiembros as $miembro) {
$idU = (int)$miembro['idUsuario'];
$idE = (int)$miembro['idEquipo'];
if ($idE === $idEquipoGanador) {
$updateVictoria->execute([':idUsuario' => $idU]);
} else {
$updateDerrota->execute([':idUsuario' => $idU]);
}
}
$conexion->commit();
$_SESSION['partidas_procesadas'][$idPartida] = true;
}
echo json_encode(['terminada' => $terminada]);
} catch (PDOException $e) {
if ($conexion->inTransaction()) {
$conexion->rollBack();
}
echo json_encode(['error' => $e->getMessage()]);
}
break;
default:
echo json_encode(['error' => 'Acción no permitida']);
break;
}
+32 -2
View File
@@ -47,7 +47,7 @@ switch ($_POST['orden']) {
case 'comprobarUsuario': case 'comprobarUsuario':
$email = trim($_POST['email'] ?? ''); $email = trim($_POST['email'] ?? '');
$contrasena = $_POST['contrasena'] ?? ''; $contrasena = $_POST['contrasena'] ?? '';
@@ -55,6 +55,13 @@ switch ($_POST['orden']) {
if ($resultado instanceof Usuario) { if ($resultado instanceof Usuario) {
// === GUARDAR EN SESIÓN (incluido avatar)===
$_SESSION['idUsuario'] = $resultado->getIdUsuario();
$_SESSION['nombreUsuario'] = $resultado->getNombreUsuario();
$_SESSION['email'] = $resultado->getEmail();
$_SESSION['avatar'] = $resultado->getAvatar();
// =================================================
echo json_encode([ echo json_encode([
'exito' => 'Login correcto', 'exito' => 'Login correcto',
'idUsuario' => $resultado->getIdUsuario(), 'idUsuario' => $resultado->getIdUsuario(),
@@ -77,6 +84,7 @@ switch ($_POST['orden']) {
unset($_SESSION['idUsuario']); unset($_SESSION['idUsuario']);
unset($_SESSION['email']); unset($_SESSION['email']);
unset($_SESSION['nombreUsuario']); unset($_SESSION['nombreUsuario']);
unset($_SESSION['avatar']);
// Destruimos la sesión // Destruimos la sesión
session_destroy(); session_destroy();
@@ -86,7 +94,6 @@ switch ($_POST['orden']) {
]); ]);
break; break;
case 'mostrarEstadisticas': case 'mostrarEstadisticas':
$usuario = Usuario::buscarPorId($_SESSION['idUsuario']); $usuario = Usuario::buscarPorId($_SESSION['idUsuario']);
@@ -221,4 +228,27 @@ switch ($_POST['orden']) {
} }
break; break;
case 'obtenerRanking':
$ranking = Usuario::obtenerRanking(5); //Cambiar para mostrar X jugadores en index
echo json_encode([
'exito' => true,
'ranking' => $ranking
]);
break;
case 'comprobarSesion':
if (isset($_SESSION['idUsuario']) && !empty($_SESSION['idUsuario'])) {
echo json_encode([
'activa' => true,
'usuario' => [
'idUsuario' => $_SESSION['idUsuario'],
'nombreUsuario' => $_SESSION['nombreUsuario'] ?? '',
'avatar' => $_SESSION['avatar'] ?? ''
]
]);
} else {
echo json_encode(['activa' => false]);
}
break;
} }
+179
View File
@@ -0,0 +1,179 @@
/* ==========================================================================
ESTILOS GENERALES Y FONDO
========================================================================== */
* {
margin: 0;
padding: 0;
box-shadow: none;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background-color: #f0f4f8;
color: #2c3e50;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
/* Contenedor principal estilo tarjeta */
.contenedor {
width: 100%;
max-width: 900px;
background: #ffffff;
padding: 40px;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
text-align: center;
animation: fadeIn 0.5s ease-in-out;
}
h1 {
font-size: 2.5rem;
color: #1a365d;
margin-bottom: 30px;
}
h2 {
font-size: 1.6rem;
color: #2b6cb0;
margin-top: 30px;
margin-bottom: 15px;
text-align: left;
border-bottom: 2px solid #e2e8f0;
padding-bottom: 8px;
}
p {
font-size: 1.1rem;
color: #718096;
margin-bottom: 30px;
}
/* ==========================================================================
PANTALLA DE ESPERA Y ANIMACIÓN DE CARGA (LOADER)
========================================================================== */
#pantalla-espera {
padding: 60px 20px;
}
.loader {
width: 60px;
height: 60px;
border: 6px solid #e2e8f0;
border-top: 6px solid #3182ce;
border-radius: 50%;
margin: 0 auto;
animation: spin 1.2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* ==========================================================================
TABLAS DE CLASIFICACIÓN (RANKING)
========================================================================== */
.tabla-ranking {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
font-size: 1.05rem;
}
.tabla-ranking th,
.tabla-ranking td {
padding: 16px 20px;
text-align: left;
}
.tabla-ranking th {
background-color: #2d3748;
color: #ffffff;
font-weight: 600;
text-transform: uppercase;
font-size: 0.9rem;
letter-spacing: 0.5px;
}
/* Alinear los puntos y aciertos a la derecha para mejor lectura numérica */
.tabla-ranking th:last-child,
.tabla-ranking td:last-child {
text-align: right;
}
.tabla-ranking tr {
border-bottom: 1px solid #e2e8f0;
transition: background-color 0.2s;
}
.tabla-ranking tbody tr:hover {
background-color: #f7fafc;
}
/* ==========================================================================
RESALTADO DE GANADORES (1º PUESTO)
========================================================================== */
/* Fila del Equipo Ganador y Jugador Ganador */
.tabla-ranking tr.top-team,
.tabla-ranking tr.top-player {
background-color: #fefcbf !important; /* Amarillo suave */
font-weight: bold;
}
/* Cambiar el color del texto del puesto #1 a dorado/corona */
.tabla-ranking tr.top-team td:first-child,
.tabla-ranking tr.top-player td:first-child {
color: #b7791f;
font-size: 1.2rem;
}
.tabla-ranking td strong {
color: #2f855a; /* Verde para destacar los aciertos conseguidos */
font-size: 1.1rem;
}
/* ==========================================================================
EFECTOS VISUALES SUAVES
========================================================================== */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* ==========================================================================
ESTILOS DEL BOTÓN DE RETORNO A INICIO
========================================================================== */
.contenedor-boton {
margin-top: 40px;
padding-top: 20px;
text-align: center;
}
.btn-inicio {
display: inline-block;
background-color: #3182ce; /* Azul corporativo */
color: #ffffff;
padding: 14px 28px;
font-size: 1.1rem;
font-weight: 600;
text-decoration: none;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(49, 130, 206, 0.2);
transition: background-color 0.2s, transform 0.2s, box-shadow 0.2s;
}
.btn-inicio:hover {
background-color: #2b6cb0; /* Azul ligeramente más oscuro al pasar el cursor */
box-shadow: 0 6px 12px rgba(43, 108, 176, 0.3);
transform: translateY(-2px); /* Pequeño salto hacia arriba */
}
.btn-inicio:active {
transform: translateY(0); /* Vuelve a su posición normal al pulsar */
box-shadow: 0 2px 4px rgba(43, 108, 176, 0.2);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

+11 -17
View File
@@ -1,8 +1,3 @@
<?php
include 'cabecera.php';
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="es-ES"> <html lang="es-ES">
@@ -10,27 +5,26 @@ include 'cabecera.php';
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Triviagmático</title> <title>Triviagmático</title>
<script src="js/jquery-4.0.0.min.js"></script>
<link rel="icon" type="image/svg+xml" href="img/favicon/favicon.svg"> <link rel="icon" type="image/svg+xml" href="img/favicon/favicon.svg">
</head> </head>
<body> <body>
<?php include 'cabecera.php'; ?>
<div class="container my-5"> <div class="container my-5">
<div class="row justify-content-center align-items-center g-4"> <div class="row justify-content-center align-items-center g-4">
<!-- Botón Jugar (solo se muestra si está logueado) --> <!-- Botón Jugar (oculto por defecto, JS lo muestra si hay sesión activa) -->
<?php if ($isLoggedIn): ?> <div class="col-12 col-lg-5 col-xl-4 d-none" id="colBotonJugar">
<div class="col-12 col-lg-5 col-xl-4"> <a href="buscadorSala.php" class="btn btn-play-kahoot" id="btnJugar">
<a href="buscadorSala.php" class="btn btn-play-kahoot" id="btnJugar"> <i class="fa-solid fa-play"></i>
<i class="fa-solid fa-play"></i> <span>¡JUGAR!</span>
<span>¡JUGAR!</span> </a>
</a> </div>
</div>
<?php endif; ?>
<!-- Ranking --> <!-- Ranking -->
<div class="col-12 <?= $isLoggedIn ? 'col-lg-7 col-xl-8' : 'col-lg-8' ?>"> <div class="col-12 col-lg-8" id="colRanking">
<div class="card ranking-card"> <div class="card ranking-card">
<div class="ranking-header"> <div class="ranking-header">
<h3 class="m-0"><i class="fa-solid fa-trophy me-2"></i> RANKING GLOBAL DE JUGADORES</h3> <h3 class="m-0"><i class="fa-solid fa-trophy me-2"></i> RANKING GLOBAL DE JUGADORES</h3>
@@ -51,7 +45,7 @@ include 'cabecera.php';
<!-- JS de Bootstrap --> <!-- JS de Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="js/index.js"></script>
</body> </body>
</html> </html>
+291 -517
View File
@@ -1,606 +1,380 @@
let usuarioYaEstaEnEquipo = false; let usuarioYaEstaEnEquipo = false;
$(document).ready(function () { $(document).ready(function () {
comprobarSalaUsuario(); comprobarSalaUsuario();
}); });
// 1. Comprobar si el usuario actual ya pertenece a una sala
function comprobarSalaUsuario() { function comprobarSalaUsuario() {
$("#cargandoSalas").remove();
$("#cargandoSalas").remove(); $.ajax({
$.ajax({
url: "controladores/ControladorEquipoxUsuario.php", url: "controladores/ControladorEquipoxUsuario.php",
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { orden: "obtenerSalaUsuario" },
data: {
orden: "obtenerSalaUsuario"
},
success: function (respuesta) { success: function (respuesta) {
if (respuesta.error || !respuesta.asociado) {
console.log("Sala del usuario:", respuesta);
if (respuesta.error) {
console.error(respuesta.error);
usuarioYaEstaEnEquipo = false;
cargarSalas();
return;
}
if (respuesta.asociado) {
usuarioYaEstaEnEquipo = true;
$("#contenedorCrearSala").hide();
cargarSalaUsuario(respuesta.idPartida);
} else {
usuarioYaEstaEnEquipo = false;
cargarSalas();
}
},
error: function (xhr, status, error) {
console.error(
"Error al comprobar la sala del usuario:",
error
);
usuarioYaEstaEnEquipo = false; usuarioYaEstaEnEquipo = false;
$("#contenedorCrearSala").show();
cargarSalas(); cargarSalas();
} } else {
}); usuarioYaEstaEnEquipo = true;
$("#contenedorCrearSala").hide(); // Ocultar "Crear Sala" si ya pertenece a una
cargarSalaUsuario(respuesta.idPartida);
}
},
error: function (xhr, status, error) {
console.error("Error al comprobar la sala del usuario:", error);
usuarioYaEstaEnEquipo = false;
cargarSalas();
},
});
} }
// 2. Cargar únicamente la sala en la que está metido el usuario
function cargarSalaUsuario(idPartida) { function cargarSalaUsuario(idPartida) {
$.ajax({
$.ajax({
url: "controladores/controladorPartida.php", url: "controladores/controladorPartida.php",
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { orden: "buscar", idPartida: idPartida },
data: {
orden: "buscar",
idPartida: idPartida
},
success: function (partida) { success: function (partida) {
if (partida.error) {
if (partida.error) { console.error(partida.error);
return;
console.error(partida.error); }
$("#contenedorSalas").empty();
return; cargarInformacionSala(partida);
}
$("#contenedorSalas").empty();
cargarInformacionSala(partida);
}, },
error: function (xhr, status, error) { error: function (xhr, status, error) {
console.error("Error al obtener la sala del usuario:", error);
console.error( },
"Error al obtener la sala del usuario:", });
error
);
}
});
} }
// 3. Cargar la lista completa de todas las salas
function cargarSalas() { function cargarSalas() {
$.ajax({
$.ajax({
url: "controladores/controladorPartida.php", url: "controladores/controladorPartida.php",
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { orden: "listar" },
data: {
orden: "listar"
},
success: function (partidas) { success: function (partidas) {
const contenedor = $("#contenedorSalas");
contenedor.empty();
const contenedor = $("#contenedorSalas"); if (!Array.isArray(partidas) || partidas.length === 0) {
contenedor.html(`
<div class="col-12 text-center">
<p class="text-muted">No hay salas disponibles actualmente.</p>
</div>
`);
return;
}
contenedor.empty(); partidas.forEach(function (partida) {
contenedor.empty(); cargarInformacionSala(partida);
});
if (!Array.isArray(partidas) || partidas.length === 0) {
contenedor.html(`
<div class="col-12 text-center">
<p class="text-muted">
No hay salas disponibles.
</p>
</div>
`);
return;
}
partidas.forEach(function (partida) {
cargarInformacionSala(partida);
});
}, },
error: function (xhr, status, error) { error: function (xhr, status, error) {
console.error("Error al obtener las partidas:", error);
console.error( },
"Error al obtener las partidas:", });
error
);
}
});
} }
// 4. Obtener equipos y jugadores asociados a una sala concreta
function cargarInformacionSala(partida) { function cargarInformacionSala(partida) {
$.ajax({
$.ajax({
url: "controladores/controladorPartida.php", url: "controladores/controladorPartida.php",
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { orden: "getEquipos", idPartida: partida.idPartida },
data: {
orden: "getEquipos",
idPartida: partida.idPartida
},
success: function (equipos) { success: function (equipos) {
$.ajax({
$.ajax({ url: "controladores/controladorPartida.php",
url: "controladores/controladorPartida.php", type: "POST",
type: "POST", dataType: "json",
dataType: "json", data: { orden: "getJugadores", idPartida: partida.idPartida },
success: function (jugadores) {
data: { mostrarSala(partida, equipos, jugadores);
orden: "getJugadores", },
idPartida: partida.idPartida error: function (xhr, status, error) {
}, console.error("Error al obtener jugadores:", error);
},
success: function (jugadores) { });
mostrarSala(
partida,
equipos,
jugadores
);
},
error: function (xhr, status, error) {
console.error(
"Error al obtener jugadores:",
error
);
}
});
}, },
error: function (xhr, status, error) { error: function (xhr, status, error) {
console.error("Error al obtener equipos:", error);
console.error( },
"Error al obtener equipos:", });
error
);
}
});
} }
// 5. Renderizar el HTML de la sala y botones según estado
function mostrarSala(partida, equipos, jugadores) { function mostrarSala(partida, equipos, jugadores) {
const contenedor = $("#contenedorSalas");
let equiposHTML = "";
const contenedor = $("#contenedorSalas"); equipos.forEach(function (equipo) {
let equiposHTML = "";
equipos.forEach(function (equipo) {
const jugadoresEquipo = jugadores.filter(function (jugador) { const jugadoresEquipo = jugadores.filter(function (jugador) {
return jugador.idEquipo == equipo.idEquipo;
return jugador.idEquipo == equipo.idEquipo;
}); });
let jugadoresHTML = ""; let jugadoresHTML = "";
if (jugadoresEquipo.length > 0) { if (jugadoresEquipo.length > 0) {
jugadoresEquipo.forEach(function (jugador) {
jugadoresEquipo.forEach(function (jugador) { jugadoresHTML += `
<div class="jugador">
jugadoresHTML += ` <span class="avatar">👤</span>
<div class="jugador"> ${escapeHTML(jugador.nombreUsuario)}
</div>
<span class="avatar">
👤
</span>
${escapeHTML(jugador.nombreUsuario)}
</div>
`;
});
} else {
jugadoresHTML = `
<div class="text-muted small">
Sin jugadores
</div>
`; `;
});
} else {
jugadoresHTML = `<div class="text-muted small">Sin jugadores</div>`;
} }
// Botón "Unirse" solo visible si NO pertenece a ningún equipo
let botonUnirseHTML = ""; let botonUnirseHTML = "";
if (!usuarioYaEstaEnEquipo) { if (!usuarioYaEstaEnEquipo) {
botonUnirseHTML = `
botonUnirseHTML = ` <button type="button" class="btn btn-unirse w-100 btn-unirse-equipo mt-2"
<button
type="button"
class="btn btn-unirse w-100 btn-unirse-equipo"
data-id-partida="${partida.idPartida}" data-id-partida="${partida.idPartida}"
data-id-equipo="${equipo.idEquipo}"> data-id-equipo="${equipo.idEquipo}">
Unirse
Unirse </button>
`;
</button>
`;
} }
equiposHTML += ` equiposHTML += `
<div class="equipo"> <div class="equipo me-2 ms-2 p-3 border rounded">
<h6>${escapeHTML(equipo.nombreEquipo)}</h6>
<h6> <div class="jugadores mb-2">
${escapeHTML(equipo.nombreEquipo)} ${jugadoresHTML}
</h6>
<div class="jugadores">
${jugadoresHTML}
</div>
${botonUnirseHTML}
</div> </div>
${botonUnirseHTML}
</div>
`; `;
});
// Acciones disponibles si el usuario YA ESTÁ dentro de esta sala
let accionesSalaHTML = "";
if (usuarioYaEstaEnEquipo) {
accionesSalaHTML = `
<div class="sala-acciones text-center mt-4 pt-3 border-top d-flex justify-content-center gap-3">
<button type="button" class="btn btn-outline-danger btn-abandonar-sala" data-id-partida="${partida.idPartida}">
Abandonar sala
</button>
<a href="juego.php?idPartida=${partida.idPartida}" class="btn btn-success btn-lg px-4">
🎮 ¡Iniciar Partida!
</a>
</div>
`;
}
const salaHTML = `
<div class="col-12 col-md-10 col-lg-8">
<div class="sala card p-3 shadow-sm mb-4">
<div class="sala-header h4 text-center mb-3">
${escapeHTML(partida.nombrePartida)}
</div>
<div class="sala-body">
<div class="equipos d-flex justify-content-around">
${equiposHTML}
</div>
${accionesSalaHTML}
</div>
</div>
</div>
`;
contenedor.append(salaHTML);
}
// 6. Evento: Unirse a un Equipo
$(document).on("click", ".btn-unirse-equipo", function () {
const boton = $(this);
const idEquipo = boton.data("id-equipo");
const idPartida = boton.data("id-partida");
boton.prop("disabled", true).text("Uniéndose...");
$.ajax({
url: "controladores/ControladorEquipoxUsuario.php",
type: "POST",
dataType: "json",
data: {
orden: "registrarUsuarioEnEquipo",
idEquipo: idEquipo,
},
success: function (respuesta) {
if (respuesta.error) {
alert(respuesta.error);
boton.prop("disabled", false).text("Unirse");
return;
}
usuarioYaEstaEnEquipo = true;
$("#contenedorCrearSala").hide();
$("#contenedorSalas").empty();
cargarSalaUsuario(idPartida);
},
error: function (xhr, status, error) {
console.error("Error al unirse al equipo:", error);
alert("No se ha podido unir al equipo.");
boton.prop("disabled", false).text("Unirse");
},
});
}); });
// 7. Evento: Abandonar Sala
// Guardamos temporalmente el botón presionado
let botonAbandonarReferencia = null;
const salaHTML = ` // A. Al hacer clic en el botón "Abandonar sala" de la tarjeta, abrimos el modal
<div class="col-12 col-md-10 col-lg-8"> $(document).on("click", ".btn-abandonar-sala", function () {
botonAbandonarReferencia = $(this);
const modal = new bootstrap.Modal(document.getElementById('modalAbandonarSala'));
modal.show();
});
<div class="sala"> // B. Al hacer clic en "Sí, salir" dentro del modal Kahoot
$(document).on("click", "#btnConfirmarAbandonar", function () {
const modalEl = document.getElementById('modalAbandonarSala');
const modalInstance = bootstrap.Modal.getInstance(modalEl);
<div class="sala-header"> const btnConfirmar = $(this);
btnConfirmar.prop("disabled", true).text("Saliendo...");
${escapeHTML(partida.nombrePartida)} $.ajax({
url: "controladores/ControladorEquipoxUsuario.php",
type: "POST",
dataType: "json",
data: { orden: "salirDeSala" },
success: function (respuesta) {
btnConfirmar.prop("disabled", false).text("Sí, salir");
if (modalInstance) {
modalInstance.hide();
}
</div> if (respuesta.error) {
alert(respuesta.error);
return;
}
<div class="sala-body"> // Restablecemos la interfaz a la lista completa de salas
usuarioYaEstaEnEquipo = false;
$("#contenedorCrearSala").show();
cargarSalas();
},
error: function (xhr, status, error) {
console.error("Error al salir de la sala:", error);
alert("No se pudo salir de la sala.");
btnConfirmar.prop("disabled", false).text("Sí, salir");
if (modalInstance) {
modalInstance.hide();
}
}
});
});
// 8. Evento: Crear Sala
$("#btnCrearSala").on("click", function () {
const nombreSala = $("#nombreSala").val().trim();
const nombreEquipo1 = $("#nombreEquipo1").val().trim();
const nombreEquipo2 = $("#nombreEquipo2").val().trim();
<div class="equipos"> let valido = true;
$(".mensaje-error-sala").remove();
$(".input-kahoot").removeClass("is-invalid");
${equiposHTML} if (nombreSala === "" || nombreSala.length < 3) {
mostrarError(
"#nombreSala",
"El nombre de la sala debe tener al menos 3 caracteres.",
);
valido = false;
}
</div> if (nombreEquipo1 === "" || nombreEquipo1.length < 2) {
mostrarError(
"#nombreEquipo1",
"El nombre del equipo debe tener al menos 2 caracteres.",
);
valido = false;
}
</div> if (nombreEquipo2 === "" || nombreEquipo2.length < 2) {
mostrarError(
"#nombreEquipo2",
"El nombre del equipo debe tener al menos 2 caracteres.",
);
valido = false;
}
</div> if (
nombreEquipo1 !== "" &&
nombreEquipo2 !== "" &&
nombreEquipo1.toLowerCase() === nombreEquipo2.toLowerCase()
) {
mostrarError(
"#nombreEquipo2",
"Los dos equipos deben tener nombres diferentes.",
);
valido = false;
}
</div> if (!valido) return;
`;
const boton = $("#btnCrearSala");
boton.prop("disabled", true).text("Creando sala...");
contenedor.append(salaHTML); $.ajax({
url: "controladores/controladorPartida.php",
type: "POST",
dataType: "json",
data: {
orden: "crear",
nombrePartida: nombreSala,
nombreEquipo1: nombreEquipo1,
nombreEquipo2: nombreEquipo2,
},
success: function (respuesta) {
if (respuesta.error) {
alert(respuesta.error);
boton.prop("disabled", false).text("Crear sala");
return;
}
if (respuesta.exito) {
$("#modalCrearSala").modal("hide");
location.reload();
}
},
error: function (xhr, status, error) {
console.error("Error al crear la sala:", error);
alert("No se ha podido crear la sala.");
boton.prop("disabled", false).text("Crear sala");
},
});
});
} // Auxiliares
// ======================================================
// UNIRSE A UN EQUIPO
// ======================================================
$(document).on(
"click",
".btn-unirse-equipo",
function () {
const boton = $(this);
const idEquipo = boton.data("id-equipo");
const idPartida = boton.data("id-partida");
boton.prop("disabled", true);
boton.text("Uniéndose...");
$.ajax({
url: "controladores/ControladorEquipoxUsuario.php",
type: "POST",
dataType: "json",
data: {
orden: "registrarUsuarioEnEquipo",
idEquipo: idEquipo
},
success: function (respuesta) {
console.log(
"Respuesta al unirse:",
respuesta
);
if (respuesta.error) {
alert(respuesta.error);
boton.prop("disabled", false);
boton.text("Unirse");
return;
}
// ==========================================
// UNIÓN CORRECTA
// ==========================================
usuarioYaEstaEnEquipo = true;
// Ocultamos el botón "Crear sala"
$("#contenedorCrearSala").hide();
// Eliminamos las salas actuales
$("#contenedorSalas").empty();
// Cargamos directamente la sala
// donde acaba de entrar el usuario
cargarSalaUsuario(idPartida);
},
error: function (xhr, status, error) {
console.error(
"Error al unirse al equipo:",
error
);
console.error(
"Respuesta del servidor:",
xhr.responseText
);
alert(
"No se ha podido unir al equipo."
);
boton.prop("disabled", false);
boton.text("Unirse");
}
});
}
);
// ======================================================
// ESCAPAR HTML
// ======================================================
function escapeHTML(texto) { function escapeHTML(texto) {
return $("<div>")
return $("<div>")
.text(texto ?? "") .text(texto ?? "")
.html(); .html();
} }
// ======================================================
// CREAR SALA
// ======================================================
$("#btnCrearSala").on(
"click",
function () {
const nombreSala =
$("#nombreSala").val().trim();
const nombreEquipo1 =
$("#nombreEquipo1").val().trim();
const nombreEquipo2 =
$("#nombreEquipo2").val().trim();
let valido = true;
let valido = true;
$(".mensaje-error-sala").remove();
$(".input-kahoot").removeClass(
"is-invalid"
);
if (nombreSala === "") {
mostrarError(
"#nombreSala",
"El nombre de la sala es obligatorio."
);
valido = false;
} else if (nombreSala.length < 3) {
mostrarError(
"#nombreSala",
"El nombre de la sala debe tener al menos 3 caracteres."
);
valido = false;
}
if (nombreEquipo1 === "") {
mostrarError(
"#nombreEquipo1",
"El nombre del equipo 1 es obligatorio."
);
valido = false;
} else if (nombreEquipo1.length < 2) {
mostrarError(
"#nombreEquipo1",
"El nombre del equipo debe tener al menos 2 caracteres."
);
valido = false;
}
if (nombreEquipo2 === "") {
mostrarError(
"#nombreEquipo2",
"El nombre del equipo 2 es obligatorio."
);
valido = false;
} else if (nombreEquipo2.length < 2) {
mostrarError(
"#nombreEquipo2",
"El nombre del equipo debe tener al menos 2 caracteres."
);
valido = false;
}
if (
nombreEquipo1 !== "" &&
nombreEquipo2 !== "" &&
nombreEquipo1.toLowerCase() ===
nombreEquipo2.toLowerCase()
) {
mostrarError(
"#nombreEquipo2",
"Los dos equipos deben tener nombres diferentes."
);
valido = false;
}
if (!valido) {
return;
}
console.log("Datos válidos:");
console.log({
nombreSala: nombreSala,
nombreEquipo1: nombreEquipo1,
nombreEquipo2: nombreEquipo2
});
}
);
// ======================================================
// MOSTRAR ERROR
// ======================================================
function mostrarError(selector, mensaje) { function mostrarError(selector, mensaje) {
const input = $(selector);
const input = $(selector); input.addClass("is-invalid");
input.after(
input.addClass("is-invalid"); `<div class="mensaje-error-sala text-danger mt-1 small">${mensaje}</div>`,
);
input.after(`
<div class="mensaje-error-sala text-danger mt-1 small">
${mensaje}
</div>
`);
} }
// ====================================================== $(document).on("input", ".input-kahoot", function () {
// QUITAR ERROR AL ESCRIBIR $(this).removeClass("is-invalid");
// ====================================================== $(this).next(".mensaje-error-sala").remove();
});
$(".input-kahoot").on(
"input",
function () {
$(this).removeClass(
"is-invalid"
);
$(this)
.next(".mensaje-error-sala")
.remove();
}
);
+198 -117
View File
@@ -1,133 +1,214 @@
// Registro $(document).ready(function () {
$("#botonAceptarRegistro").click(function (event) { // Comprobar la sesión activa al cargar la página
event.preventDefault(); comprobarEstadoSesion();
console.log("hola");
let nombreUsuario = $("#regNombre").val().trim();
let email = $("#regEmail").val().trim();
let contrasena = $("#regPassword").val();
let contrasenaConfirmacion = $("#regPasswordConfirm").val();
// Limpiamos errores anteriores // Evento Click: Login
$("#regNombre").removeClass("is-invalid"); $('#botonAceptarLogin').on('click', function () {
$("#regEmail").removeClass("is-invalid"); ejecutarLogin();
$("#regPassword").removeClass("is-invalid"); });
$("#regPasswordConfirm").removeClass("is-invalid");
$("#errorRegistro").text("");
// Comprobamos que las contraseñas coincidan // Permitir Submit con tecla Enter en el formulario de Login
if (contrasena !== contrasenaConfirmacion) { $('#formLogin').on('submit', function (e) {
$("#regPassword").addClass("is-invalid"); e.preventDefault();
$("#regPasswordConfirm").addClass("is-invalid"); ejecutarLogin();
});
$("#errorRegistro").text("Las contraseñas no coinciden."); // Evento Click: Registro
$('#botonAceptarRegistro').on('click', function () {
ejecutarRegistro();
});
return; // Permitir Submit con tecla Enter en el formulario de Registro
} $('#formRegistro').on('submit', function (e) {
e.preventDefault();
$.ajax({ ejecutarRegistro();
method: "POST", });
url: "controladores/controladorUsuario.php",
data: {
nombreUsuario: nombreUsuario,
email: email,
contrasena: contrasena,
orden: "registrarUsuario",
},
}).done(function (respuesta) {
//console.log(respuesta);
respuesta = JSON.parse(respuesta);
if (respuesta.error) {
$("#errorRegistro").text(respuesta.error);
// Marcamos los campos si hay error
$("#regNombre").addClass("is-invalid");
$("#regEmail").addClass("is-invalid");
} else {
// Registro correcto
$("#errorRegistro")
.removeClass("text-danger")
.addClass("text-success")
.text(respuesta.exito);
// Limpiamos formulario
$("#formRegistro")[0].reset();
// Cerramos modal después de un segundo
setTimeout(function () {
location.reload();
}, 1000);
}
}); // Fin función ajax
}); });
// Login /**
$("#botonAceptarLogin").click(function (event) { * Comprueba con el servidor si existe una sesión PHP
event.preventDefault(); */
function comprobarEstadoSesion() {
$.ajax({
url: 'controladores/controladorUsuario.php',
type: 'POST',
dataType: 'json',
data: { orden: 'comprobarSesion' },
success: function (respuesta) {
if (respuesta.activa) {
renderizarCabeceraConSesion(respuesta.usuario);
$('#colBotonJugar').removeClass('d-none');
} else {
renderizarCabeceraSinSesion();
$('#colBotonJugar').addClass('d-none');
}
},
error: function () {
renderizarCabeceraSinSesion();
}
});
}
let email = $("#loginEmail").val().trim(); /**
let contrasena = $("#loginPassword").val(); * Petición AJAX para iniciar sesión
*/
function ejecutarLogin() {
let email = $('#loginEmail').val().trim();
let contrasena = $('#loginPassword').val().trim();
$('#errorLogin').text('');
// Limpiamos errores anteriores if (email === '' || contrasena === '') {
$("#loginEmail").removeClass("is-invalid"); $('#errorLogin').text('Por favor, rellena todos los campos.');
$("#loginPassword").removeClass("is-invalid"); return;
$("#errorLogin").text("");
// Comprobación básica
if (email === "" || contrasena === "") {
$("#errorLogin").text("Todos los campos son obligatorios.");
if (email === "") {
$("#loginEmail").addClass("is-invalid");
} }
if (contrasena === "") { $.ajax({
$("#loginPassword").addClass("is-invalid"); url: 'controladores/controladorUsuario.php',
type: 'POST',
dataType: 'json',
data: {
orden: 'comprobarUsuario',
email: email,
contrasena: contrasena
},
success: function (respuesta) {
if (respuesta.error) {
$('#errorLogin').text(respuesta.error);
} else if (respuesta.exito) {
$('#modalLogin').modal('hide');
$('#formLogin')[0].reset();
// Cargar datos de la sesión actualizados
comprobarEstadoSesion();
}
},
error: function () {
$('#errorLogin').text('Error al conectar con el servidor.');
}
});
}
/**
* Petición AJAX para registrar un usuario
*/
function ejecutarRegistro() {
let nombre = $('#regNombre').val().trim();
let email = $('#regEmail').val().trim();
let pass = $('#regPassword').val().trim();
let passConfirm = $('#regPasswordConfirm').val().trim();
$('#errorRegistro').text('');
if (nombre === '' || email === '' || pass === '') {
$('#errorRegistro').text('Todos los campos son obligatorios.');
return;
} }
return; if (pass !== passConfirm) {
} $('#errorRegistro').text('Las contraseñas no coinciden.');
return;
$.ajax({
method: "POST",
url: "controladores/controladorUsuario.php",
data: {
email: email,
contrasena: contrasena,
orden: "comprobarUsuario",
},
}).done(function (respuesta) {
//console.log(respuesta);
respuesta = JSON.parse(respuesta);
if (respuesta.error) {
$("#loginEmail").addClass("is-invalid");
$("#loginPassword").addClass("is-invalid");
$("#errorLogin").text(respuesta.error);
} else {
location.reload();
} }
}); // Fin función ajax
});
// Cerrar sesión $.ajax({
$("#botonCerrarSesion").click(function (event) { url: 'controladores/controladorUsuario.php',
event.preventDefault(); type: 'POST',
dataType: 'json',
data: {
orden: 'registrarUsuario',
nombreUsuario: nombre,
email: email,
contrasena: pass
},
success: function (respuesta) {
if (respuesta.error) {
$('#errorRegistro').text(respuesta.error);
} else {
$('#modalRegistro').modal('hide');
$('#formRegistro')[0].reset();
$.ajax({ // Autologin tras registrarse
method: "POST", $('#loginEmail').val(email);
url: "controladores/controladorUsuario.php", $('#loginPassword').val(pass);
data: { ejecutarLogin();
orden: "cerrarSesion", }
}, },
}).done(function (respuesta) { error: function () {
//console.log(respuesta); $('#errorRegistro').text('Error al procesar el registro.');
respuesta = JSON.parse(respuesta); }
if (respuesta.error) { });
console.log(respuesta.error); }
} else {
// Sesión cerrada correctamente
window.location.href = 'index.php';
} /**
}); // Fin función ajax * Petición AJAX para cerrar la sesión
}); // Fin función click */
function cerrarSesion() {
$.ajax({
url: 'controladores/controladorUsuario.php',
type: 'POST',
dataType: 'json',
data: { orden: 'cerrarSesion' },
success: function () {
renderizarCabeceraSinSesion();
$('#colBotonJugar').addClass('d-none');
if (window.location.pathname.includes('perfil.php') || window.location.pathname.includes('buscadorSala.php')) {
window.location.href = 'index.php';
}
}
});
}
/**
* Renderiza la cabecera cuando HAY sesión iniciada
*/
function renderizarCabeceraConSesion(usuario) {
//Mete el avatar en cabecera
let avatarImg = (usuario.avatar && usuario.avatar !== '')
? usuario.avatar
: 'img/avatars/defaultProfile.jpeg';
// Refrescar avatar si se cambia
let avatarConCacheBuster = avatarImg + '?v=' + new Date().getTime();
let html = `
<div class="dropdown">
<button class="btn btn-outline-light dropdown-toggle d-flex align-items-center gap-2 rounded-pill px-3 py-1 fw-bold" type="button" id="userMenu" data-bs-toggle="dropdown" aria-expanded="false">
<img src="${avatarConCacheBuster}" alt="Avatar" class="rounded-circle border" style="width: 32px; height: 32px; object-fit: cover;">
<span>${escapeHtml(usuario.nombreUsuario)}</span>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow border-0 mt-2" aria-labelledby="userMenu">
<li>
<a class="dropdown-item py-2 fw-semibold" href="perfil.php">
<i class="fa-solid fa-user me-2 text-primary"></i>Mi Perfil
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<button class="dropdown-item py-2 fw-semibold text-danger" onclick="cerrarSesion()">
<i class="fa-solid fa-right-from-bracket me-2"></i>Cerrar Sesión
</button>
</li>
</ul>
</div>
`;
$('#contenedorUsuarioCabecera').html(html);
}
/**
* Renderiza los botones en la cabecera cuando NO hay sesión (Iniciar sesión azul)
*/
function renderizarCabeceraSinSesion() {
let html = `
<button class="btn btn-primary rounded-pill px-4 fw-bold shadow-sm" data-bs-toggle="modal" data-bs-target="#modalLogin">
<i class="fa-solid fa-right-to-bracket me-1"></i> Iniciar sesión
</button>
<button class="btn btn-success rounded-pill px-4 fw-bold shadow-sm" data-bs-toggle="modal" data-bs-target="#modalRegistro">
<i class="fa-solid fa-user-plus me-1"></i> Registrarse
</button>
`;
$('#contenedorUsuarioCabecera').html(html);
}
function escapeHtml(texto) {
return $('<div>').text(texto).html();
}
+95
View File
@@ -0,0 +1,95 @@
$(document).ready(function () {
cargarRanking();
});
function cargarRanking() {
$.ajax({
url: 'controladores/controladorUsuario.php',
type: 'POST',
data: { orden: 'obtenerRanking' },
dataType: 'json',
success: function (response) {
if (response.exito && response.ranking.length > 0) {
renderizarTablaRanking(response.ranking);
} else {
$('#ranking-container').html(`
<div class="alert alert-info my-3">
<i class="fa-solid fa-info-circle me-2"></i>Aún no hay partidas registradas para mostrar el ranking.
</div>
`);
}
},
error: function () {
$('#ranking-container').html(`
<div class="alert alert-danger my-3">
<i class="fa-solid fa-exclamation-triangle me-2"></i>Error al cargar la clasificación.
</div>
`);
}
});
}
function renderizarTablaRanking(jugadores) {
let html = `
<div class="table-responsive">
<table class="table table-striped table-hover align-middle mb-0 text-center">
<thead class="table-dark">
<tr>
<th scope="col" style="width: 10%;">#</th>
<th scope="col" class="text-start" style="width: 35%;">Jugador</th>
<th scope="col" style="width: 15%;"><i class="fa-solid fa-trophy text-warning me-1"></i> Vic</th>
<th scope="col" style="width: 15%;"><i class="fa-solid fa-xmark text-danger me-1"></i> Der</th>
<th scope="col" style="width: 15%;"><i class="fa-solid fa-bullseye text-success me-1"></i> Aciertos</th>
<th scope="col" style="width: 10%;"><i class="fa-solid fa-percent text-info me-1"></i> % Vic</th>
</tr>
</thead>
<tbody>
`;
jugadores.forEach((jugador, index) => {
let posicion = index + 1;
let medalla = '';
// Medallas para el Top 3
if (posicion === 1) {
medalla = '<i class="fa-solid fa-medal text-warning fa-lg" title="1º Puesto"></i>';
} else if (posicion === 2) {
medalla = '<i class="fa-solid fa-medal text-secondary fa-lg" title="2º Puesto"></i>';
} else if (posicion === 3) {
medalla = '<i class="fa-solid fa-medal text-brown fa-lg" style="color: #cd7f32;" title="3º Puesto"></i>';
} else {
medalla = `<span class="fw-bold text-muted">${posicion}</span>`;
}
let avatarImg = jugador.avatar ? jugador.avatar : 'img/avatars/defaultProfile.jpeg';
html += `
<tr>
<td class="fw-bold fs-5">${medalla}</td>
<td class="text-start fw-bold">
<img src="${avatarImg}" alt="Avatar" class="rounded-circle me-2 border" style="width: 32px; height: 32px; object-fit: cover;">
${escapeHtml(jugador.nombreUsuario)}
</td>
<td><span class="badge bg-success rounded-pill px-3 py-2 fs-6">${jugador.victorias}</span></td>
<td><span class="badge bg-danger rounded-pill px-3 py-2 fs-6">${jugador.derrotas}</span></td>
<td class="fw-bold text-primary fs-6">${jugador.aciertos}</td>
<td>
<span class="badge bg-info text-dark rounded-pill px-2 py-1">${jugador.porcentajeVictoria}%</span>
</td>
</tr>
`;
});
html += `
</tbody>
</table>
</div>
`;
$('#ranking-container').removeClass('text-center p-4 ranking-placeholder').html(html);
}
function escapeHtml(texto) {
return $('<div>').text(texto).html();
}
+145 -7
View File
@@ -26,6 +26,10 @@ $.ajax({
function cambiarNombre() { function cambiarNombre() {
let nuevoNombre = $("#nuevoNombre").val().trim(); let nuevoNombre = $("#nuevoNombre").val().trim();
if (nuevoNombre === "") {
return;
}
$.ajax({ $.ajax({
method: "POST", method: "POST",
url: "controladores/controladorUsuario.php", url: "controladores/controladorUsuario.php",
@@ -42,8 +46,13 @@ function cambiarNombre() {
// Actualizamos el nombre mostrado en la página // Actualizamos el nombre mostrado en la página
$("#nombre").text(respuesta.nombreUsuario); $("#nombre").text(respuesta.nombreUsuario);
// Limpiamos el input
$("#nuevoNombre").val(""); $("#nuevoNombre").val("");
if (typeof comprobarEstadoSesion === "function") {
comprobarEstadoSesion();
}
} }
}); });
} }
@@ -56,7 +65,6 @@ function borrarNombre() {
document.getElementById("nuevoNombre").value = ""; document.getElementById("nuevoNombre").value = "";
} }
// ========================= // =========================
// CAMBIAR FOTO // CAMBIAR FOTO
// ========================= // =========================
@@ -75,14 +83,11 @@ $("#inputFoto").change(function () {
// Comprobamos que sea una imagen // Comprobamos que sea una imagen
if (!archivo.type.startsWith("image/")) { if (!archivo.type.startsWith("image/")) {
alert("El archivo seleccionado no es una imagen."); alert("El archivo seleccionado no es una imagen.");
$("#inputFoto").val(""); $("#inputFoto").val("");
return; return;
} }
let datos = new FormData(); let datos = new FormData();
datos.append("avatar", archivo); datos.append("avatar", archivo);
datos.append("orden", "cambiarAvatar"); datos.append("orden", "cambiarAvatar");
@@ -98,11 +103,144 @@ $("#inputFoto").change(function () {
if (respuesta.error) { if (respuesta.error) {
alert(respuesta.error); alert(respuesta.error);
} else { } else {
// Actualizamos la imagen sin recargar la página // Actualizamos la imagen en la página de perfil sin recargar
$("#fotoPerfil").attr( $("#fotoPerfil").attr(
"src", "src",
respuesta.avatar + "?t=" + new Date().getTime(), respuesta.avatar + "?t=" + new Date().getTime()
); );
// Actualizamos también el avatar superior en la cabecera
if (typeof comprobarEstadoSesion === "function") {
comprobarEstadoSesion();
}
} }
}); });
}); });
// =========================
// RECOGER CATEGORIAS
// =========================
$("#modalCrearPregunta").on("show.bs.modal", function () {
const selectCategoria = $("#idCategoria");
// Limpiamos las categorías anteriores
selectCategoria.empty();
// Opción inicial
selectCategoria.append('<option value="">Selecciona una categoría</option>');
$.ajax({
url: "controladores/controladorCategoria.php",
type: "POST",
dataType: "json",
data: {
orden: "listarCategorias",
},
success: function (respuesta) {
console.log("Categorías:", respuesta);
if (respuesta.error) {
alert(respuesta.error);
return;
}
$.each(respuesta, function (index, categoria) {
selectCategoria.append(
$("<option>", {
value: categoria.idCategoria,
text: categoria.nombreCategoria,
})
);
});
},
error: function (xhr, status, error) {
console.error("Error al cargar las categorías:", error);
console.error("Respuesta del servidor:", xhr.responseText);
alert("No se han podido cargar las categorías.");
},
});
});
// =========================
// CREAR PREGUNTA
// =========================
$("#formCrearPregunta").on("submit", function (e) {
e.preventDefault();
const boton = $("#btnCrearPregunta");
const pregunta = $("#pregunta").val().trim();
const respuestaCorrecta = $("#respuestaCorrecta").val().trim();
const respuestaIncorrecta1 = $("#respuestaIncorrecta1").val().trim();
const respuestaIncorrecta2 = $("#respuestaIncorrecta2").val().trim();
const respuestaIncorrecta3 = $("#respuestaIncorrecta3").val().trim();
// Comprobamos que no haya campos vacíos
if (
pregunta === "" ||
respuestaCorrecta === "" ||
respuestaIncorrecta1 === "" ||
respuestaIncorrecta2 === "" ||
respuestaIncorrecta3 === ""
) {
alert("Todos los campos son obligatorios.");
return;
}
boton.prop("disabled", true);
boton.text("Creando pregunta...");
$.ajax({
url: "controladores/controladorPregunta.php",
type: "POST",
dataType: "json",
data: {
orden: "crearPregunta",
idCategoria: $("#idCategoria").val(),
nombrePregunta: pregunta,
respuestaCorrecta: respuestaCorrecta,
respuestaIncorrecta1: respuestaIncorrecta1,
respuestaIncorrecta2: respuestaIncorrecta2,
respuestaIncorrecta3: respuestaIncorrecta3,
},
success: function (respuesta) {
console.log("Respuesta del servidor:", respuesta);
if (respuesta.error) {
alert(respuesta.error);
boton.prop("disabled", false);
boton.text("Crear pregunta");
return;
}
if (respuesta.exito) {
console.log("Pregunta creada:", respuesta.idPregunta);
// Cerramos el modal
$("#modalCrearPregunta").modal("hide");
// Limpiamos el formulario
$("#formCrearPregunta")[0].reset();
// Volvemos a activar el botón
boton.prop("disabled", false);
boton.text("Crear pregunta");
}
},
error: function (xhr, status, error) {
console.error("Error al crear la pregunta:", error);
console.error("Respuesta del servidor:", xhr.responseText);
alert("No se ha podido crear la pregunta.");
boton.prop("disabled", false);
boton.text("Crear pregunta");
},
});
});
+38
View File
@@ -0,0 +1,38 @@
$(document).ready(function () {
const idPartida = $("body").data("id-partida");
comprobarEstadoPartida(idPartida);
const intervalo = setInterval(function () {
comprobarEstadoPartida(idPartida, intervalo);
}, 3000);
});
function comprobarEstadoPartida(idPartida, intervalo = null) {
$.ajax({
url: "controladores/ControladorResultados.php",
type: "POST",
dataType: "json",
data: {
orden: "comprobarEstado",
idPartida: idPartida
},
success: function (respuesta) {
if (respuesta.error) {
console.error("Error:", respuesta.error);
return;
}
if (respuesta.terminada) {
if (intervalo !== null) clearInterval(intervalo);
$("#pantalla-espera").fadeOut(400, function() {
location.reload();
});
}
},
error: function () {
console.log("Error de comunicación con el controlador.");
}
});
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

+109 -237
View File
@@ -1,3 +1,17 @@
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Redirección si el usuario no ha iniciado sesión
if (!isset($_SESSION['idUsuario'])) {
header('Location: login.php');
exit();
}
$nombreUsuario = htmlspecialchars($_SESSION['nombreUsuario'] ?? 'Usuario');
$avatarUsuario = htmlspecialchars($_SESSION['avatar'] ?? 'img/avatars/defaultProfile.jpeg');
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="es"> <html lang="es">
@@ -9,151 +23,99 @@
<title>Perfil</title> <title>Perfil</title>
<!-- Bootstrap --> <!-- Bootstrap -->
<link <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet">
<!-- Bootstrap Icons --> <!-- Bootstrap Icons -->
<link <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<!-- Google Font: Fredoka --> <!-- Google Font: Fredoka -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600;700&display=swap" rel="stylesheet">
<link
href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600;700&display=swap"
rel="stylesheet">
<!-- Tu CSS --> <!-- Tu CSS -->
<link rel="stylesheet" href="css/index.css"> <link rel="stylesheet" href="css/index.css">
<link rel="stylesheet" href="css/perfil.css"> <link rel="stylesheet" href="css/perfil.css">
<script src="js/jquery-4.0.0.min.js"></script> <script src="js/jquery-4.0.0.min.js"></script>
</head> </head>
<body> <body>
<?php <?php include_once 'cabecera.php'; ?>
include_once 'cabecera.php';
?>
<div class="perfil-container"> <div class="perfil-container">
<div class="perfil-card"> <div class="perfil-card">
<!-- ========================= -->
<!-- CABECERA --> <!-- CABECERA -->
<!-- ========================= -->
<div class="perfil-header"> <div class="perfil-header">
<i class="bi bi-person-circle"></i> <i class="bi bi-person-circle"></i>
Mi perfil Mi perfil
</div> </div>
<div class="perfil-content"> <div class="perfil-content">
<div class="row align-items-center g-5"> <div class="row align-items-center g-5">
<!-- ========================= -->
<!-- PERFIL --> <!-- PERFIL -->
<!-- ========================= -->
<div class="col-md-6 text-center"> <div class="col-md-6 text-center">
<!-- Nombre --> <!-- Nombre -->
<h1 id="nombre" class="nombre"> <h1 id="nombre" class="nombre">
<?php echo $_SESSION['nombreUsuario'] ?> <?= $nombreUsuario ?>
</h1> </h1>
<!-- ========================= -->
<!-- FOTO DE PERFIL --> <!-- FOTO DE PERFIL -->
<!-- ========================= -->
<div class="foto-container"> <div class="foto-container">
<img <img id="fotoPerfil"
id="fotoPerfil" src="<?= $avatarUsuario ?>"
src="<?= htmlspecialchars($_SESSION['avatar'] ?? '') ?>" alt="Foto de perfil"
alt="Foto de perfil" class="avatar rounded-circle">
class="avatar rounded-circle">
<!-- Botón lápiz --> <!-- Botón lápiz -->
<button type="button"
<button class="btn-foto"
type="button" onclick="seleccionarFoto()"
class="btn-foto" title="Cambiar foto de perfil"
onclick="seleccionarFoto()" aria-label="Cambiar foto de perfil">
title="Cambiar foto de perfil"
aria-label="Cambiar foto de perfil">
<i class="bi bi-pencil-fill"></i> <i class="bi bi-pencil-fill"></i>
</button> </button>
<!-- Input oculto --> <!-- Input oculto -->
<input type="file"
<input id="inputFoto"
type="file" accept="image/*"
id="inputFoto" hidden>
accept="image/*"
hidden>
</div> </div>
<!-- ========================= -->
<!-- CAMBIAR NOMBRE --> <!-- CAMBIAR NOMBRE -->
<!-- ========================= -->
<div class="formulario-nombre"> <div class="formulario-nombre">
<label <label for="nuevoNombre" class="form-label">
for="nuevoNombre"
class="form-label">
Cambia tu nombre Cambia tu nombre
</label> </label>
<input type="text"
<input id="nuevoNombre"
type="text" class="form-control mb-3"
id="nuevoNombre" placeholder="Escribe tu nuevo nombre">
class="form-control mb-3"
placeholder="Escribe tu nuevo nombre">
<div class="d-flex justify-content-center gap-2"> <div class="d-flex justify-content-center gap-2">
<button <button type="button"
type="button" class="btn-perfil-cambiar"
class="btn-perfil-cambiar" onclick="cambiarNombre()">
onclick="cambiarNombre()">
<i class="bi bi-check-lg"></i> <i class="bi bi-check-lg"></i>
Cambiar nombre Cambiar nombre
</button> </button>
<button type="button"
<button class="btn-perfil-borrar"
type="button" onclick="borrarNombre()">
class="btn-perfil-borrar"
onclick="borrarNombre()">
<i class="bi bi-x-lg"></i> <i class="bi bi-x-lg"></i>
Borrar Borrar
</button> </button>
</div> </div>
@@ -162,11 +124,7 @@
</div> </div>
<!-- ========================= -->
<!-- ESTADÍSTICAS --> <!-- ESTADÍSTICAS -->
<!-- ========================= -->
<div class="col-md-6"> <div class="col-md-6">
<div class="estadisticas"> <div class="estadisticas">
@@ -176,60 +134,33 @@
Estadísticas Estadísticas
</h2> </h2>
<div class="estadistica estadistica-victorias"> <div class="estadistica estadistica-victorias">
<i class="bi bi-trophy-fill"></i> <i class="bi bi-trophy-fill"></i>
&nbsp; Victorias: &nbsp; Victorias:
<strong id="victorias">0</strong>
<strong id="victorias">
</strong>
</div> </div>
<div class="estadistica estadistica-derrotas"> <div class="estadistica estadistica-derrotas">
<i class="bi bi-x-circle-fill"></i> <i class="bi bi-x-circle-fill"></i>
&nbsp; Derrotas: &nbsp; Derrotas:
<strong id="derrotas">0</strong>
<strong id="derrotas">
</strong>
</div> </div>
<div class="estadistica estadistica-aciertos"> <div class="estadistica estadistica-aciertos">
<i class="bi bi-bullseye"></i> <i class="bi bi-bullseye"></i>
&nbsp; Aciertos: &nbsp; Aciertos:
<strong id="aciertos">0</strong>
<strong id="aciertos">
</strong>
</div> </div>
<!-- ========================= -->
<!-- CREAR PREGUNTA --> <!-- CREAR PREGUNTA -->
<!-- ========================= -->
<div class="text-center mt-4"> <div class="text-center mt-4">
<button type="button"
<button class="btn btn-play-kahoot"
type="button" data-bs-toggle="modal"
class="btn btn-play-kahoot" data-bs-target="#modalCrearPregunta">
data-bs-toggle="modal"
data-bs-target="#modalCrearPregunta">
<i class="bi bi-plus-circle-fill"></i> <i class="bi bi-plus-circle-fill"></i>
Crear pregunta Crear pregunta
</button> </button>
</div> </div>
</div> </div>
@@ -245,172 +176,118 @@
</div> </div>
<!-- ================================================= -->
<!-- MODAL CREAR PREGUNTA --> <!-- MODAL CREAR PREGUNTA -->
<!-- ================================================= --> <div class="modal fade"
id="modalCrearPregunta"
<div tabindex="-1"
class="modal fade" aria-labelledby="modalCrearPreguntaLabel"
id="modalCrearPregunta" aria-hidden="true">
tabindex="-1"
aria-labelledby="modalCrearPreguntaLabel"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered"> <div class="modal-dialog modal-dialog-centered">
<div class="modal-content modal-kahoot"> <div class="modal-content modal-kahoot">
<!-- CABECERA DEL MODAL -->
<div class="modal-header modal-kahoot-header"> <div class="modal-header modal-kahoot-header">
<h5 class="modal-title" id="modalCrearPreguntaLabel">
<h5
class="modal-title"
id="modalCrearPreguntaLabel">
<i class="bi bi-question-circle-fill me-2"></i> <i class="bi bi-question-circle-fill me-2"></i>
Crear pregunta Crear pregunta
</h5> </h5>
<button type="button"
class="btn-close btn-close-white"
<button data-bs-dismiss="modal"
type="button" aria-label="Cerrar">
class="btn-close btn-close-white"
data-bs-dismiss="modal"
aria-label="Cerrar">
</button> </button>
</div> </div>
<!-- CUERPO DEL MODAL -->
<div class="modal-body p-4"> <div class="modal-body p-4">
<form id="formCrearPregunta"> <form id="formCrearPregunta">
<!-- PREGUNTA --> <!-- PREGUNTA -->
<div class="mb-4"> <div class="mb-4">
<label for="pregunta" class="form-label fw-semibold">
<label
for="pregunta"
class="form-label fw-semibold">
<i class="bi bi-question-lg me-1"></i> <i class="bi bi-question-lg me-1"></i>
Pregunta Pregunta
</label> </label>
<textarea id="pregunta"
<textarea name="pregunta"
id="pregunta" class="form-control input-kahoot"
name="pregunta" rows="3"
class="form-control input-kahoot" placeholder="Escribe aquí la pregunta..."
rows="3" required></textarea>
placeholder="Escribe aquí la pregunta..."
required></textarea>
</div> </div>
<!-- CATEGORÍA -->
<div class="mb-4">
<label for="idCategoria" class="form-label fw-semibold">
<i class="bi bi-folder-fill me-1"></i>
Categoría
</label>
<select id="idCategoria"
name="idCategoria"
class="form-select input-kahoot"
required>
<option value="">Selecciona una categoría</option>
</select>
</div>
<!-- RESPUESTA CORRECTA --> <!-- RESPUESTA CORRECTA -->
<div class="mb-3"> <div class="mb-3">
<label for="respuestaCorrecta" class="form-label fw-semibold text-success">
<label
for="respuestaCorrecta"
class="form-label fw-semibold text-success">
<i class="bi bi-check-circle-fill me-1"></i> <i class="bi bi-check-circle-fill me-1"></i>
Respuesta correcta Respuesta correcta
</label> </label>
<input type="text"
<input id="respuestaCorrecta"
type="text" name="respuestaCorrecta"
id="respuestaCorrecta" class="form-control input-kahoot"
name="respuestaCorrecta" placeholder="Escribe la respuesta correcta..."
class="form-control input-kahoot" required>
placeholder="Escribe la respuesta correcta..."
required>
</div> </div>
<!-- RESPUESTAS INCORRECTAS --> <!-- RESPUESTAS INCORRECTAS -->
<div class="mb-3"> <div class="mb-3">
<label class="form-label fw-semibold text-danger">
<label
class="form-label fw-semibold text-danger">
<i class="bi bi-x-circle-fill me-1"></i> <i class="bi bi-x-circle-fill me-1"></i>
Respuestas incorrectas Respuestas incorrectas
</label> </label>
<input type="text"
id="respuestaIncorrecta1"
name="respuestaIncorrecta1"
class="form-control input-kahoot mb-2"
placeholder="Respuesta incorrecta 1"
required>
<input <input type="text"
type="text" id="respuestaIncorrecta2"
id="respuestaIncorrecta1" name="respuestaIncorrecta2"
name="respuestaIncorrecta1" class="form-control input-kahoot mb-2"
class="form-control input-kahoot mb-2" placeholder="Respuesta incorrecta 2"
placeholder="Respuesta incorrecta 1" required>
required>
<input
type="text"
id="respuestaIncorrecta2"
name="respuestaIncorrecta2"
class="form-control input-kahoot mb-2"
placeholder="Respuesta incorrecta 2"
required>
<input
type="text"
id="respuestaIncorrecta3"
name="respuestaIncorrecta3"
class="form-control input-kahoot"
placeholder="Respuesta incorrecta 3"
required>
<input type="text"
id="respuestaIncorrecta3"
name="respuestaIncorrecta3"
class="form-control input-kahoot"
placeholder="Respuesta incorrecta 3"
required>
</div> </div>
</form> </form>
</div> </div>
<!-- PIE DEL MODAL -->
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal">
<i class="bi bi-x-lg me-1"></i> <i class="bi bi-x-lg me-1"></i>
Cancelar Cancelar
</button> </button>
<button type="submit" form="formCrearPregunta" class="btn btn-kahoot-login" id="btnCrearPregunta">
<button
type="submit"
form="formCrearPregunta"
class="btn btn-kahoot-login">
<i class="bi bi-check-lg me-1"></i> <i class="bi bi-check-lg me-1"></i>
Crear pregunta Crear pregunta
</button> </button>
</div> </div>
</div> </div>
@@ -420,14 +297,9 @@
</div> </div>
<!-- Bootstrap JS --> <!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js">
</script>
<!-- Tu JavaScript --> <!-- Tu JavaScript -->
<script src="js/perfil.js"></script> <script src="js/perfil.js"></script>
</body> </body>
+155 -290
View File
@@ -1,291 +1,156 @@
<!DOCTYPE html> <?php
<html lang="es"> session_start();
require_once $_SERVER['DOCUMENT_ROOT'] . '/triviagmatico/includes/conexionBD.php';
<head>
<meta charset="UTF-8"> $idPartida = intval($_GET['idPartida'] ?? 0);
<meta name="viewport" content="width=device-width, initial-scale=1.0"> if ($idPartida <= 0) {
die("Partida no válida.");
<title>Trivial - Resultado final</title> }
<link rel="icon" type="image/svg+xml" href="img/favicon/favicon.svg"> $conexion = conexionBD();
if (is_array($conexion)) {
<link die("Error de conexión a la base de datos.");
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" }
rel="stylesheet">
// Obtener listado de jugadores y sus equipos en esta partida
<!-- Bootstrap Icons --> $stmt = $conexion->prepare("
<link SELECT u.idUsuario, u.nombreUsuario, e.idEquipo, e.nombreEquipo
rel="stylesheet" FROM equipoxpartida exp
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"> INNER JOIN equipoxusuario exu ON exp.idEquipo = exu.idEquipo
INNER JOIN usuario u ON exu.idUsuario = u.idUsuario
<link INNER JOIN equipo e ON exu.idEquipo = e.idEquipo
href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600;700&display=swap" WHERE exp.idPartida = :idPartida
rel="stylesheet"> ");
$stmt->execute([':idPartida' => $idPartida]);
<link rel="stylesheet" href="css/index.css"> $listaJugadoresRaw = $stmt->fetchAll(PDO::FETCH_ASSOC);
</head>
$primerosEnAcertar = $_SESSION['primeros_en_acertar'][$idPartida] ?? [];
<body>
$jugadoresFinales = [];
<?php $equiposFinales = [];
include_once("cabecera.php");
?> // Respuestas de velocidad (+2 o +1)
foreach ($listaJugadoresRaw as $jugador) {
<main class="container py-5"> $idU = (int)$jugador['idUsuario'];
$idE = (int)$jugador['idEquipo'];
<!-- Título -->
<div class="text-center mb-5"> $stmtRespuestas = $conexion->prepare("
SELECT ra.idPartidaxPregunta, r.correcta
<div class="trophy-icon"> FROM respuestaalmacenada ra
<i class="bi bi-trophy-fill"></i> INNER JOIN respuesta r ON ra.idRespuesta = r.idRespuesta
</div> INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta
WHERE pxp.idPartida = :idPartida AND ra.idUsuario = :idUsuario
<h1 class="fw-bold"> ");
¡Trivial terminado! $stmtRespuestas->execute([':idPartida' => $idPartida, ':idUsuario' => $idU]);
</h1> $respuestasUsuario = $stmtRespuestas->fetchAll(PDO::FETCH_ASSOC);
<p class="text-muted fs-5 mb-0"> $aciertos = 0;
Estos son los resultados finales $puntosTotalesJugador = 0;
</p>
foreach ($respuestasUsuario as $resp) {
</div> if ((int)$resp['correcta'] === 1) {
$aciertos++;
$idPxp = $resp['idPartidaxPregunta'];
<!-- Equipo ganador -->
<section class="row justify-content-center mb-5"> // Si el ID de usuario coincide con el primero guardado de esa pregunta se lleva 2 puntos
if (isset($primerosEnAcertar[$idPxp]) && $primerosEnAcertar[$idPxp] === $idU) {
<div class="col-12 col-lg-8"> $puntosTotalesJugador += 2;
} else {
<div class="ranking-card"> $puntosTotalesJugador += 1;
}
<div class="ranking-header text-center"> }
<i class="bi bi-trophy-fill me-2"></i> }
Equipo ganador
</div> $jugadoresFinales[] = [
'nombre' => $jugador['nombreUsuario'],
<div class="card-body text-center p-4"> 'equipo' => $jugador['nombreEquipo'],
'aciertos' => $aciertos,
<h2 class="fw-bold mb-2"> 'puntos' => $puntosTotalesJugador
Los Cerebritos ];
</h2>
if (!isset($equiposFinales[$idE])) {
<div class="display-3 fw-bold mb-3"> $equiposFinales[$idE] = [
850 'nombre' => $jugador['nombreEquipo'],
<span class="fs-4 text-muted"> 'puntos' => 0
puntos ];
</span> }
</div> $equiposFinales[$idE]['puntos'] += $puntosTotalesJugador;
}
<p class="text-muted mb-0">
<i class="bi bi-stars me-1"></i> // Ordenar según la puntuación final de mayor a menor
¡Enhorabuena por la victoria! usort($jugadoresFinales, function($a, $b) { return $b['puntos'] <=> $a['puntos']; });
</p> usort($equiposFinales, function($a, $b) { return $b['puntos'] <=> $a['puntos']; });
?>
</div>
<!DOCTYPE html>
</div> <html lang="es">
<head>
</div> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</section> <title>Resultados - Trivial</title>
<link rel="stylesheet" href="css/resultados.css">
<script src="https://jquery.com"></script>
<!-- Resultados de los dos equipos --> </head>
<section class="row justify-content-center g-4"> <body data-id-partida="<?php echo $idPartida; ?>">
<!-- EQUIPO GANADOR --> <div id="pantalla-espera" class="contenedor">
<div class="col-12 col-lg-6"> <h2>⌛ Esperando a que todos los jugadores terminen...</h2>
<p>Calculando estadísticas de velocidad y actualizando perfiles históricos en el servidor.</p>
<div class="ranking-card h-100"> <div class="loader"></div>
</div>
<div class="ranking-header d-flex justify-content-between align-items-center">
<div id="pantalla-resultados" class="contenedor" style="display:none;">
<span> <h1>🏆 Resultados de la Partida 🏆</h1>
Los Cerebritos
</span> <h2>Clasificación por Equipos</h2>
<table class="tabla-ranking">
<span> <thead>
<i class="bi bi-trophy-fill"></i> <tr>
</span> <th>Posición</th>
<th>Equipo</th>
</div> <th>Puntos Totales</th>
</tr>
<div class="card-body p-4"> </thead>
<tbody>
<div class="text-center mb-4"> <?php foreach ($equiposFinales as $index => $eq): ?>
<tr class="<?php echo $index === 0 ? 'top-team' : ''; ?>">
<div class="fs-1 fw-bold"> <td>#<?php echo $index + 1; ?></td>
850 <td><?php echo htmlspecialchars($eq['nombre']); ?></td>
</div> <td><strong><?php echo $eq['puntos']; ?> pts</strong></td>
</tr>
<div class="text-muted"> <?php endforeach; ?>
puntos </tbody>
</div> </table>
</div> <h2>Rendimiento Individual</h2>
<table class="tabla-ranking">
<h5 class="fw-bold mb-3"> <thead>
<i class="bi bi-people-fill me-2"></i> <tr>
Jugadores <th>Posición</th>
</h5> <th>Jugador</th>
<th>Equipo</th>
<ul class="list-group"> <th>Aciertos</th>
<th>Puntos Logrados</th>
<li class="list-group-item"> </tr>
1. Carlos </thead>
</li> <tbody>
<?php foreach ($jugadoresFinales as $index => $jug): ?>
<li class="list-group-item"> <tr class="<?php echo $index === 0 ? 'top-player' : ''; ?>">
2. Marta <td>#<?php echo $index + 1; ?></td>
</li> <td><?php echo htmlspecialchars($jug['nombre']); ?></td>
<td><?php echo htmlspecialchars($jug['equipo']); ?></td>
<li class="list-group-item"> <td><?php echo $jug['aciertos']; ?> / 10</td>
3. Pablo <td><strong><?php echo $jug['puntos']; ?> pts</strong></td>
</li> </tr>
<?php endforeach; ?>
<li class="list-group-item"> </tbody>
4. Laura </table>
</li>
<div class="contenedor-boton">
<li class="list-group-item"> <a href="/triviagmatico/buscadorSala.php" class="btn-inicio">Volver al Inicio 🏠</a>
5. David </div>
</li> </div>
<li class="list-group-item"> <script src="js/resultados.js"></script>
6. Ana </body>
</li>
<li class="list-group-item">
7. Sergio
</li>
<li class="list-group-item">
8. Lucía
</li>
<li class="list-group-item">
9. Miguel
</li>
<li class="list-group-item">
10. Elena
</li>
</ul>
</div>
</div>
</div>
<!-- EQUIPO PERDEDOR -->
<div class="col-12 col-lg-6">
<div class="ranking-card h-100">
<!-- Cabecera plateada -->
<div
class="ranking-header d-flex justify-content-between align-items-center"
style="background-color: #c0c0c0;">
<span>
Los Campeones
</span>
<span>
<i class="bi bi-award-fill"></i>
</span>
</div>
<div class="card-body p-4">
<div class="text-center mb-4">
<div class="fs-1 fw-bold">
720
</div>
<div class="text-muted">
puntos
</div>
</div>
<h5 class="fw-bold mb-3">
<i class="bi bi-people-fill me-2"></i>
Jugadores
</h5>
<ul class="list-group">
<li class="list-group-item">
1. Javier
</li>
<li class="list-group-item">
2. Sofía
</li>
<li class="list-group-item">
3. Diego
</li>
<li class="list-group-item">
4. María
</li>
<li class="list-group-item">
5. Alejandro
</li>
<li class="list-group-item">
6. Paula
</li>
<li class="list-group-item">
7. Álvaro
</li>
<li class="list-group-item">
8. Carmen
</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Volver al buscador -->
<div class="text-center mt-5">
<a
href="buscadorSala.php"
class="btn btn-play-kahoot">
<i class="bi bi-arrow-left-circle-fill"></i>
Volver al buscador de salas
</a>
</div>
</main>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js">
</script>
</body>
</html> </html>
File diff suppressed because it is too large Load Diff