import PDFDocument from "pdfkit"; import fs from "node:fs"; import path from "node:path"; const CCDS_LOGO_PATH = path.resolve(process.cwd(), "client/src/assets/ccds.png"); function drawLogo(doc: PDFKit.PDFDocument, x: number, y: number, width: number, height: number) { if (!fs.existsSync(CCDS_LOGO_PATH)) return; try { doc.image(CCDS_LOGO_PATH, x, y, { fit: [width, height], align: "center", valign: "center" }); } catch (error) { console.warn("[SalleAdministrativeDecisionPdf] Impossible de charger le logo CCDS:", error); } } export async function generateSalleAdministrativeDecisionPdf(input: { requestId: number; decisionText: string; signedAt?: string | Date | null; signedByLabel?: string | null; }) { const pdfBuffer = await new Promise((resolve, reject) => { try { const doc = new PDFDocument({ size: "A4", margins: { top: 42, bottom: 42, left: 42, right: 42 }, }); const chunks: Buffer[] = []; doc.on("data", (chunk: Buffer) => chunks.push(chunk)); doc.on("end", () => resolve(Buffer.concat(chunks))); doc.on("error", reject); const width = doc.page.width - doc.page.margins.left - doc.page.margins.right; let y = doc.page.margins.top; drawLogo(doc, doc.page.margins.left + (width - 90) / 2, y, 90, 90); y += 102; doc.font("Helvetica-Bold").fontSize(18).fillColor("#0f2d63").text( "DÉCISION ADMINISTRATIVE PRIORITAIRE", doc.page.margins.left, y, { width, align: "center" } ); y += 22; doc.font("Helvetica").fontSize(10).fillColor("#475569").text( `Dossier salle #${input.requestId}`, doc.page.margins.left, y, { width, align: "center" } ); y += 34; const bodyHeight = input.signedAt ? 360 : 420; doc.roundedRect(doc.page.margins.left, y, width, bodyHeight, 10).stroke("#cbd5e1"); doc.font("Helvetica").fontSize(11).fillColor("#1f2937").text( input.decisionText, doc.page.margins.left + 18, y + 18, { width: width - 36, lineGap: 4 } ); if (input.signedAt) { const signatureY = y + bodyHeight + 18; doc.roundedRect(doc.page.margins.left, signatureY, width, 62, 8).fillAndStroke("#eef6ff", "#93c5fd"); doc.font("Helvetica-Bold").fontSize(11).fillColor("#1d4ed8").text( "Visa de la Direction", doc.page.margins.left + 16, signatureY + 12, { width: width - 32 } ); doc.font("Helvetica").fontSize(10).fillColor("#1f2937").text( `Validation électronique le ${new Date(input.signedAt).toLocaleString("fr-FR")}${input.signedByLabel ? ` par ${input.signedByLabel}` : ""}.`, doc.page.margins.left + 16, signatureY + 32, { width: width - 32 } ); } doc.end(); } catch (error) { reject(error); } }); return { buffer: pdfBuffer, fileName: `decision-administrative-salle-${input.requestId}.pdf`, }; }