[FE][Certs] Move button to download carnet to the main UI
This commit is contained in:
parent
e00a0f7c81
commit
37045f9c79
@ -1,4 +1,4 @@
|
|||||||
import { Show } from "solid-js";
|
import { Show, createMemo } from "solid-js";
|
||||||
import { certGenerator } from "../../certGenerator";
|
import { certGenerator } from "../../certGenerator";
|
||||||
import { Person } from "../../types/Person";
|
import { Person } from "../../types/Person";
|
||||||
import { Register } from "../../types/Register";
|
import { Register } from "../../types/Register";
|
||||||
@ -6,6 +6,15 @@ import { courseMap } from "../../utils/allCourses";
|
|||||||
import { customLabelsMap } from "../../utils/allCustomLabels";
|
import { customLabelsMap } from "../../utils/allCustomLabels";
|
||||||
import { DownloadSimpleIcon } from "../../icons/DownloadSimpleIcon";
|
import { DownloadSimpleIcon } from "../../icons/DownloadSimpleIcon";
|
||||||
import { CaretRight } from "../../icons/CaretRight";
|
import { CaretRight } from "../../icons/CaretRight";
|
||||||
|
import { IdentificationCardIcon } from "../../icons/IdentificationCardIcon";
|
||||||
|
import { numberToMonth } from "../../utils/functions";
|
||||||
|
import { genCarnet } from "../../utils/carnetGenerator";
|
||||||
|
import { Canvg } from "canvg";
|
||||||
|
import QR from "qrcode";
|
||||||
|
import saveAs from "file-saver";
|
||||||
|
|
||||||
|
// TODO: use
|
||||||
|
// const carnetEnabledIds = [12];
|
||||||
|
|
||||||
export function RegisterElement(props: {register: Register, person: Person, onClick: () => void}) {
|
export function RegisterElement(props: {register: Register, person: Person, onClick: () => void}) {
|
||||||
|
|
||||||
@ -42,6 +51,65 @@ export function RegisterElement(props: {register: Register, person: Person, onCl
|
|||||||
return certGenerator[courseN] !== undefined;
|
return certGenerator[courseN] !== undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Check if the course is enabled for carnet generation
|
||||||
|
// with the list above
|
||||||
|
const canGenerateCarnet = () => props.register.register_course_id === 12;
|
||||||
|
|
||||||
|
const gridClass = () => (canGenerateCarnet() ? "grid-cols-[11rem_1.5rem_1.5rem_1.25rem]" : "grid-cols-[12.5rem_1.5rem_1.25rem]");
|
||||||
|
|
||||||
|
const paddedCertCode = createMemo(() => {
|
||||||
|
const code = props.register.register_code.toString();
|
||||||
|
return code.padStart(4, "0");
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateCarnet = () => {
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
||||||
|
|
||||||
|
const p = props.person;
|
||||||
|
const r = props.register;
|
||||||
|
|
||||||
|
const [expiryYear, month] = r.register_display_date.split("-");
|
||||||
|
|
||||||
|
const expiryMonth = numberToMonth(parseInt(month, 10));
|
||||||
|
|
||||||
|
if (expiryMonth === null) {
|
||||||
|
alert(`El cert. tiene un mes invalido (${month}), no se puede generar carnet`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QR code
|
||||||
|
QR.toDataURL(`https://eegsac.com/certificado/${p.person_dni}`, {margin: 1}, (err, base64) => {
|
||||||
|
if (err) {
|
||||||
|
alert("Error creando codigo QR para el carnet.");
|
||||||
|
console.error("Error creating QR code");
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullname = `${p.person_names} ${p.person_paternal_surname} ${p.person_maternal_surname}`;
|
||||||
|
const svgHtml = genCarnet({
|
||||||
|
fullname,
|
||||||
|
dni: p.person_dni.toString(),
|
||||||
|
code: r.register_code.toString().padStart(4, "0"),
|
||||||
|
expiryMonth,
|
||||||
|
expiryYear,
|
||||||
|
qrBase64: base64,
|
||||||
|
});
|
||||||
|
const v = Canvg.fromString(ctx, svgHtml);
|
||||||
|
v.start();
|
||||||
|
v.ready().then(() => {
|
||||||
|
canvas.toBlob((blob) => {
|
||||||
|
if (blob !== null) {
|
||||||
|
saveAs(blob, `CARNET MATPEL - ${fullname}.png`);
|
||||||
|
} else {
|
||||||
|
console.log("blob is null... :c");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const createdTodayClasses = () => {
|
const createdTodayClasses = () => {
|
||||||
// current dat in YYYY-MM-DD format
|
// current dat in YYYY-MM-DD format
|
||||||
const today = new Date().toISOString()
|
const today = new Date().toISOString()
|
||||||
@ -52,7 +120,7 @@ export function RegisterElement(props: {register: Register, person: Person, onCl
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="grid grid-cols-[11rem_1.5rem_1.25rem] border border-c-outline rounded-md overflow-hidden">
|
<div class={`grid ${gridClass()} border border-c-outline rounded-md overflow-hidden`}>
|
||||||
<div class="border-r border-c-outline-50 align-middle">
|
<div class="border-r border-c-outline-50 align-middle">
|
||||||
<p
|
<p
|
||||||
class="font-bold overflow-hidden whitespace-nowrap pt-1 px-1"
|
class="font-bold overflow-hidden whitespace-nowrap pt-1 px-1"
|
||||||
@ -83,16 +151,26 @@ export function RegisterElement(props: {register: Register, person: Person, onCl
|
|||||||
<span
|
<span
|
||||||
class="font-mono underline cursor-pointer hover:text-c-primary"
|
class="font-mono underline cursor-pointer hover:text-c-primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const code = props.register.register_code.toString();
|
navigator.clipboard.writeText(paddedCertCode());
|
||||||
const paddedCode = code.padStart(4, "0");
|
|
||||||
navigator.clipboard.writeText(paddedCode);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.register.register_code}
|
{paddedCertCode()}
|
||||||
</span>
|
</span>
|
||||||
</Show>
|
</Show>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<Show when={canGenerateCarnet()}>
|
||||||
|
<button
|
||||||
|
class="hover:bg-c-primary-container rounded-md transition-colors
|
||||||
|
disabled:opacity-0 disabled:cursor-default
|
||||||
|
disabled:hover:bg-c-transparent"
|
||||||
|
title="Descargar Carnet"
|
||||||
|
onclick={generateCarnet}
|
||||||
|
disabled={!canGenerateCarnet()}
|
||||||
|
>
|
||||||
|
<IdentificationCardIcon fill="var(--c-on-primary-container)" size={20} />
|
||||||
|
</button>
|
||||||
|
</Show>
|
||||||
<button
|
<button
|
||||||
class="hover:bg-c-primary-container rounded-md transition-colors
|
class="hover:bg-c-primary-container rounded-md transition-colors
|
||||||
disabled:opacity-0 disabled:cursor-default
|
disabled:opacity-0 disabled:cursor-default
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
import saveAs from "file-saver";
|
|
||||||
import { Register } from "../../types/Register";
|
import { Register } from "../../types/Register";
|
||||||
import { courseMap } from "../../utils/allCourses";
|
import { courseMap } from "../../utils/allCourses";
|
||||||
import { genCarnet } from "../../utils/carnetGenerator";
|
import { formatDate } from "../../utils/functions";
|
||||||
import { formatDate, numberToMonth } from "../../utils/functions";
|
|
||||||
import { Canvg } from "canvg";
|
|
||||||
import { Show } from "solid-js";
|
|
||||||
import { Person } from "../../types/Person";
|
|
||||||
import QR from "qrcode";
|
|
||||||
|
|
||||||
export function RegisterSidebar(props: {
|
export function RegisterSidebar(props: {
|
||||||
register: Register,
|
register: Register,
|
||||||
person: Person,
|
|
||||||
close: () => void,
|
close: () => void,
|
||||||
onDelete: () => void,
|
onDelete: () => void,
|
||||||
}) {
|
}) {
|
||||||
@ -28,54 +21,6 @@ export function RegisterSidebar(props: {
|
|||||||
|
|
||||||
const courseName = () => courseMap()[props.register.register_course_id]?.course_name ?? "<curso no encontrado>";
|
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 [expiryYear, month] = r.register_display_date.split("-");
|
|
||||||
|
|
||||||
const expiryMonth = numberToMonth(parseInt(month, 10));
|
|
||||||
|
|
||||||
if (expiryMonth === null) {
|
|
||||||
alert(`El cert. tiene un mes invalido (${month}), no se puede generar carnet`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// QR code
|
|
||||||
QR.toDataURL(`https://eegsac.com/certificado/${p.person_dni}`, {margin: 1}, (err, base64) => {
|
|
||||||
if (err) {
|
|
||||||
alert("Error creando codigo QR para el carnet.");
|
|
||||||
console.error("Error creating QR code");
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullname = `${p.person_names} ${p.person_paternal_surname} ${p.person_maternal_surname}`;
|
|
||||||
const svgHtml = genCarnet({
|
|
||||||
fullname,
|
|
||||||
dni: p.person_dni.toString(),
|
|
||||||
code: r.register_code.toString().padStart(4, "0"),
|
|
||||||
expiryMonth,
|
|
||||||
expiryYear,
|
|
||||||
qrBase64: base64,
|
|
||||||
});
|
|
||||||
const v = Canvg.fromString(ctx, svgHtml);
|
|
||||||
v.start();
|
|
||||||
v.ready().then(() => {
|
|
||||||
canvas.toBlob((blob) => {
|
|
||||||
if (blob !== null) {
|
|
||||||
saveAs(blob, `CARNET MATPEL - ${fullname}.png`);
|
|
||||||
} else {
|
|
||||||
console.log("blob is null... :c");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="absolute top-0 bg-c-surface-variant right-0
|
<div class="absolute top-0 bg-c-surface-variant right-0
|
||||||
py-4 px-6 w-[20rem]
|
py-4 px-6 w-[20rem]
|
||||||
@ -101,16 +46,6 @@ export function RegisterSidebar(props: {
|
|||||||
<p class="underline text-lg">¿Es cert. sin firmas?</p>
|
<p class="underline text-lg">¿Es cert. sin firmas?</p>
|
||||||
<p class="mb-8">{props.register.register_is_preview ? "Si" : "No"}</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
|
<button
|
||||||
class="bg-c-error text-c-on-error px-4 py-2 rounded-full cursor-pointer
|
class="bg-c-error text-c-on-error px-4 py-2 rounded-full cursor-pointer
|
||||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
@ -174,7 +174,6 @@ export function Registers(props: {person: Person | null, count: number}) {
|
|||||||
register={sidebarRegister()!}
|
register={sidebarRegister()!}
|
||||||
close={() => setSidebarRegister(null)}
|
close={() => setSidebarRegister(null)}
|
||||||
onDelete={loadRegisters}
|
onDelete={loadRegisters}
|
||||||
person={props.person!}
|
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
15
frontend/src/icons/IdentificationCardIcon.tsx
Normal file
15
frontend/src/icons/IdentificationCardIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
export function IdentificationCardIcon(props: {fill: string, size?: number}) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="inline-block w-6"
|
||||||
|
width={props.size ?? 32}
|
||||||
|
height={props.size ?? 32}
|
||||||
|
fill={props.fill}
|
||||||
|
viewBox="0 0 256 256"
|
||||||
|
>
|
||||||
|
<path d="M200,112a8,8,0,0,1-8,8H152a8,8,0,0,1,0-16h40A8,8,0,0,1,200,112Zm-8,24H152a8,8,0,0,0,0,16h40a8,8,0,0,0,0-16Zm40-80V200a16,16,0,0,1-16,16H40a16,16,0,0,1-16-16V56A16,16,0,0,1,40,40H216A16,16,0,0,1,232,56ZM216,200V56H40V200H216Zm-80.26-34a8,8,0,1,1-15.5,4c-2.63-10.26-13.06-18-24.25-18s-21.61,7.74-24.25,18a8,8,0,1,1-15.5-4,39.84,39.84,0,0,1,17.19-23.34,32,32,0,1,1,45.12,0A39.76,39.76,0,0,1,135.75,166ZM96,136a16,16,0,1,0-16-16A16,16,0,0,0,96,136Z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user