Mostrar horarios cargados

master
Araozu 2022-10-14 12:05:25 -05:00
parent 93eb18cd6d
commit 93db894306
3 changed files with 255 additions and 41 deletions

View File

@ -1,11 +1,134 @@
import { TopBar } from "./SistemasMovil/TopBar";
import { Table } from "./SistemasMovil/Table";
import { GrupoDia, Table, TableInput } from "./SistemasMovil/Table";
import { getHorariosMock, ListaCursosCompleto } from "../API/CargaHorarios";
import { createSignal } from "solid-js";
import { generarMapaCeldas } from "./SistemasMovil/mapaCeldas";
export function SistemasMovil() {
const [rawData, setRawData] = createSignal<ListaCursosCompleto>([]);
// Obtener cursos seleccionados del servidor
(async() => {
const cursos: Array<string> = JSON.parse(localStorage.getItem("cursos-seleccionados") ?? "[]");
const data = await getHorariosMock({
cursos: cursos.map((x) => parseInt(x, 10)),
});
setRawData(data);
})();
return (
<div>
<TopBar tituloBarra="Mi Horario" />
<Table />
<Table datos={transformar(rawData())} />
</div>
);
}
/*
{
id_horario: number,
id_laboratorio: number,
abreviado: string,
grupo: string,
offsetVertical: number, // 07:00 -> 0, 07:50 -> 1
nroHoras: number,
offsetHorizontal: number, // 0, 1, 2
fraccion: number, // por cuanto dividir la celda. 1, 2, 3, ...
}
*/
function transformar(input: ListaCursosCompleto): TableInput {
const data: TableInput = {
lunes: [],
martes: [],
miercoles: [],
jueves: [],
viernes: [],
};
// Organizar por dias
for (const curso of input) {
for (const lab of curso.laboratorios) {
for (const horas of lab.horario) {
const dia = horas.dia;
const [idx, nroHoras] = infoDiaAOffsets(horas.hora_inicio, horas.hora_fin);
const datos = {
id_horario: horas.id_horario,
id_laboratorio: lab.id_laboratorio,
abreviado: curso.abreviado,
grupo: lab.grupo,
offsetVertical: idx,
nroHoras: nroHoras,
offsetHorizontal: 0,
fraccion: 0,
};
if (dia === "Lunes") {
data.lunes.push(datos);
} else if (dia === "Martes") {
data.martes.push(datos);
} else if (dia === "Miercoles") {
data.miercoles.push(datos);
} else if (dia === "Jueves") {
data.jueves.push(datos);
} else if (dia === "Viernes") {
data.viernes.push(datos);
}
}
}
}
// Procesar cada dia y devolver
return {
lunes: generarMapaCeldas(data.lunes),
martes: generarMapaCeldas(data.martes),
miercoles: generarMapaCeldas(data.miercoles),
jueves: generarMapaCeldas(data.jueves),
viernes: generarMapaCeldas(data.viernes),
};
}
const horas = [
700,
750,
850,
940,
1040,
1130,
1220,
1310,
1400,
1450,
1550,
1640,
1740,
1830,
1920,
2010,
2100,
2150,
];
/**
* Convierte horas en texto a offsets
*/
// Ejm: 0700, 0850 -> 0, 2
function infoDiaAOffsets(horaInicio: string, horaFinal: string): [number, number] {
const inicio = parseInt(horaInicio, 10);
const final = parseInt(horaFinal, 10);
const idxInicio = horas.findIndex((x) => x === inicio);
let nroHoras = 0;
for (let i = idxInicio; i < horas.length; i += 1) {
if (final > horas[i]) {
nroHoras += 1;
} else {
break;
}
}
return [idxInicio, nroHoras];
}

View File

@ -25,19 +25,21 @@ const s = StyleSheet.create({
},
});
type DayIndex = 0 | 1 | 2 | 3;
type DayIndex = 0 | 1 | 2 | 3 | 4;
const days = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes"];
type Output = {
curso: string,
export type GrupoDia = {
id_horario: number,
id_laboratorio: number,
abreviado: string,
grupo: string,
idxHoraInicio: number,
offsetVertical: number, // 07:00 -> 0, 07:50 -> 1
nroHoras: number,
offset: number, // 0, 1, 2
offsetHorizontal: number, // 0, 1, 2
fraccion: number, // por cuanto dividir la celda. 1, 2, 3, ...
}
function Grupo(props: {data: Output}) {
function Grupo(props: {data: GrupoDia}) {
const ss = StyleSheet.create({
button: {
display: "inline-block",
@ -48,16 +50,24 @@ function Grupo(props: {data: Output}) {
position: "absolute",
},
});
const estilo = () => {
const fraccion = props.data.fraccion;
const offsetHorizontal = props.data.offsetHorizontal + 1;
const offsetVertical = props.data.offsetVertical;
const nroHoras = props.data.nroHoras;
return `left: calc((43vw / ${fraccion}) * ${offsetHorizontal} - 14vw); top: ${offsetVertical * 3}rem;` +
`height: ${nroHoras * 3}rem; width: calc(100% / ${fraccion})`;
};
return (
<button className={css(ss.button)} style={`left: calc((43vw / ${props.data.fraccion}) * ${props.data.offset} - 14vw); top: ${props.data.idxHoraInicio * 3}rem; height: ${props.data.nroHoras * 3}rem; width: calc(100% / ${props.data.fraccion})`}>
{props.data.curso}
<button className={css(ss.button)} style={estilo()}>
{props.data.abreviado}
<br />
{props.data.grupo}
</button>
);
}
function Dia(props: {dia: string}) {
function Dia(props: {dia: string, grupos: Array<GrupoDia>}) {
const ss = StyleSheet.create({
contenedorDia: {
position: "relative",
@ -67,41 +77,33 @@ function Dia(props: {dia: string}) {
<div className={css(s.columna)}>
<div className={css(s.tableIndex)}>{props.dia}</div>
<div className={css(ss.contenedorDia)}>
<Grupo data={{
curso: "TAIS",
grupo: "LA",
idxHoraInicio: 0,
nroHoras: 3,
offset: 1,
fraccion: 3,
}}
/>
<Grupo data={{
curso: "PPP",
grupo: "LB",
idxHoraInicio: 2,
nroHoras: 2,
offset: 2,
fraccion: 3,
}}
/>
<Grupo data={{
curso: "FC",
grupo: "LC",
idxHoraInicio: 1,
nroHoras: 4,
offset: 3,
fraccion: 3,
}}
/>
<For each={props.grupos}>
{(grupo) => (
<Grupo data={grupo} />
)}
</For>
</div>
</div>
);
}
export function Table() {
export type TableInput = {
lunes: Array<GrupoDia>,
martes: Array<GrupoDia>,
miercoles: Array<GrupoDia>,
jueves: Array<GrupoDia>,
viernes: Array<GrupoDia>,
}
export function Table(props: {datos: TableInput}) {
const [currentDay, setCurrentDay] = createSignal<DayIndex>(0);
const lunes = <Dia dia={"Lunes"} grupos={props.datos.lunes} />;
const martes = <Dia dia={"Martes"} grupos={props.datos.martes} />;
const miercoles = <Dia dia={"Miercoles"} grupos={props.datos.miercoles} />;
const jueves = <Dia dia={"Jueves"} grupos={props.datos.jueves} />;
const viernes = <Dia dia={"Viernes"} grupos={props.datos.viernes} />;
return (
<div className={css(s.container)}>
<div className={css(s.columna)}>
@ -110,8 +112,8 @@ export function Table() {
{(hora) => <div className={css(s.celdaHora)}>{hora.substring(0, 5)}</div>}
</For>
</div>
<Dia dia={days[currentDay()]} />
<Dia dia={days[currentDay() + 1]} />
{martes}
{miercoles}
</div>
);
}

View File

@ -0,0 +1,89 @@
import { GrupoDia } from "./Table";
export class MapaCeldas {
// Almacena referencias a input
private mapa: Map<number, Map<number, null>> = new Map();
private disponible(nroFila: number, nroColumna: number): boolean {
if (!this.mapa.has(nroFila)) return true;
const fila = this.mapa.get(nroFila)!;
return fila.has(nroColumna) === false;
}
private obtenerFilaOCrear(nro: number): Map<number, null> {
if (!this.mapa.has(nro)) {
const m = new Map<number, null>();
this.mapa.set(nro, m);
return m;
}
return this.mapa.get(nro)!;
}
// Devuelve el offset
public solicitar(inicio: number, cantidad: number): number {
const filas = [];
for (let i = 0; i < cantidad; i += 1) filas.push(inicio + i);
for (let offsetActual = 0; offsetActual < 8; offsetActual += 1) {
let todasCeldasDisponibles = true;
for (const fila of filas) {
if (!this.disponible(fila, offsetActual)) {
todasCeldasDisponibles = false;
break;
}
}
if (todasCeldasDisponibles) {
// Crear estas celdas y almacenar
filas.forEach((nroFila) => {
const fila = this.obtenerFilaOCrear(nroFila);
fila.set(offsetActual, null);
});
// Devolver nro de offset
return offsetActual;
}
}
throw new Error("Limite de celdas alcanzado");
}
public generarFraccion(nroFila: number, nroColumna: number, cantidad: number): number {
let fraccionActual = 1;
for (let i = 0; i < cantidad; i += 1) {
const nroFilaActual = nroFila + i;
const filaActual = this.mapa.get(nroFilaActual)!;
const numeroColumnas = filaActual.size;
if (numeroColumnas > fraccionActual) {
fraccionActual = numeroColumnas;
}
}
return fraccionActual;
}
}
export function generarMapaCeldas(entrada: Readonly<Array<GrupoDia>>): Array<GrupoDia> {
const mapa = new MapaCeldas();
const salida: Array<GrupoDia> = [];
// Obtener los offsets de cada curso
for (const input of entrada) {
const offset = mapa.solicitar(input.offsetVertical, input.nroHoras);
salida.push({
...input,
offsetHorizontal: offset,
fraccion: -1,
});
}
// Generar las fracciones de cada curso
for (const output of salida) {
output.fraccion = mapa.generarFraccion(output.offsetVertical, output.offsetHorizontal, output.nroHoras);
}
return salida;
}