diff --git a/bd/tablas.sql b/bd/tablas.sql index e10e6a0..6ac4921 100644 --- a/bd/tablas.sql +++ b/bd/tablas.sql @@ -30,7 +30,6 @@ CREATE TABLE conciertos ( capacidad_total INT NOT NULL ); INSERT INTO conciertos (nombre_concierto, artista, fecha, calle, colonia, numero_direccion, codigo_postal, estado, capacidad_total) -VALUES ('Linux Fest', 'Junior H', '2025-06-15', 'Av. Xalapa', 'Obrero Campesina', 's/n', '91020', 'Veracruz', 5000); SELECT * FROM conciertos; DROP TABLE conciertos; -- Zona @@ -42,11 +41,7 @@ CREATE TABLE zonas ( precio DECIMAL(10,2) NOT NULL, FOREIGN KEY (id_concierto) REFERENCES conciertos(id_concierto) ON DELETE CASCADE ); -INSERT INTO zonas (id_concierto, nombre_zona, capacidad, precio) VALUES -(1, 'General', 20000, 800.00), -(1, 'Plata', 15000, 1500.00), -(1, 'Oro', 10000, 2500.00), -(1, 'VIP', 5000, 5000.00); + DROP TABLE zonas; -- Obtener todos los conciertos con sus zonas y precios SELECT c.id_concierto, c.nombre_concierto, c.artista, c.fecha, diff --git a/controladores/comprar_asiento.php b/controladores/comprar_asiento.php new file mode 100644 index 0000000..1698ebb --- /dev/null +++ b/controladores/comprar_asiento.php @@ -0,0 +1,22 @@ +<?php +include 'conexion.php'; + +header('Content-Type: application/json'); + +$data = json_decode(file_get_contents("php://input"), true); + +if (!isset($data['asientos']) || !is_array($data['asientos'])) { + echo json_encode(["error" => "Datos inválidos"]); + exit; +} + +foreach ($data['asientos'] as $idAsiento) { + $consulta = "UPDATE asientos SET estado = 'ocupado' WHERE id_asiento = ?"; + $stmt = $conexionBD->prepare($consulta); + $stmt->bind_param("i", $idAsiento); + $stmt->execute(); +} + +echo json_encode(["success" => true]); +exit; +?> diff --git a/controladores/concierto_zonas.php b/controladores/concierto_zonas.php index 5f0ec38..f7458c1 100644 --- a/controladores/concierto_zonas.php +++ b/controladores/concierto_zonas.php @@ -3,26 +3,109 @@ include 'conexion.php'; header('Content-Type: application/json'); -if (!isset($_GET['id']) || !isset($_GET['zona'])) { - echo json_encode(["error" => "Faltan parámetros"]); +if ($_SERVER['REQUEST_METHOD'] === 'GET') { + // Verificar si es solicitud de concierto + if (isset($_GET['id_concierto'])) { + $idConcierto = intval($_GET['id_concierto']); + + // Obtener la información del concierto + $consultaConcierto = "SELECT * FROM conciertos WHERE id_concierto = ?"; + $stmt = $conexionBD->prepare($consultaConcierto); + $stmt->bind_param("i", $idConcierto); + $stmt->execute(); + $resultadoConcierto = $stmt->get_result(); + $concierto = $resultadoConcierto->fetch_assoc(); + + if (!$concierto) { + echo json_encode(["error" => "Concierto no encontrado"]); + exit; + } + + // Obtener zonas del concierto + $consultaZonas = "SELECT * FROM zonas WHERE id_concierto = ?"; + $stmtZonas = $conexionBD->prepare($consultaZonas); + $stmtZonas->bind_param("i", $idConcierto); + $stmtZonas->execute(); + $resultadoZonas = $stmtZonas->get_result(); + + $zonas = []; + while ($zona = $resultadoZonas->fetch_assoc()) { + // Contar asientos disponibles y ocupados + $consultaAsientos = "SELECT estado FROM asientos WHERE id_zona = ?"; + $stmtAsientos = $conexionBD->prepare($consultaAsientos); + $stmtAsientos->bind_param("i", $zona['id_zona']); + $stmtAsientos->execute(); + $resultadoAsientos = $stmtAsientos->get_result(); + + $asientos_disponibles = 0; + $asientos_ocupados = 0; + + while ($asiento = $resultadoAsientos->fetch_assoc()) { + if ($asiento['estado'] === 'disponible') { + $asientos_disponibles++; + } else { + $asientos_ocupados++; + } + } + + // Agregar datos de asientos a la zona + $zona['asientos_disponibles'] = $asientos_disponibles; + $zona['asientos_ocupados'] = $asientos_ocupados; + + $zonas[] = $zona; + } + + // Agregar las zonas al concierto + $concierto['zonas'] = $zonas; + + echo json_encode($concierto); + exit; + } + + // Verificar si es solicitud de zona + if (isset($_GET['id_zona'])) { + $idZona = intval($_GET['id_zona']); + + // Obtener la información de la zona específica + $consultaZona = "SELECT * FROM zonas WHERE id_zona = ?"; + $stmtZona = $conexionBD->prepare($consultaZona); + $stmtZona->bind_param("i", $idZona); + $stmtZona->execute(); + $resultadoZona = $stmtZona->get_result(); + $zona = $resultadoZona->fetch_assoc(); + + if (!$zona) { + echo json_encode(["error" => "Zona no encontrada"]); + exit; + } + + // Obtener asientos de la zona + $consultaAsientos = "SELECT estado FROM asientos WHERE id_zona = ?"; + $stmtAsientos = $conexionBD->prepare($consultaAsientos); + $stmtAsientos->bind_param("i", $idZona); + $stmtAsientos->execute(); + $resultadoAsientos = $stmtAsientos->get_result(); + + $asientos_disponibles = 0; + $asientos_ocupados = 0; + + while ($asiento = $resultadoAsientos->fetch_assoc()) { + if ($asiento['estado'] === 'disponible') { + $asientos_disponibles++; + } else { + $asientos_ocupados++; + } + } + + // Agregar información de asientos a la zona + $zona['asientos_disponibles'] = $asientos_disponibles; + $zona['asientos_ocupados'] = $asientos_ocupados; + + echo json_encode($zona); + exit; + } + + echo json_encode(["error" => "Solicitud incorrecta"]); exit; } - -$conciertoId = intval($_GET['id']); -$nombreZona = $_GET['zona']; - -$consulta = "SELECT numero_asiento FROM boletos WHERE id_concierto = ? AND nombre_zona = ?"; -$stmt = $conexionBD->prepare($consulta); -$stmt->bind_param('is', $conciertoId, $nombreZona); -$stmt->execute(); -$resultado = $stmt->get_result(); - -$asientosOcupados = []; -while ($fila = $resultado->fetch_assoc()) { - $asientosOcupados[] = intval($fila['numero_asiento']); -} - -echo json_encode($asientosOcupados); -$stmt->close(); -$conexionBD->close(); ?> diff --git a/controladores/obtener_asiento.php b/controladores/obtener_asiento.php new file mode 100644 index 0000000..a066f1a --- /dev/null +++ b/controladores/obtener_asiento.php @@ -0,0 +1,27 @@ +<?php +include 'conexion.php'; + +header('Content-Type: application/json'); + +if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['id_zona'])) { + $idZona = intval($_GET['id_zona']); + + // Consultar los asientos de la zona específica + $consultaAsientos = "SELECT id_asiento, estado FROM asientos WHERE id_zona = ?"; + $stmtAsientos = $conexionBD->prepare($consultaAsientos); + $stmtAsientos->bind_param("i", $idZona); + $stmtAsientos->execute(); + $resultadoAsientos = $stmtAsientos->get_result(); + + $asientos = []; + while ($asiento = $resultadoAsientos->fetch_assoc()) { + $asientos[] = $asiento; + } + + echo json_encode($asientos); + exit; +} else { + echo json_encode(["error" => "Parámetro id_zona faltante"]); + exit; +} +?> diff --git a/css/ventanaBoletos.css b/css/ventanaBoletos.css index b1eb96c..578d8bd 100644 --- a/css/ventanaBoletos.css +++ b/css/ventanaBoletos.css @@ -1,14 +1,14 @@ -/* Contenedor principal que divide la pantalla */ +/* Contenedor principal */ .main-container { display: flex; - height: 80vh; /* Ocupar 80% de la pantalla */ + height: 80vh; gap: 20px; padding: 20px; } -/* Lado izquierdo (imagen + botones) */ +/* Lado izquierdo */ .cardIzq { - flex: 2; /* Ocupar 2/3 del ancho */ + flex: 2; display: flex; flex-direction: column; align-items: center; @@ -21,23 +21,27 @@ margin-bottom: 20px; } -.cardIzq h2{ +.cardIzq h2 { font-size: 44px; margin: 20px; } .zones-container { display: flex; - gap: 10px; + flex-wrap: wrap; + justify-content: space-around; margin-top: 15px; + width: 100%; } -/* Lado derecho (tarjeta con info) */ +/* Lado derecho (tarjetas en columna) */ .cardDer { - flex: 1; /* Ocupar 1/3 del ancho */ + flex: 1; display: flex; + flex-direction: column; /* Se colocan en columna */ align-items: center; justify-content: center; + gap: 20px; /* Espacio entre las tarjetas */ } .card { @@ -47,54 +51,83 @@ width: 100%; max-width: 300px; box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.3); - color:#ffffff; + color: #ffffff; } -.zone-btn { +/* Botón centrado en la parte inferior */ +.button-container { + position: relative; + width: 100%; + text-align: center; + margin-top: 20px; +} + +#comprarBoletos { + padding: 10px 20px; + border-radius: 8px; + font-size: 16px; + font-weight: bold; + cursor: pointer; + transition: all 0.3s ease; + border: none; + background-color: #5e17eb; + color: white; + position: absolute; + left: 50%; + transform: translateX(-50%); +} + +#comprarBoletos:hover { + background-color: #4c11c9; +} +/* Contenedor de asientos dentro de la tarjeta */ +.asientos-container { + display: grid; + grid-template-columns: repeat(5, 1fr); /* 5 columnas por fila */ + gap: 10px; + justify-content: center; + width: 100%; padding: 10px; - margin-left: 10px; - margin-right: 10px; +} + +/* Estilos para cada asiento */ +.asiento { + display: flex; + align-items: center; + justify-content: center; + width: 50px; + height: 50px; border-radius: 8px; cursor: pointer; - font-size: 18px; - color: white; - transition: 0.5s; + font-weight: bold; + transition: all 0.2s ease; + user-select: none; + border: 1px solid #ccc; } -.zone-btn p{ - padding: 10px; +/* Iconos dentro de los asientos */ +.asiento i { + font-size: 24px; /* Ajusta el tamaño del icono */ } -.zone-btn:hover { - transform: scale(1.1); -} - -.vip-zone { background-color: #5e17eb; } -.oro-zone { background-color: #d5ce2d; } -.plata-zone { background-color: #737373; } -.general-zone { background-color: #725e2b; color: rgb(255, 255, 255); } - -.asiento { - display: inline-block; - width: 40px; - height: 40px; - margin: 5px; - text-align: center; - line-height: 40px; - font-size: 1.2em; - border: 1px solid #000; - cursor: pointer; - background-color: #f8f9fa; - border-radius: 5px; -} - -.asiento.seleccionado { +/* Asientos disponibles */ +.asiento.disponible { background-color: #28a745; color: white; } +/* Asientos ocupados */ .asiento.ocupado { background-color: #dc3545; color: white; cursor: not-allowed; } + +/* Asientos seleccionados */ +.asiento.seleccionado { + background-color: #007bff; + color: white; + transform: scale(1.1); + box-shadow: 0 0 5px rgba(255, 255, 255, 0.5); +} + diff --git a/js/ventaBoletos.js b/js/ventaBoletos.js index dff27a9..d646e86 100644 --- a/js/ventaBoletos.js +++ b/js/ventaBoletos.js @@ -1,83 +1,140 @@ document.addEventListener("DOMContentLoaded", async () => { - const urlParams = new URLSearchParams(window.location.search); - const conciertoId = urlParams.get("id"); + const params = new URLSearchParams(window.location.search); + const conciertoId = params.get("id"); + if (!conciertoId) { - alert("No se encontró el ID del concierto."); + console.error("Error: No se proporcionó un ID de concierto en la URL."); return; } try { - const respuesta = await fetch(`controladores/concierto_zonas.php?id=${conciertoId}`); - if (!respuesta.ok) throw new Error("Error al cargar las zonas del concierto"); + const respuesta = await fetch(`controladores/concierto_zonas.php?id_concierto=${conciertoId}`); + if (!respuesta.ok) throw new Error("Error al cargar los datos del concierto"); + + const concierto = await respuesta.json(); + + if (concierto.error) { + console.error(`Error: ${concierto.error}`); + return; + } + + // Mostrar información del concierto + document.getElementById("nombre_concierto").textContent = concierto.nombre_concierto; + document.getElementById("artista").textContent = `Artista: ${concierto.artista}`; + document.getElementById("fecha").textContent = `Fecha: ${concierto.fecha}`; + + // Mostrar zonas del concierto + const zonasContainer = document.getElementById("zonas-container"); + zonasContainer.innerHTML = ""; + + if (!concierto.zonas || concierto.zonas.length === 0) { + console.error("No se encontraron zonas para este concierto."); + return; + } + + concierto.zonas.forEach(zona => { + const zonaBtn = document.createElement("button"); + zonaBtn.classList.add("boton-zona"); + zonaBtn.textContent = `Ver Zona ${zona.nombre_zona}`; + zonaBtn.dataset.idZona = zona.id_zona; + + zonaBtn.addEventListener("click", () => cargarDatosZona(zona)); + + zonasContainer.appendChild(zonaBtn); + }); - const zonas = await respuesta.json(); - cargarZonas(zonas, conciertoId); } catch (error) { - console.error(error); + console.error("Error al obtener los datos del concierto:", error); } }); -function cargarZonas(zonas, conciertoId) { - const container = document.getElementById('zonas-container'); - container.innerHTML = ""; +async function cargarDatosZona(zona) { + if (!zona) { + console.error("Error: Datos de zona no disponibles"); + return; + } - zonas.forEach(zona => { - let div = document.createElement('div'); - div.classList.add('zona', zona.nombre_zona.toLowerCase()); - div.textContent = `${zona.nombre_zona} - ${zona.capacidad} asientos - $${zona.precio}`; - div.onclick = async function () { - document.querySelectorAll('.zona').forEach(el => el.classList.remove('selected')); - div.classList.add('selected'); - await mostrarAsientos(conciertoId, zona.nombre_zona, zona.capacidad); - }; - container.appendChild(div); - }); + // Mostrar información de la zona + document.getElementById("zonaNombre").textContent = `Zona: ${zona.nombre_zona || 'N/A'}`; + document.getElementById("zonaCapacidad").textContent = `Capacidad: ${zona.capacidad || 'N/A'}`; + document.getElementById("zonaPrecio").textContent = `Precio: $${zona.precio || 'N/A'}`; + document.getElementById("asientosDisponibles").textContent = `Disponibles: ${zona.asientos_disponibles ?? 0}`; + document.getElementById("asientosOcupados").textContent = `Ocupados: ${zona.asientos_ocupados ?? 0}`; + + // Cargar los asientos disponibles + await cargarAsientos(zona.id_zona); } -async function mostrarAsientos(conciertoId, nombreZona, capacidad) { - const asientosContainer = document.getElementById('asientos-container'); - asientosContainer.innerHTML = ""; - asientosContainer.style.display = "flex"; +async function cargarAsientos(idZona) { + try { + const respuesta = await fetch(`controladores/obtener_asiento.php?id_zona=${idZona}`); + if (!respuesta.ok) throw new Error("Error al cargar los asientos"); + + const asientos = await respuesta.json(); + + // Seleccionamos el contenedor de asientos dentro de la tarjeta de "Asientos" + const asientosContainer = document.getElementById("asientos-container"); + asientosContainer.innerHTML = ""; // Limpiar antes de agregar nuevos + + asientos.forEach(asiento => { + const asientoDiv = document.createElement("div"); + asientoDiv.classList.add("asiento", asiento.estado); + asientoDiv.dataset.idAsiento = asiento.id_asiento; + asientoDiv.setAttribute("title", `Asiento #${asiento.id_asiento}`); + + // Agregar el icono de Bootstrap Icons + const icono = document.createElement("i"); + icono.classList.add("bi", "bi-person-fill"); + + if (asiento.estado === "disponible") { + asientoDiv.appendChild(icono); + asientoDiv.addEventListener("click", () => seleccionarAsiento(asientoDiv, asiento.id_asiento)); + } else { + icono.style.opacity = "0.3"; // Opacidad para los asientos ocupados + asientoDiv.appendChild(icono); + } + + asientosContainer.appendChild(asientoDiv); + }); + + } catch (error) { + console.error("Error al obtener los asientos:", error); + } +} + +const asientosSeleccionados = new Set(); + +function seleccionarAsiento(elemento, idAsiento) { + if (asientosSeleccionados.has(idAsiento)) { + asientosSeleccionados.delete(idAsiento); + elemento.classList.remove("seleccionado"); + } else { + asientosSeleccionados.add(idAsiento); + elemento.classList.add("seleccionado"); + } + + // Habilitar el botón de compra si hay al menos un asiento seleccionado + document.getElementById("comprarBoletos").disabled = asientosSeleccionados.size === 0; +} + +document.getElementById("comprarBoletos").addEventListener("click", async () => { + if (asientosSeleccionados.size === 0) return; try { - const respuesta = await fetch(`controladores/asientos_ocupados.php?id=${conciertoId}&zona=${nombreZona}`); - if (!respuesta.ok) throw new Error("Error al cargar los asientos ocupados"); - - const asientosOcupados = await respuesta.json(); + const respuesta = await fetch("controladores/comprar_asientos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ asientos: Array.from(asientosSeleccionados) }) + }); - for (let i = 1; i <= capacidad; i++) { - let asiento = document.createElement('div'); - asiento.classList.add('asiento'); - asiento.innerHTML = `<i class="bi bi-person-fill"></i> ${i}`; - - if (asientosOcupados.includes(i)) { - asiento.classList.add('ocupado'); - } else { - asiento.onclick = function () { - asiento.classList.toggle('seleccionado'); - }; - } - asientosContainer.appendChild(asiento); + const resultado = await respuesta.json(); + if (resultado.success) { + alert("Compra realizada con éxito."); + location.reload(); + } else { + alert("Error al realizar la compra."); } } catch (error) { - console.error(error); - alert("Error al cargar los asientos"); + console.error("Error al comprar boletos:", error); } -} - -document.getElementById("confirmarSeleccion").addEventListener("click", () => { - let selectedZona = document.querySelector('.zona.selected'); - if (!selectedZona) { - alert("No has seleccionado ninguna zona."); - return; - } - - let selectedAsientos = document.querySelectorAll('.asiento.seleccionado'); - if (selectedAsientos.length === 0) { - alert("No has seleccionado ningún asiento."); - return; - } - - let asientosSeleccionados = Array.from(selectedAsientos).map(asiento => asiento.textContent.trim()); - alert(`Zona seleccionada: ${selectedZona.textContent}\nAsientos: ${asientosSeleccionados.join(', ')}`); }); diff --git a/ventaBoletos.html b/ventaBoletos.html index 9a19679..33e5958 100644 --- a/ventaBoletos.html +++ b/ventaBoletos.html @@ -6,8 +6,10 @@ <title>Compra de Boletos</title> <script src="https://cdn.tailwindcss.com"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script> - <link rel="stylesheet" href="css/conciertos.css"> <!-- Aquí se incluye el CSS --> + <link rel="stylesheet" href="css/conciertos.css"> <link rel="stylesheet" href="css/ventanaBoletos.css"> + <link rel="stylesheet" + href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css"> </head> <body> <nav> @@ -19,38 +21,41 @@ </div> </nav> + <!-- Contenedor principal --> <div class="main-container"> - <div class="cardIzq"> <h2>Zonas del Concierto</h2> <img src="img/mapa.png" alt="Mapa de zonas del concierto"> - - <div class="zones-container"> - <button class="zone-btn vip-zone" onclick="seleccionarZona('vip')">Zona VIP</button> - <button class="zone-btn oro-zone" onclick="seleccionarZona('oro')">Zona ORO</button> - <button class="zone-btn plata-zone" onclick="seleccionarZona('plata')">Zona PLATA</button> - <button class="zone-btn general-zone" onclick="seleccionarZona('general')">Zona GENERAL</button> - </div> - + <div id="zonas-container" class="zones-container"></div> </div> - + + <!-- Lado derecho con tarjetas --> <div class="cardDer"> <div class="card"> - <h2 class="text-xl font-bold mb-4">Detalles de la Zona</h2> + <h2 class="text-xl font-bold mb-4">Detalles del concierto</h2> <div id="zona-info" class="space-y-2"> - <p><strong>Zona:</strong> <span id="zona-nombre">-</span></p> - <p><strong>Capacidad:</strong> <span id="zona-capacidad">-</span></p> - <p><strong>Precio por asiento:</strong> $<span id="zona-precio">-</span></p> + <h2 id="nombre_concierto">Nombre del Concierto</h2> + <p id="artista">Artista: </p> + <p id="fecha">Fecha: </p> + <h2 id="zonaNombre">Zona</h2> + <p id="zonaCapacidad">Capacidad: </p> + <p id="zonaPrecio">Precio: </p> + <p id="asientosDisponibles">Disponibles: </p> + <p id="asientosOcupados">Ocupados: </p> </div> </div> + <!-- Tarjeta para los asientos dentro de la columna derecha --> + <div class="card"> + <h2 class="text-xl font-bold mb-4">Asientos</h2> + <div id="asientos-container" class="asientos-container"></div> + </div> + </div> </div> - <div id="zonas-container"></div> - <div id="asientos-container" class="asientos-container"></div> - - <div class="text-center mt-3"> - <button class="btn btn-primary" id="confirmarSeleccion">Confirmar selección</button> + <!-- Contenedor del botón centrado en la parte inferior --> + <div class="button-container"> + <button id="comprarBoletos" class="btn btn-primary" disabled>Comprar Asientos</button> </div> <script defer src="js/ventaBoletos.js"></script>