diff --git a/frontend/package.json b/frontend/package.json index fc04c0f..0a933a4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,7 +7,8 @@ "dev": "vite", "build": "vite build", "serve": "vite preview", - "lint": "eslint --fix" + "lint": "eslint --fix", + "typecheck": "tsc --noEmit" }, "license": "MIT", "devDependencies": { diff --git a/frontend/src/certs/CustomLabelContext.tsx b/frontend/src/certs/CustomLabelContext.tsx new file mode 100644 index 0000000..306c9c4 --- /dev/null +++ b/frontend/src/certs/CustomLabelContext.tsx @@ -0,0 +1,45 @@ +import { JSX, createContext, createMemo, createResource, useContext } from "solid-js"; +import { CustomLabel } from "../types/CustomLabel"; +import axios from "axios"; + +export type CustomLabelsMap = {[custom_label_id: number]: CustomLabel}; + +const CustomLabelContext = createContext<{ + labels: () => CustomLabelsMap +}>(); + +export function CustomLabelProvider(props: {children: JSX.Element}) { + const [labels] = createResource(fetchAllLabels); + + const customLabelData = { + labels: createMemo(() => labels() ?? {}), + }; + + return ( + + {props.children} + + ); +} + +let cachedLabels: CustomLabelsMap | null = null; + +async function fetchAllLabels(useCache = true): Promise { + if (useCache && cachedLabels !== null) { + return cachedLabels; + } + + const result = await axios.get>(`${import.meta.env.VITE_BACKEND_URL}/api/label`); + + const map: CustomLabelsMap = {}; + for (const label of result.data) { + map[label.custom_label_id] = label; + } + + cachedLabels = map; + return map; +} + +export function useCustomLabel() { + return useContext(CustomLabelContext); +} diff --git a/frontend/src/certs/NewRegister/CustomLabelSelect.tsx b/frontend/src/certs/NewRegister/CustomLabelSelect.tsx index f0eec82..ea4008c 100644 --- a/frontend/src/certs/NewRegister/CustomLabelSelect.tsx +++ b/frontend/src/certs/NewRegister/CustomLabelSelect.tsx @@ -1,5 +1,5 @@ import { createEffect, createSignal, For, onMount } from "solid-js"; -import { customLabelsMap } from "../../utils/allCustomLabels"; +import { useCustomLabel } from "../CustomLabelContext"; export function CustomLabelSelect(props: { onChange: (value: string) => void, @@ -8,6 +8,7 @@ export function CustomLabelSelect(props: { const [filter, setFilter] = createSignal(""); const [selected, setSelected] = createSignal(false); const [inputValue, setInputValue] = createSignal(""); + const customLabels = useCustomLabel(); const iHandler = (ev: KeyboardEvent & {currentTarget: HTMLInputElement, target: Element}) => { const inputEl = ev.target as HTMLInputElement; @@ -49,9 +50,13 @@ export function CustomLabelSelect(props: { const filteredOptions = () => { + if (customLabels === undefined) { + return []; + } + const filterText = filter(); - return Object.entries(customLabelsMap()).filter(([, label]) => { + return Object.entries(customLabels.labels()).filter(([, label]) => { let courseText = label.custom_label_value.toLowerCase(); courseText = courseText.replace("á", "a"); courseText = courseText.replace("é", "e"); diff --git a/frontend/src/certs/NewRegister/ManualRegistration.tsx b/frontend/src/certs/NewRegister/ManualRegistration.tsx index dd376f3..0c60f78 100644 --- a/frontend/src/certs/NewRegister/ManualRegistration.tsx +++ b/frontend/src/certs/NewRegister/ManualRegistration.tsx @@ -2,8 +2,8 @@ import { JSX, Show, createSignal } from "solid-js"; import { SearchableSelect } from "./SearchableSelect"; import { CustomLabelSelect } from "./CustomLabelSelect"; import { RegistrationPreview } from "."; -import { customLabelsMap } from "../../utils/allCustomLabels"; import { useCourses } from "../CourseContext"; +import { useCustomLabel } from "../CustomLabelContext"; type HTMLEventFn = JSX.EventHandlerUnion (v.custom_label_value === label))?.[1].custom_label_id ?? -1; + const custom_label_id = Object.entries(customLabels.labels()).find(([, v]) => (v.custom_label_value === label))?.[1].custom_label_id ?? -1; const data: RegistrationPreview = { courseId: subject, diff --git a/frontend/src/certs/Registers/RegisterElement.tsx b/frontend/src/certs/Registers/RegisterElement.tsx index 5c4155d..eeb5198 100644 --- a/frontend/src/certs/Registers/RegisterElement.tsx +++ b/frontend/src/certs/Registers/RegisterElement.tsx @@ -2,7 +2,6 @@ import { Show, createMemo } from "solid-js"; import { certGenerator } from "../../certGenerator"; import { Person } from "../../types/Person"; import { Register } from "../../types/Register"; -import { customLabelsMap } from "../../utils/allCustomLabels"; import { DownloadSimpleIcon } from "../../icons/DownloadSimpleIcon"; import { CaretRight } from "../../icons/CaretRight"; import { IdentificationCardIcon } from "../../icons/IdentificationCardIcon"; @@ -14,6 +13,7 @@ import { genMatpelCarnet } from "../../carnetGenerator/matpel"; import { genMachineryCarnet } from "../../carnetGenerator/machinery"; import { Course } from "../../types/Course"; import { useCourses } from "../CourseContext"; +import { CustomLabelsMap, useCustomLabel } from "../CustomLabelContext"; const carnetEnabled = [ "Matpel 3", @@ -27,6 +27,7 @@ const carnetEnabled = [ export function RegisterElement(props: {register: Register, person: Person, onClick: () => void}) { const courses = useCourses(); + const customLabels = useCustomLabel(); const dateComponents = () => { const [, year, month, day] = /(\d{4})-(\d{2})-(\d{2})/.exec(props.register.register_display_date) ?? []; @@ -44,13 +45,18 @@ export function RegisterElement(props: {register: Register, person: Person, onCl }; const customLabel = () => { + if (customLabels === undefined) { + return "~~Denominaciones no cargadas~~"; + } + const labelId = props.register.register_custom_label; if (labelId === 1) return ""; - return customLabelsMap()[labelId]?.custom_label_value ?? ""; + + return customLabels.labels()[labelId]?.custom_label_value ?? "~~Denominación no encontrada~~"; }; const genCert = () => { - if (courses === undefined) { + if (courses === undefined || customLabels === undefined) { alert("Error. La lista de cursos no esta cargada."); return; } @@ -58,7 +64,7 @@ export function RegisterElement(props: {register: Register, person: Person, onCl const person = props.person; const register = props.register; - generateCert(person, register, courses.idMap()); + generateCert(person, register, courses.idMap(), customLabels.labels()); }; const generateable = () => { @@ -164,7 +170,12 @@ export function RegisterElement(props: {register: Register, person: Person, onCl ); } -export function generateCert(person: Person, register: Register, coursesMap: {[course_id: number]: Course}) { +export function generateCert( + person: Person, + register: Register, + coursesMap: {[course_id: number]: Course}, + labelsMap: CustomLabelsMap, +) { const courseN = coursesMap[register.register_course_id]?.course_name ?? "Curso no encontrado"; const generator = certGenerator[courseN]; @@ -181,7 +192,7 @@ export function generateCert(person: Person, register: Register, coursesMap: {[c if (register.register_custom_label === 1) { certCustomLabel = ""; } else { - const customLabel = customLabelsMap()[register.register_custom_label]; + const customLabel = labelsMap[register.register_custom_label]; if (customLabel === undefined) { alert(`Error. No se encontró la denominación con id ${register.register_custom_label}`); return; diff --git a/frontend/src/certs/Registers/index.tsx b/frontend/src/certs/Registers/index.tsx index 2665319..5fa6eea 100644 --- a/frontend/src/certs/Registers/index.tsx +++ b/frontend/src/certs/Registers/index.tsx @@ -8,6 +8,7 @@ import { JsonResult } from "../../types/JsonResult"; import { LoadingIcon } from "../../icons/LoadingIcon"; import { RegisterElement, generateCert } from "./RegisterElement"; import { useCourses } from "../CourseContext"; +import { useCustomLabel } from "../CustomLabelContext"; export function Registers(props: {person: Person | null, count: number}) { const [registers, setRegisters] = createSignal>([]); @@ -16,6 +17,7 @@ export function Registers(props: {person: Person | null, count: number}) { const [loading, setLoading] = createSignal(false); const [error, setError] = createSignal(""); const courses = useCourses(); + const customLabels = useCustomLabel(); const loadRegisters = async() => { setLoading(true); @@ -103,10 +105,10 @@ export function Registers(props: {person: Person | null, count: number}) { const [downButtonBg, setDownButtonBg] = createSignal("bg-c-primary text-c-on-primary"); const downloadTodayCerts = () => { - if (props.person === null || courses === undefined) return; + if (props.person === null || courses === undefined || customLabels === undefined) return; todayRegisters().forEach((register) => { - generateCert(props.person!, register, courses.idMap()); + generateCert(props.person!, register, courses.idMap(), customLabels.labels()); }); setDownButtonBg("bg-c-success text-c-on-success"); diff --git a/frontend/src/certs/index.tsx b/frontend/src/certs/index.tsx index 4f30b19..de47dad 100644 --- a/frontend/src/certs/index.tsx +++ b/frontend/src/certs/index.tsx @@ -1,10 +1,13 @@ import { CertsImpl } from "./CertsImpl"; import { CoursesProvider } from "./CourseContext"; +import { CustomLabelProvider } from "./CustomLabelContext"; export function Certs() { return ( - + + + ); } diff --git a/frontend/src/utils/allCustomLabels.ts b/frontend/src/utils/allCustomLabels.ts index 3c02807..90fc198 100644 --- a/frontend/src/utils/allCustomLabels.ts +++ b/frontend/src/utils/allCustomLabels.ts @@ -1,10 +1,7 @@ -import { createSignal } from "solid-js"; import { CustomLabel } from "../types/CustomLabel"; type CustomLabelsMap = {[k: number]: CustomLabel}; -// TODO: Refactor, this is inefficient -export const [customLabelsMap, setCustomLabelsMap] = createSignal<{[k: number]: CustomLabel}>({}); export function loadCustomLabels() { fetch(`${import.meta.env.VITE_BACKEND_URL}/api/label`) @@ -14,7 +11,6 @@ export function loadCustomLabels() { for (const label of data) { map[label.custom_label_id] = label; } - setCustomLabelsMap(map); }); }