[FE] Begin work on a new batch mode

master
Araozu 2023-06-12 22:08:21 -05:00
parent 459d5ceaff
commit 36cff473ef
13 changed files with 265 additions and 98 deletions

View File

@ -4,6 +4,29 @@ const path = require("path");
const fs = require("fs"); const fs = require("fs");
const { glob } = require("glob"); const { glob } = require("glob");
const buildHydration = (path) => {
build({
platform: "browser",
entryPoints: [
path,
],
bundle: true,
minify: true,
sourcemap: false,
logLevel: "info",
plugins: [
solidPlugin({
solid: {
generate: "dom",
hydratable: true,
},
})
],
outdir: "static",
format: "cjs",
});
}
(async() => { (async() => {
const files = await glob("dist/**/*.jsx"); const files = await glob("dist/**/*.jsx");
@ -26,44 +49,6 @@ const { glob } = require("glob");
}); });
})(); })();
build({ buildHydration("src/views/hydration.ts");
platform: "browser", buildHydration("src/views/hydration/hydration_aulavirtual.ts");
entryPoints: [ buildHydration("src/views/hydration/hydration_batch_mode.ts");
"src/views/hydration.ts",
],
bundle: true,
minify: true,
sourcemap: false,
logLevel: "info",
plugins: [
solidPlugin({
solid: {
generate: "dom",
hydratable: true,
},
})
],
outdir: "static",
format: "cjs",
});
build({
platform: "browser",
entryPoints: [
"src/views/hydration/hydration_aulavirtual.ts",
],
bundle: true,
minify: true,
sourcemap: false,
logLevel: "info",
plugins: [
solidPlugin({
solid: {
generate: "dom",
hydratable: true,
},
})
],
outdir: "static",
format: "cjs",
});

View File

@ -1,9 +1,32 @@
const { build, context } = require("esbuild"); const { context } = require("esbuild");
const { solidPlugin } = require("esbuild-plugin-solid"); const { solidPlugin } = require("esbuild-plugin-solid");
const path = require("path");
const fs = require("fs");
const { glob } = require("glob"); const { glob } = require("glob");
const genHydration = (path) => async () => {
const ctx = await context({
platform: "browser",
entryPoints: [
path,
],
bundle: true,
minify: false,
logLevel: "info",
plugins: [
solidPlugin({
solid: {
generate: "dom",
hydratable: true,
},
})
],
outdir: "static",
format: "cjs",
});
await ctx.watch();
console.log("Watching hydration script...");
};
/** /**
* Compile JSX files * Compile JSX files
*/ */
@ -34,52 +57,6 @@ const { glob } = require("glob");
/** /**
* Generate hydration script * Generate hydration script
*/ */
(async () => { (genHydration("src/views/hydration.ts"))();
const ctx = await context({ (genHydration("src/views/hydration/hydration_aulavirtual.ts"))();
platform: "browser", (genHydration("src/views/hydration/hydration_batch_mode.ts"))();
entryPoints: [
"src/views/hydration.ts",
],
bundle: true,
minify: false,
logLevel: "info",
plugins: [
solidPlugin({
solid: {
generate: "dom",
hydratable: true,
},
})
],
outdir: "static",
format: "cjs",
});
await ctx.watch();
console.log("Watching hydration script...");
})();
(async () => {
const ctx = await context({
platform: "browser",
entryPoints: [
"src/views/hydration/hydration_aulavirtual.ts",
],
bundle: true,
minify: false,
logLevel: "info",
plugins: [
solidPlugin({
solid: {
generate: "dom",
hydratable: true,
},
})
],
outdir: "static",
format: "cjs",
});
await ctx.watch();
console.log("Watching hydration script...");
})();

View File

@ -11,6 +11,7 @@ import { SubjectController } from "./controller/subject/subject.controller";
import { SubjectService } from "./controller/subject/subject.service"; import { SubjectService } from "./controller/subject/subject.service";
import * as dotenv from "dotenv"; import * as dotenv from "dotenv";
import { AulaVirtualController } from "./controller/aulavirtual/aulavirtual.controller"; import { AulaVirtualController } from "./controller/aulavirtual/aulavirtual.controller";
import { BatchCertController } from "./controller/batch_certs/BatchCerts.controller";
// Must be done before initializing DB. // Must be done before initializing DB.
console.log(dotenv.config()); console.log(dotenv.config());
@ -45,7 +46,13 @@ const db = process.env.MY_SQL_DB;
synchronize: false, synchronize: false,
}), }),
], ],
controllers: [CertificateController, PersonController, SubjectController, AulaVirtualController], controllers: [
CertificateController,
PersonController,
SubjectController,
AulaVirtualController,
BatchCertController,
],
providers: [CertificateService, PersonService, SubjectService], providers: [CertificateService, PersonService, SubjectService],
}) })
export class AppModule {} export class AppModule {}

View File

@ -0,0 +1,13 @@
import { Controller, Get } from "@nestjs/common";
import { renderToString } from "solid-js/web";
import { CertsBatch } from "src/views/BatchCerts";
import { template } from "./BatchCerts.template";
@Controller("batch-certs")
export class BatchCertController {
@Get()
entry(): string {
const html = renderToString(CertsBatch);
return template(html);
}
}

View File

@ -0,0 +1,28 @@
import { generateHydrationScript } from "solid-js/web";
export function template(ssr: string): string {
return `
<!DOCTYPE html>
<html lang="es">
<head>
<title>Batch Certs - EEGSAC</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/static/styles.css?t=${Date.now()}" />
<!-- Phosphor icons -->
<link
rel="stylesheet"
type="text/css"
href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/regular/style.css"
/>
${generateHydrationScript()}
</head>
<body>
<div id="root">
${ssr}
</div>
</body>
<script src="/static/hydration_batch_mode.js?t=${Date.now()}"></script>
</html>
`;
}

View File

@ -1,4 +1,3 @@
import { Hydration } from "solid-js/web";
export function AulaVirtual() { export function AulaVirtual() {
return ( return (

View File

@ -0,0 +1,43 @@
import { createSignal, onMount } from "solid-js";
import { Person } from "src/types/Person";
export function DniEntry(props: {dni: string}) {
const [person, setPerson] = createSignal<Person | null>(null);
onMount(async() => {
try {
const response = await fetch(`/person/${props.dni}`);
const body = await response.json();
if (response.ok) {
setPerson(body);
} else if (response.status === 404) {
console.error(body);
// setWarning("Persona no encontrada. Se debe insertar manualmente sus datos.");
setPerson(null);
} else {
// setError(body);
}
} catch (e) {
// setError(JSON.stringify(e));
}
});
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>
);
}

View File

@ -0,0 +1,23 @@
import { For } from "solid-js";
import { DniEntry } from "./DniEntry";
export function DniGroup(props: {group: string}) {
const dnis = () => [...props.group.matchAll(/\d+/g)];
return (
<div>
<h2>DNI Group</h2>
<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>
</div>
<For each={dnis()}>
{(dni) => <DniEntry dni={dni.toString()} />}
</For>
</div>
);
}

View File

@ -0,0 +1,14 @@
import { For } from "solid-js";
import { DniGroup } from "./DniGroup";
export function DniTable(props: {dniGroups: Array<string>}) {
return (
<div class="m-4">
<h2 class="my-2 font-bold text-xl">2. Revisar grupos</h2>
<For each={props.dniGroups}>
{(g) => <DniGroup group={g} />}
</For>
</div>
);
}

View File

@ -0,0 +1,52 @@
import { createSignal, JSX } from "solid-js";
type HTMLEventFn = JSX.EventHandlerUnion<HTMLFormElement, Event & {
submitter: HTMLElement;
}>;
export function Dnis(props: {addDniGroup: (v: string) => void}) {
const [dnis, setDnis] = createSignal("");
const agregarGrupo: HTMLEventFn = (ev) => {
ev.preventDefault();
props.addDniGroup(dnis());
setDnis("");
};
return (
<div class="m-4">
<h2 class="my-2 font-bold text-xl">1. Crear grupos de DNIs</h2>
<p>
Inserta dnis separados por comas, espacios, etc. Los DNIs se separan con
la expresión <code>/\d+/g</code>.
</p>
<form onsubmit={agregarGrupo}>
<input
id="search-dni"
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 font-mono
disabled:opacity-50 disabled:cursor-not-allowed
w-1/2"
type="text"
minLength={8}
placeholder="Números de DNI"
value={dnis()}
required={true}
onChange={(e) => setDnis(e.target.value)}
/>
<br />
<input
class="bg-c-primary text-c-on-primary px-4 py-2 rounded-md cursor-pointer
disabled:opacity-50 disabled:cursor-not-allowed"
type="submit"
value="Agregar grupo"
/>
</form>
</div>
);
}

17
src/views/BatchCerts.tsx Normal file
View File

@ -0,0 +1,17 @@
import { createSignal } from "solid-js";
import { DniTable } from "./AulaVirtual/DniTable";
import { Dnis } from "./AulaVirtual/Dnis";
export function CertsBatch() {
const [dniGroups, setDniGroups] = createSignal<Array<string>>([]);
return (
<div>
<h1 class="px-4 py-2 text-2xl font-bold">
Batch mode
</h1>
<Dnis addDniGroup={(s) => setDniGroups((x) => [...x, s])} />
<DniTable dniGroups={dniGroups()} />
</div>
);
}

View File

@ -10,9 +10,7 @@ export function Certs() {
return ( return (
<div> <div>
<h1 <h1 class="px-4 py-2 text-2xl font-bold">
class="px-4 py-2 text-2xl font-bold"
>
Registrar certificado Registrar certificado
</h1> </h1>
<Search setPerson={setPerson}/> <Search setPerson={setPerson}/>

View File

@ -0,0 +1,11 @@
/**
* This file generates a hidration script, which must
* then be sent to the client.
*/
import {hydrate} from "solid-js/web";
import { CertsBatch } from "../BatchCerts";
const root = document.getElementById("root")!;
hydrate(CertsBatch, root);