Commit Bulk
This commit is contained in:
140
ts/horario.ts
Normal file
140
ts/horario.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
|
||||
type Profesor = {
|
||||
profesor_clave: string;
|
||||
profesor_correo: string;
|
||||
profesor_grado: null | string;
|
||||
profesor_id: number;
|
||||
profesor_nombre: string;
|
||||
}
|
||||
|
||||
type Horario = {
|
||||
carrera: string;
|
||||
carrera_id: number;
|
||||
dia: string;
|
||||
duracion: string;
|
||||
duracion_id: number;
|
||||
facultad: string;
|
||||
facultad_id: number;
|
||||
fecha_carga: Date;
|
||||
horario_dia: number;
|
||||
horario_fecha_fin: null;
|
||||
horario_fecha_inicio: Date;
|
||||
horario_fin: string;
|
||||
horario_grupo: string;
|
||||
horario_hora: string;
|
||||
horario_id: number;
|
||||
limite: null;
|
||||
materia: string;
|
||||
materia_id: number;
|
||||
nivel: string;
|
||||
nivel_id: number;
|
||||
periodo: string;
|
||||
periodo_fecha_fin: Date;
|
||||
periodo_fecha_inicio: Date;
|
||||
periodo_id: number;
|
||||
profesor_id: number;
|
||||
salon: string;
|
||||
salon_id: number;
|
||||
bloques: number;
|
||||
}
|
||||
|
||||
|
||||
const profesores = reactive({
|
||||
data: [] as Profesor[],
|
||||
search: null as null | string,
|
||||
fetch: async function () {
|
||||
const response = await fetch('action/action_profesor.php')
|
||||
this.data = await response.json() as Profesor[]
|
||||
},
|
||||
get clave() {
|
||||
const match = this.search.match(/^\((.+)\)/)
|
||||
return match ? match[1] : ''
|
||||
},
|
||||
get current() {
|
||||
return this.data.find((profesor: Profesor) => profesor.profesor_clave === profesores.clave)
|
||||
},
|
||||
})
|
||||
|
||||
type Structure = {
|
||||
sábado: boolean;
|
||||
hora_mínima: number;
|
||||
hora_máxima: number;
|
||||
horas_totales: number;
|
||||
}
|
||||
|
||||
const horarios = reactive({
|
||||
data: [] as Horario[],
|
||||
fetch: async function () {
|
||||
if (profesores.current) {
|
||||
const response = await fetch(`action/action_horario.php?profesor_id=${profesores.current.profesor_id}`)
|
||||
this.data = await response.json()
|
||||
}
|
||||
},
|
||||
get structure() {
|
||||
if (this.data.length === 0) return null;
|
||||
|
||||
const structure: Structure = {
|
||||
sábado: this.data.some((horario: Horario) => horario.horario_dia === 6),
|
||||
hora_mínima: Math.min(...this.data.map((horario: Horario) => parseInt(horario.horario_hora.split(':')[0]))),
|
||||
hora_máxima: Math.max(...this.data.map((horario: Horario) => {
|
||||
const [hour, minute] = horario.horario_fin.split(':').map(Number);
|
||||
return hour + Math.ceil(minute / 60);
|
||||
})),
|
||||
horas_totales: 0
|
||||
};
|
||||
|
||||
structure.horas_totales = structure.hora_máxima - structure.hora_mínima;
|
||||
|
||||
return structure;
|
||||
},
|
||||
get blocks() {
|
||||
if (this.data.length === 0) return null;
|
||||
return [...Array(this.structure.horas_totales).keys()].flatMap(hora => {
|
||||
const baseHour = hora + this.structure.hora_mínima;
|
||||
return [0, 15, 30, 45].map(block => ({ hour: baseHour, block }));
|
||||
});
|
||||
},
|
||||
getHorarioData(hour: number, block: number, día: number) {
|
||||
const foundHorario = this.data.find((horario: Horario) =>
|
||||
parseInt(horario.horario_hora.split(':')[0]) === hour &&
|
||||
parseInt(horario.horario_hora.split(':')[1]) === block &&
|
||||
horario.horario_dia === día
|
||||
);
|
||||
return foundHorario;
|
||||
},
|
||||
isOccupied(hora: number, bloque: number, day: number) {
|
||||
if (this.getHorarioData(hora, bloque, day)) {
|
||||
return false;
|
||||
}
|
||||
const currentTimeInMinutes = hora * 60 + bloque;
|
||||
|
||||
for (const item of this.data) {
|
||||
if (item.horario_dia !== day) {
|
||||
continue; // Skip items that are not on the specified day
|
||||
}
|
||||
|
||||
// Split the hour and minute from horario_hora
|
||||
const [startHour, startMinute] = item.horario_hora.split(":").map(Number);
|
||||
const startTimeInMinutes = startHour * 60 + startMinute;
|
||||
|
||||
// Calculate end time using duracion
|
||||
const [durationHours, durationMinutes] = item.duracion.split(":").map(Number);
|
||||
const endTimeInMinutes = startTimeInMinutes + (durationHours * 60) + durationMinutes;
|
||||
|
||||
if (currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes < endTimeInMinutes) {
|
||||
return true; // The block is occupied
|
||||
}
|
||||
}
|
||||
|
||||
return false; // The block is not occupied by any class
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
const app = createApp({
|
||||
profesores,
|
||||
horarios,
|
||||
mounted: async function () {
|
||||
await profesores.fetch()
|
||||
}
|
||||
}).mount('#app')
|
||||
@@ -1,532 +0,0 @@
|
||||
declare function triggerMessage(message: string, title: string, color?: string): void;
|
||||
declare const write: boolean;
|
||||
declare const moment: any;
|
||||
|
||||
/**
|
||||
* Funciones auxiliares
|
||||
*/
|
||||
type Profesor = {
|
||||
id: number,
|
||||
grado: string,
|
||||
profesor: string,
|
||||
clave: string,
|
||||
}
|
||||
|
||||
type Horario = {
|
||||
id: number,
|
||||
carrera_id: number,
|
||||
materia: string,
|
||||
salon: string,
|
||||
profesores: Profesor[],
|
||||
hora: string,
|
||||
hora_final: string,
|
||||
dia: string,
|
||||
duracion: number,
|
||||
bloques: number,
|
||||
grupo: string,
|
||||
materia_id: number,
|
||||
}
|
||||
|
||||
const compareHours = (hora1: string, hora2: string): number => {
|
||||
const [h1, m1] = hora1.split(":").map(Number);
|
||||
const [h2, m2] = hora2.split(":").map(Number);
|
||||
|
||||
if (h1 !== h2) {
|
||||
return h1 > h2 ? 1 : -1;
|
||||
}
|
||||
|
||||
if (m1 !== m2) {
|
||||
return m1 > m2 ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
let horarios = [] as Horario[];
|
||||
const table = document.querySelector("table") as HTMLTableElement;
|
||||
if (!(table instanceof HTMLTableElement)) {
|
||||
triggerMessage("No se ha encontrado la tabla", "Error", "error");
|
||||
throw new Error("No se ha encontrado la tabla");
|
||||
}
|
||||
|
||||
[...Array(16).keys()].map(x => x + 7).forEach(hora => {
|
||||
// add 7 rows for each hour
|
||||
[0, 15, 30, 45].map((minute: number) => `${minute}`.padStart(2, '0')).forEach((minute: string) => {
|
||||
const tr = document.createElement("tr") as HTMLTableRowElement;
|
||||
tr.id = `hora-${hora}:${minute}`;
|
||||
tr.classList.add(hora > 13 ? "tarde" : "mañana");
|
||||
if (minute == "00") {
|
||||
const th = document.createElement("th") as HTMLTableCellElement;
|
||||
th.classList.add("text-center");
|
||||
th.scope = "row";
|
||||
th.rowSpan = 4;
|
||||
th.innerText = `${hora}:00`;
|
||||
th.style.verticalAlign = "middle";
|
||||
tr.appendChild(th);
|
||||
}
|
||||
|
||||
["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"].forEach(día => {
|
||||
const td = document.createElement("td") as HTMLTableCellElement;
|
||||
td.id = `hora-${hora}:${minute}-${día}`;
|
||||
tr.appendChild(td);
|
||||
});
|
||||
const tbody = document.querySelector("tbody#horario") as HTMLTableSectionElement;
|
||||
if (!(tbody instanceof HTMLTableSectionElement)) {
|
||||
throw new Error("No se ha encontrado el tbody");
|
||||
}
|
||||
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
});
|
||||
|
||||
const empty_table = table.cloneNode(true) as HTMLTableElement;
|
||||
document.querySelectorAll('.hidden').forEach((element: HTMLElement) => {
|
||||
element.style.display = "none";
|
||||
});
|
||||
// hide the table
|
||||
table.style.display = "none";
|
||||
|
||||
function moveHorario(id: string, día: string, hora: string) {
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("id", id);
|
||||
formData.append("hora", hora);
|
||||
formData.append("día", día);
|
||||
|
||||
fetch("action/action_horario_update.php", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
}).then(res => res.json()).then(response => {
|
||||
if (response.status == "success") {
|
||||
triggerMessage("Horario movido", "Éxito", "success");
|
||||
} else {
|
||||
triggerMessage(response.message, "Error");
|
||||
}
|
||||
}).then(() => {
|
||||
renderHorario();
|
||||
}).catch(err => {
|
||||
triggerMessage(err, "Error");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function renderHorario() {
|
||||
if (horarios.length == 0) {
|
||||
triggerMessage("Este profesor hay horarios para mostrar", "Error", "info");
|
||||
table.style.display = "none";
|
||||
document.querySelectorAll('.hidden').forEach((element: HTMLElement) => element.style.display = "none");
|
||||
return;
|
||||
}
|
||||
// show the table
|
||||
table.style.display = "table";
|
||||
document.querySelectorAll('.hidden').forEach((element: HTMLElement) => element.style.display = "block");
|
||||
// clear the table
|
||||
table.innerHTML = empty_table.outerHTML;
|
||||
|
||||
function conflicts(horario1: Horario, horario2: Horario): boolean {
|
||||
const { hora: hora_inicio1, hora_final: hora_final1, dia: dia1 } = horario1;
|
||||
const { hora: hora_inicio2, hora_final: hora_final2, dia: dia2 } = horario2;
|
||||
|
||||
if (dia1 !== dia2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const compareInicios = compareHours(hora_inicio1, hora_inicio2);
|
||||
const compareFinales = compareHours(hora_final1, hora_final2);
|
||||
|
||||
if (
|
||||
compareInicios >= 0 && compareInicios <= compareFinales ||
|
||||
compareFinales >= 0 && compareFinales <= -compareInicios
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// remove the next 5 cells
|
||||
function removeNextCells(horas: number, minutos: number, dia: string, cells: number = 5) {
|
||||
for (let i = 1; i <= cells; i++) {
|
||||
const minute = minutos + i * 15;
|
||||
const nextMinute = (minute % 60).toString().padStart(2, "0");
|
||||
const nextHour = horas + Math.floor(minute / 60);
|
||||
|
||||
const cellId = `hora-${nextHour}:${nextMinute}-${dia}`;
|
||||
const cellElement = document.getElementById(cellId);
|
||||
if (cellElement) {
|
||||
cellElement.remove();
|
||||
}
|
||||
else {
|
||||
console.log(`No se ha encontrado la celda ${cellId}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newBlock(horario: Horario, edit = false) {
|
||||
function move(horario: Horario, cells: number = 5) {
|
||||
const [horas, minutos] = horario.hora.split(":").map(Number);
|
||||
|
||||
const cell = document.getElementById(`hora-${horas}:${minutos.toString().padStart(2, "0")}-${horario.dia}`);
|
||||
const { top, left } = cell.getBoundingClientRect();
|
||||
|
||||
const block = document.getElementById(`block-${horario.id}`);
|
||||
block.style.top = `${top}px`;
|
||||
block.style.left = `${left}px`;
|
||||
|
||||
removeNextCells(horas, minutos, horario.dia, cells);
|
||||
}
|
||||
|
||||
const [horas, minutos] = horario.hora.split(":").map(x => parseInt(x));
|
||||
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
|
||||
horario.hora = hora;
|
||||
|
||||
const cell = document.getElementById(`hora-${horario.hora}-${horario.dia}`) as HTMLTableCellElement;
|
||||
if (!cell) return;
|
||||
|
||||
cell.dataset.ids = `${horario.id}`;
|
||||
|
||||
const float_menu = edit ?
|
||||
`<div class="menu-flotante p-2" style="opacity: .7;">
|
||||
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-editar">
|
||||
<i class="ing-editar ing"></i>
|
||||
</a>
|
||||
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-borrar">
|
||||
<i class="ing-basura ing"></i>
|
||||
</a>
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
cell.innerHTML =
|
||||
`<div style="overflow-y: auto; overflow-x: hidden; height: 100%;" id="block-${horario.id}" class="position-absolute w-100 h-100">
|
||||
<small class="text-gray">${horario.hora}</small>
|
||||
<b class="title">${horario.materia}</b> <br>
|
||||
<br><span>Salón: </span>${horario.salon} <br>
|
||||
<small class="my-2">
|
||||
${horario.profesores.map((profesor: Profesor) => ` <span class="ing ing-formacion mx-1"></span>${profesor.grado ?? ''} ${profesor.profesor}`).join("<br>")}
|
||||
</small>
|
||||
</div>
|
||||
${float_menu}`;
|
||||
|
||||
cell.classList.add("bloque-clase", "position-relative");
|
||||
cell.rowSpan = horario.bloques;
|
||||
// draggable
|
||||
cell.draggable = write;
|
||||
|
||||
if (horario.bloques > 0) {
|
||||
removeNextCells(horas, minutos, horario.dia, horario.bloques - 1);
|
||||
}
|
||||
}
|
||||
|
||||
function newConflictBlock(horarios: Horario[], edit = false) {
|
||||
const first_horario = horarios[0];
|
||||
const [horas, minutos] = first_horario.hora.split(":").map(x => parseInt(x));
|
||||
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
|
||||
const ids = horarios.map(horario => horario.id);
|
||||
const cell = document.getElementById(`hora-${hora}-${first_horario.dia}`);
|
||||
if (cell == null) {
|
||||
console.error(`Error: No se encontró la celda: hora-${hora}-${first_horario.dia}`);
|
||||
return;
|
||||
}
|
||||
cell.dataset.ids = ids.join(",");
|
||||
|
||||
// replace the content of the cell
|
||||
cell.innerHTML = `
|
||||
<small class='text-danger'>
|
||||
${hora}
|
||||
</small>
|
||||
<div class="d-flex justify-content-center align-items-center mt-4">
|
||||
<div class="d-flex flex-column justify-content-center align-items-center">
|
||||
<span class="ing ing-importante text-danger" style="font-size: 2rem;"></span>
|
||||
<b class='text-danger'>
|
||||
Empalme de ${ids.length} horarios
|
||||
</b>
|
||||
<hr>
|
||||
<i class="text-danger">Ver horarios …</i>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add classes and attributes
|
||||
cell.classList.add("conflict", "bloque-clase");
|
||||
cell.setAttribute("role", "button");
|
||||
|
||||
// Add event listener for the cell
|
||||
cell.addEventListener("click", () => {
|
||||
$("#modal-choose").modal("show");
|
||||
const ids = cell.getAttribute("data-ids").split(",").map(x => parseInt(x));
|
||||
const tbody = document.querySelector("#modal-choose tbody");
|
||||
tbody.innerHTML = "";
|
||||
horarios.filter(horario => ids.includes(horario.id)).sort((a, b) => compareHours(a.hora, b.hora)).forEach(horario => {
|
||||
tbody.innerHTML += `
|
||||
<tr data-ids="${horario.id}">
|
||||
<td><small>${horario.hora.slice(0, -3)}-${horario.hora_final.slice(0, -3)}</small></td>
|
||||
<td>${horario.materia}</td>
|
||||
<td>
|
||||
${horario.profesores.map(({ grado, profesor }) => `${grado ?? ''} ${profesor}`).join(", ")}
|
||||
</td>
|
||||
<td>${horario.salon}</td>
|
||||
${edit ? `
|
||||
<td class="text-center">
|
||||
<button class="btn btn-sm btn-primary dismiss-editar" data-toggle="modal" data-target="#modal-editar">
|
||||
<i class="ing-editar ing"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<button class="btn btn-sm btn-danger dismiss-editar" data-toggle="modal" data-target="#modal-borrar">
|
||||
<i class="ing-basura ing"></i>
|
||||
</button>
|
||||
</td>
|
||||
` : ""}
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
document.querySelectorAll(".dismiss-editar").forEach(btn => {
|
||||
btn.addEventListener("click", () => $("#modal-choose").modal("hide"));
|
||||
});
|
||||
});
|
||||
|
||||
function getDuration(hora_i: string, hora_f: string): number {
|
||||
const [horas_i, minutos_i] = hora_i.split(":").map(x => parseInt(x));
|
||||
const [horas_f, minutos_f] = hora_f.split(":").map(x => parseInt(x));
|
||||
const date_i = new Date(0, 0, 0, horas_i, minutos_i);
|
||||
const date_f = new Date(0, 0, 0, horas_f, minutos_f);
|
||||
const diffInMilliseconds = date_f.getTime() - date_i.getTime();
|
||||
const diffInMinutes = diffInMilliseconds / (1000 * 60);
|
||||
const diffIn15MinuteIntervals = diffInMinutes / 15;
|
||||
return Math.floor(diffIn15MinuteIntervals);
|
||||
}
|
||||
|
||||
const maxHoraFinal = horarios.reduce((max: Date, horario: Horario) => {
|
||||
const [horas, minutos] = horario.hora_final.split(":").map(x => parseInt(x));
|
||||
const date = new Date(0, 0, 0, horas, minutos);
|
||||
return date > max ? date : max;
|
||||
}, new Date(0, 0, 0, 0, 0));
|
||||
|
||||
|
||||
const horaFinalMax = new Date(0, 0, 0, maxHoraFinal.getHours(), maxHoraFinal.getMinutes());
|
||||
const blocks = getDuration(first_horario.hora, `${horaFinalMax.getHours()}:${horaFinalMax.getMinutes()}`);
|
||||
cell.setAttribute("rowSpan", blocks.toString());
|
||||
removeNextCells(horas, minutos, first_horario.dia, blocks - 1);
|
||||
}
|
||||
|
||||
|
||||
const conflictBlocks = horarios.filter((horario, index, arrayHorario) =>
|
||||
arrayHorario.filter((_, i) => i != index).some(horario2 =>
|
||||
conflicts(horario, horario2)))
|
||||
.sort((a, b) => compareHours(a.hora, b.hora));
|
||||
|
||||
const classes = horarios.filter(horario => !conflictBlocks.includes(horario));
|
||||
|
||||
const conflictBlocksPacked = []; // array of sets
|
||||
conflictBlocks.forEach(horario => {
|
||||
const setIndex = conflictBlocksPacked.findIndex(set => set.some(horario2 => conflicts(horario, horario2)));
|
||||
if (setIndex === -1) {
|
||||
conflictBlocksPacked.push([horario]);
|
||||
} else {
|
||||
conflictBlocksPacked[setIndex].push(horario);
|
||||
}
|
||||
})
|
||||
|
||||
classes.forEach(horario =>
|
||||
newBlock(horario, write)
|
||||
)
|
||||
|
||||
conflictBlocksPacked.forEach(horarios =>
|
||||
newConflictBlock(horarios, write)
|
||||
)
|
||||
|
||||
// remove the elements that are not in the limits
|
||||
let max_hour = Math.max(...horarios.map(horario => {
|
||||
const lastMoment = moment(horario.hora, "HH:mm").add(horario.bloques * 15, "minutes");
|
||||
const lastHour = moment(`${lastMoment.hours()}:00`, "HH:mm");
|
||||
const hourInt = parseInt(lastMoment.format("HH"));
|
||||
|
||||
return lastMoment.isSame(lastHour) ? hourInt - 1 : hourInt;
|
||||
}));
|
||||
|
||||
let min_hour = Math.min(...horarios.map(horario => parseInt(horario.hora.split(":")[0])));
|
||||
|
||||
document.querySelectorAll("tbody#horario tr").forEach(hora => {
|
||||
const hora_id = parseInt(hora.id.split("-")[1].split(":")[0]);
|
||||
(hora_id < min_hour || hora_id > max_hour) ? hora.remove() : null;
|
||||
})
|
||||
|
||||
// if there is no sábado, remove the column
|
||||
if (!horarios.some(horario => horario.dia == "sábado")) {
|
||||
document.querySelectorAll("tbody#horario td").forEach(td => {
|
||||
if (td.id.split("-")[2] == "sábado") {
|
||||
td.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// remove the header (the last)
|
||||
document.querySelector("#headers").lastElementChild.remove();
|
||||
}
|
||||
// adjust width
|
||||
const ths = document.querySelectorAll("tr#headers th") as NodeListOf<HTMLTableCellElement>;
|
||||
ths.forEach((th, key) =>
|
||||
th.style.width = (key == 0) ? "5%" : `${95 / (ths.length - 1)}%`
|
||||
);
|
||||
|
||||
// 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", (e) =>
|
||||
element.classList.add("d-none")
|
||||
);
|
||||
});
|
||||
|
||||
// droppables
|
||||
// forall the .bloque-elements add the event listeners for drag and drop
|
||||
|
||||
document.querySelectorAll(".bloque-clase").forEach(element => {
|
||||
function dragStart() {
|
||||
this.classList.add("dragging");
|
||||
}
|
||||
|
||||
function dragEnd() {
|
||||
this.classList.remove("dragging");
|
||||
}
|
||||
|
||||
element.addEventListener("dragstart", dragStart);
|
||||
element.addEventListener("dragend", dragEnd);
|
||||
});
|
||||
|
||||
// forall the cells that are not .bloque-clase add the event listeners for drag and drop
|
||||
document.querySelectorAll("td:not(.bloque-clase)").forEach(element => {
|
||||
function dragOver(e) {
|
||||
e.preventDefault();
|
||||
this.classList.add("dragging-over");
|
||||
}
|
||||
|
||||
function dragLeave() {
|
||||
this.classList.remove("dragging-over");
|
||||
}
|
||||
|
||||
function drop() {
|
||||
this.classList.remove("dragging-over");
|
||||
const dragging = document.querySelector(".dragging");
|
||||
|
||||
const id = dragging.getAttribute("data-ids");
|
||||
const hora = this.id.split("-")[1];
|
||||
const días = ["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"];
|
||||
let día = this.id.split("-")[2];
|
||||
día = días.indexOf(día) + 1;
|
||||
|
||||
// rowspan
|
||||
const bloques = parseInt(dragging.getAttribute("rowspan"));
|
||||
const horaMoment = moment(hora, "HH:mm");
|
||||
const horaFin = horaMoment.add(bloques * 15, "minutes");
|
||||
|
||||
const limit = moment('22:00', 'HH:mm');
|
||||
|
||||
if (horaFin.isAfter(limit)) {
|
||||
triggerMessage("No se puede mover el bloque a esa hora", "Error");
|
||||
|
||||
// scroll to the top
|
||||
window.scrollTo(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the horario
|
||||
// remove the horario
|
||||
const bloque = document.querySelector(`.bloque-clase[data-ids="${id}"]`) as HTMLElement;
|
||||
|
||||
// remove all children
|
||||
while (bloque.firstChild) {
|
||||
bloque.removeChild(bloque.firstChild);
|
||||
}
|
||||
|
||||
// prepend a loading child
|
||||
const loading = `<div class="spinner-border" role="status" style="width: 3rem; height: 3rem;">
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>`;
|
||||
bloque.insertAdjacentHTML("afterbegin", loading);
|
||||
// add style vertical-align: middle
|
||||
bloque.style.verticalAlign = "middle";
|
||||
bloque.classList.add("text-center");
|
||||
// remove draggable
|
||||
bloque.removeAttribute("draggable");
|
||||
|
||||
moveHorario(id, día, hora);
|
||||
}
|
||||
|
||||
element.addEventListener("dragover", dragOver);
|
||||
element.addEventListener("dragleave", dragLeave);
|
||||
element.addEventListener("drop", drop);
|
||||
});
|
||||
}
|
||||
const form = document.getElementById('form') as HTMLFormElement;
|
||||
|
||||
if (!(form instanceof HTMLFormElement)) {
|
||||
triggerMessage('No se ha encontrado el formulario', 'Error', 'danger');
|
||||
throw new Error("No se ha encontrado el formulario");
|
||||
}
|
||||
|
||||
form.querySelector('#clave_profesor').addEventListener('input', function (e) {
|
||||
const input = form.querySelector('#clave_profesor') as HTMLInputElement;
|
||||
const option = form.querySelector(`option[value="${input.value}"]`) as HTMLOptionElement;
|
||||
|
||||
if (input.value == "") {
|
||||
input.classList.remove("is-invalid", "is-valid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!option) {
|
||||
input.classList.remove("is-valid");
|
||||
input.classList.add("is-invalid");
|
||||
}
|
||||
else {
|
||||
const profesor_id = form.querySelector('#profesor_id') as HTMLInputElement;
|
||||
profesor_id.value = option.dataset.id;
|
||||
input.classList.remove("is-invalid");
|
||||
input.classList.add("is-valid");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
form.addEventListener('submit', async function (e) {
|
||||
e.preventDefault();
|
||||
const input = form.querySelector('#clave_profesor') as HTMLInputElement;
|
||||
if (input.classList.contains("is-invalid")) {
|
||||
triggerMessage('El profesor no se encuentra registrado', 'Error', 'danger');
|
||||
return;
|
||||
}
|
||||
const formData = new FormData(form);
|
||||
try {
|
||||
const buttons = document.querySelectorAll("button") as NodeListOf<HTMLButtonElement>;
|
||||
buttons.forEach(button => {
|
||||
button.disabled = true;
|
||||
button.classList.add("disabled");
|
||||
});
|
||||
const response = await fetch('action/action_horario_profesor.php', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
buttons.forEach(button => {
|
||||
button.disabled = false;
|
||||
button.classList.remove("disabled");
|
||||
});
|
||||
|
||||
if (data.status == 'success') {
|
||||
horarios = data.data;
|
||||
renderHorario();
|
||||
}
|
||||
else {
|
||||
triggerMessage(data.message, 'Error en la consulta', 'warning');
|
||||
}
|
||||
} catch (error) {
|
||||
triggerMessage('Fallo al consutar los datos ', 'Error', 'danger');
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
|
||||
const input = form.querySelector('#clave_profesor') as HTMLInputElement;
|
||||
const option = form.querySelector(`option[value="${input.value}"]`) as HTMLOptionElement;
|
||||
|
||||
Reference in New Issue
Block a user