[FE][Certs] Generate Matpel 3 carnet w/o QR
This commit is contained in:
parent
21c1184e2a
commit
172ec76908
@ -28,6 +28,7 @@
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/qrcode": "^1.5.1",
|
||||
"axios": "^1.5.1",
|
||||
"canvg": "^4.0.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"qrcode": "^1.5.3",
|
||||
"solid-js": "^1.7.6"
|
||||
|
@ -17,6 +17,9 @@ dependencies:
|
||||
axios:
|
||||
specifier: ^1.5.1
|
||||
version: 1.5.1
|
||||
canvg:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
file-saver:
|
||||
specifier: ^2.0.5
|
||||
version: 2.0.5
|
||||
@ -956,12 +959,20 @@ packages:
|
||||
resolution: {integrity: sha512-c0Snqx/IpY+QHnCqEQzo9NjhBNth6gm6/4wDgWt1ML24ldNiStXmxuKJUKM7ob/iAhQWH/dUH1STRt5eTUixlw==}
|
||||
dev: false
|
||||
|
||||
/@types/offscreencanvas@2019.7.2:
|
||||
resolution: {integrity: sha512-ujCjOxeA07IbEBQYAkoOI+XFw5sT3nhWJ/xZfPR6reJppDG7iPQPZacQiLTtWH1b3a2NYXWlxvYqa40y/LAixQ==}
|
||||
dev: false
|
||||
|
||||
/@types/qrcode@1.5.1:
|
||||
resolution: {integrity: sha512-HpSN675K0PmxIDRpjMI3Mc2GiKo3dNu+X/F5SoItiaDS1lVfgC6Wac1c5lQDfKWbTJUSHWiHKzpJpBZG7k9gaA==}
|
||||
dependencies:
|
||||
'@types/node': 20.5.5
|
||||
dev: false
|
||||
|
||||
/@types/raf@3.4.2:
|
||||
resolution: {integrity: sha512-sM4HyDVlDFl4goOXPF+g9nNHJFZQGot+HgySjM4cRjqXzjdatcEvYrtG4Ia8XumR9T6k8G2tW9B7hnUj51Uf0A==}
|
||||
dev: false
|
||||
|
||||
/@types/semver@7.5.0:
|
||||
resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==}
|
||||
dev: true
|
||||
@ -1345,6 +1356,18 @@ packages:
|
||||
resolution: {integrity: sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==}
|
||||
dev: true
|
||||
|
||||
/canvg@4.0.1:
|
||||
resolution: {integrity: sha512-5gD/d6SiCCT7baLnVr0hokYe93DfcHW2rSqdKOuOQD84YMlyfttnZ8iQsThTdX6koYam+PROz/FuQTo500zqGw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
dependencies:
|
||||
'@types/offscreencanvas': 2019.7.2
|
||||
'@types/raf': 3.4.2
|
||||
raf: 3.4.1
|
||||
rgbcolor: 1.0.1
|
||||
stackblur-canvas: 2.6.0
|
||||
svg-pathdata: 6.0.3
|
||||
dev: false
|
||||
|
||||
/chalk@2.4.2:
|
||||
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||
engines: {node: '>=4'}
|
||||
@ -2603,6 +2626,10 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/performance-now@2.1.0:
|
||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
||||
dev: false
|
||||
|
||||
/picocolors@1.0.0:
|
||||
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
||||
dev: true
|
||||
@ -2734,6 +2761,12 @@ packages:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
dev: true
|
||||
|
||||
/raf@3.4.1:
|
||||
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
|
||||
dependencies:
|
||||
performance-now: 2.1.0
|
||||
dev: false
|
||||
|
||||
/react-is@16.13.1:
|
||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
dev: true
|
||||
@ -2809,6 +2842,11 @@ packages:
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/rgbcolor@1.0.1:
|
||||
resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==}
|
||||
engines: {node: '>= 0.8.15'}
|
||||
dev: false
|
||||
|
||||
/rimraf@3.0.2:
|
||||
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||
hasBin: true
|
||||
@ -2944,6 +2982,11 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/stackblur-canvas@2.6.0:
|
||||
resolution: {integrity: sha512-8S1aIA+UoF6erJYnglGPug6MaHYGo1Ot7h5fuXx4fUPvcvQfcdw2o/ppCse63+eZf8PPidSu4v1JnmEVtEDnpg==}
|
||||
engines: {node: '>=0.1.14'}
|
||||
dev: false
|
||||
|
||||
/string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
@ -3035,6 +3078,11 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/svg-pathdata@6.0.3:
|
||||
resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
dev: false
|
||||
|
||||
/tailwindcss@3.3.3:
|
||||
resolution: {integrity: sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Route, Routes } from "@solidjs/router";
|
||||
import type { Component } from "solid-js";
|
||||
import { type Component } from "solid-js";
|
||||
import { Certs } from "./certs";
|
||||
import { NavRail } from "./components/NavRail";
|
||||
import { OnlineClassroom } from "./OnlineClassroom";
|
||||
@ -8,7 +8,7 @@ const App: Component = () => (
|
||||
<div class="grid grid-cols-[5rem_auto]">
|
||||
<NavRail />
|
||||
<Routes>
|
||||
<Route path="/" component={() => <p>En construccion</p>} />
|
||||
<Route path="/" component={() => <Builder />} />
|
||||
<Route path="/certs" component={Certs} />
|
||||
<Route path="/accesos" component={OnlineClassroom} />
|
||||
<Route path="/escaneo" component={() => <p>En construccion</p>} />
|
||||
@ -17,4 +17,13 @@ const App: Component = () => (
|
||||
);
|
||||
|
||||
|
||||
function Builder() {
|
||||
return (
|
||||
<div>
|
||||
<p>En construccion</p>
|
||||
<p>:D</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
148
frontend/src/certs/Registers/RegisterElement.tsx
Normal file
148
frontend/src/certs/Registers/RegisterElement.tsx
Normal file
@ -0,0 +1,148 @@
|
||||
import { Show } from "solid-js";
|
||||
import { certGenerator } from "../../certGenerator";
|
||||
import { Person } from "../../types/Person";
|
||||
import { Register } from "../../types/Register";
|
||||
import { courseMap } from "../../utils/allCourses";
|
||||
import { customLabelsMap } from "../../utils/allCustomLabels";
|
||||
import { DownloadSimpleIcon } from "../../icons/DownloadSimpleIcon";
|
||||
import { CaretRight } from "../../icons/CaretRight";
|
||||
|
||||
export function RegisterElement(props: {register: Register, person: Person, onClick: () => void}) {
|
||||
|
||||
const dateComponents = () => {
|
||||
const [, year, month, day] = /(\d{4})-(\d{2})-(\d{2})/.exec(props.register.register_display_date) ?? [];
|
||||
return {year, month, day};
|
||||
};
|
||||
|
||||
const displayDate = () => {
|
||||
const {year, month, day} = dateComponents();
|
||||
return `${day}/${month}/${year}`;
|
||||
};
|
||||
|
||||
const courseName = () => {
|
||||
const course = courseMap()[props.register.register_course_id];
|
||||
return course?.course_name ?? "Curso no encontrado";
|
||||
};
|
||||
|
||||
const customLabel = () => {
|
||||
const labelId = props.register.register_custom_label;
|
||||
if (labelId === 1) return "";
|
||||
return customLabelsMap()[labelId]?.custom_label_value ?? "";
|
||||
};
|
||||
|
||||
const genCert = () => {
|
||||
const person = props.person;
|
||||
const register = props.register;
|
||||
|
||||
generateCert(person, register);
|
||||
};
|
||||
|
||||
const generateable = () => {
|
||||
const courseN = courseName();
|
||||
return certGenerator[courseN] !== undefined;
|
||||
};
|
||||
|
||||
const createdTodayClasses = () => {
|
||||
// current dat in YYYY-MM-DD format
|
||||
const today = new Date().toISOString()
|
||||
.split("T")[0];
|
||||
const createdToday = props.register.register_creation_date === today;
|
||||
|
||||
return createdToday ? "bg-c-surface-variant" : "";
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-[11rem_1.5rem_1.25rem] border border-c-outline rounded-md overflow-hidden">
|
||||
<div class="border-r border-c-outline-50 align-middle">
|
||||
<p
|
||||
class="font-bold overflow-hidden whitespace-nowrap pt-1 px-1"
|
||||
title={`${courseName()} ${customLabel()}`}
|
||||
>
|
||||
{courseName()}
|
||||
</p>
|
||||
<p class="font-mono text-sm px-1">
|
||||
<span class="underline">
|
||||
{customLabel()}
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p class={`text-sm px-1 pb-1 ${createdTodayClasses()}`}>
|
||||
<span class="font-mono">
|
||||
{displayDate()}
|
||||
</span>
|
||||
|
||||
<Show when={props.register.register_is_preview}>
|
||||
<span class="text-c-error font-bold select-none">
|
||||
sin firmas
|
||||
</span>
|
||||
</Show>
|
||||
<Show when={!props.register.register_is_preview}>
|
||||
<span class="font-mono">
|
||||
-
|
||||
</span>
|
||||
<span
|
||||
class="font-mono underline cursor-pointer hover:text-c-primary"
|
||||
onClick={() => {
|
||||
const code = props.register.register_code.toString();
|
||||
const paddedCode = code.padStart(4, "0");
|
||||
navigator.clipboard.writeText(paddedCode);
|
||||
}}
|
||||
>
|
||||
{props.register.register_code}
|
||||
</span>
|
||||
</Show>
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="hover:bg-c-primary-container rounded-md transition-colors
|
||||
disabled:opacity-0 disabled:cursor-default
|
||||
disabled:hover:bg-c-transparent"
|
||||
title="Descargar DOCX"
|
||||
onclick={genCert}
|
||||
disabled={!generateable()}
|
||||
>
|
||||
<DownloadSimpleIcon fill="var(--c-on-primary-container)" size={20} />
|
||||
</button>
|
||||
<button
|
||||
class="hover:bg-c-surface-variant rounded-md transition-colors"
|
||||
title="Más opciones"
|
||||
onclick={props.onClick}
|
||||
>
|
||||
<CaretRight fill="var(--c-primary)" size={20} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function generateCert(person: Person, register: Register) {
|
||||
const courseN = courseMap()[register.register_course_id]?.course_name ?? "Curso no encontrado";
|
||||
|
||||
const generator = certGenerator[courseN];
|
||||
if (generator === undefined) {
|
||||
alert(`El cert \`${courseN}\` no está implementado`);
|
||||
return;
|
||||
}
|
||||
|
||||
const [, year, month, day] = /(\d{4})-(\d{2})-(\d{2})/.exec(register.register_display_date) ?? [];
|
||||
const personFullName = `${person.person_names} ${person.person_paternal_surname} ${person.person_maternal_surname}`;
|
||||
|
||||
// Manage custom label
|
||||
const certCustomLabel = register.register_custom_label === 1
|
||||
? ""
|
||||
: customLabelsMap()[register.register_custom_label]?.custom_label_value ?? "";
|
||||
|
||||
const certCode = register.register_is_preview ? "0000" : register.register_code.toString().padStart(4, "0");
|
||||
|
||||
generator(`${courseN} - ${personFullName} [${register.register_id.toString(16).toUpperCase()}].docx`, {
|
||||
matpel: null,
|
||||
personFullName,
|
||||
personDni: person.person_dni.toString(),
|
||||
certCode,
|
||||
certYear: year,
|
||||
certMonth: month,
|
||||
certDay: day,
|
||||
certIId: register.register_code,
|
||||
certCustomLabel,
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,18 @@
|
||||
import saveAs from "file-saver";
|
||||
import { Register } from "../../types/Register";
|
||||
import { courseMap } from "../../utils/allCourses";
|
||||
import { formatDate } from "../../utils/functions";
|
||||
import { genCarnet } from "../../utils/carnetGenerator";
|
||||
import { formatDate, numberToMonth } from "../../utils/functions";
|
||||
import { Canvg } from "canvg";
|
||||
import { Show } from "solid-js";
|
||||
import { Person } from "../../types/Person";
|
||||
|
||||
export function RegisterSidebar(props: {register: Register, close: () => void, onDelete: () => void}) {
|
||||
export function RegisterSidebar(props: {
|
||||
register: Register,
|
||||
person: Person,
|
||||
close: () => void,
|
||||
onDelete: () => void,
|
||||
}) {
|
||||
const deleteRegister = async() => {
|
||||
|
||||
const res = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/register/${props.register.register_id}`,{
|
||||
@ -17,6 +27,41 @@ export function RegisterSidebar(props: {register: Register, close: () => void, o
|
||||
|
||||
const courseName = () => courseMap()[props.register.register_course_id]?.course_name ?? "<curso no encontrado>";
|
||||
|
||||
const generateCarnet = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
||||
|
||||
const p = props.person;
|
||||
const r = props.register;
|
||||
|
||||
const [,month] = r.register_display_date.split("-");
|
||||
|
||||
const monthStr = numberToMonth(parseInt(month, 10));
|
||||
|
||||
if (monthStr === null) {
|
||||
alert(`El cert. tiene un mes invalido (${month}), no se puede generar carnet`);
|
||||
return;
|
||||
}
|
||||
|
||||
const svgHtml = genCarnet(
|
||||
`${p.person_names} ${p.person_paternal_surname} ${p.person_maternal_surname}`,
|
||||
p.person_dni.toString(),
|
||||
r.register_code.toString().padStart(4, "0"),
|
||||
monthStr,
|
||||
);
|
||||
const v = Canvg.fromString(ctx, svgHtml);
|
||||
v.start();
|
||||
v.ready().then(() => {
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob !== null) {
|
||||
saveAs(blob, "carnet.png");
|
||||
} else {
|
||||
console.log("blob is null... :c");
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="absolute top-0 bg-c-surface-variant right-0
|
||||
py-4 px-6 w-[20rem]
|
||||
@ -42,6 +87,16 @@ export function RegisterSidebar(props: {register: Register, close: () => void, o
|
||||
<p class="underline text-lg">¿Es cert. sin firmas?</p>
|
||||
<p class="mb-8">{props.register.register_is_preview ? "Si" : "No"}</p>
|
||||
|
||||
{/* 12 is the ID for Matpel 3 in the DB */}
|
||||
<Show when={props.register.register_course_id === 12}>
|
||||
<button
|
||||
class="bg-c-primary text-c-on-primary px-4 py-2 rounded-full cursor-pointer
|
||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
onclick={generateCarnet}
|
||||
>
|
||||
Generar carnet
|
||||
</button>
|
||||
</Show>
|
||||
<button
|
||||
class="bg-c-error text-c-on-error px-4 py-2 rounded-full cursor-pointer
|
||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
|
@ -1,15 +1,12 @@
|
||||
import { For, Show, createEffect, createMemo, createSignal } from "solid-js";
|
||||
import { Person } from "../../types/Person";
|
||||
import { Register } from "../../types/Register";
|
||||
import { courseMap } from "../../utils/allCourses";
|
||||
import { certGenerator } from "../../certGenerator";
|
||||
import { CaretRight } from "../../icons/CaretRight";
|
||||
import { RegisterSidebar } from "./RegisterSidebar";
|
||||
import { customLabelsMap } from "../../utils/allCustomLabels";
|
||||
import { DownloadSimpleIcon } from "../../icons/DownloadSimpleIcon";
|
||||
import { backend, wait } from "../../utils/functions";
|
||||
import { JsonResult } from "../../types/JsonResult";
|
||||
import { LoadingIcon } from "../../icons/LoadingIcon";
|
||||
import { RegisterElement, generateCert } from "./RegisterElement";
|
||||
|
||||
export function Registers(props: {person: Person | null, count: number}) {
|
||||
const [registers, setRegisters] = createSignal<Array<Register>>([]);
|
||||
@ -151,7 +148,7 @@ export function Registers(props: {person: Person | null, count: number}) {
|
||||
<div class="flex flex-wrap justify-start gap-2 my-6">
|
||||
<For each={year}>
|
||||
{(register) => (
|
||||
<RegisterEl
|
||||
<RegisterElement
|
||||
register={register}
|
||||
person={props.person!}
|
||||
onClick={() => setSidebarRegister(register)}
|
||||
@ -177,147 +174,9 @@ export function Registers(props: {person: Person | null, count: number}) {
|
||||
register={sidebarRegister()!}
|
||||
close={() => setSidebarRegister(null)}
|
||||
onDelete={loadRegisters}
|
||||
person={props.person!}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RegisterEl(props: {register: Register, person: Person, onClick: () => void}) {
|
||||
|
||||
const dateComponents = () => {
|
||||
const [, year, month, day] = /(\d{4})-(\d{2})-(\d{2})/.exec(props.register.register_display_date) ?? [];
|
||||
return {year, month, day};
|
||||
};
|
||||
|
||||
const displayDate = () => {
|
||||
const {year, month, day} = dateComponents();
|
||||
return `${day}/${month}/${year}`;
|
||||
};
|
||||
|
||||
const courseName = () => {
|
||||
const course = courseMap()[props.register.register_course_id];
|
||||
return course?.course_name ?? "Curso no encontrado";
|
||||
};
|
||||
|
||||
const customLabel = () => {
|
||||
const labelId = props.register.register_custom_label;
|
||||
if (labelId === 1) return "";
|
||||
return customLabelsMap()[labelId]?.custom_label_value ?? "";
|
||||
};
|
||||
|
||||
const genCert = () => {
|
||||
const person = props.person;
|
||||
const register = props.register;
|
||||
|
||||
generateCert(person, register);
|
||||
};
|
||||
|
||||
const generateable = () => {
|
||||
const courseN = courseName();
|
||||
return certGenerator[courseN] !== undefined;
|
||||
};
|
||||
|
||||
const createdTodayClasses = () => {
|
||||
// current dat in YYYY-MM-DD format
|
||||
const today = new Date().toISOString()
|
||||
.split("T")[0];
|
||||
const createdToday = props.register.register_creation_date === today;
|
||||
|
||||
return createdToday ? "bg-c-surface-variant" : "";
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-[11rem_1.5rem_1.25rem] border border-c-outline rounded-md overflow-hidden">
|
||||
<div class="border-r border-c-outline-50 align-middle">
|
||||
<p
|
||||
class="font-bold overflow-hidden whitespace-nowrap pt-1 px-1"
|
||||
title={`${courseName()} ${customLabel()}`}
|
||||
>
|
||||
{courseName()}
|
||||
</p>
|
||||
<p class="font-mono text-sm px-1">
|
||||
<span class="underline">
|
||||
{customLabel()}
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p class={`text-sm px-1 pb-1 ${createdTodayClasses()}`}>
|
||||
<span class="font-mono">
|
||||
{displayDate()}
|
||||
</span>
|
||||
|
||||
<Show when={props.register.register_is_preview}>
|
||||
<span class="text-c-error font-bold select-none">
|
||||
sin firmas
|
||||
</span>
|
||||
</Show>
|
||||
<Show when={!props.register.register_is_preview}>
|
||||
<span class="font-mono">
|
||||
-
|
||||
</span>
|
||||
<span
|
||||
class="font-mono underline cursor-pointer hover:text-c-primary"
|
||||
onClick={() => {
|
||||
const code = props.register.register_code.toString();
|
||||
const paddedCode = code.padStart(4, "0");
|
||||
navigator.clipboard.writeText(paddedCode);
|
||||
}}
|
||||
>
|
||||
{props.register.register_code}
|
||||
</span>
|
||||
</Show>
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="hover:bg-c-primary-container rounded-md transition-colors
|
||||
disabled:opacity-0 disabled:cursor-default
|
||||
disabled:hover:bg-c-transparent"
|
||||
title="Descargar DOCX"
|
||||
onclick={genCert}
|
||||
disabled={!generateable()}
|
||||
>
|
||||
<DownloadSimpleIcon fill="var(--c-on-primary-container)" size={20} />
|
||||
</button>
|
||||
<button
|
||||
class="hover:bg-c-surface-variant rounded-md transition-colors"
|
||||
title="Más opciones"
|
||||
onclick={props.onClick}
|
||||
>
|
||||
<CaretRight fill="var(--c-primary)" size={20} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function generateCert(person: Person, register: Register) {
|
||||
const courseN = courseMap()[register.register_course_id]?.course_name ?? "Curso no encontrado";
|
||||
|
||||
const generator = certGenerator[courseN];
|
||||
if (generator === undefined) {
|
||||
alert(`El cert \`${courseN}\` no está implementado`);
|
||||
return;
|
||||
}
|
||||
|
||||
const [, year, month, day] = /(\d{4})-(\d{2})-(\d{2})/.exec(register.register_display_date) ?? [];
|
||||
const personFullName = `${person.person_names} ${person.person_paternal_surname} ${person.person_maternal_surname}`;
|
||||
|
||||
// Manage custom label
|
||||
const certCustomLabel = register.register_custom_label === 1
|
||||
? ""
|
||||
: customLabelsMap()[register.register_custom_label]?.custom_label_value ?? "";
|
||||
|
||||
const certCode = register.register_is_preview ? "0000" : register.register_code.toString().padStart(4, "0");
|
||||
|
||||
generator(`${courseN} - ${personFullName} [${register.register_id.toString(16).toUpperCase()}].docx`, {
|
||||
matpel: null,
|
||||
personFullName,
|
||||
personDni: person.person_dni.toString(),
|
||||
certCode,
|
||||
certYear: year,
|
||||
certMonth: month,
|
||||
certDay: day,
|
||||
certIId: register.register_code,
|
||||
certCustomLabel,
|
||||
});
|
||||
}
|
||||
|
78
frontend/src/utils/carnetGenerator.ts
Normal file
78
frontend/src/utils/carnetGenerator.ts
Normal file
File diff suppressed because one or more lines are too long
@ -28,3 +28,21 @@ export function useLoading() {
|
||||
|
||||
return {error, setError, status, setStatus};
|
||||
}
|
||||
|
||||
export function numberToMonth(n: number): string | null {
|
||||
switch (n) {
|
||||
case 1: return "ENERO";
|
||||
case 2: return "FEBRERO";
|
||||
case 3: return "MARZO";
|
||||
case 4: return "ABRIL";
|
||||
case 5: return "MAYO";
|
||||
case 6: return "JUNIO";
|
||||
case 7: return "JULIO";
|
||||
case 8: return "AGOSTO";
|
||||
case 9: return "SEPTIEMBRE";
|
||||
case 10: return "OCTUBRE";
|
||||
case 11: return "NOVIEMBRE";
|
||||
case 12: return "DICIEMBRE";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user