[FE] Use resources & context to load courses, instead of global state
This commit is contained in:
parent
1a236dc505
commit
16efa06639
@ -1,53 +1,11 @@
|
|||||||
import { Accessor, For, createSignal } from "solid-js";
|
import { For, createMemo, createSignal } from "solid-js";
|
||||||
import { Chip } from "../../components/Chip";
|
import { Chip } from "../../components/Chip";
|
||||||
import { getCourseMemo } from "../../utils/allCourses";
|
|
||||||
import { Course } from "../../types/Course";
|
import { Course } from "../../types/Course";
|
||||||
import { RegistrationPreview } from ".";
|
import { RegistrationPreview } from ".";
|
||||||
|
import { useCourses } from "..";
|
||||||
|
|
||||||
type PresetName = "None" | "2 Matpel" | "3 Matpel" | "4 Escolta" | "MD, 2 Matpel" | "3 4x4" | "2 4x4" | "6 Sibia";
|
type PresetName = "None" | "2 Matpel" | "3 Matpel" | "4 Escolta" | "MD, 2 Matpel" | "3 4x4" | "2 4x4" | "6 Sibia";
|
||||||
|
|
||||||
function genPresets(): {[k: string]: Array<Accessor<Course | null>>} {
|
|
||||||
return {
|
|
||||||
"2 Matpel": [
|
|
||||||
getCourseMemo("Matpel 2"),
|
|
||||||
getCourseMemo("Matpel 1"),
|
|
||||||
],
|
|
||||||
"3 Matpel": [
|
|
||||||
getCourseMemo("Matpel 3"),
|
|
||||||
getCourseMemo("Matpel 2"),
|
|
||||||
getCourseMemo("Matpel 1"),
|
|
||||||
],
|
|
||||||
"4 Escolta": [
|
|
||||||
getCourseMemo("Sup. Escolta"),
|
|
||||||
getCourseMemo("Matpel 3"),
|
|
||||||
getCourseMemo("Matpel 2"),
|
|
||||||
getCourseMemo("Matpel 1"),
|
|
||||||
],
|
|
||||||
"MD, 2 Matpel": [
|
|
||||||
getCourseMemo("Matpel 2"),
|
|
||||||
getCourseMemo("Matpel 1"),
|
|
||||||
getCourseMemo("Manejo Defensivo"),
|
|
||||||
],
|
|
||||||
"3 4x4": [
|
|
||||||
getCourseMemo("4x4"),
|
|
||||||
getCourseMemo("Mecanica Basica"),
|
|
||||||
getCourseMemo("Manejo Defensivo"),
|
|
||||||
],
|
|
||||||
"2 4x4": [
|
|
||||||
getCourseMemo("4x4"),
|
|
||||||
getCourseMemo("Manejo Defensivo"),
|
|
||||||
],
|
|
||||||
"6 Sibia": [
|
|
||||||
getCourseMemo("Matpel 2"),
|
|
||||||
getCourseMemo("Matpel 1"),
|
|
||||||
getCourseMemo("Manejo Defensivo"),
|
|
||||||
getCourseMemo("Primeros Auxilios"),
|
|
||||||
getCourseMemo("IPERC"),
|
|
||||||
getCourseMemo("Lucha contra Incendios"),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RegisterPresets(props: {
|
export function RegisterPresets(props: {
|
||||||
disableCreation: boolean,
|
disableCreation: boolean,
|
||||||
onAdd: (v: RegistrationPreview) => void
|
onAdd: (v: RegistrationPreview) => void
|
||||||
@ -56,7 +14,46 @@ export function RegisterPresets(props: {
|
|||||||
const [selectedPreset, setSelectedPreset] = createSignal<PresetName>("None");
|
const [selectedPreset, setSelectedPreset] = createSignal<PresetName>("None");
|
||||||
const [isPreview, setIsPreview] = createSignal(false);
|
const [isPreview, setIsPreview] = createSignal(false);
|
||||||
const [error, setError] = createSignal("");
|
const [error, setError] = createSignal("");
|
||||||
const presets = genPresets();
|
const courses = useCourses();
|
||||||
|
|
||||||
|
const presets = createMemo<{[key: string]: Array<Course>}>(() => {
|
||||||
|
if (courses === undefined) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const coursesMap = courses.map();
|
||||||
|
|
||||||
|
const matpel1 = coursesMap["Matpel 1"];
|
||||||
|
const matpel2 = coursesMap["Matpel 2"];
|
||||||
|
const matpel3 = coursesMap["Matpel 3"];
|
||||||
|
const escolta = coursesMap["Sup. Escolta"];
|
||||||
|
const mecanica = coursesMap["Mecanica Basica"];
|
||||||
|
const manejo = coursesMap["Manejo Defensivo"];
|
||||||
|
const primerosAuxilios = coursesMap["Primeros Auxilios"];
|
||||||
|
const iperc = coursesMap.IPERC;
|
||||||
|
const luchaIncendios = coursesMap["Lucha contra Incendios"];
|
||||||
|
const cuatroXcuatro = coursesMap["4x4"];
|
||||||
|
|
||||||
|
if (matpel1 === undefined || matpel2 === undefined || matpel3 === undefined || escolta === undefined ||
|
||||||
|
mecanica === undefined || manejo === undefined || primerosAuxilios === undefined || iperc === undefined ||
|
||||||
|
luchaIncendios === undefined || cuatroXcuatro === undefined
|
||||||
|
) {
|
||||||
|
setError("Un curso de los presets no existe. Error fatal.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: {[key: string]: Array<Course>} = {
|
||||||
|
"2 Matpel": [matpel2, matpel1],
|
||||||
|
"3 Matpel": [matpel3,matpel2, matpel1],
|
||||||
|
"4 Escolta": [escolta, matpel3,matpel2, matpel1],
|
||||||
|
"MD, 2 Matpel": [matpel2, matpel1, manejo],
|
||||||
|
"3 4x4": [cuatroXcuatro, mecanica, manejo],
|
||||||
|
"2 4x4": [cuatroXcuatro, manejo],
|
||||||
|
"6 Sibia": [matpel2, matpel1, manejo, primerosAuxilios, iperc, luchaIncendios],
|
||||||
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
|
||||||
const add = () => {
|
const add = () => {
|
||||||
if (datePicker === undefined) {
|
if (datePicker === undefined) {
|
||||||
@ -76,11 +73,9 @@ export function RegisterPresets(props: {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const presetIds = presets[preset];
|
const presetIds = presets()[preset];
|
||||||
const currentDate = new Date(date);
|
const currentDate = new Date(date);
|
||||||
for (const courseMemo of presetIds) {
|
for (const course of presetIds) {
|
||||||
// Get course and course duration from the memo
|
|
||||||
const course = courseMemo();
|
|
||||||
if (course === null) {
|
if (course === null) {
|
||||||
setError(`Un curso no existe. Error fatal. (${preset})`);
|
setError(`Un curso no existe. Error fatal. (${preset})`);
|
||||||
return;
|
return;
|
||||||
@ -112,7 +107,7 @@ export function RegisterPresets(props: {
|
|||||||
<p>Las fechas se colocan automáticamente según la duración del curso y su jeraquía.</p>
|
<p>Las fechas se colocan automáticamente según la duración del curso y su jeraquía.</p>
|
||||||
<br />
|
<br />
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<For each={Object.keys(presets)}>
|
<For each={Object.keys(presets())}>
|
||||||
{(key) => (
|
{(key) => (
|
||||||
<Chip
|
<Chip
|
||||||
selected={selectedPreset() === key}
|
selected={selectedPreset() === key}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { FilledCard } from "../../components/FilledCard";
|
import { FilledCard } from "../../components/FilledCard";
|
||||||
import { For, Show, createSignal } from "solid-js";
|
import { For, Show, createSignal } from "solid-js";
|
||||||
import { XIcon } from "../../icons/XIcon";
|
import { XIcon } from "../../icons/XIcon";
|
||||||
import { allCourses } from "../../utils/allCourses";
|
|
||||||
import { RegisterBatchCreate } from "../../types/Register";
|
import { RegisterBatchCreate } from "../../types/Register";
|
||||||
import { RegistrationPreview } from ".";
|
import { RegistrationPreview } from ".";
|
||||||
import { loadCustomLabels } from "../../utils/allCustomLabels";
|
import { loadCustomLabels } from "../../utils/allCustomLabels";
|
||||||
import { FileDashedIcon } from "../../icons/FileDashedIcon";
|
import { FileDashedIcon } from "../../icons/FileDashedIcon";
|
||||||
import { LoadingIcon } from "../../icons/LoadingIcon";
|
import { LoadingIcon } from "../../icons/LoadingIcon";
|
||||||
|
import { useCourses } from "..";
|
||||||
|
|
||||||
|
|
||||||
function isoDateToLocalDate(date: string): string {
|
function isoDateToLocalDate(date: string): string {
|
||||||
@ -101,9 +101,18 @@ function Register(props: {
|
|||||||
onDelete: (v: number) => void,
|
onDelete: (v: number) => void,
|
||||||
isPreview: boolean,
|
isPreview: boolean,
|
||||||
}) {
|
}) {
|
||||||
const courseName = () => {
|
const courses = useCourses();
|
||||||
const courses = allCourses();
|
|
||||||
return courses.find((course) => course.course_id === props.courseId)?.course_name ?? `Curso invalido! (${props.courseId})`;
|
const courseName = (): string => {
|
||||||
|
if (courses === undefined || courses?.data.state !== "ready") {
|
||||||
|
return "~~Cursos cargando~~";
|
||||||
|
}
|
||||||
|
|
||||||
|
return courses
|
||||||
|
.data()
|
||||||
|
.find((course) => course.course_id === props.courseId)
|
||||||
|
?.course_name ??
|
||||||
|
`~~Curso invalido! (${props.courseId})~~`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { createEffect, createSignal, For } from "solid-js";
|
import { createEffect, createSignal, For, onMount } from "solid-js";
|
||||||
// import type {CursoGIE} from "../../../model/CursoGIE/cursoGIE.entity";
|
import { useCourses } from "..";
|
||||||
import { isServer } from "solid-js/web";
|
|
||||||
import { allCourses } from "../../utils/allCourses";
|
|
||||||
|
|
||||||
export function SearchableSelect(props: {
|
export function SearchableSelect(props: {
|
||||||
onChange: (id: number | null) => void,
|
onChange: (id: number | null) => void,
|
||||||
@ -11,6 +9,8 @@ export function SearchableSelect(props: {
|
|||||||
const [selected, setSelected] = createSignal<number | null>(null);
|
const [selected, setSelected] = createSignal<number | null>(null);
|
||||||
const [inputValue, setInputValue] = createSignal("");
|
const [inputValue, setInputValue] = createSignal("");
|
||||||
|
|
||||||
|
const courses = useCourses();
|
||||||
|
|
||||||
const iHandler = (ev: KeyboardEvent & {currentTarget: HTMLInputElement, target: Element}) => {
|
const iHandler = (ev: KeyboardEvent & {currentTarget: HTMLInputElement, target: Element}) => {
|
||||||
const inputEl = ev.target as HTMLInputElement;
|
const inputEl = ev.target as HTMLInputElement;
|
||||||
// Clear current selection
|
// Clear current selection
|
||||||
@ -58,18 +58,22 @@ export function SearchableSelect(props: {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isServer) {
|
onMount(() => {
|
||||||
(inputElement as HTMLInputElement).addEventListener("keydown", (ev) => {
|
(inputElement as HTMLInputElement).addEventListener("keydown", (ev) => {
|
||||||
if (ev.code === "Enter") {
|
if (ev.code === "Enter") {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
const filteredOptions = () => {
|
const filteredOptions = () => {
|
||||||
const filterText = filter();
|
const filterText = filter();
|
||||||
|
|
||||||
return allCourses().filter((course) => {
|
if (courses === undefined || courses?.data.state !== "ready") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return courses.data().filter((course) => {
|
||||||
let courseText = course.course_name.toLowerCase();
|
let courseText = course.course_name.toLowerCase();
|
||||||
courseText = courseText.replace("á", "a");
|
courseText = courseText.replace("á", "a");
|
||||||
courseText = courseText.replace("é", "e");
|
courseText = courseText.replace("é", "e");
|
||||||
|
@ -1,21 +1,80 @@
|
|||||||
import { createSignal } from "solid-js";
|
import { JSX, Resource, createContext, createMemo, createResource, createSignal, useContext } from "solid-js";
|
||||||
import { NewRegister } from "./NewRegister";
|
import { NewRegister } from "./NewRegister";
|
||||||
import { Registers } from "./Registers";
|
import { Registers } from "./Registers";
|
||||||
import { Search } from "./Search";
|
import { Search } from "./Search";
|
||||||
import { Person } from "../types/Person";
|
import { Person } from "../types/Person";
|
||||||
|
import axios from "axios";
|
||||||
|
import { Course } from "../types/Course";
|
||||||
|
|
||||||
export function Certs() {
|
export function Certs() {
|
||||||
const [person, setPerson] = createSignal<Person | null>(null);
|
const [person, setPerson] = createSignal<Person | null>(null);
|
||||||
const [count, setCount] = createSignal(0);
|
const [count, setCount] = createSignal(0);
|
||||||
|
|
||||||
|
const [courses] = createResource(fetchAllCourses);
|
||||||
|
|
||||||
|
const coursesReady = createMemo(() => courses.state === "ready");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="grid grid-cols-[16rem_25rem_1fr]">
|
<>
|
||||||
<Search setPerson={setPerson} />
|
<div class={`top-0 left-0 w-screen h-1 ${coursesReady() ? "hidden" : "fixed"}`}>
|
||||||
<NewRegister
|
<div class='h-1 w-full bg-c-on-primary overflow-hidden'>
|
||||||
personId={person()?.person_id ?? null}
|
<div class='progress w-full h-full bg-c-primary left-right' />
|
||||||
onSuccess={() => setCount((x) => x + 1)}
|
</div>
|
||||||
/>
|
</div>
|
||||||
<Registers person={person()} count={count()} />
|
<CoursesProvider courses={courses}>
|
||||||
</div>
|
<div class={`grid grid-cols-[16rem_25rem_1fr] ${coursesReady() ? "" : "opacity-25"}`}>
|
||||||
|
<Search setPerson={setPerson} />
|
||||||
|
<NewRegister
|
||||||
|
personId={person()?.person_id ?? null}
|
||||||
|
onSuccess={() => setCount((x) => x + 1)}
|
||||||
|
/>
|
||||||
|
<Registers person={person()} count={count()} />
|
||||||
|
</div>
|
||||||
|
</CoursesProvider>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const CoursesContext = createContext<{
|
||||||
|
data: Resource<Course[]>,
|
||||||
|
map: () => {[course_name: string]: Course},
|
||||||
|
}>();
|
||||||
|
|
||||||
|
function CoursesProvider(props: {courses: Resource<Course[]>, children: JSX.Element}) {
|
||||||
|
const courseMapMemo = createMemo(() => {
|
||||||
|
if (props.courses === undefined || props.courses?.state !== "ready") {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = props.courses();
|
||||||
|
|
||||||
|
type CourseMap = {[k: string]: Course};
|
||||||
|
const map: CourseMap = {};
|
||||||
|
for (const course of data) {
|
||||||
|
map[course.course_name] = course;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
|
const coursesData = {
|
||||||
|
data: props.courses,
|
||||||
|
map: courseMapMemo,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CoursesContext.Provider value={coursesData}>
|
||||||
|
{props.children}
|
||||||
|
</CoursesContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchAllCourses(): Promise<Array<Course>> {
|
||||||
|
const result = await axios.get<Array<Course>>(`${import.meta.env.VITE_BACKEND_URL}/api/course`);
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCourses() {
|
||||||
|
return useContext(CoursesContext);
|
||||||
|
}
|
||||||
|
@ -29,3 +29,23 @@ body {
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
animation: progress 1s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-right {
|
||||||
|
transform-origin: 0% 50%;
|
||||||
|
}
|
||||||
|
@keyframes progress {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0) scaleX(0);
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: translateX(0) scaleX(0.4);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(100%) scaleX(0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { Course } from "../types/Course";
|
|||||||
|
|
||||||
type CourseMap = {[k: number]: Course};
|
type CourseMap = {[k: number]: Course};
|
||||||
|
|
||||||
export const [allCourses, setAllCourses] = createSignal<Array<Course>>([]);
|
const [allCourses, setAllCourses] = createSignal<Array<Course>>([]);
|
||||||
export const [courseMap, setCourseMap] = createSignal<CourseMap>({});
|
export const [courseMap, setCourseMap] = createSignal<CourseMap>({});
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
|
@ -8,6 +8,20 @@ module.exports = {
|
|||||||
fontFamily: {
|
fontFamily: {
|
||||||
"mono": ["Inconsolata", "monospace"],
|
"mono": ["Inconsolata", "monospace"],
|
||||||
},
|
},
|
||||||
|
animation: {
|
||||||
|
progress: "progress 1s infinite linear",
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
progress: {
|
||||||
|
"0%": { transform: " translateX(0) scaleX(0)" },
|
||||||
|
"40%": { transform: "translateX(0) scaleX(0.4)" },
|
||||||
|
"100%": { transform: "translateX(100%) scaleX(0.5)" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
transformOrigin: {
|
||||||
|
"left-right": "0% 50%",
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
"c-primary": "var(--c-primary)",
|
"c-primary": "var(--c-primary)",
|
||||||
|
Loading…
Reference in New Issue
Block a user