commit 2de036f40601f6d54e433371139d9a47ec4df7bb Author: alexis.palestina <zs22016131@estudiantes.uv.mx> Date: Thu Mar 13 08:58:42 2025 -0600 Proyecto BoleTC diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..0aae3d2 Binary files /dev/null and b/.DS_Store differ diff --git a/css/agregar_evento.css b/css/agregar_evento.css new file mode 100644 index 0000000..15ea19a --- /dev/null +++ b/css/agregar_evento.css @@ -0,0 +1,65 @@ +/* Estilos generales */ +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; + text-align: center; +} + +h1 { + color: #333; + margin-top: 20px; +} + +/* Contenedor del formulario */ +form { + background: white; + padding: 20px; + max-width: 400px; + margin: 20px auto; + border-radius: 10px; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2); +} + +/* Estilos de etiquetas */ +label { + display: block; + font-weight: bold; + margin: 10px 0 5px; +} + +/* Estilos de los inputs y selects */ +input, select { + width: 100%; + padding: 8px; + margin-bottom: 10px; + border-radius: 5px; + border: 1px solid #ccc; + font-size: 16px; +} + +/* Botón de agregar evento */ +button { + background-color: #008cba; + color: white; + padding: 10px 15px; + border: none; + border-radius: 5px; + font-weight: bold; + font-size: 16px; + cursor: pointer; + width: 100%; +} + +button:hover { + background-color: #005f7f; +} + +/* Mensaje de éxito o error */ +#mensaje { + margin-top: 15px; + font-size: 16px; + font-weight: bold; + color: #333; +} diff --git a/css/comprobante.css b/css/comprobante.css new file mode 100644 index 0000000..afacc96 --- /dev/null +++ b/css/comprobante.css @@ -0,0 +1,60 @@ +/* Estilos generales */ +body { + font-family: 'Arial', sans-serif; + background-color: #f4f4f4; + color: #333; + margin: 0; + padding: 20px; + display: flex; + flex-direction: column; + align-items: center; +} + +/* Contenedor principal */ +.comprobante-container { + background: white; + padding: 20px; + border-radius: 10px; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2); + width: 50%; + text-align: center; +} + +/* Título */ +h1 { + color: #4d4d4d; + font-size: 24px; + margin-bottom: 20px; +} + +/* Información del boleto */ +.boleto { + background: #f9f9f9; + padding: 15px; + border-radius: 8px; + margin-bottom: 10px; +} + +/* Separador entre boletos */ +hr { + border: none; + height: 1px; + background: #ccc; + margin: 20px 0; +} + +/* Botón de volver */ +.boton-volver { + display: inline-block; + margin-top: 20px; + padding: 10px 15px; + background-color: #008cba; + color: white; + text-decoration: none; + font-weight: bold; + border-radius: 5px; +} + +.boton-volver:hover { + background-color: #005f7f; +} diff --git a/css/editar_evento.css b/css/editar_evento.css new file mode 100644 index 0000000..9e7546f --- /dev/null +++ b/css/editar_evento.css @@ -0,0 +1,48 @@ +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; + text-align: center; +} + +h1 { + color: #333; +} + +form { + background: white; + padding: 20px; + max-width: 400px; + margin: 20px auto; + border-radius: 10px; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2); +} + +label { + display: block; + font-weight: bold; + margin: 10px 0 5px; +} + +input, select { + width: 100%; + padding: 8px; + margin-bottom: 10px; + border-radius: 5px; + border: 1px solid #ccc; +} + +button { + background-color: #008cba; + color: white; + padding: 10px 15px; + border: none; + border-radius: 5px; + font-weight: bold; + cursor: pointer; +} + +button:hover { + background-color: #005f7f; +} diff --git a/css/estilos.css b/css/estilos.css new file mode 100644 index 0000000..1a4fabe --- /dev/null +++ b/css/estilos.css @@ -0,0 +1,76 @@ +/* Contenedor del carrusel */ +.carousel-container { + position: relative; + width: 100%; + overflow: hidden; + padding: 20px; + background: #f4f4f4; +} + +/* Contenedor de conciertos con desplazamiento horizontal */ +.contenedor-conciertos { + display: flex; + overflow-x: auto; + scroll-behavior: smooth; + gap: 15px; + padding: 10px; + white-space: nowrap; +} + +/* Ocultar scrollbar */ +.contenedor-conciertos::-webkit-scrollbar { + display: none; +} + +/* Estilos para cada tarjeta de concierto */ +.concierto { + background: white; + padding: 15px; + border-radius: 10px; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2); + text-align: center; + width: 250px; + flex-shrink: 0; /* Evita que se reduzcan de tamaño */ +} + +/* Botones de desplazamiento */ +.scroll-btn { + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: rgba(0, 0, 0, 0.5); + color: white; + border: none; + padding: 10px 15px; + cursor: pointer; + font-size: 20px; + border-radius: 50%; +} + +.scroll-btn:hover { + background-color: rgba(0, 0, 0, 0.8); +} + +.scroll-btn.left { + left: 10px; +} + +.scroll-btn.right { + right: 10px; +} + +.btn-volver { + display: inline-block; + background-color: #008cba; + color: white; + padding: 10px 15px; + text-decoration: none; + border-radius: 5px; + font-weight: bold; + margin-bottom: 15px; + transition: background 0.3s; +} + +.btn-volver:hover { + background-color: #005f7f; +} diff --git a/css/venta_boletos.css b/css/venta_boletos.css new file mode 100644 index 0000000..76040cb --- /dev/null +++ b/css/venta_boletos.css @@ -0,0 +1,127 @@ +/* Estilos generales */ +body { + font-family: 'Arial', sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; + text-align: center; +} + +/* Contenedor principal */ +.container { + width: 90%; + max-width: 800px; + margin: 20px auto; + background: white; + padding: 20px; + border-radius: 10px; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2); +} + +/* Título */ +h1 { + color: #4d4d4d; +} + +/* Select de conciertos */ +select { + padding: 10px; + margin: 10px 0; + border-radius: 5px; + border: 1px solid #ccc; + font-size: 16px; +} + +/* Contenedor de zonas */ +.zona-container { + margin-top: 20px; +} + +/* Nombre de la zona */ +.zona-titulo { + font-size: 20px; + font-weight: bold; + color: #333; + margin-bottom: 10px; + text-align: center; +} + +/* Contenedor de asientos */ +#asientosContainer { + display: flex; + flex-direction: column; + gap: 20px; + align-items: center; +} + +/* Fila de asientos */ +.fila-asientos { + display: flex; + gap: 10px; + justify-content: center; + flex-wrap: wrap; +} + +/* VIP: en una sola fila */ +#asientosVIP { + display: flex; + gap: 10px; + justify-content: center; +} + +/* General: en 2 filas de 5 */ +#asientosGeneral { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 10px; + justify-content: center; +} + +/* Estilos de los asientos */ +.asiento { + width: 50px; + height: 50px; + line-height: 50px; + text-align: center; + border-radius: 5px; + font-weight: bold; + cursor: pointer; +} + +/* Asientos disponibles */ +.asiento.disponible { + background-color: #4CAF50; + color: white; + border: 2px solid #3e8e41; +} + +/* Asientos vendidos */ +.asiento.vendido { + background-color: #d9534f; + color: white; + border: 2px solid #a94442; + cursor: not-allowed; +} + +/* Asientos seleccionados */ +.asiento.seleccionado { + background-color: #FFD700; + color: black; + border: 2px solid #DAA520; +} + +/* Botón de compra */ +button { + background-color: #008cba; + color: white; + padding: 12px 20px; + border: none; + border-radius: 5px; + font-size: 16px; + cursor: pointer; + margin-top: 20px; +} + +button:hover { + background-color: #005f7f; +} diff --git a/img/.DS_Store b/img/.DS_Store new file mode 100644 index 0000000..109e1db Binary files /dev/null and b/img/.DS_Store differ diff --git a/img/default.jpg b/img/default.jpg new file mode 100644 index 0000000..6b9f3fd Binary files /dev/null and b/img/default.jpg differ diff --git a/js/agregar_evento.js b/js/agregar_evento.js new file mode 100644 index 0000000..b0057bc --- /dev/null +++ b/js/agregar_evento.js @@ -0,0 +1,22 @@ +document.getElementById("formConcierto").addEventListener("submit", function(e) { + e.preventDefault(); + + let formData = new FormData(this); + + console.log("Datos enviados:"); + for (let pair of formData.entries()) { + console.log(pair[0] + ": " + pair[1]); // Ver qué valores se están enviando + } + + fetch("../php/insertar_concierto.php", { + method: "POST", // ✅ Asegurar que la solicitud es POST + body: formData + }) + .then(response => response.text()) + .then(data => { + console.log("Respuesta del servidor:", data); + alert(data); // Mensaje de éxito o error + this.reset(); + }) + .catch(error => console.error("Error:", error)); +}); diff --git a/js/conciertos.js b/js/conciertos.js new file mode 100644 index 0000000..96cd770 --- /dev/null +++ b/js/conciertos.js @@ -0,0 +1,37 @@ +document.addEventListener("DOMContentLoaded", function() { + fetch("../php/conciertos.php") + .then(response => response.json()) + .then(data => { + let div = document.getElementById("conciertos"); + div.innerHTML = ""; // Limpiar contenido + + data.forEach(concierto => { + let evento = document.createElement("div"); + evento.classList.add("concierto"); + evento.innerHTML = ` + <img src="${concierto.imagen}" alt="${concierto.nombre}"> + <h2>${concierto.nombre}</h2> + <p><strong>Artista:</strong> ${concierto.artista}</p> + <p><strong>Ubicación:</strong> ${concierto.direccion}</p> + <p><strong>Fecha:</strong> ${concierto.fecha} - ${concierto.hora}</p> + <button class="btn-comprar" onclick="comprarBoletos(${concierto.id})">COMPRAR</button> + `; + div.appendChild(evento); + }); + }) + .catch(error => console.error("Error cargando conciertos:", error)); +}); + +function comprarBoletos(conciertoId) { + window.location.href = `venta_boletos.html?concierto_id=${conciertoId}`; +} + +// Función para desplazar los conciertos +function scrollConciertos(direction) { + const container = document.getElementById("conciertos"); + const scrollAmount = 300; // Ajusta el valor para controlar la velocidad de desplazamiento + container.scrollBy({ + left: direction * scrollAmount, + behavior: "smooth" + }); +} diff --git a/js/editar_evento.js b/js/editar_evento.js new file mode 100644 index 0000000..60af9be --- /dev/null +++ b/js/editar_evento.js @@ -0,0 +1,93 @@ +document.addEventListener("DOMContentLoaded", function() { + cargarEventos(); +}); + +// 🔹 Cargar eventos en el desplegable +function cargarEventos() { + fetch("../php/obtener_conciertos.php") + .then(response => response.json()) + .then(data => { + let select = document.getElementById("eventoSeleccionado"); + select.innerHTML = '<option value="">Seleccione un evento</option>'; + + data.forEach(concierto => { + let option = document.createElement("option"); + option.value = concierto.id; + option.textContent = concierto.nombre; + select.appendChild(option); + }); + + // Evento para cargar detalles cuando se seleccione un evento + select.addEventListener("change", function() { + cargarDatosEvento(select.value); + }); + }) + .catch(error => console.error("Error cargando conciertos:", error)); +} + +// 🔹 Cargar los detalles del evento seleccionado +function cargarDatosEvento(eventoId) { + if (!eventoId) return; + + fetch(`../php/obtener_detalle_concierto.php?id=${eventoId}`) + .then(response => response.json()) + .then(data => { + document.querySelector("input[name='nombre']").value = data.nombre; + document.querySelector("input[name='artista']").value = data.artista; + document.querySelector("input[name='fecha']").value = data.fecha; + document.querySelector("input[name='hora']").value = data.hora; + document.querySelector("input[name='direccion']").value = data.direccion; + document.querySelector("input[name='precio_vip']").value = data.precio_vip; + document.querySelector("input[name='precio_general']").value = data.precio_general; + }) + .catch(error => console.error("Error cargando detalles del evento:", error)); +} + +// 🔹 Guardar cambios al hacer submit +document.getElementById("formEditarEvento").addEventListener("submit", function(e) { + e.preventDefault(); + + let formData = new FormData(this); + + fetch("../php/editar_concierto.php", { + method: "POST", + body: formData + }) + .then(response => response.text()) + .then(data => { + alert(data); + cargarEventos(); // Recargar la lista de eventos + }) + .catch(error => console.error("Error:", error)); +}); + +// 🔹 Eliminar evento +document.getElementById("btnEliminar").addEventListener("click", function() { + let eventoId = document.getElementById("eventoSeleccionado").value; + + if (!eventoId) { + alert("Selecciona un evento para eliminar."); + return; + } + + if (!confirm("¿Estás seguro de que quieres eliminar este evento?")) { + return; + } + + fetch("../php/eliminar_concierto.php", { + method: "POST", + body: JSON.stringify({ id: eventoId }), + headers: { "Content-Type": "application/json" } + }) + .then(response => response.text()) + .then(data => { + alert(data); + cargarEventos(); // Recargar la lista de eventos + }) + .catch(error => console.error("Error eliminando evento:", error)); +}); + +// 🔹 Botón de volver al inicio +document.getElementById("btnVolver").addEventListener("click", function() { + window.location.href = "../views/index.html"; +}); diff --git a/js/venta_boletos.js b/js/venta_boletos.js new file mode 100644 index 0000000..fed4a0c --- /dev/null +++ b/js/venta_boletos.js @@ -0,0 +1,105 @@ +document.addEventListener("DOMContentLoaded", function() { + cargarConciertos(); +}); + +function cargarConciertos() { + fetch("../php/conciertos.php") + .then(response => response.json()) + .then(data => { + let select = document.getElementById("concierto"); + select.innerHTML = '<option value="">Selecciona un concierto</option>'; + + data.forEach(concierto => { + let option = document.createElement("option"); + option.value = concierto.id; + option.textContent = concierto.nombre; + select.appendChild(option); + }); + + select.addEventListener("change", function() { + cargarAsientos(select.value); + }); + }) + .catch(error => console.error("Error cargando conciertos:", error)); +} + +function cargarAsientos(conciertoId) { + fetch(`../php/asientos.php?concierto_id=${conciertoId}`) + .then(response => response.json()) + .then(data => { + console.log("Asientos recibidos:", data); + + // 💡 Verificamos que 'data' es un array antes de hacer forEach + if (!Array.isArray(data)) { + console.error("Error: La respuesta del servidor no es un array.", data); + return; + } + + let containerVIP = document.getElementById("asientosVIP"); + let containerGeneral = document.getElementById("asientosGeneral"); + + containerVIP.innerHTML = ""; + containerGeneral.innerHTML = ""; + + if (data.length === 0) { + containerVIP.innerHTML = "<p>No hay asientos VIP disponibles.</p>"; + containerGeneral.innerHTML = "<p>No hay asientos Generales disponibles.</p>"; + return; + } + + data.forEach(asiento => { + let div = document.createElement("div"); + div.classList.add("asiento", asiento.estado); + div.textContent = `Asiento ${asiento.numero}`; + + if (asiento.estado === "disponible") { + div.addEventListener("click", () => seleccionarAsiento(div, asiento.id)); + } + + if (asiento.zona === "VIP") { + containerVIP.appendChild(div); + } else { + containerGeneral.appendChild(div); + } + }); + }) + .catch(error => console.error("Error cargando asientos:", error)); +} + +let asientosSeleccionados = []; + +function seleccionarAsiento(element, asientoId) { + if (asientosSeleccionados.includes(asientoId)) { + asientosSeleccionados = asientosSeleccionados.filter(id => id !== asientoId); + element.classList.remove("seleccionado"); + } else { + asientosSeleccionados.push(asientoId); + element.classList.add("seleccionado"); + } +} + +document.getElementById("confirmarCompra").addEventListener("click", function() { + if (asientosSeleccionados.length === 0) { + alert("Selecciona al menos un asiento."); + return; + } + + const conciertoId = document.getElementById("concierto").value; + + fetch("../php/comprar_asiento.php", { + method: "POST", + body: JSON.stringify({ concierto_id: conciertoId, asientos: asientosSeleccionados }), + headers: { "Content-Type": "application/json" } + }) + .then(response => response.json()) + .then(data => { + if (data.error) { + alert("Error: " + data.error); + } else { + alert("Compra realizada con éxito."); + window.location.href = `../php/comprobante.php?transaction_id=${data.transaction_id}`; + } + }) + .catch(error => console.error("Error al comprar boletos:", error)); +}); + diff --git a/php/asientos.php b/php/asientos.php new file mode 100644 index 0000000..e66555e --- /dev/null +++ b/php/asientos.php @@ -0,0 +1,36 @@ +<?php +include 'conexion.php'; + +$concierto_id = $_GET['concierto_id'] ?? null; + +if (!$concierto_id) { + die(json_encode(["error" => "No se proporcionó un ID de concierto."])); +} + +// Revisar si existen zonas para el concierto +$sql_zonas = "SELECT id FROM zonas WHERE concierto_id = ?"; +$stmt_zonas = $conn->prepare($sql_zonas); +$stmt_zonas->bind_param("i", $concierto_id); +$stmt_zonas->execute(); +$result_zonas = $stmt_zonas->get_result(); + +if ($result_zonas->num_rows === 0) { + die(json_encode(["error" => "No hay zonas registradas para este concierto."])); +} + +$sql = "SELECT asientos.id, asientos.numero, asientos.estado, zonas.nombre AS zona + FROM asientos + JOIN zonas ON asientos.zona_id = zonas.id + WHERE zonas.concierto_id = ?"; +$stmt = $conn->prepare($sql); +$stmt->bind_param("i", $concierto_id); +$stmt->execute(); +$result = $stmt->get_result(); + +$asientos = []; +while ($row = $result->fetch_assoc()) { + $asientos[] = $row; +} + +echo json_encode($asientos); +?> diff --git a/php/comprar_asiento.php b/php/comprar_asiento.php new file mode 100644 index 0000000..a6f4f19 --- /dev/null +++ b/php/comprar_asiento.php @@ -0,0 +1,57 @@ +<?php +error_reporting(E_ALL); +ini_set('display_errors', 1); + +include 'conexion.php'; + +header("Content-Type: application/json"); + +$data = json_decode(file_get_contents("php://input"), true); +$asientos = $data['asientos'] ?? []; +$concierto_id = $data['concierto_id'] ?? null; + +if (empty($asientos) || !$concierto_id) { + echo json_encode(["error" => "No se recibieron asientos para la compra."]); + exit; +} + +$conn->begin_transaction(); + +try { + // Generar un ID de transacción único + $transaction_id = uniqid("trx_"); + + foreach ($asientos as $asiento_id) { + // **Depuración** + error_log("Procesando asiento ID: $asiento_id para Concierto ID: $concierto_id"); + + // Marcar asiento como vendido + $sql = "UPDATE asientos SET estado = 'vendido' WHERE id = ?"; + $stmt = $conn->prepare($sql); + if (!$stmt) { + throw new Exception("Error en la preparación del UPDATE: " . $conn->error); + } + $stmt->bind_param("i", $asiento_id); + $stmt->execute(); + + // Insertar en la tabla de boletos + $sql_boleto = "INSERT INTO boletos (asiento_id, concierto_id, transaction_id, fecha_venta, precio) + SELECT ?, ?, ?, NOW(), z.precio FROM asientos a + JOIN zonas z ON a.zona_id = z.id WHERE a.id = ?"; + $stmt_boleto = $conn->prepare($sql_boleto); + if (!$stmt_boleto) { + throw new Exception("Error en la preparación del INSERT: " . $conn->error); + } + $stmt_boleto->bind_param("iisi", $asiento_id, $concierto_id, $transaction_id, $asiento_id); + $stmt_boleto->execute(); + } + + $conn->commit(); + echo json_encode(["success" => "Compra realizada con éxito", "transaction_id" => $transaction_id]); + +} catch (Exception $e) { + $conn->rollback(); + error_log("Error en la compra: " . $e->getMessage()); + echo json_encode(["error" => "Error en la compra: " . $e->getMessage()]); +} +?> diff --git a/php/comprobante.php b/php/comprobante.php new file mode 100644 index 0000000..17705ea --- /dev/null +++ b/php/comprobante.php @@ -0,0 +1,51 @@ +<?php +include 'conexion.php'; + +$transaction_id = $_GET['transaction_id'] ?? null; + +if (!$transaction_id) { + die("Error: No se proporcionó un ID de transacción."); +} + +$sql = "SELECT b.id, c.nombre AS concierto, c.hora, a.numero, z.nombre AS zona, b.fecha_venta, b.precio + FROM boletos b + JOIN asientos a ON b.asiento_id = a.id + JOIN zonas z ON a.zona_id = z.id + JOIN conciertos c ON z.concierto_id = c.id + WHERE b.transaction_id = ?"; +$stmt = $conn->prepare($sql); +$stmt->bind_param("s", $transaction_id); +$stmt->execute(); +$result = $stmt->get_result(); +$boletos = $result->fetch_all(MYSQLI_ASSOC); +?> + +<!DOCTYPE html> +<html lang="es"> +<head> + <meta charset="UTF-8"> + <title>Comprobante de Compra</title> + <link rel="stylesheet" href="../css/comprobante.css"> +</head> +<body> + <div class="comprobante-container"> + <h1>Comprobante de Compra</h1> + <?php if (empty($boletos)): ?> + <p>No hay boletos registrados para esta compra.</p> + <?php else: ?> + <?php foreach ($boletos as $boleto): ?> + <div class="boleto"> + <p><strong>Concierto:</strong> <?= $boleto['concierto'] ?></p> + <p><strong>Hora:</strong> <?= $boleto['hora'] ?></p> + <p><strong>Zona:</strong> <?= $boleto['zona'] ?></p> + <p><strong>Asiento:</strong> <?= $boleto['numero'] ?></p> + <p><strong>Precio:</strong> $<?= number_format($boleto['precio'], 2) ?></p> + <p><strong>Fecha de compra:</strong> <?= $boleto['fecha_venta'] ?></p> + </div> + <hr> + <?php endforeach; ?> + <?php endif; ?> + <a href="../views/venta_boletos.html" class="boton-volver">Volver</a> + </div> +</body> +</html> diff --git a/php/conciertos.php b/php/conciertos.php new file mode 100644 index 0000000..5973f29 --- /dev/null +++ b/php/conciertos.php @@ -0,0 +1,12 @@ +<?php +include 'conexion.php'; + +$sql = "SELECT * FROM conciertos"; +$result = $conn->query($sql); + +$conciertos = []; +while ($row = $result->fetch_assoc()) { + $conciertos[] = $row; +} +echo json_encode($conciertos); +?> diff --git a/php/conexion.php b/php/conexion.php new file mode 100644 index 0000000..0cb3f36 --- /dev/null +++ b/php/conexion.php @@ -0,0 +1,13 @@ +<?php +$host = "127.0.0.1"; +$user = "root"; +$password = "root"; +$dbname = "BoleTC"; +$port = 8889; // Puerto de MySQL en MAMP + +$conn = new mysqli($host, $user, $password, $dbname, $port); + +if ($conn->connect_error) { + die("Error de conexión: " . $conn->connect_error); +} +?> \ No newline at end of file diff --git a/php/editar_concierto.php b/php/editar_concierto.php new file mode 100644 index 0000000..b9db19b --- /dev/null +++ b/php/editar_concierto.php @@ -0,0 +1,47 @@ +<?php +include 'conexion.php'; + +if ($_SERVER["REQUEST_METHOD"] == "POST") { + $id = $_POST['id']; + $nombre = $_POST['nombre']; + $artista = $_POST['artista']; + $fecha = $_POST['fecha']; + $hora = $_POST['hora']; + $direccion = $_POST['direccion']; + $precio_vip = $_POST['precio_vip']; + $precio_general = $_POST['precio_general']; + + // Verificar si se subió una nueva imagen + if (!empty($_FILES["imagen"]["name"])) { + $imagenNombre = time() . "_" . $_FILES["imagen"]["name"]; + $rutaImagen = "../img/" . $imagenNombre; + move_uploaded_file($_FILES["imagen"]["tmp_name"], $rutaImagen); + + // Actualizar con nueva imagen + $sql = "UPDATE conciertos SET nombre=?, artista=?, fecha=?, hora=?, direccion=?, imagen=? WHERE id=?"; + $stmt = $conn->prepare($sql); + $stmt->bind_param("ssssssi", $nombre, $artista, $fecha, $hora, $direccion, $imagenNombre, $id); + } else { + // Actualizar sin cambiar la imagen + $sql = "UPDATE conciertos SET nombre=?, artista=?, fecha=?, hora=?, direccion=? WHERE id=?"; + $stmt = $conn->prepare($sql); + $stmt->bind_param("sssssi", $nombre, $artista, $fecha, $hora, $direccion, $id); + } + + if ($stmt->execute()) { + // Actualizar precios de zonas + $sql_zonas = "UPDATE zonas SET precio = CASE + WHEN nombre = 'VIP' THEN ? + WHEN nombre = 'General' THEN ? + ELSE precio END + WHERE concierto_id = ?"; + $stmt_zonas = $conn->prepare($sql_zonas); + $stmt_zonas->bind_param("ddi", $precio_vip, $precio_general, $id); + $stmt_zonas->execute(); + + echo "Concierto actualizado correctamente"; + } else { + echo "Error al actualizar concierto: " . $conn->error; + } +} +?> diff --git a/php/eliminar_concierto.php b/php/eliminar_concierto.php new file mode 100644 index 0000000..501f53b --- /dev/null +++ b/php/eliminar_concierto.php @@ -0,0 +1,20 @@ +<?php +include 'conexion.php'; + +$data = json_decode(file_get_contents("php://input"), true); +$id = $data['id'] ?? null; + +if (!$id) { + die("Error: No se recibió un ID válido."); +} + +$sql = "DELETE FROM conciertos WHERE id = ?"; +$stmt = $conn->prepare($sql); +$stmt->bind_param("i", $id); + +if ($stmt->execute()) { + echo "Concierto eliminado correctamente."; +} else { + echo "Error al eliminar concierto: " . $conn->error; +} +?> diff --git a/php/eliminar_conciertos_pasados.php b/php/eliminar_conciertos_pasados.php new file mode 100644 index 0000000..d8aee80 --- /dev/null +++ b/php/eliminar_conciertos_pasados.php @@ -0,0 +1,18 @@ +<?php +include 'conexion.php'; + +// Obtener la fecha actual +$fecha_actual = date("Y-m-d"); + +// Eliminar conciertos cuya fecha ya pasó +$sql = "DELETE FROM conciertos WHERE fecha < ?"; +$stmt = $conn->prepare($sql); +$stmt->bind_param("s", $fecha_actual); +$sql = "DELETE FROM conciertos WHERE CONCAT(fecha, ' ', hora) < NOW()"; + +if ($stmt->execute()) { + echo "Conciertos pasados eliminados."; +} else { + echo "Error al eliminar conciertos: " . $stmt->error; +} +?> diff --git a/php/insertar_concierto.php b/php/insertar_concierto.php new file mode 100644 index 0000000..78dbd24 --- /dev/null +++ b/php/insertar_concierto.php @@ -0,0 +1,83 @@ +<?php +error_reporting(E_ALL); +ini_set('display_errors', 1); + +include 'conexion.php'; + +if ($_SERVER["REQUEST_METHOD"] !== "POST") { + die("Error: La solicitud no es POST."); +} + +$nombre = $_POST['nombre'] ?? ''; +$artista = $_POST['artista'] ?? ''; +$fecha = $_POST['fecha'] ?? ''; +$hora = $_POST['hora'] ?? ''; +$direccion = $_POST['direccion'] ?? ''; +$precio_vip = $_POST['precio_vip'] ?? null; +$precio_general = $_POST['precio_general'] ?? null; + +if (empty($nombre) || empty($artista) || empty($fecha) || empty($hora) || empty($direccion) || empty($precio_vip) || empty($precio_general)) { + die("Error: Todos los campos son obligatorios."); +} + +// Manejo de imagen +if (!empty($_FILES["imagen"]["name"])) { + $extension = pathinfo($_FILES["imagen"]["name"], PATHINFO_EXTENSION); + $imagenNombre = time() . "_" . uniqid() . "." . $extension; + $rutaImagen = __DIR__ . "/../img/" . $imagenNombre; + + if (!move_uploaded_file($_FILES["imagen"]["tmp_name"], $rutaImagen)) { + die("Error: No se pudo mover la imagen."); + } +} else { + $imagenNombre = "default.jpg"; +} + +$conn->begin_transaction(); + +try { + // Insertar el concierto con hora + $sql = "INSERT INTO conciertos (nombre, artista, fecha, hora, direccion, imagen) VALUES (?, ?, ?, ?, ?, ?)"; + $stmt = $conn->prepare($sql); + $stmt->bind_param("ssssss", $nombre, $artista, $fecha, $hora, $direccion, $imagenNombre); + $stmt->execute(); + $concierto_id = $stmt->insert_id; + + // Insertar las zonas (VIP y General) + $sql_zonas = "INSERT INTO zonas (concierto_id, nombre, capacidad, precio) VALUES + (?, 'VIP', 5, ?), + (?, 'General', 10, ?)"; + $stmt_zonas = $conn->prepare($sql_zonas); + $stmt_zonas->bind_param("idid", $concierto_id, $precio_vip, $concierto_id, $precio_general); + $stmt_zonas->execute(); + + // Obtener los IDs de las zonas insertadas + $zona_vip_id = $conn->insert_id; + $zona_general_id = $zona_vip_id + 1; + + // Insertar los asientos (VIP y General) + $sql_asientos = "INSERT INTO asientos (zona_id, numero, estado) VALUES "; + $values = []; + $params = []; + + for ($i = 1; $i <= 5; $i++) { + $values[] = "(?, ?, 'disponible')"; + array_push($params, $zona_vip_id, $i); + } + for ($i = 1; $i <= 10; $i++) { + $values[] = "(?, ?, 'disponible')"; + array_push($params, $zona_general_id, $i); + } + + $sql_asientos .= implode(", ", $values); + $stmt_asientos = $conn->prepare($sql_asientos); + $stmt_asientos->bind_param(str_repeat("ii", count($params) / 2), ...$params); + $stmt_asientos->execute(); + + $conn->commit(); + echo "Concierto agregado con éxito."; +} catch (Exception $e) { + $conn->rollback(); + die("Error en la transacción: " . $e->getMessage()); +} +?> diff --git a/php/obtener_conciertos.php b/php/obtener_conciertos.php new file mode 100644 index 0000000..660e1d1 --- /dev/null +++ b/php/obtener_conciertos.php @@ -0,0 +1,13 @@ +<?php +include 'conexion.php'; + +$sql = "SELECT id, nombre FROM conciertos"; +$result = $conn->query($sql); + +$conciertos = []; +while ($row = $result->fetch_assoc()) { + $conciertos[] = $row; +} +header('Content-Type: application/json'); +echo json_encode($conciertos); +?> diff --git a/php/obtener_detalle_concierto.php b/php/obtener_detalle_concierto.php new file mode 100644 index 0000000..b6ec238 --- /dev/null +++ b/php/obtener_detalle_concierto.php @@ -0,0 +1,38 @@ +<?php +include 'conexion.php'; + +$id = $_GET['id'] ?? null; +if (!$id) { + die(json_encode(["error" => "No se proporcionó un ID de evento."])); +} + +// Obtener detalles básicos del concierto +$sql = "SELECT nombre, artista, fecha, hora, direccion FROM conciertos WHERE id = ?"; +$stmt = $conn->prepare($sql); +$stmt->bind_param("i", $id); +$stmt->execute(); +$result = $stmt->get_result(); +$concierto = $result->fetch_assoc(); + +if (!$concierto) { + die(json_encode(["error" => "Concierto no encontrado."])); +} + +// Obtener precios de zonas +$sql_zonas = "SELECT nombre, precio FROM zonas WHERE concierto_id = ?"; +$stmt = $conn->prepare($sql_zonas); +$stmt->bind_param("i", $id); +$stmt->execute(); +$result = $stmt->get_result(); +$zonas = $result->fetch_all(MYSQLI_ASSOC); + +foreach ($zonas as $zona) { + if ($zona['nombre'] === 'VIP') { + $concierto['precio_vip'] = $zona['precio']; + } else if ($zona['nombre'] === 'General') { + $concierto['precio_general'] = $zona['precio']; + } +} + +echo json_encode($concierto); +?> diff --git a/views/agregar_evento.html b/views/agregar_evento.html new file mode 100644 index 0000000..9e7bb34 --- /dev/null +++ b/views/agregar_evento.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<html lang="es"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Agregar Evento - BoleTC</title> + <link rel="stylesheet" href="../css/agregar_evento.css"> +</head> +<body> + + <a href="index.html" class="btn-volver">← Volver</a> + + <h1>Agregar Nuevo Evento</h1> + + <form id="formConcierto" action="../php/insertar_concierto.php" method="POST" enctype="multipart/form-data"> + <label>Nombre del Concierto:</label> + <input type="text" name="nombre" required> + + <label>Artista:</label> + <input type="text" name="artista" required> + + <label>Fecha del Concierto:</label> + <input type="date" name="fecha" required> + + <label>Hora del Concierto:</label> + <input type="time" name="hora" required> + + <label>Dirección:</label> + <input type="text" name="direccion" required> + + <label>Imagen del Concierto:</label> + <input type="file" name="imagen" accept="image/*" required> + + <h3>Zonas</h3> + + <div class="zona-container"> + <label>Zona: <strong>VIP</strong></label> + <input type="hidden" name="zona_vip" value="VIP"> + <label>Capacidad:</label> + <input type="number" value="5" readonly> <!-- No editable --> + <label>Precio:</label> + <input type="number" name="precio_vip" min="1" required> + </div> + + <div class="zona-container"> + <label>Zona: <strong>General</strong></label> + <input type="hidden" name="zona_general" value="General"> + <label>Capacidad:</label> + <input type="number" value="10" readonly> <!-- No editable --> + <label>Precio:</label> + <input type="number" name="precio_general" min="1" required> + </div> + + <button type="submit">Agregar Concierto</button> + </form> + + <div id="mensaje"></div> + + <script src="../js/agregar_evento.js"></script> + +</body> +</html> diff --git a/views/editar_evento.html b/views/editar_evento.html new file mode 100644 index 0000000..649e267 --- /dev/null +++ b/views/editar_evento.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<html lang="es"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Editar Evento - BoleTC</title> + <link rel="stylesheet" href="../css/editar_evento.css"> +</head> +<body> + + <a href="index.html" class="btn-volver">← Volver</a> + + <h1>Editar Evento</h1> + + <form id="formEditarEvento" enctype="multipart/form-data"> + <label>Seleccionar Evento:</label> + <select id="eventoSeleccionado" name="id" required> + <option value="">Seleccione un evento</option> + </select> + + <label>Nuevo Nombre:</label> + <input type="text" name="nombre"> + + <label>Nuevo Artista:</label> + <input type="text" name="artista"> + + <label>Nueva Fecha:</label> + <input type="date" name="fecha"> + + <label>Nueva Hora:</label> + <input type="time" name="hora"> + + <label>Nueva Dirección:</label> + <input type="text" name="direccion"> + + <label>Precio VIP:</label> + <input type="number" name="precio_vip" min="0" step="0.01" required> + + <label>Precio General:</label> + <input type="number" name="precio_general" min="0" step="0.01" required> + + <label>Nueva Imagen (opcional):</label> + <input type="file" name="imagen" accept="image/*"> + + <button type="submit">Actualizar Concierto</button> + <button type="button" id="btnEliminar">Eliminar Concierto</button> + </form> + + <div id="mensaje"></div> + + <script src="../js/editar_evento.js"></script> + +</body> +</html> diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..8cb1127 --- /dev/null +++ b/views/index.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html lang="es"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>BoleTC - Inicio</title> + <link rel="stylesheet" href="../css/estilos.css"> + <script src="../js/conciertos.js" defer></script> +</head> +<body> + + <!-- Banner superior --> + <header> + <h1>BoleTC</h1> + <a href="agregar_evento.html" class="btn">Agregar Evento</a> + <a href="editar_evento.html" class="btn">Editar Evento</a> + </header> + + <!-- Contenedor principal con botones de desplazamiento --> + <div class="carousel-container"> + <button class="scroll-btn left" onclick="scrollConciertos(-1)">❮</button> + <div class="contenedor-conciertos" id="conciertos"></div> + <button class="scroll-btn right" onclick="scrollConciertos(1)">❯</button> + </div> + +</body> +</html> diff --git a/views/venta_boletos.html b/views/venta_boletos.html new file mode 100644 index 0000000..91df5b1 --- /dev/null +++ b/views/venta_boletos.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="es"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Venta de Boletos - BoleTC</title> + <link rel="stylesheet" href="../css/venta_boletos.css"> + <script src="../js/venta_boletos.js" defer></script> +</head> +<body> + + <a href="index.html" class="btn-volver">← Volver</a> + + <div class="container"> + <h1>Venta de Boletos</h1> + + <label for="concierto">Seleccionar Concierto:</label> + <select id="concierto"></select> + + <div id="asientosContainer"> + <div class="zona-container"> + <div class="zona-titulo">VIP</div> + <div id="asientosVIP" class="fila-asientos"></div> + </div> + + <div class="zona-container"> + <div class="zona-titulo">General</div> + <div id="asientosGeneral" class="fila-asientos"></div> + </div> + </div> + + <button id="confirmarCompra">Confirmar Compra</button> + </div> + +</body> +</html>