[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 { For, createSignal, onMount } from "solid-js";
|
||||||
import { DniEntry } from "./DniEntry";
|
import { DniEntry } from "./DniEntry";
|
||||||
|
import { NewRegister } from "../components/NewRegister";
|
||||||
|
import { subjects } from "../subjects";
|
||||||
|
|
||||||
export function DniGroup(props: {group: string, index: number}) {
|
export function DniGroup(props: {group: string, index: number}) {
|
||||||
const [dnis, setDnis] = createSignal<Array<string>>([]);
|
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">
|
<h2 class="font-medium text-xl text-c-success pb-2">
|
||||||
Grupo #{props.index + 1} - cursos y fechas
|
Grupo #{props.index + 1} - cursos y fechas
|
||||||
</h2>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -17,7 +17,7 @@ export function Certs() {
|
|||||||
<div class="grid grid-cols-2 gap-2">
|
<div class="grid grid-cols-2 gap-2">
|
||||||
<Registers person={person()} lastUpdate={lastUpdate()} />
|
<Registers person={person()} lastUpdate={lastUpdate()} />
|
||||||
<NewRegister
|
<NewRegister
|
||||||
person={person()}
|
personId={person()?.id ?? -1}
|
||||||
onSuccess={() => setLastUpdate((x) => x + 1)}
|
onSuccess={() => setLastUpdate((x) => x + 1)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,45 @@
|
|||||||
import { createSignal, onMount, Show } from "solid-js";
|
import { createSignal, Show } from "solid-js";
|
||||||
import type { CursoGIE } from "../../model/CursoGIE/cursoGIE.entity";
|
|
||||||
import { SearchableSelect } from "./NewRegister/SearchableSelect";
|
import { SearchableSelect } from "./NewRegister/SearchableSelect";
|
||||||
import { JSX } from "solid-js/jsx-runtime";
|
import { JSX } from "solid-js/jsx-runtime";
|
||||||
import { Person } from "src/types/Person";
|
import { subjects } from "../subjects";
|
||||||
|
|
||||||
|
|
||||||
type HTMLEventFn = JSX.EventHandlerUnion<HTMLFormElement, Event & {
|
type HTMLEventFn = JSX.EventHandlerUnion<HTMLFormElement, Event & {
|
||||||
submitter: HTMLElement;
|
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 [error, setError] = createSignal("");
|
||||||
const [loading, setLoading] = createSignal(false);
|
const [loading, setLoading] = createSignal(false);
|
||||||
// Used to update SearchableSelect.tsx manually
|
// 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) => {
|
const register: HTMLEventFn = async(ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
||||||
@ -65,24 +77,17 @@ export function NewRegister(props: {person: Person | null, onSuccess: () => void
|
|||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const response = await fetch("/certificate", {
|
const result = await (props.registerFn ?? defaultNewRegisterFn)(
|
||||||
method: "POST",
|
props.personId ?? -1,
|
||||||
headers: {
|
subject,
|
||||||
"Content-Type": "application/json",
|
date,
|
||||||
},
|
);
|
||||||
body: JSON.stringify({
|
|
||||||
personId: props.person?.id ?? -1,
|
|
||||||
subjectId: subject,
|
|
||||||
date,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
if (result === null) {
|
||||||
props.onSuccess();
|
props.onSuccess();
|
||||||
setCount((x) => x + 1);
|
setCount((x) => x + 1);
|
||||||
} else {
|
} else {
|
||||||
const data = await response.json();
|
setError(result);
|
||||||
setError(JSON.stringify(data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@ -90,9 +95,9 @@ export function NewRegister(props: {person: Person | null, onSuccess: () => void
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="p-4">
|
<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
|
<form
|
||||||
class="px-4 grid"
|
class="px-4 grid"
|
||||||
style={{"grid-template-columns": "30rem 12rem 10rem auto", "grid-column-gap": "1rem"}}
|
style={{"grid-template-columns": "30rem 12rem 10rem auto", "grid-column-gap": "1rem"}}
|
||||||
|
@ -63,8 +63,7 @@ export function SearchableSelect(props: {
|
|||||||
{inputElement}
|
{inputElement}
|
||||||
<br/>
|
<br/>
|
||||||
<div
|
<div
|
||||||
class="border-c-outline border-2 rounded overflow-y-scroll"
|
class="border-c-outline border-2 rounded overflow-y-scroll h-[18rem]"
|
||||||
style={{"max-height": "18rem", "min-height": "12rem"}}
|
|
||||||
>
|
>
|
||||||
<For each={props.subjects}>
|
<For each={props.subjects}>
|
||||||
{(s) => (
|
{(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