diff --git a/src/App.tsx b/src/App.tsx index 3dae758..e7c6cf2 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,7 @@ import { Creditos } from "./Creditos" function App() { /// @ts-ignore const soportaBackdropFilter = document.body.style.backdropFilter !== undefined - const mostrarMensajeBackdropFilterRaw = localStorage.getItem("mensaje-backdrop-filter-oculto") === undefined + const mostrarMensajeBackdropFilterRaw = !localStorage.getItem("mensaje-backdrop-filter-oculto") const [mostrarMensajeBackdropFilter, setMostrarMensaje] = createSignal(mostrarMensajeBackdropFilterRaw) diff --git a/src/ContenedorHorarios/Tabla.tsx b/src/ContenedorHorarios/Tabla.tsx index ffa7b2d..c485134 100755 --- a/src/ContenedorHorarios/Tabla.tsx +++ b/src/ContenedorHorarios/Tabla.tsx @@ -1,7 +1,7 @@ import { StyleSheet, css } from "aphrodite" -import { createMemo, For, SetStateFunction } from "solid-js" +import { batch, createMemo, For, produce, SetStateFunction } from "solid-js" import { estilosGlobales } from "../Estilos" -import { Cursos, ListaCursosUsuario, DataProcesada } from "../types/DatosHorario" +import { Cursos, ListaCursosUsuario, DataProcesada, DatosGrupo } from "../types/DatosHorario" import { Dia, dias, horas } from "../Store" import { FilaTabla } from "./Tabla/FilaTabla" import { TablaObserver } from "./TablaObserver" @@ -115,8 +115,17 @@ const procesarAnio = (data: Cursos, anio: string, version: number, setCursosUsua esLab: false, datosGrupo: grupo, fnSeleccionar: () => { - /// @ts-ignore - setCursosUsuarios("cursos", indiceCurso, "Teoria", grupoStr, "seleccionado", (x) => !x) + setCursosUsuarios("cursos", Number(indiceCurso), "Teoria", produce<{ [p: string]: DatosGrupo }>((x) => { + const grupoActualSeleccionado = x[grupoStr].seleccionado + + if (grupoActualSeleccionado) { + x[grupoStr].seleccionado = false + } else { + for (let xKey in x) { + x[xKey].seleccionado = xKey === grupoStr + } + } + })) }, }) } @@ -146,8 +155,22 @@ const procesarAnio = (data: Cursos, anio: string, version: number, setCursosUsua esLab: true, datosGrupo: grupo, fnSeleccionar: () => { - /// @ts-ignore - setCursosUsuarios("cursos", indiceCurso, "Laboratorio", grupoStr, "seleccionado", (x) => !x) + setCursosUsuarios( + "cursos", + Number(indiceCurso), + "Laboratorio", + produce<{ [p: string]: DatosGrupo }>((x) => { + const grupoActualSeleccionado = x[grupoStr].seleccionado + + if (grupoActualSeleccionado) { + x[grupoStr].seleccionado = false + } else { + for (let xKey in x) { + x[xKey].seleccionado = xKey === grupoStr + } + } + }), + ) }, }) } diff --git a/src/ContenedorHorarios/Tabla/CeldaFila.tsx b/src/ContenedorHorarios/Tabla/CeldaFila.tsx index 921cacb..fb7bd15 100755 --- a/src/ContenedorHorarios/Tabla/CeldaFila.tsx +++ b/src/ContenedorHorarios/Tabla/CeldaFila.tsx @@ -1,6 +1,6 @@ import { StyleSheet, css } from "aphrodite" import { estilosGlobales } from "../../Estilos" -import { For, createSignal, createMemo } from "solid-js" +import { For, createSignal, createMemo, createEffect } from "solid-js" import { Dia } from "../../Store" import { DatosGrupo } from "../../types/DatosHorario" import { TablaObserver } from "../TablaObserver" @@ -32,6 +32,9 @@ const e = StyleSheet.create({ celdaSeleccionado: { textDecoration: "underline", }, + celdaOculto: { + opacity: 0.3, + }, }) const eColores = StyleSheet.create({ @@ -99,18 +102,15 @@ export function CeldaFila(props: Props) { const esLab = datos.esLab const fnSeleccionar = datos.fnSeleccionar - const estadoCeldaMemo = props.tablaObserver.registrarConId(id) + const estadoCeldaMemo = props.tablaObserver.registrarConId(id, datos.datosGrupo) const [estabaResaltado, setEstabaResaltado] = createSignal(false) - const estaSeleccionado = createMemo(() => datos.datosGrupo.seleccionado) - const clases = createMemo( () => { const clases = [ e.celdaCurso, - esLab ? e.celdaCursoLab : e.celdaCursoTeoria, - estaSeleccionado() && e.celdaSeleccionado, + esLab ? e.celdaCursoLab : e.celdaCursoTeoria ] let adicional = "" @@ -131,7 +131,7 @@ export function CeldaFila(props: Props) { setEstabaResaltado(false) } - // TODO + clases.push(e.celdaOculto) break } case "Resaltado": { @@ -147,6 +147,7 @@ export function CeldaFila(props: Props) { setEstabaResaltado(false) } + clases.push(e.celdaSeleccionado) break } case "ResaltadoOculto": { diff --git a/src/ContenedorHorarios/TablaObserver.ts b/src/ContenedorHorarios/TablaObserver.ts index e023e56..8960e26 100644 --- a/src/ContenedorHorarios/TablaObserver.ts +++ b/src/ContenedorHorarios/TablaObserver.ts @@ -1,4 +1,11 @@ -import { createMemo, createState, SetStateFunction, State } from "solid-js" +import { createMemo, createState, SetStateFunction, State, produce, createEffect } from "solid-js" +import { DatosGrupo } from "../types/DatosHorario" + +const createMemoDefault = (f: () => T) => createMemo( + f, + undefined, + (x, y) => x === y, +) /** * - Normal @@ -16,22 +23,38 @@ type EstadoCelda = | "ResaltadoSeleccionado" | "ResaltadoOculto" -interface Datos { +type EstadoSeleccionado = + | "Seleccionado" + | "Oculto" + | "Normal" + +interface IResaltado { anio?: string, curso?: string, esLab?: boolean, grupo?: string, } +interface ISeleccionado { + [anio: string]: { + [curso: string]: { + Laboratorio: string[] + Teoria: string[] + }, + }, +} + export class TablaObserver { - private readonly resaltado: State - private readonly setResaltado: SetStateFunction - private gruposSeleccionados = {} - private memos: {[id: string]: () => EstadoCelda} = {}; + private readonly resaltado: State + private readonly setResaltado: SetStateFunction + private memos: { [id: string]: () => EstadoCelda } = {} + + private readonly seleccionado: State + private readonly setSeleccionado: SetStateFunction constructor() { - const [resaltado, setResaltado] = createState({ + const [resaltado, setResaltado] = createState({ anio: undefined, curso: undefined, esLab: undefined, @@ -39,6 +62,10 @@ export class TablaObserver { }) this.resaltado = resaltado this.setResaltado = setResaltado + + const [seleccionado, setSeleccionado] = createState({}) + this.seleccionado = seleccionado + this.setSeleccionado = setSeleccionado } /** @@ -47,55 +74,107 @@ export class TablaObserver { * @param curso Curso abreviado * @param esLab Si es laboratorio * @param grupo Una única letra + * @param datosGrupo Contiene `seleccionado`, se usa ese valor reactivo */ - private registrar(anio: string, curso: string, esLab: boolean, grupo: string): () => EstadoCelda { + private registrar( + anio: string, + curso: string, + esLab: boolean, + grupo: string, + datosGrupo: DatosGrupo, + ): () => EstadoCelda { const resaltado = this.resaltado - 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 { + const resaltadoMemo = createMemoDefault(() => { + if (resaltado.anio === anio && resaltado.curso === curso) { + if (resaltado.esLab === undefined) { + return true + } else if (resaltado.esLab !== esLab) { return false - } - }, - undefined, - (x, y) => x === y, - ) - - return createMemo( - (): EstadoCelda => { - if (resaltadoMemo()) { - return "Resaltado" } else { - return "Normal" + if (resaltado.grupo === undefined) { + return true + } else return resaltado.grupo === grupo } - }, - undefined, - (x, y) => x === y, - ) + } else { + return false + } + }) + + // Registrar curso en `seleccionado` + this.setSeleccionado((obj) => { + const nuevoObj = {...obj} + + if (!nuevoObj[anio]) { + nuevoObj[anio] = {} + } + + if (!nuevoObj[anio][curso]) { + nuevoObj[anio][curso] = { + Laboratorio: [], + Teoria: [], + } + } + + return nuevoObj + }) + + // Crear un effect para que cada vez que la celda se seleccione se actualize `seleccionado` + createEffect(() => { + const seleccionado = datosGrupo.seleccionado + if (seleccionado){ + this.setSeleccionado(anio, curso, esLab ? "Laboratorio" : "Teoria", (x) => [...x, grupo]) + } else { + this.setSeleccionado(anio, curso, esLab ? "Laboratorio" : "Teoria", (x) => x.filter((x) => x !== grupo)) + } + }) + + const seleccionadoMemo = createMemoDefault(() => { + const gruposSeleccionados = this.seleccionado[anio][curso][esLab ? "Laboratorio" : "Teoria"] + + if (gruposSeleccionados.length > 0) { + return gruposSeleccionados.find((x) => x === grupo) ? "Seleccionado" : "Oculto" + } else { + return "Normal" + } + }) + + return createMemoDefault((): EstadoCelda => { + const resaltado = resaltadoMemo() + const seleccionado = seleccionadoMemo() + + switch (seleccionado) { + case "Normal": { + return resaltado ? "Resaltado" : "Normal" + } + case "Oculto": { + return resaltado ? "ResaltadoOculto" : "Oculto" + } + case "Seleccionado": { + return resaltado ? "ResaltadoSeleccionado" : "Seleccionado" + } + default: { + let _: never + _ = seleccionado + return _ + } + } + }) } /** * 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]] + * @param datosGrupo Contiene `seleccionado`, se usa ese valor reactivo */ - registrarConId(id: string): () => EstadoCelda { + registrarConId(id: string, datosGrupo: DatosGrupo): () => 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; + const memo = this.registrar(anio, curso, lab === "L", grupo, datosGrupo) + this.memos[id] = memo + return memo } /**