Crear TablaObserver para reemplazar la forma en la que se resaltan celdas en la tabla

master
Araozu 2021-03-26 19:19:09 -05:00
parent f325f08fc8
commit cc36f070b7
10 changed files with 199 additions and 100 deletions

View File

@ -10,6 +10,9 @@
<link rel="stylesheet" href="css/phosphor.min.css"> <link rel="stylesheet" href="css/phosphor.min.css">
<link rel="stylesheet" href="css/global.css"> <link rel="stylesheet" href="css/global.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -9,7 +9,7 @@ import { Creditos } from "./Creditos"
function App() { function App() {
/// @ts-ignore /// @ts-ignore
const soportaBackdropFilter = document.body.style.backdropFilter !== undefined const soportaBackdropFilter = document.body.style.backdropFilter !== undefined
const mostrarMensajeBackdropFilterRaw = localStorage.getItem("mensaje-backdrop-filter-oculto") !== undefined const mostrarMensajeBackdropFilterRaw = localStorage.getItem("mensaje-backdrop-filter-oculto") === undefined
const [mostrarMensajeBackdropFilter, setMostrarMensaje] = createSignal(mostrarMensajeBackdropFilterRaw) const [mostrarMensajeBackdropFilter, setMostrarMensaje] = createSignal(mostrarMensajeBackdropFilterRaw)

View File

@ -2,7 +2,7 @@ import { estilosGlobales } from "./Estilos"
import { StyleSheet, css } from "aphrodite" import { StyleSheet, css } from "aphrodite"
import { numWallpaper, setNumWallpaper } from "./Store" import { numWallpaper, setNumWallpaper } from "./Store"
const totalWallpapers = 5 const ultimoIndiceWallpaper = 5
const e = StyleSheet.create({ const e = StyleSheet.create({
contCambiador: { contCambiador: {
@ -36,14 +36,14 @@ const retrocederWallpaper = () => {
setNumWallpaper(num - 1) setNumWallpaper(num - 1)
localStorage.setItem("num-img", (num - 1).toString()) localStorage.setItem("num-img", (num - 1).toString())
} else { } else {
setNumWallpaper(totalWallpapers) setNumWallpaper(ultimoIndiceWallpaper)
localStorage.setItem("num-img", (totalWallpapers).toString()) localStorage.setItem("num-img", (ultimoIndiceWallpaper).toString())
} }
} }
const avanzarWallpaper = () => { const avanzarWallpaper = () => {
const num = numWallpaper() const num = numWallpaper()
if (num < totalWallpapers) { if (num < ultimoIndiceWallpaper) {
setNumWallpaper(num + 1) setNumWallpaper(num + 1)
localStorage.setItem("num-img", (num + 1).toString()) localStorage.setItem("num-img", (num + 1).toString())
} else { } else {

View File

@ -1,7 +1,8 @@
import { Cursos, CursoRaw, DatosGrupo, ListaCursosUsuario, Curso } from "../types/DatosHorario" import { Cursos, DatosGrupo, ListaCursosUsuario, Curso } from "../types/DatosHorario"
import { createEffect, createMemo, For, SetStateFunction } from "solid-js" import { createMemo, For, SetStateFunction } from "solid-js"
import { StyleSheet, css } from "aphrodite" import { StyleSheet, css } from "aphrodite"
import { estilosGlobales } from "../Estilos" import { estilosGlobales } from "../Estilos"
import { TablaObserver } from "./TablaObserver"
const e = StyleSheet.create({ const e = StyleSheet.create({
inline: { inline: {
@ -29,14 +30,14 @@ const e = StyleSheet.create({
}) })
interface Props { interface Props {
version: number,
dataAnio: Cursos, dataAnio: Cursos,
anioActual: () => string, anioActual: () => string,
fnAgregarCurso: (c: Curso) => void, fnAgregarCurso: (c: Curso) => void,
listaCursosUsuario: ListaCursosUsuario, listaCursosUsuario: ListaCursosUsuario,
idHover: () => string,
setIdHover: (v: string) => string,
esCursoMiHorario: boolean, esCursoMiHorario: boolean,
setCursosUsuarios: SetStateFunction<ListaCursosUsuario> setCursosUsuarios: SetStateFunction<ListaCursosUsuario>,
tablaObserver: TablaObserver,
} }
type FnSetCursosUsuarios = SetStateFunction<ListaCursosUsuario>; type FnSetCursosUsuarios = SetStateFunction<ListaCursosUsuario>;
@ -45,7 +46,7 @@ interface PropsIndicadorGrupo {
nombre: string, nombre: string,
esLab: boolean, esLab: boolean,
idParcial: string, idParcial: string,
setIdHover: (v: string) => string, tablaObserver: TablaObserver,
onClick: () => void onClick: () => void
} }
@ -54,8 +55,8 @@ function IndicadorGrupo(props: PropsIndicadorGrupo) {
return ( return (
<span className={css(e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)} <span className={css(e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)}
style={props.esLab ? {"font-style": "italic"} : {"font-weight": "bold"}} style={props.esLab ? {"font-style": "italic"} : {"font-weight": "bold"}}
onMouseEnter={() => props.setIdHover(id)} onMouseEnter={() => props.tablaObserver.resaltar(id)}
onMouseLeave={() => props.setIdHover("")} onMouseLeave={() => props.tablaObserver.quitarResaltado()}
onClick={props.onClick} onClick={props.onClick}
> >
{props.esLab ? "L" : ""}{props.nombre} {props.esLab ? "L" : ""}{props.nombre}
@ -114,7 +115,7 @@ export function CursosElem(props: Props) {
<For each={Object.entries(props.dataAnio)}> <For each={Object.entries(props.dataAnio)}>
{([indiceCurso, datosCurso]) => { {([indiceCurso, datosCurso]) => {
const idCurso = `${anio()}_${datosCurso.abreviado}` const idCurso = `${props.version}_${anio()}_${datosCurso.abreviado}`
const cursoAgregadoMemo = createMemo( const cursoAgregadoMemo = createMemo(
() => props.listaCursosUsuario.cursos.find((x) => x.nombre === datosCurso.nombre && !x.oculto) !== undefined, () => props.listaCursosUsuario.cursos.find((x) => x.nombre === datosCurso.nombre && !x.oculto) !== undefined,
@ -152,8 +153,8 @@ export function CursosElem(props: Props) {
<div className={claseMemo()}> <div className={claseMemo()}>
<div <div
className={css(e.inline, e.lineaTexto, e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)} className={css(e.inline, e.lineaTexto, e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)}
onMouseEnter={() => props.setIdHover(idCurso)} onMouseEnter={() => props.tablaObserver.resaltar(idCurso)}
onMouseLeave={() => props.setIdHover("")} onMouseLeave={() => props.tablaObserver.quitarResaltado()}
> >
{datosCurso.abreviado} - {datosCurso.nombre} {datosCurso.abreviado} - {datosCurso.nombre}
</div> </div>
@ -168,10 +169,11 @@ export function CursosElem(props: Props) {
</span> </span>
<For each={grupos}> <For each={grupos}>
{([x, fnOnClick]) => ( {([x, fnOnClick]) => (
<IndicadorGrupo nombre={x} <IndicadorGrupo
nombre={x}
esLab={false} esLab={false}
idParcial={idCurso} idParcial={idCurso}
setIdHover={props.setIdHover} tablaObserver={props.tablaObserver}
onClick={fnOnClick} onClick={fnOnClick}
/> />
) )
@ -190,10 +192,11 @@ export function CursosElem(props: Props) {
</span> </span>
<For each={grupos}> <For each={grupos}>
{([x, fnOnClick]) => ( {([x, fnOnClick]) => (
<IndicadorGrupo nombre={x} <IndicadorGrupo
nombre={x}
esLab esLab
idParcial={idCurso} idParcial={idCurso}
setIdHover={props.setIdHover} tablaObserver={props.tablaObserver}
onClick={fnOnClick} onClick={fnOnClick}
/> />
) )

View File

@ -7,6 +7,7 @@ import { CursosElem } from "./CursosElem"
import { EstadoLayout } from "./ContenedorHorarios" import { EstadoLayout } from "./ContenedorHorarios"
import { BotonMaxMin } from "./BotonMaxMin" import { BotonMaxMin } from "./BotonMaxMin"
import { useListaCursos } from "./useListaCursos" import { useListaCursos } from "./useListaCursos"
import { TablaObserver } from "./TablaObserver"
interface HorariosProps { interface HorariosProps {
data: DatosHorario, data: DatosHorario,
@ -25,8 +26,8 @@ const {
export function Horarios(props: HorariosProps) { export function Horarios(props: HorariosProps) {
const [anioActual, setAnioActual] = createSignal("1er año") const [anioActual, setAnioActual] = createSignal("1er año")
// ID que indica cuales celdas resaltar.
const [idHover, setIdHover] = createSignal("") const tablaObserver = new TablaObserver()
const elAnios = ( const elAnios = (
<For each={Object.entries(props.data.años)}> <For each={Object.entries(props.data.años)}>
@ -102,21 +103,20 @@ export function Horarios(props: HorariosProps) {
data={dataTabla()} data={dataTabla()}
version={props.data.version} version={props.data.version}
anio={anioActual()} anio={anioActual()}
idHover={idHover}
setIdHover={setIdHover}
setCursosUsuarios={setListaCursos} setCursosUsuarios={setListaCursos}
tablaObserver={tablaObserver}
/> />
</div> </div>
<div> <div>
<CursosElem <CursosElem
version={props.data.version}
dataAnio={dataTabla()} dataAnio={dataTabla()}
anioActual={anioActual} anioActual={anioActual}
fnAgregarCurso={props.fnAgregarCurso} fnAgregarCurso={props.fnAgregarCurso}
listaCursosUsuario={props.listaCursosUsuario} listaCursosUsuario={props.listaCursosUsuario}
idHover={idHover}
setIdHover={setIdHover}
esCursoMiHorario={false} esCursoMiHorario={false}
setCursosUsuarios={setListaCursos} setCursosUsuarios={setListaCursos}
tablaObserver={tablaObserver}
/> />
</div> </div>
</Match> </Match>

View File

@ -1,13 +1,13 @@
import { estilosGlobales } from "../Estilos" import { estilosGlobales } from "../Estilos"
import { StyleSheet, css } from "aphrodite" import { StyleSheet, css } from "aphrodite"
import { Tabla } from "./Tabla" import { Tabla } from "./Tabla"
import { mostrarDescansos } from "../Store"
import { EstadoLayout } from "./ContenedorHorarios" import { EstadoLayout } from "./ContenedorHorarios"
import { Switch, Match, For, createMemo, createSignal, SetStateFunction } from "solid-js" import { Switch, Match, createMemo, SetStateFunction } from "solid-js"
import { BotonMaxMin } from "./BotonMaxMin" import { BotonMaxMin } from "./BotonMaxMin"
import { BotonIcono } from "./BotonIcono" import { BotonIcono } from "./BotonIcono"
import { Curso, Cursos, ListaCursosUsuario } from "../types/DatosHorario" import { Curso, Cursos, ListaCursosUsuario } from "../types/DatosHorario"
import { CursosElem } from "./CursosElem" import { CursosElem } from "./CursosElem"
import { TablaObserver } from "./TablaObserver"
interface MiHorarioProps { interface MiHorarioProps {
estadoLayout: EstadoLayout, estadoLayout: EstadoLayout,
@ -31,7 +31,7 @@ const e = StyleSheet.create({
}) })
export function MiHorario(props: MiHorarioProps) { export function MiHorario(props: MiHorarioProps) {
const [idHover, setIdHover] = createSignal("") const tablaObserver = new TablaObserver()
const datosMiHorario = createMemo(() => { const datosMiHorario = createMemo(() => {
const obj: Cursos = {} const obj: Cursos = {}
@ -48,7 +48,7 @@ export function MiHorario(props: MiHorarioProps) {
/* TODO: En barra superior colocar todos los horarios. En barra inferior el horario /* TODO: En barra superior colocar todos los horarios. En barra inferior el horario
actual. actual.
Al hacer click en un horario de la barra superior, llevarlo al inicio de la lista. Al hacer click en un horario de la barra superior, llevarlo al inicio de la lista.
*/ */
return ( return (
<div> <div>
<Switch> <Switch>
@ -110,21 +110,20 @@ export function MiHorario(props: MiHorarioProps) {
data={datosMiHorario()} data={datosMiHorario()}
anio={"Mi horario"} anio={"Mi horario"}
version={1} version={1}
idHover={idHover}
setIdHover={setIdHover}
setCursosUsuarios={props.setCursosUsuarios} setCursosUsuarios={props.setCursosUsuarios}
tablaObserver={tablaObserver}
/> />
</div> </div>
<CursosElem <CursosElem
version={Number(Math.random() * 1_000_000)}
anioActual={() => "Mi horario"} anioActual={() => "Mi horario"}
dataAnio={datosMiHorario()} dataAnio={datosMiHorario()}
fnAgregarCurso={props.fnAgregarCurso} fnAgregarCurso={props.fnAgregarCurso}
listaCursosUsuario={props.cursosUsuario} listaCursosUsuario={props.cursosUsuario}
idHover={idHover}
setIdHover={setIdHover}
esCursoMiHorario esCursoMiHorario
setCursosUsuarios={props.setCursosUsuarios} setCursosUsuarios={props.setCursosUsuarios}
tablaObserver={tablaObserver}
/> />
</Match> </Match>
<Match when={props.estadoLayout === "MaxHorarios"}> <Match when={props.estadoLayout === "MaxHorarios"}>

View File

@ -4,6 +4,7 @@ import { estilosGlobales } from "../Estilos"
import { Cursos, ListaCursosUsuario, DataProcesada } from "../types/DatosHorario" import { Cursos, ListaCursosUsuario, DataProcesada } from "../types/DatosHorario"
import { Dia, dias, horas } from "../Store" import { Dia, dias, horas } from "../Store"
import { FilaTabla } from "./Tabla/FilaTabla" import { FilaTabla } from "./Tabla/FilaTabla"
import { TablaObserver } from "./TablaObserver"
export const coloresBorde = Object.freeze([ export const coloresBorde = Object.freeze([
"rgba(33,150,243,1)", "rgba(33,150,243,1)",
@ -160,16 +161,13 @@ interface Props {
data: Cursos, data: Cursos,
anio: string, anio: string,
version: number, version: number,
idHover: () => string, setCursosUsuarios: SetStateFunction<ListaCursosUsuario>,
setIdHover: (v: string) => string, tablaObserver: TablaObserver,
setCursosUsuarios: SetStateFunction<ListaCursosUsuario>
} }
export function Tabla(props: Props) { export function Tabla(props: Props) {
const anio = () => props.anio.substring(0, props.anio.indexOf(" ")) const anio = () => props.anio.substring(0, props.anio.indexOf(" "))
const data = createMemo(() => procesarAnio(props.data, anio(), props.version, props.setCursosUsuarios)) const data = createMemo(() => procesarAnio(props.data, anio(), props.version, props.setCursosUsuarios))
const idHover = props.idHover
const setIdHover = props.setIdHover
const celdas = createMemo(() => { const celdas = createMemo(() => {
// Hace reaccionar a la reactividad de Solid // Hace reaccionar a la reactividad de Solid
@ -180,8 +178,7 @@ export function Tabla(props: Props) {
<FilaTabla <FilaTabla
data={data()} data={data()}
hora={hora} hora={hora}
idHover={idHover} tablaObserver={props.tablaObserver}
setIdHover={setIdHover}
/> />
)} )}
</For> </For>

View File

@ -1,8 +1,9 @@
import { StyleSheet, css } from "aphrodite" import { StyleSheet, css } from "aphrodite"
import { estilosGlobales } from "../../Estilos" import { estilosGlobales } from "../../Estilos"
import { For, createSignal, createMemo, createEffect, SetStateFunction } from "solid-js" import { For, createSignal, createMemo } from "solid-js"
import { Dia } from "../../Store" import { Dia } from "../../Store"
import { DatosGrupo, ListaCursosUsuario } from "../../types/DatosHorario" import { DatosGrupo } from "../../types/DatosHorario"
import { TablaObserver } from "../TablaObserver"
const e = StyleSheet.create({ const e = StyleSheet.create({
celdaComun: { celdaComun: {
@ -19,7 +20,7 @@ const e = StyleSheet.create({
borderRadius: "5px", borderRadius: "5px",
// transition: "background-color 100ms, color 100ms" // transition: "background-color 100ms, color 100ms"
}, },
celdaCursoActiva: { celdaResaltado: {
// color: "#151515" // color: "#151515"
}, },
celdaCursoTeoria: { celdaCursoTeoria: {
@ -28,7 +29,7 @@ const e = StyleSheet.create({
celdaCursoLab: { celdaCursoLab: {
fontStyle: "italic", fontStyle: "italic",
}, },
celdaSeleccionada: { celdaSeleccionado: {
textDecoration: "underline", textDecoration: "underline",
}, },
}) })
@ -78,22 +79,16 @@ interface Props {
datosGrupo: DatosGrupo, datosGrupo: DatosGrupo,
fnSeleccionar: () => void fnSeleccionar: () => void
}[], }[],
idHover: () => string,
setIdHover: (v: string) => string,
fnResaltarFila: () => void, fnResaltarFila: () => void,
fnDesresaltarFila: () => void, fnDesresaltarFila: () => void,
dia: Dia, dia: Dia,
tablaObserver: TablaObserver,
} }
const claseSeldaSeleccionada = css(e.celdaSeleccionada) const claseSeldaSeleccionada = css(e.celdaSeleccionado)
export function CeldaFila(props: Props) { export function CeldaFila(props: Props) {
const datos = props.datos const datos = props.datos
const idHover = props.idHover
const setIdHover = props.setIdHover
const fnOnMouseEnter = (id: string) => setIdHover(id)
const fnOnMouseLeave = () => setIdHover("")
return ( return (
<div className={css(e.celdaComun, estilosGlobales.inlineBlock)}> <div className={css(e.celdaComun, estilosGlobales.inlineBlock)}>
@ -104,6 +99,8 @@ export function CeldaFila(props: Props) {
const esLab = datos.esLab const esLab = datos.esLab
const fnSeleccionar = datos.fnSeleccionar const fnSeleccionar = datos.fnSeleccionar
const estadoCeldaMemo = props.tablaObserver.registrarConId(id)
const [estabaResaltado, setEstabaResaltado] = createSignal(false) const [estabaResaltado, setEstabaResaltado] = createSignal(false)
const estaSeleccionado = createMemo(() => datos.datosGrupo.seleccionado) const estaSeleccionado = createMemo(() => datos.datosGrupo.seleccionado)
@ -113,20 +110,59 @@ export function CeldaFila(props: Props) {
const clases = [ const clases = [
e.celdaCurso, e.celdaCurso,
esLab ? e.celdaCursoLab : e.celdaCursoTeoria, esLab ? e.celdaCursoLab : e.celdaCursoTeoria,
estaSeleccionado() && e.celdaSeleccionada, estaSeleccionado() && e.celdaSeleccionado,
] ]
let adicional = "" let adicional = ""
const idHoverS = idHover()
if (idHoverS !== "" && id.search(idHoverS) !== -1) {
props.fnResaltarFila()
clases.push(e.celdaCursoActiva)
adicional = clasesColores[props.dia]
setEstabaResaltado(true) const estadoCelda = estadoCeldaMemo()
} else if (estabaResaltado()) {
props.fnDesresaltarFila() switch (estadoCelda) {
setEstabaResaltado(false) case "Normal": {
if (estabaResaltado()) {
props.fnDesresaltarFila()
setEstabaResaltado(false)
}
break
}
case "Oculto": {
if (estabaResaltado()) {
props.fnDesresaltarFila()
setEstabaResaltado(false)
}
// TODO
break
}
case "Resaltado": {
props.fnResaltarFila()
setEstabaResaltado(true)
clases.push(e.celdaResaltado)
adicional = clasesColores[props.dia]
break
}
case "Seleccionado": {
if (estabaResaltado()) {
props.fnDesresaltarFila()
setEstabaResaltado(false)
}
break
}
case "ResaltadoOculto": {
props.fnResaltarFila()
setEstabaResaltado(true)
break
}
case "ResaltadoSeleccionado": {
props.fnResaltarFila()
setEstabaResaltado(true)
break
}
} }
return `${css(...clases)} ${adicional}` return `${css(...clases)} ${adicional}`
}, },
undefined, undefined,
@ -135,9 +171,13 @@ export function CeldaFila(props: Props) {
return ( return (
<span className={clases()} <span className={clases()}
onMouseEnter={() => fnOnMouseEnter(id)} onMouseEnter={() => {
onMouseLeave={fnOnMouseLeave} props.tablaObserver.resaltar(id)
onClick={fnSeleccionar} }}
onMouseLeave={() => {
props.tablaObserver.quitarResaltado()
}}
onClick={fnSeleccionar}
> >
{txt} {txt}
</span> </span>

View File

@ -1,10 +1,11 @@
import { StyleSheet, css } from "aphrodite" import { StyleSheet, css } from "aphrodite"
import { estilosGlobales } from "../../Estilos" import { estilosGlobales } from "../../Estilos"
import { For, createSignal, createMemo, createState, createEffect, State, SetStateFunction } from "solid-js" import { For, createMemo, createState, State } from "solid-js"
import { Dia, dias } from "../../Store" import { Dia, dias } from "../../Store"
import { CeldaFila } from "./CeldaFila" import { CeldaFila } from "./CeldaFila"
import { DataProcesada, ListaCursosUsuario } from "../../types/DatosHorario" import { DataProcesada } from "../../types/DatosHorario"
import { coloresBorde, diaANum } from "../Tabla" import { coloresBorde, diaANum } from "../Tabla"
import { TablaObserver } from "../TablaObserver"
const e = StyleSheet.create({ const e = StyleSheet.create({
celdaHora: { celdaHora: {
@ -61,8 +62,7 @@ const [diasResaltados, setDiasResaltados] = createState({
interface Props { interface Props {
hora: string, hora: string,
data: DataProcesada, data: DataProcesada,
idHover: () => string, tablaObserver: TablaObserver,
setIdHover: (v: string) => string
} }
const diasFilter = createMemo(() => Object.entries(diasResaltados) const diasFilter = createMemo(() => Object.entries(diasResaltados)
@ -140,16 +140,15 @@ export function FilaTabla(props: Props) {
return ( return (
<CeldaFila <CeldaFila
datos={datos} datos={datos}
idHover={props.idHover}
setIdHover={props.setIdHover}
fnResaltarFila={() => fnResaltar(dia)} fnResaltarFila={() => fnResaltar(dia)}
fnDesresaltarFila={() => fnDesresaltar(dia)} fnDesresaltarFila={() => fnDesresaltar(dia)}
dia={dia} dia={dia}
tablaObserver={props.tablaObserver}
/> />
) )
}} }}
</For> </For>
<div className={css(e.filaBorde)} /> <div className={css(e.filaBorde)}/>
</div> </div>
</div> </div>
) )

View File

@ -1,18 +1,18 @@
import { createMemo, createState, SetStateFunction, State } from "solid-js"
/** /**
* - Normal * - Normal
* - Oculto - Otro grupo seleccionado * - Oculto - Otro grupo seleccionado
* - Seleccionado - Cursor ensima * - Resaltado - Cursor encima
* - Resaltado - Grupo seleccionado * - Seleccionado - Grupo escogido
* - ResaltadoSeleccionado - Grupo seleccionado y cursor encima * - ResaltadoSeleccionado - Grupo escogido y cursor encima
* - ResaltadoOculto - Otro grupo seleccionado y cursor encima * - ResaltadoOculto - Otro grupo escogido y cursor encima
*/ */
import { createMemo, createState, SetStateFunction, State } from "solid-js";
type EstadoCelda = type EstadoCelda =
| "Normal" | "Normal"
| "Oculto" | "Oculto"
| "Seleccionado"
| "Resaltado" | "Resaltado"
| "Seleccionado"
| "ResaltadoSeleccionado" | "ResaltadoSeleccionado"
| "ResaltadoOculto" | "ResaltadoOculto"
@ -20,7 +20,7 @@ interface Datos {
anio?: string, anio?: string,
curso?: string, curso?: string,
esLab?: boolean, esLab?: boolean,
grupo?: string grupo?: string,
} }
export class TablaObserver { export class TablaObserver {
@ -28,35 +28,93 @@ export class TablaObserver {
private readonly resaltado: State<Datos> private readonly resaltado: State<Datos>
private readonly setResaltado: SetStateFunction<Datos> private readonly setResaltado: SetStateFunction<Datos>
private gruposSeleccionados = {} private gruposSeleccionados = {}
private memos: {[id: string]: () => EstadoCelda} = {};
constructor() { constructor() {
const [resaltado, setResaltado] = createState<Datos>({ const [resaltado, setResaltado] = createState<Datos>({
anio: undefined, anio: undefined,
curso: undefined, curso: undefined,
esLab: undefined, esLab: undefined,
grupo: undefined grupo: undefined,
}); })
this.resaltado = resaltado; this.resaltado = resaltado
this.setResaltado = setResaltado; this.setResaltado = setResaltado
} }
// Cada celda se registra dando estos datos /**
// Devuelve un memo con un valor de EstadoCelda, * Crea un memo que indica el estado de la celda
// el cual cada celda sabra como manejar * @param anio El año
registrar(anio: string, cursoAbreviado: string, esLab: boolean, grupo: string) { * @param curso Curso abreviado
const fn = () => { * @param esLab Si es laboratorio
* @param grupo Una única letra
}; */
private registrar(anio: string, curso: string, esLab: boolean, grupo: string): () => EstadoCelda {
const memo = createMemo( const resaltado = this.resaltado
fn, const resaltadoMemo = createMemo(
() => {
if (resaltado.anio === anio && resaltado.curso === curso) {
if (resaltado.esLab === undefined) {
return true
} else if (resaltado.esLab !== esLab) {
return false
} else {
if (resaltado.grupo === undefined) {
return true
} else return resaltado.grupo === grupo;
}
} else {
return false
}
},
undefined, undefined,
(x, y) => x === y (x, y) => x === y,
); )
return createMemo(
(): EstadoCelda => {
if (resaltadoMemo()) {
return "Resaltado"
} else {
return "Normal"
}
},
undefined,
(x, y) => x === y,
)
} }
resaltar(id: string) { /**
* Crea un memo que indica el estado de la celda a partir de un id
* @param id Id a registrar - YYYYMMDD_Año_Curso[\_Lab[_Grupo]]
*/
registrarConId(id: string): () => EstadoCelda {
if (this.memos[id]) {
return this.memos[id]
}
const [, anio, curso, lab, grupo] = id.split("_")
const memo = this.registrar(anio, curso, lab === "L", grupo)
this.memos[id] = memo;
return memo;
}
/**
* Parsea el id y hace que las celdas registradas se actualizen adecuadamente
* @param id Id a resaltar - YYYYMMDD_Año_Curso[\_Lab[_Grupo]]
*/
resaltar(id: string) {
const [, anio, curso, lab, grupo] = id.split("_")
if (anio === undefined || curso === undefined) {
console.error("Error al intentar resaltar celda: anio o curso son undefined:", anio, curso)
return
}
this.setResaltado({
anio,
curso,
esLab: lab === "L",
grupo,
})
} }
quitarResaltado() { quitarResaltado() {
@ -64,7 +122,7 @@ export class TablaObserver {
anio: undefined, anio: undefined,
curso: undefined, curso: undefined,
esLab: undefined, esLab: undefined,
grupo: undefined grupo: undefined,
}); })
} }
} }