Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions backend/routes/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,54 @@ const pool = require("../db");
const router = express.Router();

// LISTAR (con filtros opcionales)
router.get("/tareas", async (req, res) => {
const { materia, estado } = req.query;
router.get("/polls", async (req, res) => {
const { categoria, estado } = req.query;

const where = [];
const params = [];

if (materia) { where.push("materia = ?"); params.push(materia); }
if (categoria) { where.push("categoria = ?"); params.push(categoria); }
if (estado) { where.push("estado = ?"); params.push(estado); }

const sql = `SELECT * FROM tareas ${where.length ? "WHERE " + where.join(" AND ") : ""} ORDER BY id DESC`;
const sql = `SELECT * FROM encuestas ${where.length ? "WHERE " + where.join(" AND ") : ""} ORDER BY id DESC`;
const [rows] = await pool.query(sql, params);
res.json(rows);
});

router.post("/tareas", async (req, res) => {
const { materia, titulo, descripcion } = req.body;
if (!materia || !titulo) return res.status(400).json({ error: "materia y titulo son obligatorios" });
router.post("/polls", async (req, res) => {
const { categoria, pregunta, opciones } = req.body;
if (!categoria || !pregunta)
return res.status(400).json({ error: "categoria y pregunta son obligatorios" });

const [r] = await pool.query(
"INSERT INTO tareas (materia, titulo, descripcion) VALUES (?,?,?)",
[materia.trim(), titulo.trim(), (descripcion || "").trim() || null]
"INSERT INTO encuestas (categoria, pregunta, opciones) VALUES (?,?,?)",
[categoria.trim(), pregunta.trim(), (opciones || "").trim() || null]
);
res.status(201).json({ id: r.insertId });
});

router.put("/tareas/:id", async (req, res) => {
router.put("/polls/:id", async (req, res) => {
const id = Number(req.params.id);
const { materia, titulo, descripcion, estado } = req.body;
const { categoria, pregunta, opciones, estado } = req.body;

const [r] = await pool.query(
`UPDATE tareas
SET materia = ?, titulo = ?, descripcion = ?, estado = ?
`UPDATE encuestas
SET categoria = ?, pregunta = ?, opciones = ?, estado = ?
WHERE id = ?`,
[materia, titulo, descripcion || null, estado, id]
[categoria, pregunta, opciones || null, estado, id]
);
if (r.affectedRows === 0) return res.status(404).json({ error: "No existe" });
if (r.affectedRows === 0)
return res.status(404).json({ error: "No existe" });

res.json({ ok: true });
});

router.delete("/tareas/:id", async (req, res) => {
router.delete("/polls/:id", async (req, res) => {
const id = Number(req.params.id);
const [r] = await pool.query("DELETE FROM tareas WHERE id = ?", [id]);
if (r.affectedRows === 0) return res.status(404).json({ error: "No existe" });
const [r] = await pool.query("DELETE FROM encuestas WHERE id = ?", [id]);
if (r.affectedRows === 0)
return res.status(404).json({ error: "No existe" });

res.json({ ok: true });
});

Expand Down
2 changes: 1 addition & 1 deletion backend/sql/schema.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE TABLE IF NOT EXISTS tareas (
CREATE TABLE IF NOT EXISTS encuestas (
id INT AUTO_INCREMENT PRIMARY KEY,
materia VARCHAR(80) NOT NULL,
titulo VARCHAR(120) NOT NULL,
Expand Down
174 changes: 101 additions & 73 deletions frontend/app.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,107 @@
const tbody = document.querySelector("#tbody");
const frm = document.querySelector("#frm");
const fMateria = document.querySelector("#fMateria");
const fEstado = document.querySelector("#fEstado");

async function load() {
const qs = new URLSearchParams();
if (fMateria.value.trim()) qs.set("materia", fMateria.value.trim());
if (fEstado.value) qs.set("estado", fEstado.value);

const res = await fetch("/api/tareas?" + qs.toString());
const data = await res.json();

tbody.innerHTML = data.map(t => `
<tr>
<td>${t.id}</td>
<td>${escapeHtml(t.materia)}</td>
<td>${escapeHtml(t.titulo)}</td>
<td>
<select data-id="${t.id}" class="estado">
<option ${t.estado==="PENDIENTE"?"selected":""}>PENDIENTE</option>
<option ${t.estado==="HECHA"?"selected":""}>HECHA</option>
</select>
</td>
<td>
<button data-del="${t.id}">Eliminar</button>
</td>
</tr>
`).join("");

document.querySelectorAll(".estado").forEach(sel => {
sel.addEventListener("change", async (e) => {
const id = e.target.dataset.id;
const estado = e.target.value;
const row = data.find(x => x.id == id);
await fetch("/api/tareas/" + id, {
method: "PUT",
headers: {"Content-Type":"application/json"},
body: JSON.stringify({ ...row, estado })
});
load();
document.addEventListener("DOMContentLoaded", () => {

let votos = {
excelente: 0,
bueno: 0,
regular: 0,
malo: 0
};

const formEncuesta = document.getElementById("formEncuesta");
const btnVotar = document.getElementById("btnVotar");
const btnNuevaEncuesta = document.getElementById("btnNuevaEncuesta");
const btnReiniciarVotos = document.getElementById("btnReiniciarVotos");

const barras = {
excelente: document.querySelector(".progreso.excelente"),
bueno: document.querySelector(".progreso.bueno"),
regular: document.querySelector(".progreso.regular"),
malo: document.querySelector(".progreso.malo")
};

actualizarBarras();

// CREAR NUEVA ENCUESTA
btnNuevaEncuesta.addEventListener("click", () => {

const preguntas = [
document.getElementById("preg1").value,
document.getElementById("preg2").value,
document.getElementById("preg3").value
];

if (preguntas.some(p => p.trim() === "")) {
alert("Debes escribir todas las preguntas");
return;
}

// Limpiar SOLO preguntas, no el botón
const botonVotar = btnVotar;
formEncuesta.innerHTML = "";
formEncuesta.appendChild(botonVotar);

preguntas.forEach((texto, index) => {
const bloque = document.createElement("div");
bloque.innerHTML = `
<h4>${texto}</h4>
<label><input type="radio" name="opinion${index}" value="excelente"> Excelente</label>
<label><input type="radio" name="opinion${index}" value="bueno"> Bueno</label>
<label><input type="radio" name="opinion${index}" value="regular"> Regular</label>
<label><input type="radio" name="opinion${index}" value="malo"> Malo</label>
`;
formEncuesta.insertBefore(bloque, botonVotar);
});

reiniciarVotos();
});
});

document.querySelectorAll("button[data-del]").forEach(btn => {
btn.addEventListener("click", async () => {
await fetch("/api/tareas/" + btn.dataset.del, { method: "DELETE" });
load();
// VOTAR
btnVotar.addEventListener("click", () => {

const seleccionados = document.querySelectorAll("input[type='radio']:checked");

if (seleccionados.length === 0) {
alert("Debes seleccionar al menos una opción");
return;
}

seleccionados.forEach(radio => {
votos[radio.value]++;
});

actualizarBarras();
limpiarFormulario();
});
});
}

frm.addEventListener("submit", async (e) => {
e.preventDefault();
const materia = document.querySelector("#materia").value;
const titulo = document.querySelector("#titulo").value;
const descripcion = document.querySelector("#descripcion").value;

await fetch("/api/tareas", {
method: "POST",
headers: {"Content-Type":"application/json"},
body: JSON.stringify({ materia, titulo, descripcion })
});
frm.reset();
load();
});

document.querySelector("#btnFiltrar").addEventListener("click", load);
document.querySelector("#btnReset").addEventListener("click", () => {
fMateria.value = "";
fEstado.value = "";
load();
});
// REINICIAR VOTOS
btnReiniciarVotos.addEventListener("click", () => {
reiniciarVotos();
});

function reiniciarVotos() {
votos = {
excelente: 0,
bueno: 0,
regular: 0,
malo: 0
};
actualizarBarras();
limpiarFormulario();
}

function actualizarBarras() {
const total = Object.values(votos).reduce((a, b) => a + b, 0);

function escapeHtml(s) {
return String(s).replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;");
}
for (let opcion in votos) {
const porcentaje = total === 0 ? 0 : Math.round((votos[opcion] / total) * 100);
barras[opcion].style.width = porcentaje + "%";
barras[opcion].textContent = porcentaje + "%";
}
}

load();
function limpiarFormulario() {
document.querySelectorAll("input[type='radio']")
.forEach(r => r.checked = false);
}

});
114 changes: 73 additions & 41 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -1,47 +1,79 @@
<!doctype html>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Grupo 1 - Tareas</title>
<link rel="stylesheet" href="style.css" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Encuesta y Resultados - Grupo 5</title>
<link rel="stylesheet" href="Style.css">
</head>
<body>
<main class="container">
<h1>Gestor de Tareas (Grupo 1)</h1>

<section class="card">
<h2>Nueva tarea</h2>
<form id="frm">
<input id="materia" placeholder="Materia (ej. Programación Web)" required />
<input id="titulo" placeholder="Título" required />
<input id="descripcion" placeholder="Descripción (opcional)" />
<button>Guardar</button>
</form>
</section>

<section class="card">
<h2>Listado</h2>
<div class="filters">
<input id="fMateria" placeholder="Filtrar por materia" />
<select id="fEstado">
<option value="">(Todos)</option>
<option value="PENDIENTE">PENDIENTE</option>
<option value="HECHA">HECHA</option>
</select>
<button id="btnFiltrar" type="button">Aplicar</button>
<button id="btnReset" type="button">Reset</button>
</div>

<table>
<thead>
<tr><th>ID</th><th>Materia</th><th>Título</th><th>Estado</th><th>Acciones</th></tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</section>
</main>

<script src="app.js"></script>

<div class="encuesta">
<h1>Encuesta y Resultados - Grupo 5</h1>

<form id="formEncuesta">

<h4>¿Cómo calificarías nuestra encuesta?</h4>
<label><input type="radio" name="opinion1" value="excelente"> Excelente</label>
<label><input type="radio" name="opinion1" value="bueno"> Bueno</label>
<label><input type="radio" name="opinion1" value="regular"> Regular</label>
<label><input type="radio" name="opinion1" value="malo"> Malo</label>

<h4>¿Qué le pareció nuestra encuesta sencilla?</h4>
<label><input type="radio" name="opinion2" value="excelente"> Excelente</label>
<label><input type="radio" name="opinion2" value="bueno"> Bueno</label>
<label><input type="radio" name="opinion2" value="regular"> Regular</label>
<label><input type="radio" name="opinion2" value="malo"> Malo</label>

<h4>¿Qué calificación nos darían por esta encuesta?</h4>
<label><input type="radio" name="opinion3" value="excelente"> Excelente</label>
<label><input type="radio" name="opinion3" value="bueno"> Bueno</label>
<label><input type="radio" name="opinion3" value="regular"> Regular</label>
<label><input type="radio" name="opinion3" value="malo"> Malo</label>

<button type="button" id="btnVotar">Votar</button>
</form>

<h3>Resultados de la Encuesta</h3>

<div class="Resultados">
<span>Excelente</span>
<div class="barra"><div class="progreso excelente">60%</div></div>
</div>

<div class="Resultados">
<span>Bueno</span>
<div class="barra"><div class="progreso bueno">25%</div></div>
</div>

<div class="Resultados">
<span>Regular</span>
<div class="barra"><div class="progreso regular">10%</div></div>
</div>

<div class="Resultados">
<span>Malo</span>
<div class="barra"><div class="progreso malo">5%</div></div>
</div>
<button type="button" id="btnReiniciarVotos">Reiniciar Votos</button>


<!-- Crear nueva encuesta -->
<div class="nueva-encuesta">
<h3>Nueva encuesta</h3>

<input type="text" id="preg1" placeholder="Pregunta 1">
<input type="text" id="preg2" placeholder="Pregunta 2">
<input type="text" id="preg3" placeholder="Pregunta 3">

<button type="button" id="btnNuevaEncuesta">
Crear nueva encuesta
</button>
</div>


</div>

<script src="app.js"></script>
</body>
</html>
Loading