[FE] Batch mode: Add selector for courses
This commit is contained in:
parent
89bdc1499a
commit
ab378de775
@ -1,5 +1,7 @@
|
||||
import { For, createSignal, onMount } from "solid-js";
|
||||
import { DniEntry } from "./DniEntry";
|
||||
import { NewRegister } from "../components/NewRegister";
|
||||
import { subjects } from "../subjects";
|
||||
|
||||
export function DniGroup(props: {group: string, index: number}) {
|
||||
const [dnis, setDnis] = createSignal<Array<string>>([]);
|
||||
@ -33,7 +35,63 @@ export function DniGroup(props: {group: string, index: number}) {
|
||||
<h2 class="font-medium text-xl text-c-success pb-2">
|
||||
Grupo #{props.index + 1} - cursos y fechas
|
||||
</h2>
|
||||
|
||||
<hr />
|
||||
<CourseManager />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CourseManager() {
|
||||
const [courses, setCourses] = createSignal<Array<[number, string]>>([]);
|
||||
|
||||
async function registerCourse(_: number, subjectId: number, date: string): Promise<null | string> {
|
||||
setCourses((x) => [...x, [subjectId, date]]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<NewRegister
|
||||
personId={0}
|
||||
onSuccess={() => {}}
|
||||
registerFn={registerCourse}
|
||||
labelText={"Seleccionar cursos"}
|
||||
/>
|
||||
<div class="p-4">
|
||||
<h2 class="mb-4 font-bold text-xl">Verificar y confirmar cursos</h2>
|
||||
<div class="">
|
||||
<For each={courses()}>
|
||||
{(course) => <Course
|
||||
id={course[0]}
|
||||
date={course[1]}
|
||||
onDelete={(id) => setCourses((x) => x.filter((y) => y[0] !== id))}
|
||||
/>}
|
||||
</For>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="my-2 bg-c-primary text-c-on-primary px-4 py-2 rounded-md cursor-pointer
|
||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
type="button"
|
||||
>
|
||||
Registrar <b>todas</b> las personas en <b>todos</b> los cursos
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Course(props: {id: number, date: string, onDelete: (id: number) => void}) {
|
||||
const courseName = () => subjects().find((x) => x.id === props.id)?.nombre ?? "NOT FOUND";
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-[auto_10rem_5rem] gap-2 hover:bg-c-surface-variant hover:text-c-on-surface-variant font-mono">
|
||||
<p>{courseName()}</p>
|
||||
<p>{props.date}</p>
|
||||
<div>
|
||||
<button class="underline" onclick={() => props.onDelete(props.id)}>Eliminar</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ export function Certs() {
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<Registers person={person()} lastUpdate={lastUpdate()} />
|
||||
<NewRegister
|
||||
person={person()}
|
||||
personId={person()?.id ?? -1}
|
||||
onSuccess={() => setLastUpdate((x) => x + 1)}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,16 +1,45 @@
|
||||
import { createSignal, onMount, Show } from "solid-js";
|
||||
import type { CursoGIE } from "../../model/CursoGIE/cursoGIE.entity";
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import { SearchableSelect } from "./NewRegister/SearchableSelect";
|
||||
import { JSX } from "solid-js/jsx-runtime";
|
||||
import { Person } from "src/types/Person";
|
||||
import { subjects } from "../subjects";
|
||||
|
||||
|
||||
type HTMLEventFn = JSX.EventHandlerUnion<HTMLFormElement, Event & {
|
||||
submitter: HTMLElement;
|
||||
}>;
|
||||
|
||||
export function NewRegister(props: {person: Person | null, onSuccess: () => void}) {
|
||||
const [subjects, setSubjects] = createSignal<Array<CursoGIE>>([]);
|
||||
|
||||
async function defaultNewRegisterFn(personId: number, subjectId: number, date: string): Promise<null | string> {
|
||||
const response = await fetch("/certificate", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
personId,
|
||||
subjectId,
|
||||
date,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
return null;
|
||||
} else {
|
||||
const data = await response.json();
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
}
|
||||
|
||||
type RegisterFn = (personId: number, subjectId: number, date: string) => Promise<null | string>;
|
||||
|
||||
const defaultLabelText = "3. Crear nuevos registros";
|
||||
|
||||
export function NewRegister(props: {
|
||||
personId: number | null,
|
||||
onSuccess: () => void,
|
||||
registerFn?: RegisterFn,
|
||||
labelText?: string,
|
||||
}) {
|
||||
const [error, setError] = createSignal("");
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
// Used to update SearchableSelect.tsx manually
|
||||
@ -27,23 +56,6 @@ export function NewRegister(props: {person: Person | null, onSuccess: () => void
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
// Loads subjects from DB
|
||||
onMount(async() => {
|
||||
console.log("Retrieve all subjects");
|
||||
|
||||
try {
|
||||
const response = await fetch("/subject/");
|
||||
if (response.ok) {
|
||||
setSubjects(await response.json());
|
||||
} else {
|
||||
setError("No se pudo cargar cursos");
|
||||
}
|
||||
} catch (e) {
|
||||
setError(`No se pudo cargar cursos. ${JSON.stringify(e)}`);
|
||||
}
|
||||
});
|
||||
|
||||
const register: HTMLEventFn = async(ev) => {
|
||||
ev.preventDefault();
|
||||
|
||||
@ -65,24 +77,17 @@ export function NewRegister(props: {person: Person | null, onSuccess: () => void
|
||||
|
||||
setLoading(true);
|
||||
|
||||
const response = await fetch("/certificate", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
personId: props.person?.id ?? -1,
|
||||
subjectId: subject,
|
||||
const result = await (props.registerFn ?? defaultNewRegisterFn)(
|
||||
props.personId ?? -1,
|
||||
subject,
|
||||
date,
|
||||
}),
|
||||
});
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
if (result === null) {
|
||||
props.onSuccess();
|
||||
setCount((x) => x + 1);
|
||||
} else {
|
||||
const data = await response.json();
|
||||
setError(JSON.stringify(data));
|
||||
setError(result);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
@ -90,9 +95,9 @@ export function NewRegister(props: {person: Person | null, onSuccess: () => void
|
||||
|
||||
return (
|
||||
<div class="p-4">
|
||||
<h2 class="mb-4 font-bold text-xl">3. Crear nuevos registros</h2>
|
||||
<h2 class="mb-4 font-bold text-xl">{props.labelText ?? defaultLabelText}</h2>
|
||||
|
||||
<Show when={props.person?.id !== -1}>
|
||||
<Show when={props.personId !== -1}>
|
||||
<form
|
||||
class="px-4 grid"
|
||||
style={{"grid-template-columns": "30rem 12rem 10rem auto", "grid-column-gap": "1rem"}}
|
||||
|
@ -63,8 +63,7 @@ export function SearchableSelect(props: {
|
||||
{inputElement}
|
||||
<br/>
|
||||
<div
|
||||
class="border-c-outline border-2 rounded overflow-y-scroll"
|
||||
style={{"max-height": "18rem", "min-height": "12rem"}}
|
||||
class="border-c-outline border-2 rounded overflow-y-scroll h-[18rem]"
|
||||
>
|
||||
<For each={props.subjects}>
|
||||
{(s) => (
|
||||
|
16
src/views/subjects.ts
Normal file
16
src/views/subjects.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { CursoGIE } from "src/model/CursoGIE/cursoGIE.entity";
|
||||
|
||||
export const [subjects, setSubjects] = createSignal<Array<CursoGIE>>([]);
|
||||
|
||||
(async() => {
|
||||
try {
|
||||
const response = await fetch("/subject/");
|
||||
if (response.ok) {
|
||||
setSubjects(await response.json());
|
||||
}
|
||||
} catch (e) {
|
||||
/* empty */
|
||||
}
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user