genración del pdf de plan de estudios ya funciona
This commit is contained in:
25
package-lock.json
generated
25
package-lock.json
generated
@@ -30,6 +30,7 @@
|
||||
"@tanstack/router-plugin": "^1.121.2",
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"canvas-confetti": "^1.9.3",
|
||||
"carbone-sdk-js": "^1.2.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -2819,6 +2820,12 @@
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/carbone-sdk-js": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/carbone-sdk-js/-/carbone-sdk-js-1.2.2.tgz",
|
||||
"integrity": "sha512-3bc4F04DizC8ULB6j6JsOq8G0sW/pwdwvfbbZ8exBZbcOCV4WE8KHsY6GiED/3tmH++Z1I5XMppjkBhjg60zjA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/ccount": {
|
||||
"version": "2.0.1",
|
||||
"license": "MIT",
|
||||
@@ -3372,6 +3379,20 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"license": "MIT",
|
||||
@@ -5514,7 +5535,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.3.5",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
|
||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@tanstack/router-plugin": "^1.121.2",
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"canvas-confetti": "^1.9.3",
|
||||
"carbone-sdk-js": "^1.2.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
|
||||
@@ -1,49 +1,132 @@
|
||||
import { Button } from "../ui/button"
|
||||
import { Download } from "lucide-react"
|
||||
import { supabase } from "@/auth/supabase";
|
||||
import { Button } from "../ui/button";
|
||||
import { Download } from "lucide-react";
|
||||
|
||||
export type PlanLike = Record<string, string | number | object | null | undefined>
|
||||
export type PlanLike = Record<
|
||||
string,
|
||||
string | number | object | null | undefined
|
||||
>;
|
||||
|
||||
export function DownloadPlanPDF({ plan }: { plan: PlanLike }) {
|
||||
export function DownloadPlanPDF({ plan }: { plan: Record<string, any> }) {
|
||||
async function fetchPDF() {
|
||||
try {
|
||||
const response = await fetch(
|
||||
"https://reportes-template.nicesand-99c6cbb8.westus2.azurecontainerapps.io/api/report",
|
||||
{
|
||||
const planObj = {
|
||||
...plan,
|
||||
nivel_y_nombre_del_plan_de_estudios: `${plan["nivel"]} en ${plan["nombre"]}`,
|
||||
nivel: undefined,
|
||||
nombre: undefined,
|
||||
};
|
||||
const fileName = `Plan_${planObj.nivel_y_nombre_del_plan_de_estudios || "Desconocido"}.pdf`;
|
||||
// const jsonData = JSON.stringify(planObj);
|
||||
|
||||
const triggerDownload = (blob: Blob, name: string) => {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.setAttribute("download", name);
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
const fetchBinaryFallback = async () => {
|
||||
// Intenta construir la URL del runtime de Functions
|
||||
const anyClient = supabase as any;
|
||||
const baseUrl =
|
||||
anyClient?.functions?.url ||
|
||||
`${(anyClient?.supabaseUrl || "").replace(/\/$/, "")}/functions/v1`;
|
||||
const { data: sess } = await supabase.auth.getSession();
|
||||
const token = sess?.session?.access_token;
|
||||
|
||||
console.log(JSON.stringify(planObj, null, 2));
|
||||
console.log(planObj);
|
||||
|
||||
|
||||
|
||||
const resp = await fetch(`${baseUrl}/carbone-io-api`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/pdf",
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
template: { name: "plan-estudios" },
|
||||
data: {
|
||||
nombre_autorizado_de_la_institucion: "Probando pdf",
|
||||
// (plan["nombre"] ? String(plan["nombre"]) : "Plan de estudios"),
|
||||
},
|
||||
action: "downloadReport",
|
||||
templateId: "1302213091201757023",
|
||||
fileName,
|
||||
convertTo: "pdf",
|
||||
data: planObj,
|
||||
}),
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => "")
|
||||
console.error("Error HTTP al obtener PDF:", response.status, text)
|
||||
throw new Error(`HTTP ${response.status}`)
|
||||
}
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||
const blob = await resp.blob();
|
||||
triggerDownload(blob, fileName);
|
||||
};
|
||||
|
||||
const ct = response.headers.get("Content-Type") || ""
|
||||
if (!ct.includes("application/pdf")) {
|
||||
const text = await response.text().catch(() => "")
|
||||
console.error("Respuesta no-PDF recibida:", text)
|
||||
}
|
||||
try {
|
||||
// const { data, error } = await supabase.functions.invoke(
|
||||
// "carbone-io-api",
|
||||
// {
|
||||
// method: "POST",
|
||||
// headers: { Accept: "application/octet-stream" }, // preferir binario
|
||||
// body: {
|
||||
// action: "downloadReport",
|
||||
// templateId: "1302213091201757023",
|
||||
// fileName,
|
||||
// convertTo: "pdf",
|
||||
// data: planObj,
|
||||
// },
|
||||
// }
|
||||
// );
|
||||
|
||||
const blob = await response.blob()
|
||||
const pdfUrl = URL.createObjectURL(blob)
|
||||
window.open(pdfUrl, "_blank")
|
||||
// if (error) throw error;
|
||||
|
||||
// Limpia el objeto URL después de un tiempo
|
||||
setTimeout(() => URL.revokeObjectURL(pdfUrl), 60_000)
|
||||
// // Si ya viene binario, descargar directo
|
||||
// if (typeof Blob !== "undefined" && data instanceof Blob) {
|
||||
// triggerDownload(data, fileName);
|
||||
// return;
|
||||
// }
|
||||
// if (data instanceof ArrayBuffer) {
|
||||
// triggerDownload(
|
||||
// new Blob([data], { type: "application/pdf" }),
|
||||
// fileName
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Si vino como string (ej. empieza con %PDF), usa el fallback binario
|
||||
// if (typeof data === "string") {
|
||||
// await fetchBinaryFallback();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Si vino JSON con base64, decodificar y descargar
|
||||
// if (data && typeof data === "object") {
|
||||
// const b64 =
|
||||
// (data as any).file || (data as any).buffer || (data as any).base64;
|
||||
// if (typeof b64 === "string") {
|
||||
// const clean = b64.replace(/^data:.*;base64,/, "");
|
||||
// const binary = atob(clean);
|
||||
// const bytes = new Uint8Array(binary.length);
|
||||
// for (let i = 0; i < binary.length; i++)
|
||||
// bytes[i] = binary.charCodeAt(i);
|
||||
// triggerDownload(
|
||||
// new Blob([bytes], { type: "application/pdf" }),
|
||||
// fileName
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// console.warn("Respuesta no reconocida para descarga de PDF.", {
|
||||
// type: typeof data,
|
||||
// });
|
||||
|
||||
await fetchBinaryFallback();
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error("Error al obtener PDF:", error)
|
||||
console.error("Error al obtener PDF:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +139,7 @@ export function DownloadPlanPDF({ plan }: { plan: PlanLike }) {
|
||||
Descargar PDF
|
||||
<Download className="w-4 h-4" />
|
||||
</Button>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default DownloadPlanPDF
|
||||
export default DownloadPlanPDF;
|
||||
|
||||
Reference in New Issue
Block a user