348 lines
13 KiB
TypeScript
348 lines
13 KiB
TypeScript
// initial state
|
|
const días = ["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"];
|
|
const horas_estándar = /* range from 7 to 22 */ Array.from(Array(22 - 7 + 1).keys()).map(x => x + 7);
|
|
// fill the table with empty cells
|
|
for (let i = 0; i < horas_estándar.length - 1; i++) {
|
|
const hora = horas_estándar[i];
|
|
const tr = document.createElement("tr");
|
|
tr.id = `hora-${hora}-00`;
|
|
tr.classList.add(hora > 13 ? "tarde" : "mañana");
|
|
const th = document.createElement("th");
|
|
th.classList.add("text-center");
|
|
th.scope = "row";
|
|
th.rowSpan = 4;
|
|
th.innerText = `${hora}:00`;
|
|
th.style.verticalAlign = "middle";
|
|
tr.appendChild(th);
|
|
for (let j = 0; j < días.length; j++) {
|
|
const día = días[j];
|
|
const td = document.createElement("td");
|
|
td.id = `hora-${hora}-00-${día}`;
|
|
tr.appendChild(td);
|
|
}
|
|
document.querySelector("tbody#horario")?.appendChild(tr);
|
|
|
|
// add 7 rows for each hour
|
|
const hours = [15, 30, 45];
|
|
for (let j = 1; j < 4; j++) {
|
|
const tr = document.createElement("tr");
|
|
tr.id = `hora-${hora}-${hours[j - 1]}`;
|
|
tr.classList.add(hora > 13 ? "tarde" : "mañana");
|
|
for (let k = 0; k < días.length; k++) {
|
|
const día = días[k];
|
|
const td = document.createElement("td");
|
|
td.id = `hora-${hora}-${hours[j - 1]}-${día}`;
|
|
// td.innerText = `hora-${hora}-${hours[j - 1]}-${día}`;
|
|
tr.appendChild(td);
|
|
}
|
|
document.querySelector("tbody#horario")?.appendChild(tr);
|
|
}
|
|
}
|
|
|
|
// add an inital height to the table cells
|
|
const tds = document.querySelectorAll<HTMLTableRowElement>("tbody#horario td");
|
|
tds.forEach(td => td.style.height = "2rem");
|
|
|
|
var table = document.querySelector("table") as HTMLTableElement;
|
|
var empty_table = table?.innerHTML || "";
|
|
|
|
// hide the table
|
|
table.style.display = "none";
|
|
|
|
|
|
document.getElementById('dlProfesor')?.addEventListener('input', function () {
|
|
var input = document.getElementById('dlProfesor') as HTMLInputElement;
|
|
var value = input.value;
|
|
var option = document.querySelector(`option[value="${value}"]`);
|
|
if (option) {
|
|
var id: string = option.getAttribute('data-id')!;
|
|
const input_profesor: HTMLInputElement = document.getElementById('editor_profesor') as HTMLInputElement;
|
|
input_profesor.value = id;
|
|
|
|
// remove is invalid class
|
|
input.classList.remove("is-invalid");
|
|
|
|
// add is valid class
|
|
input.classList.add("is-valid");
|
|
} else {
|
|
const input_profesor: HTMLInputElement = document.getElementById('editor_profesor') as HTMLInputElement;
|
|
input_profesor.value = "";
|
|
// remove is valid class
|
|
input.classList.remove("is-valid");
|
|
|
|
// add is invalid class
|
|
input.classList.add("is-invalid");
|
|
}
|
|
});
|
|
|
|
|
|
/**
|
|
* Functions and Methods
|
|
**/
|
|
|
|
const buscarGrupo = async () => {
|
|
|
|
// Add loading animation in the button
|
|
const btn = document.querySelector("#btn-buscar") as HTMLButtonElement;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Cargando...';
|
|
btn.disabled = true;
|
|
|
|
|
|
const carrera = document.querySelector<HTMLInputElement>("#filter_carrera")?.value as string;
|
|
const grupo = document.querySelector<HTMLInputElement>("#filter_grupo")?.value as string;
|
|
console.log(`Carrera: ${carrera}, Grupo: ${grupo}`);
|
|
|
|
if (carrera == "" || grupo == "") {
|
|
triggerMessage("El nombre del grupo y la carrera son requeridos", "Faltan campos");
|
|
|
|
// Remove loading animation in the button
|
|
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
|
|
btn.disabled = false;
|
|
|
|
return;
|
|
}
|
|
const formData = new FormData();
|
|
|
|
formData.append("carrera", carrera);
|
|
formData.append("grupo", grupo);
|
|
formData.append("periodo", document.querySelector<HTMLInputElement>("#periodo")?.value!);
|
|
const thisScript = document.currentScript as HTMLScriptElement;
|
|
const facultad = thisScript.getAttribute("data-facultad") as string;
|
|
formData.append('facultad', facultad);
|
|
|
|
try {
|
|
const response = await fetch("action/action_horario.php", {
|
|
method: "POST",
|
|
body: formData
|
|
}).then(res => res.json());
|
|
if (response.status == "success") {
|
|
let limits = {
|
|
min: 22,
|
|
max: 7
|
|
};
|
|
let sábado = false;
|
|
const horario = response.horario;
|
|
// show the table
|
|
table.style.display = "table";
|
|
|
|
// clear the table
|
|
table.innerHTML = empty_table;
|
|
|
|
// fill the table
|
|
for (let i = 0; i < horario.length; i++) {
|
|
const dia = horario[i].dia;
|
|
if (dia == "sábado") sábado = true;
|
|
const {
|
|
hora,
|
|
minutos
|
|
} = {
|
|
hora: parseInt(horario[i].hora.split(":")[0]),
|
|
minutos: horario[i].hora.split(":")[1]
|
|
}
|
|
|
|
// update the limits
|
|
if (hora < limits.min) {
|
|
limits.min = hora;
|
|
}
|
|
if (hora > limits.max) {
|
|
limits.max = hora;
|
|
}
|
|
|
|
const materia = horario[i].materia;
|
|
const profesor = horario[i].profesor;
|
|
const salon = horario[i].salon;
|
|
const id = horario[i].horario_id;
|
|
const prof_id = horario[i].profesor_id;
|
|
|
|
const cell = document.querySelector(`#hora-${hora}-${minutos}-${dia}`) as HTMLTableCellElement;
|
|
cell.innerHTML =
|
|
`
|
|
<div>
|
|
<small class="text-gray">${hora}:${minutos}</small>
|
|
<b class="title">${materia}</b> <br>
|
|
<br><span>Salón: </span>${salon} <br>
|
|
<span class="ing ing-formacion mx-1"></span>${profesor}
|
|
</div>
|
|
`;
|
|
|
|
|
|
const html = `<div class="menu-flotante p-2">
|
|
<a
|
|
class="mx-2"
|
|
href="#"
|
|
data-toggle="modal"
|
|
data-target="#modal-editar"
|
|
data-dia="${dia}"
|
|
data-hora="${hora}:${minutos}"
|
|
data-materia="${materia}"
|
|
data-profesor="${prof_id}"
|
|
data-salon="${salon}"
|
|
data-id="${id}"
|
|
>
|
|
<i class="ing-editar ing"></i>
|
|
</a>
|
|
<a
|
|
class="mx-2"
|
|
href="#"
|
|
data-toggle="modal"
|
|
data-target="#modal-borrar"
|
|
data-hoario_id="${id}"
|
|
>
|
|
<i class="ing-basura ing"></i>
|
|
</a>
|
|
</div>`;
|
|
|
|
const td = cell.closest("td") as HTMLTableCellElement;
|
|
td.innerHTML += html;
|
|
td.classList.add("position-relative");
|
|
|
|
// this cell spans 4 rows
|
|
cell.rowSpan = 6;
|
|
cell.classList.add("bloque-clase", "overflow");
|
|
|
|
for (let j = 1; j < 6; j++) {
|
|
const minute = (parseInt(minutos) + j * 15)
|
|
const next_minute = (minute % 60).toString().padStart(2, "0");
|
|
const next_hour = (hora + Math.floor(minute / 60))
|
|
const next_cell = document.querySelector(`#hora-${next_hour}-${next_minute}-${dia}`) as HTMLTableCellElement;
|
|
next_cell.remove();
|
|
}
|
|
}
|
|
|
|
// remove the elements that are not in the limits
|
|
const horas = document.querySelectorAll("tbody#horario tr") as NodeListOf<HTMLTableRowElement>;
|
|
for (let i = 0; i < horas.length; i++) {
|
|
const hora = horas[i];
|
|
const hora_id = parseInt(hora.id.split("-")[1]);
|
|
if (hora_id < limits.min || hora_id > limits.max) {
|
|
hora.remove();
|
|
}
|
|
}
|
|
|
|
// if there is no sábado, remove the column
|
|
if (!sábado) {
|
|
document.querySelectorAll("tbody#horario td").forEach(td => {
|
|
if (td.id.split("-")[3] == "sábado") {
|
|
td.remove();
|
|
}
|
|
});
|
|
|
|
// remove the header (the last)
|
|
const headers = document.querySelector("#headers") as HTMLTableRowElement;
|
|
headers.lastElementChild?.remove();
|
|
}
|
|
|
|
// adjust width
|
|
const ths = document.querySelectorAll("tr#headers th") as NodeListOf<HTMLTableHeaderCellElement>;
|
|
const width = 95 / (ths.length - 1);
|
|
|
|
ths.forEach((th, key) =>
|
|
th.style.width = (key == 0) ? "5%" : `${width}%`
|
|
);
|
|
|
|
// search item animation
|
|
const menúFlontantes = document.querySelectorAll(".menu-flotante");
|
|
menúFlontantes.forEach((element) => {
|
|
element.classList.add("d-none");
|
|
element.parentElement?.addEventListener("mouseover", () => {
|
|
element.classList.remove("d-none");
|
|
});
|
|
element.parentElement?.addEventListener("mouseout", () => {
|
|
element.classList.add("d-none");
|
|
});
|
|
});
|
|
|
|
} else {
|
|
triggerMessage(response.message, "Error");
|
|
// Remove loading animation in the button
|
|
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
|
|
btn.disabled = false;
|
|
}
|
|
|
|
} catch (error) {
|
|
triggerMessage("Error al cargar el horario", "Error");
|
|
triggerMessage(error, "Error");
|
|
}
|
|
|
|
// Remove loading animation in the button
|
|
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
|
|
btn.disabled = false;
|
|
}
|
|
|
|
async function guardar(id: string) {
|
|
interface Data {
|
|
hora: HTMLInputElement;
|
|
dia: HTMLInputElement;
|
|
profesor: HTMLInputElement;
|
|
salon: HTMLInputElement;
|
|
}
|
|
const btn: HTMLButtonElement = document.querySelector("#btn-guardar") as HTMLButtonElement;
|
|
const clone: HTMLButtonElement = btn.cloneNode(true) as HTMLButtonElement;
|
|
btn.innerHTML = '<i class="ing-cargando ing"></i> Guardando...';
|
|
btn.disabled = true;
|
|
|
|
const data: Data = {
|
|
hora: document.querySelector("#editor_hora") as HTMLInputElement,
|
|
dia: document.querySelector("#editor_dia") as HTMLInputElement,
|
|
salon: document.querySelector("#editor_salón") as HTMLInputElement,
|
|
profesor: document.querySelector("#editor_profesor") as HTMLInputElement,
|
|
};
|
|
|
|
const hora = data.hora.value; // h:mm
|
|
const { compareHours } = await import('./date_functions');
|
|
const hora_antes = compareHours(hora, "07:15") < 0;
|
|
const hora_después = compareHours(hora, "21:30") > 0;
|
|
|
|
if (hora_antes || hora_después) {
|
|
alert(`La hora ${hora} no es válida`);
|
|
triggerMessage("Selecciona una hora", "Error");
|
|
btn.innerHTML = clone.innerHTML;
|
|
btn.disabled = false;
|
|
data.hora.focus();
|
|
data.hora.classList.add("is-invalid");
|
|
return;
|
|
}
|
|
|
|
const dia = data.dia.value;
|
|
const salon = data.salon.value;
|
|
const profesor = data.profesor.value;
|
|
|
|
|
|
const formData = new FormData();
|
|
|
|
formData.append("id", id);
|
|
formData.append("hora", hora);
|
|
formData.append("dia", dia);
|
|
formData.append("salon", salon);
|
|
formData.append("profesor", profesor);
|
|
|
|
const response = await fetch("action/action_horario_update.php", {
|
|
method: "POST",
|
|
body: formData
|
|
}).then(res => res.json());
|
|
|
|
if (response.status == "success") {
|
|
triggerMessage(response.message, "Éxito", "success");
|
|
btn.innerHTML = '<i class="ing-aceptar ing"></i> Guardado';
|
|
btn.classList.add("btn-success");
|
|
btn.classList.remove("btn-primary");
|
|
|
|
// return to the initial state
|
|
setTimeout(() => {
|
|
buscarGrupo();
|
|
btn.replaceWith(clone);
|
|
$("#modal-editar").modal("hide");
|
|
}, 1000);
|
|
} else {
|
|
triggerMessage(response.message, "Error");
|
|
btn.replaceWith(clone);
|
|
|
|
$("#modal-editar").modal("hide");
|
|
}
|
|
|
|
}
|
|
|
|
function triggerMessage(message: string, header: string, colour: string = "danger") {
|
|
throw new Error('Function not implemented.');
|
|
}
|