consulta_horarios.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // initial state
  2. const días = ["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"];
  3. const horas_estándar = /* range from 7 to 22 */ Array.from(Array(22 - 7 + 1).keys()).map(x => x + 7);
  4. // fill the table with empty cells
  5. for (let i = 0; i < horas_estándar.length - 1; i++) {
  6. const hora = horas_estándar[i];
  7. const tr = document.createElement("tr");
  8. tr.id = `hora-${hora}-00`;
  9. tr.classList.add(hora > 13 ? "tarde" : "mañana");
  10. const th = document.createElement("th");
  11. th.classList.add("text-center");
  12. th.scope = "row";
  13. th.rowSpan = 4;
  14. th.innerText = `${hora}:00`;
  15. th.style.verticalAlign = "middle";
  16. tr.appendChild(th);
  17. for (let j = 0; j < días.length; j++) {
  18. const día = días[j];
  19. const td = document.createElement("td");
  20. td.id = `hora-${hora}-00-${día}`;
  21. tr.appendChild(td);
  22. }
  23. document.querySelector("tbody#horario")?.appendChild(tr);
  24. // add 7 rows for each hour
  25. const hours = [15, 30, 45];
  26. for (let j = 1; j < 4; j++) {
  27. const tr = document.createElement("tr");
  28. tr.id = `hora-${hora}-${hours[j - 1]}`;
  29. tr.classList.add(hora > 13 ? "tarde" : "mañana");
  30. for (let k = 0; k < días.length; k++) {
  31. const día = días[k];
  32. const td = document.createElement("td");
  33. td.id = `hora-${hora}-${hours[j - 1]}-${día}`;
  34. // td.innerText = `hora-${hora}-${hours[j - 1]}-${día}`;
  35. tr.appendChild(td);
  36. }
  37. document.querySelector("tbody#horario")?.appendChild(tr);
  38. }
  39. }
  40. // add an inital height to the table cells
  41. const tds = document.querySelectorAll<HTMLTableRowElement>("tbody#horario td");
  42. tds.forEach(td => td.style.height = "2rem");
  43. var table = document.querySelector("table") as HTMLTableElement;
  44. var empty_table = table?.innerHTML || "";
  45. // hide the table
  46. table.style.display = "none";
  47. document.getElementById('dlProfesor')?.addEventListener('input', function () {
  48. var input = document.getElementById('dlProfesor') as HTMLInputElement;
  49. var value = input.value;
  50. var option = document.querySelector(`option[value="${value}"]`);
  51. if (option) {
  52. var id: string = option.getAttribute('data-id')!;
  53. const input_profesor: HTMLInputElement = document.getElementById('editor_profesor') as HTMLInputElement;
  54. input_profesor.value = id;
  55. // remove is invalid class
  56. input.classList.remove("is-invalid");
  57. // add is valid class
  58. input.classList.add("is-valid");
  59. } else {
  60. const input_profesor: HTMLInputElement = document.getElementById('editor_profesor') as HTMLInputElement;
  61. input_profesor.value = "";
  62. // remove is valid class
  63. input.classList.remove("is-valid");
  64. // add is invalid class
  65. input.classList.add("is-invalid");
  66. }
  67. });
  68. /**
  69. * Functions and Methods
  70. **/
  71. const buscarGrupo = async () => {
  72. // Add loading animation in the button
  73. const btn = document.querySelector("#btn-buscar") as HTMLButtonElement;
  74. btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Cargando...';
  75. btn.disabled = true;
  76. const carrera = document.querySelector<HTMLInputElement>("#filter_carrera")?.value as string;
  77. const grupo = document.querySelector<HTMLInputElement>("#filter_grupo")?.value as string;
  78. console.log(`Carrera: ${carrera}, Grupo: ${grupo}`);
  79. if (carrera == "" || grupo == "") {
  80. triggerMessage("El nombre del grupo y la carrera son requeridos", "Faltan campos");
  81. // Remove loading animation in the button
  82. btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
  83. btn.disabled = false;
  84. return;
  85. }
  86. const formData = new FormData();
  87. formData.append("carrera", carrera);
  88. formData.append("grupo", grupo);
  89. formData.append("periodo", document.querySelector<HTMLInputElement>("#periodo")?.value!);
  90. const thisScript = document.currentScript as HTMLScriptElement;
  91. const facultad = thisScript.getAttribute("data-facultad") as string;
  92. formData.append('facultad', facultad);
  93. try {
  94. const response = await fetch("action/action_horario.php", {
  95. method: "POST",
  96. body: formData
  97. }).then(res => res.json());
  98. if (response.status == "success") {
  99. let limits = {
  100. min: 22,
  101. max: 7
  102. };
  103. let sábado = false;
  104. const horario = response.horario;
  105. // show the table
  106. table.style.display = "table";
  107. // clear the table
  108. table.innerHTML = empty_table;
  109. // fill the table
  110. for (let i = 0; i < horario.length; i++) {
  111. const dia = horario[i].dia;
  112. if (dia == "sábado") sábado = true;
  113. const {
  114. hora,
  115. minutos
  116. } = {
  117. hora: parseInt(horario[i].hora.split(":")[0]),
  118. minutos: horario[i].hora.split(":")[1]
  119. }
  120. // update the limits
  121. if (hora < limits.min) {
  122. limits.min = hora;
  123. }
  124. if (hora > limits.max) {
  125. limits.max = hora;
  126. }
  127. const materia = horario[i].materia;
  128. const profesor = horario[i].profesor;
  129. const salon = horario[i].salon;
  130. const id = horario[i].horario_id;
  131. const prof_id = horario[i].profesor_id;
  132. const cell = document.querySelector(`#hora-${hora}-${minutos}-${dia}`) as HTMLTableCellElement;
  133. cell.innerHTML =
  134. `
  135. <div>
  136. <small class="text-gray">${hora}:${minutos}</small>
  137. <b class="title">${materia}</b> <br>
  138. <br><span>Salón: </span>${salon} <br>
  139. <span class="ing ing-formacion mx-1"></span>${profesor}
  140. </div>
  141. `;
  142. const html = `<div class="menu-flotante p-2">
  143. <a
  144. class="mx-2"
  145. href="#"
  146. data-toggle="modal"
  147. data-target="#modal-editar"
  148. data-dia="${dia}"
  149. data-hora="${hora}:${minutos}"
  150. data-materia="${materia}"
  151. data-profesor="${prof_id}"
  152. data-salon="${salon}"
  153. data-id="${id}"
  154. >
  155. <i class="ing-editar ing"></i>
  156. </a>
  157. <a
  158. class="mx-2"
  159. href="#"
  160. data-toggle="modal"
  161. data-target="#modal-borrar"
  162. data-hoario_id="${id}"
  163. >
  164. <i class="ing-basura ing"></i>
  165. </a>
  166. </div>`;
  167. const td = cell.closest("td") as HTMLTableCellElement;
  168. td.innerHTML += html;
  169. td.classList.add("position-relative");
  170. // this cell spans 4 rows
  171. cell.rowSpan = 6;
  172. cell.classList.add("bloque-clase", "overflow");
  173. for (let j = 1; j < 6; j++) {
  174. const minute = (parseInt(minutos) + j * 15)
  175. const next_minute = (minute % 60).toString().padStart(2, "0");
  176. const next_hour = (hora + Math.floor(minute / 60))
  177. const next_cell = document.querySelector(`#hora-${next_hour}-${next_minute}-${dia}`) as HTMLTableCellElement;
  178. next_cell.remove();
  179. }
  180. }
  181. // remove the elements that are not in the limits
  182. const horas = document.querySelectorAll("tbody#horario tr") as NodeListOf<HTMLTableRowElement>;
  183. for (let i = 0; i < horas.length; i++) {
  184. const hora = horas[i];
  185. const hora_id = parseInt(hora.id.split("-")[1]);
  186. if (hora_id < limits.min || hora_id > limits.max) {
  187. hora.remove();
  188. }
  189. }
  190. // if there is no sábado, remove the column
  191. if (!sábado) {
  192. document.querySelectorAll("tbody#horario td").forEach(td => {
  193. if (td.id.split("-")[3] == "sábado") {
  194. td.remove();
  195. }
  196. });
  197. // remove the header (the last)
  198. const headers = document.querySelector("#headers") as HTMLTableRowElement;
  199. headers.lastElementChild?.remove();
  200. }
  201. // adjust width
  202. const ths = document.querySelectorAll("tr#headers th") as NodeListOf<HTMLTableHeaderCellElement>;
  203. const width = 95 / (ths.length - 1);
  204. ths.forEach((th, key) =>
  205. th.style.width = (key == 0) ? "5%" : `${width}%`
  206. );
  207. // search item animation
  208. const menúFlontantes = document.querySelectorAll(".menu-flotante");
  209. menúFlontantes.forEach((element) => {
  210. element.classList.add("d-none");
  211. element.parentElement?.addEventListener("mouseover", () => {
  212. element.classList.remove("d-none");
  213. });
  214. element.parentElement?.addEventListener("mouseout", () => {
  215. element.classList.add("d-none");
  216. });
  217. });
  218. } else {
  219. triggerMessage(response.message, "Error");
  220. // Remove loading animation in the button
  221. btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
  222. btn.disabled = false;
  223. }
  224. } catch (error) {
  225. triggerMessage("Error al cargar el horario", "Error");
  226. triggerMessage(error, "Error");
  227. }
  228. // Remove loading animation in the button
  229. btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
  230. btn.disabled = false;
  231. }
  232. async function guardar(id: string) {
  233. interface Data {
  234. hora: HTMLInputElement;
  235. dia: HTMLInputElement;
  236. profesor: HTMLInputElement;
  237. salon: HTMLInputElement;
  238. }
  239. const btn: HTMLButtonElement = document.querySelector("#btn-guardar") as HTMLButtonElement;
  240. const clone: HTMLButtonElement = btn.cloneNode(true) as HTMLButtonElement;
  241. btn.innerHTML = '<i class="ing-cargando ing"></i> Guardando...';
  242. btn.disabled = true;
  243. const data: Data = {
  244. hora: document.querySelector("#editor_hora") as HTMLInputElement,
  245. dia: document.querySelector("#editor_dia") as HTMLInputElement,
  246. salon: document.querySelector("#editor_salón") as HTMLInputElement,
  247. profesor: document.querySelector("#editor_profesor") as HTMLInputElement,
  248. };
  249. const hora = data.hora.value; // h:mm
  250. const { compareHours } = await import('./date_functions');
  251. const hora_antes = compareHours(hora, "07:15") < 0;
  252. const hora_después = compareHours(hora, "21:30") > 0;
  253. if (hora_antes || hora_después) {
  254. alert(`La hora ${hora} no es válida`);
  255. triggerMessage("Selecciona una hora", "Error");
  256. btn.innerHTML = clone.innerHTML;
  257. btn.disabled = false;
  258. data.hora.focus();
  259. data.hora.classList.add("is-invalid");
  260. return;
  261. }
  262. const dia = data.dia.value;
  263. const salon = data.salon.value;
  264. const profesor = data.profesor.value;
  265. const formData = new FormData();
  266. formData.append("id", id);
  267. formData.append("hora", hora);
  268. formData.append("dia", dia);
  269. formData.append("salon", salon);
  270. formData.append("profesor", profesor);
  271. const response = await fetch("action/action_horario_update.php", {
  272. method: "POST",
  273. body: formData
  274. }).then(res => res.json());
  275. if (response.status == "success") {
  276. triggerMessage(response.message, "Éxito", "success");
  277. btn.innerHTML = '<i class="ing-aceptar ing"></i> Guardado';
  278. btn.classList.add("btn-success");
  279. btn.classList.remove("btn-primary");
  280. // return to the initial state
  281. setTimeout(() => {
  282. buscarGrupo();
  283. btn.replaceWith(clone);
  284. $("#modal-editar").modal("hide");
  285. }, 1000);
  286. } else {
  287. triggerMessage(response.message, "Error");
  288. btn.replaceWith(clone);
  289. $("#modal-editar").modal("hide");
  290. }
  291. }
  292. function triggerMessage(message: string, header: string, colour: string = "danger") {
  293. throw new Error('Function not implemented.');
  294. }