This commit is contained in:
2023-08-08 17:04:21 +00:00
parent 31ecda89b2
commit ec382e989a
147 changed files with 18206 additions and 18063 deletions

View File

@@ -1,237 +1,277 @@
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
import { text } from 'stream/consumers';
type Registro = {
carrera: string;
carrera_id: number;
comentario: null;
dia: string;
duracion: string;
duracion_id: number;
estado_supervisor_id: number;
facultad: string;
facultad_id: number;
horario_dia: number;
horario_fin: string;
horario_grupo: string;
horario_hora: string;
horario_id: number;
materia: string;
materia_id: number;
nombre: string;
periodo: string;
periodo_id: number;
profesor_clave: string;
profesor_correo: string;
profesor_grado: null;
profesor_id: number;
profesor_nombre: string;
registro_fecha: null;
registro_fecha_ideal: Date;
registro_fecha_supervisor: Date;
registro_id: number;
registro_justificada: null;
registro_retardo: null;
salon: string;
salon_id: number;
supervisor_id: number;
}
type Estado = {
color: string;
icon: string;
estado_supervisor_id: number;
}
type Facultad = {
clave_dependencia: string;
facultad_id: number;
facultad_nombre: string;
}
type Filter = {
type: string;
value: string;
icon: string;
field: string;
label: string;
}
const store = reactive({
loading: false,
current: {
comentario: '',
clase_vista: null,
empty: '',
},
facultades: {
data: [] as Facultad[],
async fetch() {
this.data = [] as Facultad[]
const res = await fetch('action/action_facultad.php')
this.data = await res.json()
},
},
filters: {
facultad_id: null,
fecha: null,
fecha_inicio: null,
fecha_fin: null,
profesor: null,
estados: [],
switchFecha: false,
switchFechas() {
$(function () {
store.filters.fecha_inicio = store.filters.fecha_fin = store.filters.fecha = null
$("#fecha, #fecha_inicio, #fecha_fin").datepicker({
minDate: -3,
maxDate: new Date(),
dateFormat: "yy-mm-dd",
showAnim: "slide",
});
const fecha = $("#fecha"), inicio = $("#fecha_inicio"), fin = $("#fecha_fin")
inicio.on("change", function () {
store.filters.fecha_inicio = inicio.val()
fin.datepicker("option", "minDate", inicio.val());
});
fin.on("change", function () {
store.filters.fecha_fin = fin.val()
inicio.datepicker("option", "maxDate", fin.val());
});
fecha.on("change", function () {
store.filters.fecha = fecha.val()
});
});
}
},
estados: {
data: [] as Estado[],
async fetch() {
this.data = [] as Estado[]
const res = await fetch('action/action_estado_supervisor.php')
this.data = await res.json()
},
getEstado(id: number): Estado {
return this.data.find((estado: Estado) => estado.estado_supervisor_id === id)
},
printEstados() {
if (store.filters.estados.length > 0)
document.querySelector('#estados')!.innerHTML = store.filters.estados.map((estado: number) =>
`<span class="mx-2 badge badge-${store.estados.getEstado(estado).estado_color}">
<i class="${store.estados.getEstado(estado).estado_icon}"></i> ${store.estados.getEstado(estado).nombre}
</span>`
).join('')
else
document.querySelector('#estados')!.innerHTML = `Todos los registros`
}
},
toggle(arr: any, element: any) {
const newArray = arr.includes(element) ? arr.filter((item: any) => item !== element) : [...arr, element]
// if all are selected, then unselect all
if (newArray.length === this.estados.data.length) return []
return newArray
},
})
declare var $: any
type Profesor = {
profesor_id: number;
profesor_nombre: string;
profesor_correo: string;
profesor_clave: string;
profesor_grado: string;
}
createApp({
store,
get clase_vista() {
return store.current.clase_vista
},
registros: {
data: [] as Registro[],
async fetch() {
this.loading = true
this.data = [] as Registro[]
const res = await fetch('action/action_auditoria.php')
this.data = await res.json()
this.loading = false
},
invertir() {
this.data = this.data.reverse()
},
mostrarComentario(registro_id: number) {
const registro = this.data.find((registro: Registro) => registro.registro_id === registro_id)
store.current.comentario = registro.comentario
$('#ver-comentario').modal('show')
},
get relevant() {
/*
facultad_id: null,
fecha: null,
fecha_inicio: null,
fecha_fin: null,
profesor: null,
asistencia: null,
estado_id: null,
if one of the filters is null, then it is not relevant
*/
const filters = Object.keys(store.filters).filter((filtro) => store.filters[filtro] || store.filters[filtro]?.length > 0)
return this.data.filter((registro: Registro) => {
return filters.every((filtro) => {
switch (filtro) {
case 'fecha':
return registro.registro_fecha_ideal === store.filters[filtro];
case 'fecha_inicio':
return registro.registro_fecha_ideal >= store.filters[filtro];
case 'fecha_fin':
return registro.registro_fecha_ideal <= store.filters[filtro];
case 'profesor':
const textoFiltro = store.filters[filtro].toLowerCase();
if (/^\([^)]+\)\s[\s\S]+$/.test(textoFiltro)) {
const clave = registro.profesor_clave.toLowerCase();
const filtroClave = textoFiltro.match(/\((.*?)\)/)?.[1];
console.log(clave, filtroClave);
return clave.includes(filtroClave);
} else {
const nombre = registro.profesor_nombre.toLowerCase();
return nombre.includes(textoFiltro);
}
case 'facultad_id':
return registro.facultad_id === store.filters[filtro];
case 'estados':
if (store.filters[filtro].length === 0) return true;
return store.filters[filtro].includes(registro.estado_supervisor_id);
default:
return true;
}
})
})
},
},
get profesores() {
return this.registros.data.map((registro: Registro) => (
{
profesor_id: registro.profesor_id,
profesor_nombre: registro.profesor_nombre,
profesor_correo: registro.profesor_correo,
profesor_clave: registro.profesor_clave,
profesor_grado: registro.profesor_grado,
}
)).sort((a: Profesor, b: Profesor) =>
a.profesor_nombre.localeCompare(b.profesor_nombre)
)
},
async mounted() {
await this.registros.fetch()
await store.facultades.fetch()
await store.estados.fetch()
store.filters.switchFechas()
}
}).mount('#app')
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
type Registro = {
carrera: string;
carrera_id: number;
comentario: null;
dia: string;
duracion: string;
duracion_id: number;
estado_supervisor_id: number;
facultad: string;
facultad_id: number;
horario_dia: number;
horario_fin: string;
horario_grupo: string;
horario_hora: string;
horario_id: number;
materia: string;
materia_id: number;
nombre: string;
periodo: string;
periodo_id: number;
profesor_clave: string;
profesor_correo: string;
profesor_grado: null;
profesor_id: number;
profesor_nombre: string;
registro_fecha: null;
registro_fecha_ideal: Date;
registro_fecha_supervisor: Date;
registro_id: number;
registro_justificada: null;
registro_retardo: null;
salon: string;
salon_id: number;
supervisor_id: number;
}
type Estado = {
color: string;
icon: string;
estado_supervisor_id: number;
}
type Facultad = {
clave_dependencia: string;
facultad_id: number;
facultad_nombre: string;
}
type Bloque_Horario = {
hora_fin: string;
hora_inicio: string;
id: number;
selected: boolean;
}
type Filter = {
type: string;
value: string;
icon: string;
field: string;
label: string;
}
const store = reactive({
loading: false,
current: {
comentario: '',
clase_vista: null,
empty: '',
},
facultades: {
data: [] as Facultad[],
async fetch() {
this.data = [] as Facultad[]
const res = await fetch('action/action_facultad.php')
this.data = await res.json()
},
},
filters: {
facultad_id: null,
fecha: null,
fecha_inicio: null,
fecha_fin: null,
profesor: null,
bloque_horario: null,
estados: [],
switchFecha: false,
switchFechas() {
$(function () {
store.filters.fecha_inicio = store.filters.fecha_fin = store.filters.fecha = null
$("#fecha, #fecha_inicio, #fecha_fin").datepicker({
minDate: -3,
maxDate: new Date(),
dateFormat: "yy-mm-dd",
showAnim: "slide",
});
const fecha = $("#fecha"), inicio = $("#fecha_inicio"), fin = $("#fecha_fin")
inicio.on("change", function () {
store.filters.fecha_inicio = inicio.val()
fin.datepicker("option", "minDate", inicio.val());
});
fin.on("change", function () {
store.filters.fecha_fin = fin.val()
inicio.datepicker("option", "maxDate", fin.val());
});
fecha.on("change", function () {
store.filters.fecha = fecha.val()
});
});
}
},
estados: {
data: [] as Estado[],
async fetch() {
this.data = [] as Estado[]
const res = await fetch('action/action_estado_supervisor.php')
this.data = await res.json()
},
getEstado(id: number): Estado {
return this.data.find((estado: Estado) => estado.estado_supervisor_id === id)
},
printEstados() {
if (store.filters.estados.length > 0)
document.querySelector('#estados')!.innerHTML = store.filters.estados.map((estado: number) =>
`<span class="mx-2 badge badge-${store.estados.getEstado(estado).estado_color}">
<i class="${store.estados.getEstado(estado).estado_icon}"></i> ${store.estados.getEstado(estado).nombre}
</span>`
).join('')
else
document.querySelector('#estados')!.innerHTML = `Todos los registros`
}
},
bloques_horario: {
data: [] as Bloque_Horario[],
async fetch() {
this.data = [] as Bloque_Horario[]
const res = await fetch('action/action_grupo_horario.php')
this.data = await res.json()
if (this.data.every((bloque: Bloque_Horario) => !bloque.selected))
this.data[0].selected = true
},
},
toggle(arr: any, element: any) {
const newArray = arr.includes(element) ? arr.filter((item: any) => item !== element) : [...arr, element]
// if all are selected, then unselect all
if (newArray.length === this.estados.data.length) return []
return newArray
},
})
declare var $: any
type Profesor = {
profesor_id: number;
profesor_nombre: string;
profesor_correo: string;
profesor_clave: string;
profesor_grado: string;
}
createApp({
store,
get clase_vista() {
return store.current.clase_vista
},
registros: {
data: [] as Registro[],
async fetch() {
this.loading = true
this.data = [] as Registro[]
const res = await fetch('action/action_auditoria.php')
this.data = await res.json()
this.loading = false
},
invertir() {
this.data = this.data.reverse()
},
mostrarComentario(registro_id: number) {
const registro = this.data.find((registro: Registro) => registro.registro_id === registro_id)
store.current.comentario = registro.comentario
$('#ver-comentario').modal('show')
},
get relevant() {
/*
facultad_id: null,
fecha: null,
fecha_inicio: null,
fecha_fin: null,
profesor: null,
asistencia: null,
estado_id: null,
if one of the filters is null, then it is not relevant
*/
const filters = Object.keys(store.filters).filter((filtro) => store.filters[filtro] || store.filters[filtro]?.length > 0)
return this.data.filter((registro: Registro) => {
return filters.every((filtro) => {
switch (filtro) {
case 'fecha':
return registro.registro_fecha_ideal === store.filters[filtro];
case 'fecha_inicio':
return registro.registro_fecha_ideal >= store.filters[filtro];
case 'fecha_fin':
return registro.registro_fecha_ideal <= store.filters[filtro];
case 'profesor':
const textoFiltro = store.filters[filtro].toLowerCase();
if (/^\([^)]+\)\s[\s\S]+$/.test(textoFiltro)) {
const clave = registro.profesor_clave.toLowerCase();
const filtroClave = textoFiltro.match(/\((.*?)\)/)?.[1];
console.log(clave, filtroClave);
return clave.includes(filtroClave);
} else {
const nombre = registro.profesor_nombre.toLowerCase();
return nombre.includes(textoFiltro);
}
case 'facultad_id':
return registro.facultad_id === store.filters[filtro];
case 'estados':
if (store.filters[filtro].length === 0) return true;
return store.filters[filtro].includes(registro.estado_supervisor_id);
case 'bloque_horario':
const bloque = store.bloques_horario.data.find((bloque: Bloque_Horario) => bloque.id === store.filters[filtro]) as Bloque_Horario;
return registro.horario_hora <= bloque.hora_fin && registro.horario_fin >= bloque.hora_inicio;
default:
return true;
}
})
})
},
async descargar() {
if (this.relevant.length === 0) return;
const res = await fetch('export/supervisor_excel.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.relevant)
});
const blob = await res.blob();
(window as any).saveAs(blob, `auditoria_${new Date().toISOString().slice(0, 10)}.xlsx`);
}
},
get profesores() {
return this.registros.data.map((registro: Registro) => (
{
profesor_id: registro.profesor_id,
profesor_nombre: registro.profesor_nombre,
profesor_correo: registro.profesor_correo,
profesor_clave: registro.profesor_clave,
profesor_grado: registro.profesor_grado,
}
)).sort((a: Profesor, b: Profesor) =>
a.profesor_nombre.localeCompare(b.profesor_nombre)
)
},
async mounted() {
await this.registros.fetch()
await store.facultades.fetch()
await store.estados.fetch()
await store.bloques_horario.fetch()
store.filters.bloque_horario = store.bloques_horario.data.find((bloque: Bloque_Horario) => bloque.selected)?.id
store.filters.switchFechas()
}
}).mount('#app')

View File

@@ -1,149 +1,149 @@
// @ts-ignore Import module
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
export interface PeridoV1 {
IdNivel: number;
IdPeriodo: number;
NombreNivel: string;
NombrePeriodo: string;
in_db: boolean;
linked: boolean;
}
export interface PeridoV2 {
ClaveCarrera: string;
FechaFin: string;
FechaInicio: string;
IdPeriodo: number;
NombreCarrera: string;
}
const webServices = {
getPeriodosV1: async (): Promise<PeridoV1[]> => {
try {
const response = await fetch('periodos.v1.php');
return await response.json();
} catch (error) {
console.log(error);
return [];
}
},
getPeriodosV2: async (): Promise<PeridoV2[]> => {
try {
const response = await fetch('periodos.v2.php');
return await response.json();
} catch (error) {
console.log(error);
return [];
}
}
}
const store = reactive({
periodosV1: [] as PeridoV1[],
periodosV2: [] as PeridoV2[],
errors: [] as string[],
fechas(idPeriodo: number): { inicio: string, fin: string } {
const periodo = this.periodosV2.find((periodo: PeridoV2) => periodo.IdPeriodo === idPeriodo);
return {
inicio: periodo ? periodo.FechaInicio : '',
fin: periodo ? periodo.FechaFin : ''
}
},
periodov1(idPeriodo: number): PeridoV1 | undefined {
return this.periodosV1.find((periodo: PeridoV1) => periodo.IdPeriodo === idPeriodo);
},
periodov2(idPeriodo: number): PeridoV2[] {
return this.periodosV2.filter((periodo: PeridoV2) => periodo.IdPeriodo === idPeriodo);
},
async addPeriodo(periodo: PeridoV1 | PeridoV2) {
try {
const result = await fetch('backend/periodos.php', {
method: 'POST',
body: JSON.stringify({
...periodo,
...this.fechas(periodo.IdPeriodo)
}),
headers: {
'Content-Type': 'application/json'
}
}).then((response) => response.json());
if (result.success) {
this.periodosV1 = this.periodosV1.map((periodoV1: PeridoV1) => {
if (periodoV1.IdPeriodo === periodo.IdPeriodo) {
periodoV1.in_db = true;
}
return periodoV1;
});
return result;
}
else {
this.errors.push(result.message);
}
} catch (error) {
this.errors.push(error);
}
},
async addCarreras(idPeriodo: number) {
try {
const periodoV1 = this.periodov1(idPeriodo) as PeridoV1;
const periodoV2 = this.periodov2(idPeriodo) as PeridoV2[];
const data = periodoV2.map(({ ClaveCarrera, NombreCarrera }: PeridoV2) =>
({
ClaveCarrera: ClaveCarrera,
NombreCarrera: NombreCarrera,
IdNivel: periodoV1.IdNivel,
})
);
const result = await fetch('backend/carreras.php', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
}).then((response) => response.json());
if (result.success) {
await webServices.getPeriodosV1().then((periodosV1) => {
this.periodosV1 = periodosV1;
});
await webServices.getPeriodosV2().then((periodosV2) => {
this.periodosV2 = periodosV2;
});
}
} catch (error) {
this.errors.push(error);
}
}
})
createApp({
store,
info(IdPeriodo: number): PeridoV2 {
const periodo = store.periodosV2.find((periodo: PeridoV2) => periodo.IdPeriodo === IdPeriodo &&
periodo.FechaInicio != '' && periodo.FechaFin != '');
return periodo
},
complete(IdPeriodo: number): boolean {
const info = this.info(IdPeriodo);
return info !== undefined;
},
mounted: async () => {
await webServices.getPeriodosV1().then((periodosV1) => {
store.periodosV1 = periodosV1;
});
await webServices.getPeriodosV2().then((periodosV2) => {
store.periodosV2 = periodosV2;
});
}
// @ts-ignore Import module
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
export interface PeridoV1 {
IdNivel: number;
IdPeriodo: number;
NombreNivel: string;
NombrePeriodo: string;
in_db: boolean;
linked: boolean;
}
export interface PeridoV2 {
ClaveCarrera: string;
FechaFin: string;
FechaInicio: string;
IdPeriodo: number;
NombreCarrera: string;
}
const webServices = {
getPeriodosV1: async (): Promise<PeridoV1[]> => {
try {
const response = await fetch('periodos.v1.php');
return await response.json();
} catch (error) {
console.log(error);
return [];
}
},
getPeriodosV2: async (): Promise<PeridoV2[]> => {
try {
const response = await fetch('periodos.v2.php');
return await response.json();
} catch (error) {
console.log(error);
return [];
}
}
}
const store = reactive({
periodosV1: [] as PeridoV1[],
periodosV2: [] as PeridoV2[],
errors: [] as string[],
fechas(idPeriodo: number): { inicio: string, fin: string } {
const periodo = this.periodosV2.find((periodo: PeridoV2) => periodo.IdPeriodo === idPeriodo);
return {
inicio: periodo ? periodo.FechaInicio : '',
fin: periodo ? periodo.FechaFin : ''
}
},
periodov1(idPeriodo: number): PeridoV1 | undefined {
return this.periodosV1.find((periodo: PeridoV1) => periodo.IdPeriodo === idPeriodo);
},
periodov2(idPeriodo: number): PeridoV2[] {
return this.periodosV2.filter((periodo: PeridoV2) => periodo.IdPeriodo === idPeriodo);
},
async addPeriodo(periodo: PeridoV1 | PeridoV2) {
try {
const result = await fetch('backend/periodos.php', {
method: 'POST',
body: JSON.stringify({
...periodo,
...this.fechas(periodo.IdPeriodo)
}),
headers: {
'Content-Type': 'application/json'
}
}).then((response) => response.json());
if (result.success) {
this.periodosV1 = this.periodosV1.map((periodoV1: PeridoV1) => {
if (periodoV1.IdPeriodo === periodo.IdPeriodo) {
periodoV1.in_db = true;
}
return periodoV1;
});
return result;
}
else {
this.errors.push(result.message);
}
} catch (error) {
this.errors.push(error);
}
},
async addCarreras(idPeriodo: number) {
try {
const periodoV1 = this.periodov1(idPeriodo) as PeridoV1;
const periodoV2 = this.periodov2(idPeriodo) as PeridoV2[];
const data = periodoV2.map(({ ClaveCarrera, NombreCarrera }: PeridoV2) =>
({
ClaveCarrera: ClaveCarrera,
NombreCarrera: NombreCarrera,
IdNivel: periodoV1.IdNivel,
})
);
const result = await fetch('backend/carreras.php', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
}).then((response) => response.json());
if (result.success) {
await webServices.getPeriodosV1().then((periodosV1) => {
this.periodosV1 = periodosV1;
});
await webServices.getPeriodosV2().then((periodosV2) => {
this.periodosV2 = periodosV2;
});
}
} catch (error) {
this.errors.push(error);
}
}
})
createApp({
store,
info(IdPeriodo: number): PeridoV2 {
const periodo = store.periodosV2.find((periodo: PeridoV2) => periodo.IdPeriodo === IdPeriodo &&
periodo.FechaInicio != '' && periodo.FechaFin != '');
return periodo
},
complete(IdPeriodo: number): boolean {
const info = this.info(IdPeriodo);
return info !== undefined;
},
mounted: async () => {
await webServices.getPeriodosV1().then((periodosV1) => {
store.periodosV1 = periodosV1;
});
await webServices.getPeriodosV2().then((periodosV2) => {
store.periodosV2 = periodosV2;
});
}
}).mount()

File diff suppressed because it is too large Load Diff

View File

@@ -1,272 +1,272 @@
import { type } from "os";
declare function triggerMessage(message: string, title: string, type?: string): void;
declare const write: boolean;
declare const moment: any;
// from this 'horario_id', 'fecha', 'hora', 'duracion_id', 'descripcion', 'profesor_id', 'salon', 'unidad', 'periodo_id', 'fecha_clase' make a type of ReposicionParams
export interface ReposicionParams {
horario_id: number;
fecha: string;
hora: string;
duracion_id: number;
descripcion: string;
profesor_id: number;
salon: string;
unidad: number;
periodo_id: number;
fecha_clase: string;
}
type Horario = {
id: number;
carrera_id: number;
materia_id: number;
grupo: string;
profesores: Profesor[];
dia: string;
hora: string;
hora_final: string;
salon: string;
fecha_inicio: string;
fecha_final: string;
fecha_carga: string;
nivel_id: number;
periodo_id: number;
facultad_id: number;
materia: string;
horas: number;
minutos: number;
duracion: number;
retardo: boolean;
original_id: number;
last: boolean;
bloques: number;
};
type Profesor = {
id: number;
clave: string;
grado: string;
profesor: string;
nombre: string;
facultad_id: number;
};
// Get references to the HTML elements
const form = document.getElementById('form') as HTMLFormElement;
const steps = Array.from(form.querySelectorAll('.step')) as HTMLElement[];
const nextButton = document.getElementById('next-button') as HTMLButtonElement;
const prevButton = document.getElementById('prev-button') as HTMLButtonElement;
let currentStep = 0;
// #clave_profesor on change => show step 2
const clave_profesor = document.getElementById('clave_profesor') as HTMLInputElement;
const horario_reponer = document.getElementById('horario_reponer') as HTMLInputElement;
const fechas_clase = document.getElementById('fechas_clase') as HTMLInputElement;
const fecha_reponer = $('#fecha_reponer') as JQuery<HTMLElement>;
const hora_reponer = $('#hora_reponer') as JQuery<HTMLElement>;
const minutos_reponer = $('#minutos_reponer') as JQuery<HTMLElement>;
clave_profesor.addEventListener('change', async () => {
const step2 = document.getElementById('step-2') as HTMLElement;
clave_profesor.disabled = true;
// get option which value is the same as clave_profesor.value
const option = document.querySelector(`option[value="${clave_profesor.value}"]`) as HTMLOptionElement;
// make a form data with #form
const profesor_id = document.getElementById('profesor_id') as HTMLInputElement;
profesor_id.value = option.dataset.id;
const formData = new FormData(form);
const response = await fetch(`./action/action_horario_profesor.php`, {
method: 'POST',
body: formData
});
const data = await response.json();
if (data['success'] === false) {
const message = "Hubo un error al obtener los horarios del profesor."
const title = 'Error';
const color = 'danger';
triggerMessage(message, title, color);
return;
}
const horarios = data.data as Horario[];
const initial = document.createElement('option');
initial.value = '';
initial.textContent = 'Seleccione un horario';
initial.selected = true;
initial.disabled = true;
horario_reponer.innerHTML = '';
horario_reponer.appendChild(initial);
horarios.forEach((horario) => {
const dias = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'];
const option = document.createElement('option');
option.value = `${horario.id}`;
// materia máx 25 caracteres, if materia.length > 25 then slice(0, 20)
const max = 25;
option.textContent = `${horario.materia.slice(0, max) + (horario.materia.length > max ? '...' : '')} - Grupo: ${horario.grupo} - ${horario.hora.slice(0, 5)}-${horario.hora_final.slice(0, 5)} - Salon: ${horario.salon} - ${horario.dia}`;
option.dataset.materia = `${horario.materia}`;
option.dataset.grupo = `${horario.grupo}`;
option.dataset.hora = `${horario.hora.slice(0, 5)}`; // slice(0, 5) => HH:MM
option.dataset.hora_final = `${horario.hora_final.slice(0, 5)}`;
option.dataset.salon = `${horario.salon}`;
option.dataset.dia = `${horario.dia}`;
option.dataset.id = `${horario.id}`;
horario_reponer.appendChild(option);
});
currentStep = 1;
step2.style.display = 'block';
prevButton.disabled = false;
});
// disable clave_profesor
// from second step to first step
prevButton.addEventListener('click', () => {
const inputs = [clave_profesor, horario_reponer, fechas_clase, fecha_reponer, hora_reponer] as HTMLInputElement[];
switch (currentStep) {
case 1:
case 2:
case 3:
const step = document.getElementById(`step-${currentStep + 1}`) as HTMLElement;
step.style.display = 'none';
inputs[currentStep - 1].disabled = false;
inputs[currentStep - 1].value = '';
if (--currentStep === 0) {
prevButton.disabled = true;
}
break;
case 4:
const step5 = document.getElementById('step-5') as HTMLElement;
step5.style.display = 'none';
fecha_reponer.prop('disabled', false);
fecha_reponer.val('');
hora_reponer.parent().removeClass('disabled');
hora_reponer.siblings('.datalist-input').text('hh');
hora_reponer.val('');
minutos_reponer.parent().removeClass('disabled');
minutos_reponer.siblings('.datalist-input').text('mm');
minutos_reponer.val('');
currentStep--;
break;
}
nextButton.disabled = true;
});
// #horario_reponer on change => show step 3
horario_reponer.addEventListener('change', async () => {
const selected = horario_reponer.querySelector(`option[value="${horario_reponer.value}"]`) as HTMLOptionElement;
horario_reponer.title = `Materia: ${selected.dataset.materia} - Grupo: ${selected.dataset.grupo} - Horario: ${selected.dataset.hora}-${selected.dataset.hora_final} - Salon: ${selected.dataset.salon} - Día: ${selected.dataset.dia}`;
const step3 = document.getElementById('step-3') as HTMLElement;
horario_reponer.disabled = true;
// make a form data with #form
const response = await fetch(`./action/action_fechas_clase.php?horario_id=${horario_reponer.value}`, {
method: 'GET',
});
const data = await response.json();
if (data['success'] === false) {
const message = "Hubo un error al obtener las fechas de clase."
const title = 'Error';
const color = 'danger';
triggerMessage(message, title, color);
return;
}
type Fecha = {
fecha: string;
dia_mes: number;
day: number;
month: number;
year: number;
}
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
const fechas = data.data as Fecha[];
const initial = document.createElement('option');
initial.value = '';
initial.textContent = 'Seleccione la fecha de la falta';
initial.selected = true;
initial.disabled = true;
fechas_clase.innerHTML = '';
fechas_clase.appendChild(initial);
fechas_clase.title = 'Seleccione la fecha de la falta';
fechas.forEach((fecha) => {
const option = document.createElement('option');
option.value = `${fecha}`;
option.textContent = `${fecha.dia_mes} de ${meses[fecha.month - 1]} de ${fecha.year}`;
fechas_clase.appendChild(option);
});
step3.style.display = 'block';
currentStep = 2;
});
// #fechas_clase on change => show step 4
fechas_clase.addEventListener('change', () => {
const step4 = document.getElementById('step-4') as HTMLElement;
step4.style.display = 'block';
fechas_clase.disabled = true;
currentStep = 3;
});
// when both #fecha_reponer and #hora_reponer are selected => show step 5
const lastStep = () => {
// timeout to wait for the value to be set
setTimeout(() => {
if (fecha_reponer.val() !== '' && hora_reponer.val() !== '' && minutos_reponer.val() !== '') {
const step5 = document.getElementById('step-5') as HTMLElement;
step5.style.display = 'block';
// disable both
fecha_reponer.prop('disabled', true);
hora_reponer.parent().addClass('disabled');
minutos_reponer.parent().addClass('disabled');
const nextButton = document.getElementById('next-button') as HTMLButtonElement;
// remove property disabled
nextButton.removeAttribute('disabled');
currentStep = 4;
}
}, 100);
}
fecha_reponer.on('change', lastStep);
// on click on the sibling ul>li of #hora_reponer and #minutos_reponer
hora_reponer.siblings('ul').children('li').on('click', lastStep);
minutos_reponer.siblings('ul').children('li').on('click', lastStep);
// Initialize the form
hideSteps();
showCurrentStep();
function hideSteps() {
steps.forEach((step) => {
step.style.display = 'none';
});
}
function showCurrentStep() {
steps[currentStep].style.display = 'block';
prevButton.disabled = currentStep === 0;
}
function handleSubmit(event: Event) {
event.preventDefault();
// Handle form submission
// You can access the form data using the FormData API or serialize it manually
import { type } from "os";
declare function triggerMessage(message: string, title: string, type?: string): void;
declare const write: boolean;
declare const moment: any;
// from this 'horario_id', 'fecha', 'hora', 'duracion_id', 'descripcion', 'profesor_id', 'salon', 'unidad', 'periodo_id', 'fecha_clase' make a type of ReposicionParams
export interface ReposicionParams {
horario_id: number;
fecha: string;
hora: string;
duracion_id: number;
descripcion: string;
profesor_id: number;
salon: string;
unidad: number;
periodo_id: number;
fecha_clase: string;
}
type Horario = {
id: number;
carrera_id: number;
materia_id: number;
grupo: string;
profesores: Profesor[];
dia: string;
hora: string;
hora_final: string;
salon: string;
fecha_inicio: string;
fecha_final: string;
fecha_carga: string;
nivel_id: number;
periodo_id: number;
facultad_id: number;
materia: string;
horas: number;
minutos: number;
duracion: number;
retardo: boolean;
original_id: number;
last: boolean;
bloques: number;
};
type Profesor = {
id: number;
clave: string;
grado: string;
profesor: string;
nombre: string;
facultad_id: number;
};
// Get references to the HTML elements
const form = document.getElementById('form') as HTMLFormElement;
const steps = Array.from(form.querySelectorAll('.step')) as HTMLElement[];
const nextButton = document.getElementById('next-button') as HTMLButtonElement;
const prevButton = document.getElementById('prev-button') as HTMLButtonElement;
let currentStep = 0;
// #clave_profesor on change => show step 2
const clave_profesor = document.getElementById('clave_profesor') as HTMLInputElement;
const horario_reponer = document.getElementById('horario_reponer') as HTMLInputElement;
const fechas_clase = document.getElementById('fechas_clase') as HTMLInputElement;
const fecha_reponer = $('#fecha_reponer') as JQuery<HTMLElement>;
const hora_reponer = $('#hora_reponer') as JQuery<HTMLElement>;
const minutos_reponer = $('#minutos_reponer') as JQuery<HTMLElement>;
clave_profesor.addEventListener('change', async () => {
const step2 = document.getElementById('step-2') as HTMLElement;
clave_profesor.disabled = true;
// get option which value is the same as clave_profesor.value
const option = document.querySelector(`option[value="${clave_profesor.value}"]`) as HTMLOptionElement;
// make a form data with #form
const profesor_id = document.getElementById('profesor_id') as HTMLInputElement;
profesor_id.value = option.dataset.id;
const formData = new FormData(form);
const response = await fetch(`./action/action_horario_profesor.php`, {
method: 'POST',
body: formData
});
const data = await response.json();
if (data['success'] === false) {
const message = "Hubo un error al obtener los horarios del profesor."
const title = 'Error';
const color = 'danger';
triggerMessage(message, title, color);
return;
}
const horarios = data.data as Horario[];
const initial = document.createElement('option');
initial.value = '';
initial.textContent = 'Seleccione un horario';
initial.selected = true;
initial.disabled = true;
horario_reponer.innerHTML = '';
horario_reponer.appendChild(initial);
horarios.forEach((horario) => {
const dias = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'];
const option = document.createElement('option');
option.value = `${horario.id}`;
// materia máx 25 caracteres, if materia.length > 25 then slice(0, 20)
const max = 25;
option.textContent = `${horario.materia.slice(0, max) + (horario.materia.length > max ? '...' : '')} - Grupo: ${horario.grupo} - ${horario.hora.slice(0, 5)}-${horario.hora_final.slice(0, 5)} - Salon: ${horario.salon} - ${horario.dia}`;
option.dataset.materia = `${horario.materia}`;
option.dataset.grupo = `${horario.grupo}`;
option.dataset.hora = `${horario.hora.slice(0, 5)}`; // slice(0, 5) => HH:MM
option.dataset.hora_final = `${horario.hora_final.slice(0, 5)}`;
option.dataset.salon = `${horario.salon}`;
option.dataset.dia = `${horario.dia}`;
option.dataset.id = `${horario.id}`;
horario_reponer.appendChild(option);
});
currentStep = 1;
step2.style.display = 'block';
prevButton.disabled = false;
});
// disable clave_profesor
// from second step to first step
prevButton.addEventListener('click', () => {
const inputs = [clave_profesor, horario_reponer, fechas_clase, fecha_reponer, hora_reponer] as HTMLInputElement[];
switch (currentStep) {
case 1:
case 2:
case 3:
const step = document.getElementById(`step-${currentStep + 1}`) as HTMLElement;
step.style.display = 'none';
inputs[currentStep - 1].disabled = false;
inputs[currentStep - 1].value = '';
if (--currentStep === 0) {
prevButton.disabled = true;
}
break;
case 4:
const step5 = document.getElementById('step-5') as HTMLElement;
step5.style.display = 'none';
fecha_reponer.prop('disabled', false);
fecha_reponer.val('');
hora_reponer.parent().removeClass('disabled');
hora_reponer.siblings('.datalist-input').text('hh');
hora_reponer.val('');
minutos_reponer.parent().removeClass('disabled');
minutos_reponer.siblings('.datalist-input').text('mm');
minutos_reponer.val('');
currentStep--;
break;
}
nextButton.disabled = true;
});
// #horario_reponer on change => show step 3
horario_reponer.addEventListener('change', async () => {
const selected = horario_reponer.querySelector(`option[value="${horario_reponer.value}"]`) as HTMLOptionElement;
horario_reponer.title = `Materia: ${selected.dataset.materia} - Grupo: ${selected.dataset.grupo} - Horario: ${selected.dataset.hora}-${selected.dataset.hora_final} - Salon: ${selected.dataset.salon} - Día: ${selected.dataset.dia}`;
const step3 = document.getElementById('step-3') as HTMLElement;
horario_reponer.disabled = true;
// make a form data with #form
const response = await fetch(`./action/action_fechas_clase.php?horario_id=${horario_reponer.value}`, {
method: 'GET',
});
const data = await response.json();
if (data['success'] === false) {
const message = "Hubo un error al obtener las fechas de clase."
const title = 'Error';
const color = 'danger';
triggerMessage(message, title, color);
return;
}
type Fecha = {
fecha: string;
dia_mes: number;
day: number;
month: number;
year: number;
}
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
const fechas = data.data as Fecha[];
const initial = document.createElement('option');
initial.value = '';
initial.textContent = 'Seleccione la fecha de la falta';
initial.selected = true;
initial.disabled = true;
fechas_clase.innerHTML = '';
fechas_clase.appendChild(initial);
fechas_clase.title = 'Seleccione la fecha de la falta';
fechas.forEach((fecha) => {
const option = document.createElement('option');
option.value = `${fecha}`;
option.textContent = `${fecha.dia_mes} de ${meses[fecha.month - 1]} de ${fecha.year}`;
fechas_clase.appendChild(option);
});
step3.style.display = 'block';
currentStep = 2;
});
// #fechas_clase on change => show step 4
fechas_clase.addEventListener('change', () => {
const step4 = document.getElementById('step-4') as HTMLElement;
step4.style.display = 'block';
fechas_clase.disabled = true;
currentStep = 3;
});
// when both #fecha_reponer and #hora_reponer are selected => show step 5
const lastStep = () => {
// timeout to wait for the value to be set
setTimeout(() => {
if (fecha_reponer.val() !== '' && hora_reponer.val() !== '' && minutos_reponer.val() !== '') {
const step5 = document.getElementById('step-5') as HTMLElement;
step5.style.display = 'block';
// disable both
fecha_reponer.prop('disabled', true);
hora_reponer.parent().addClass('disabled');
minutos_reponer.parent().addClass('disabled');
const nextButton = document.getElementById('next-button') as HTMLButtonElement;
// remove property disabled
nextButton.removeAttribute('disabled');
currentStep = 4;
}
}, 100);
}
fecha_reponer.on('change', lastStep);
// on click on the sibling ul>li of #hora_reponer and #minutos_reponer
hora_reponer.siblings('ul').children('li').on('click', lastStep);
minutos_reponer.siblings('ul').children('li').on('click', lastStep);
// Initialize the form
hideSteps();
showCurrentStep();
function hideSteps() {
steps.forEach((step) => {
step.style.display = 'none';
});
}
function showCurrentStep() {
steps[currentStep].style.display = 'block';
prevButton.disabled = currentStep === 0;
}
function handleSubmit(event: Event) {
event.preventDefault();
// Handle form submission
// You can access the form data using the FormData API or serialize it manually
}