import * as fs from "node:fs"; import * as path from "node:path"; import * as readline from "node:readline/promises"; import { fileURLToPath } from "node:url"; import { createElement } from "react"; import { renderToFile } from "@react-pdf/renderer"; import { calculateTotals, initialState, PRICING } from "@mintel/pdf"; import { CombinedQuotePDF } from "../src/components/CombinedQuotePDF.js"; import { getTechDetails, getPrinciples, getMaintenanceDetails, getStandardsDetails, } from "../src/logic/content-provider.js"; const __filename = fileURLToPath(import.meta.url); async function main() { const args = process.argv.slice(2); const isInteractive = args.includes("--interactive") || args.includes("-I"); const isEstimationOnly = args.includes("--estimation") || args.includes("-E"); const inputPath = args.find( (_, i) => args[i - 1] === "--input" || args[i - 1] === "-i", ); let state = { ...initialState }; if (inputPath) { const rawData = fs.readFileSync( path.resolve(process.cwd(), inputPath), "utf8", ); const diskState = JSON.parse(rawData); state = { ...state, ...diskState }; } if (isInteractive) { state = await runWizard(state); } // Final confirmation of data needed for PDF if (!state.name || !state.email) { console.warn( "⚠️ Missing recipient name or email. Document might look incomplete.", ); } const totals = calculateTotals(state, PRICING); const { totalPrice, monthlyPrice, totalPagesCount } = totals; const finalOutputPath = generateDefaultPath(state); const outputDir = path.dirname(finalOutputPath); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // Resolve assets for the PDF const assetsDir = path.resolve(process.cwd(), "src/assets"); const headerIcon = path.join(assetsDir, "logo/Icon White Transparent.png"); const footerLogo = path.join(assetsDir, "logo/Logo Black Transparent.png"); console.log(`🚀 Generating PDF: ${finalOutputPath}`); const estimationProps = { state, totalPrice, monthlyPrice, totalPagesCount, pricing: PRICING, headerIcon, footerLogo, }; await renderToFile( createElement(CombinedQuotePDF as any, { estimationProps, techDetails: getTechDetails(), principles: getPrinciples(), maintenanceDetails: getMaintenanceDetails(), standardsDetails: getStandardsDetails(), mode: isEstimationOnly ? "estimation" : "full", showAgbs: !isEstimationOnly, // AGBS only for full quotes }) as any, finalOutputPath, ); console.log("✅ Done!"); } async function runWizard(state: any) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); console.log("\n--- Mintel Quote Generator Wizard ---\n"); const ask = async (q: string, def?: string) => { const answer = await rl.question(`${q}${def ? ` [${def}]` : ""}: `); return answer || def || ""; }; const selectOne = async ( q: string, options: { id: string; label: string }[], ) => { console.log(`\n${q}:`); options.forEach((opt, i) => console.log(`${i + 1}) ${opt.label}`)); const answer = await rl.question("Selection (number): "); const idx = parseInt(answer) - 1; return options[idx]?.id || options[0].id; }; state.name = await ask("Recipient Name", state.name); state.email = await ask("Recipient Email", state.email); state.companyName = await ask("Company Name", state.companyName); state.projectType = await selectOne("Project Type", [ { id: "website", label: "Website" }, { id: "web-app", label: "Web App" }, ]); if (state.projectType === "website") { state.websiteTopic = await ask("Website Topic", state.websiteTopic); // Simplified for now, in a real tool we'd loop through all options } rl.close(); return state; } function generateDefaultPath(state: any) { const now = new Date(); const month = now.toISOString().slice(0, 7); const day = now.toISOString().slice(0, 10); // Add seconds and minutes for 100% unique names without collision const time = now .toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit", second: "2-digit", }) .replace(/:/g, "-"); const company = (state.companyName || state.name || "Unknown").replace( /[^a-z0-9]/gi, "_", ); return path.join( process.cwd(), "out", "estimations", month, `${day}_${time}_${company}_${state.projectType}.pdf`, ); } main().catch((err) => { console.error("❌ Error:", err); process.exit(1); });