[FE] Improve batch mode's group UI.

master
Araozu 2023-06-13 21:25:00 -05:00
parent 42a16bd30b
commit 3ac8f1321c
5 changed files with 206 additions and 33 deletions

View File

@ -1,43 +1,103 @@
import { createSignal, onMount } from "solid-js";
import { createSignal, Match, onMount, Show, Switch } from "solid-js";
import { Person } from "src/types/Person";
import { DniRegister } from "./DniEntry/DniRegister";
/**
* Sample data
01188994
47695703
46736668
21551382
41178747
41876027
04827012
45912508
45349984
41362975
70861152
72404776
46421911
43502556
*/
enum Status {
Empty,
Loading,
Ok,
Error,
}
export function DniEntry(props: {dni: string}) {
const [person, setPerson] = createSignal<Person | null>(null);
const [status, setStatus] = createSignal<Status>(Status.Empty);
const loadPerson = async() => {
setStatus(Status.Loading);
onMount(async() => {
try {
const response = await fetch(`/person/${props.dni}`);
const body = await response.json();
if (response.ok) {
setPerson(body);
setStatus(Status.Ok);
} else if (response.status === 404) {
console.error(body);
setStatus(Status.Error);
// setWarning("Persona no encontrada. Se debe insertar manualmente sus datos.");
setPerson(null);
} else {
// setError(body);
setStatus(Status.Error);
}
} catch (e) {
// setError(JSON.stringify(e));
setStatus(Status.Error);
}
});
};
onMount(loadPerson);
return (
<div class="grid gap-1 grid-cols-[7rem_10rem_10rem_16rem]">
<div class="text-center font-mono">
{props.dni}
</div>
<div class="text-center font-mono">
{person()?.apellidoPaterno ?? "..."}
</div>
<div class="text-center font-mono">
{person()?.apellidoMaterno ?? "..."}
</div>
<div class="text-center font-mono">
{person()?.nombres ?? "..."}
</div>
</div>
<>
<Show when={status() !== Status.Error}>
<div class="grid gap-1 grid-cols-[7rem_10rem_10rem_16rem] hover:bg-c-surface-variant hover:text-c-on-surface-variant">
<div class="text-center font-mono">
{props.dni}
</div>
<Switch>
<Match when={status() === Status.Empty}>
<div class="text-center font-mono"></div>
<div class="text-center font-mono"></div>
<div class="text-center font-mono"></div>
</Match>
<Match when={status() === Status.Loading}>
<div class="text-center font-mono">...</div>
<div class="text-center font-mono">...</div>
<div class="text-center font-mono">...</div>
</Match>
<Match when={status() === Status.Ok}>
<div class="text-center font-mono">
{person()?.apellidoPaterno ?? "!"}
</div>
<div class="text-center font-mono">
{person()?.apellidoMaterno ?? "!"}
</div>
<div class="text-center font-mono">
{person()?.nombres ?? "!"}
</div>
</Match>
</Switch>
</div>
</Show>
<Show when={status() === Status.Error}>
<DniRegister dni={props.dni} onSuccess={loadPerson} />
</Show>
</>
);
}

View File

@ -0,0 +1,104 @@
import { createSignal, JSX } from "solid-js";
type HTMLEventFn = JSX.EventHandlerUnion<HTMLFormElement, Event & {
submitter: HTMLElement;
}>;
export function DniRegister(props: {dni: string, onSuccess: () => void}) {
const [nombres, setNombres] = createSignal("");
const [apellidoP, setApellidoP] = createSignal("");
const [apellidoM, setApellidoM] = createSignal("");
const [loading, setLoading] = createSignal(false);
const [error, setError] = createSignal("");
const register: HTMLEventFn = async(ev) => {
ev.preventDefault();
setLoading(true);
setError("");
if (props.dni.length !== 8) {
setLoading(false);
setError("DNI es invalido");
return;
}
const response = await fetch("/person", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
dni: props.dni.toUpperCase(),
apellidoPaterno: apellidoP().toUpperCase(),
apellidoMaterno: apellidoM().toUpperCase(),
nombres: nombres().toUpperCase(),
}),
});
if (response.ok) {
props.onSuccess();
} else {
const d = await response.json();
setError(`Error creando persona en BD. ${d}`);
}
setLoading(false);
};
return (
<form class="grid gap-1 grid-cols-[7rem_10rem_10rem_16rem_7rem] w-full" onsubmit={register}>
<div class="text-center font-mono">
{props.dni}
</div>
<input
id="add-person-apellido-paterno"
class="bg-c-background text-c-on-background border-c-outline border-2 rounded px-2 py-1
invalid:border-c-error invalid:text-c-error
focus:border-c-primary outline-none
disabled:opacity-50 disabled:cursor-not-allowed"
type="text"
placeholder="Apellido paterno"
value={apellidoP()}
required={true}
onChange={(e) => setApellidoP(e.target.value.toUpperCase())}
disabled={loading()}
/>
<input
id="add-person-apellido-materno"
class="bg-c-background text-c-on-background border-c-outline border-2 rounded px-2 py-1
invalid:border-c-error invalid:text-c-error
focus:border-c-primary outline-none
disabled:opacity-50 disabled:cursor-not-allowed"
type="text"
placeholder="Apellido materno"
value={apellidoM()}
required={true}
onChange={(e) => setApellidoM(e.target.value.toUpperCase())}
disabled={loading()}
/>
<input
id="add-person-nombres"
name="add-person-nombres"
class="bg-c-background text-c-on-background border-c-outline border-2 rounded px-2 py-1
invalid:border-c-error invalid:text-c-error
focus:border-c-primary outline-none
disabled:opacity-50 disabled:cursor-not-allowed"
type="text"
placeholder="Nombres"
value={nombres()}
required={true}
onChange={(e) => setNombres(e.target.value.toUpperCase())}
disabled={loading()}
/>
<input
class={`bg-c-primary text-c-on-primary px-4 py-2 rounded-md cursor-pointer
disabled:opacity-50 disabled:cursor-not-allowed
${loading() ? "animate-pulse" : ""}`}
type="submit"
value="Registrar"
disabled={loading()}
/>
</form>
);
}

View File

@ -1,23 +1,32 @@
import { For } from "solid-js";
import { DniEntry } from "./DniEntry";
export function DniGroup(props: {group: string}) {
export function DniGroup(props: {group: string, index: number}) {
const dnis = () => [...props.group.matchAll(/\d+/g)];
return (
<div>
<h2>DNI Group</h2>
console.log("Loading group...");
<div class="grid gap-1 grid-cols-[7rem_10rem_10rem_16rem]">
<div class="text-center">DNI</div>
<div class="text-center">Apellido Paterno</div>
<div class="text-center">Apellido Materno</div>
<div class="text-center">Nombres</div>
return (
<div class="grid grid-cols-[53rem_auto] gap-2 my-8">
<div class="border border-c-outline rounded-xl">
<div class="grid gap-1 grid-cols-[7rem_10rem_10rem_16rem] border-b">
<div class="text-center">DNI</div>
<div class="text-center">Apellido Paterno</div>
<div class="text-center">Apellido Materno</div>
<div class="text-center">Nombres</div>
</div>
<For each={dnis()}>
{(dni) => <DniEntry dni={dni.toString()} />}
</For>
</div>
<For each={dnis()}>
{(dni) => <DniEntry dni={dni.toString()} />}
</For>
<div class="border border-c-outline rounded-xl p-2">
<h2 class="font-medium text-xl text-c-success pb-2">
Grupo #{props.index + 1} - cursos y fechas
</h2>
</div>
</div>
);
}

View File

@ -7,7 +7,7 @@ export function DniTable(props: {dniGroups: Array<string>}) {
<h2 class="my-2 font-bold text-xl">2. Revisar grupos</h2>
<For each={props.dniGroups}>
{(g) => <DniGroup group={g} />}
{(g, index) => <DniGroup group={g} index={index()} />}
</For>
</div>
);

View File

@ -42,7 +42,7 @@ export function Dnis(props: {addDniGroup: (v: string) => void}) {
<input
class="bg-c-primary text-c-on-primary px-4 py-2 rounded-md cursor-pointer
disabled:opacity-50 disabled:cursor-not-allowed"
disabled:opacity-50 disabled:cursor-not-allowed mt-2"
type="submit"
value="Agregar grupo"
/>