import * as XLSX from "xlsx"; import { PDFDocument, rgb, StandardFonts } from 'pdf-lib'; /** * Export JSON data to CSV * @param {Array} data - Array of objects to export * @param {string} fileName - File name without extension */ export const exportToCSV = (data, fileName = "data") => { const headers = Object.keys(data[0] || {}); const csvContent = [ headers.join(","), // header row ...data.map(row => headers.map(field => `"${row[field] ?? ""}"`).join(",")), ].join("\n"); const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.setAttribute("download", `${fileName}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); }; /** * Export JSON data to Excel * @param {Array} data - Array of objects to export * @param {string} fileName - File name without extension */ export const exportToExcel = (data, fileName = "data") => { const ws = XLSX.utils.json_to_sheet(data); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); XLSX.writeFile(wb, `${fileName}.xlsx`); }; /** * Export JSON data to PDF using pdf-lib * @param {Array} data - Array of objects to export * @param {string} fileName - File name for the PDF (optional) */ export const exportToPDF = async (data, fileName = "data") => { if (!data || data.length === 0) return; // Create a new PDF document const pdfDoc = await PDFDocument.create(); // Set up the font const font = await pdfDoc.embedFont(StandardFonts.Helvetica); // Use Helvetica font // Calculate column widths dynamically based on data content const headers = Object.keys(data[0]); const rows = data.map(item => headers.map(header => item[header] || '')); const getMaxColumnWidth = (columnIndex) => { let maxWidth = font.widthOfTextAtSize(headers[columnIndex], 12); rows.forEach(row => { const cellText = row[columnIndex].toString(); maxWidth = Math.max(maxWidth, font.widthOfTextAtSize(cellText, 10)); }); return maxWidth + 10; // Padding for better spacing }; const columnWidths = headers.map((_, index) => getMaxColumnWidth(index)); const tableX = 30; // X-coordinate for the table start const rowHeight = 20; // Height of each row (can be adjusted) const maxPageHeight = 750; // Max available height for content (before a new page is added) const pageMargin = 30; // Margin from the top of the page let tableY = maxPageHeight; // Start Y position for the table const maxPageWidth = 600; // Max available width for content (before a new page is added) // Add the headers and rows to the page const addHeadersToPage = (page, scaleFactor) => { let xPosition = tableX; headers.forEach((header, index) => { page.drawText(header, { x: xPosition, y: tableY, font, size: 12 * scaleFactor, // Scale the header font size color: rgb(0, 0, 0), }); xPosition += columnWidths[index] * scaleFactor; // Adjust X position based on scaling }); tableY -= rowHeight; // Move down after adding headers }; // Add a new page and reset the table position const addNewPage = (scaleFactor) => { const page = pdfDoc.addPage([600, 800]); tableY = maxPageHeight; // Reset Y position for the new page addHeadersToPage(page, scaleFactor); // Re-add headers to the new page return page; }; // Create the first page and add headers let page = pdfDoc.addPage([600, 800]); // Check if the content fits within the page width, scale if necessary const checkPageWidth = (row) => { let totalWidth = columnWidths.reduce((acc, width) => acc + width, 0); let scaleFactor = 1; if (totalWidth > maxPageWidth) { scaleFactor = maxPageWidth / totalWidth; // Scale down if necessary } return scaleFactor; }; // Function to check for page breaks when adding a new row const checkPageBreak = () => { if (tableY - rowHeight < pageMargin) { page = addNewPage(scaleFactor); // Add a new page if there is no space for the next row } }; // Add rows to the PDF with pagination and horizontal scaling rows.forEach(row => { checkPageBreak(); // Check for page break before adding each row const scaleFactor = checkPageWidth(row); // Get the scaling factor for the row // Add headers to the first page and each new page with the same scale factor if (tableY === maxPageHeight) { addHeadersToPage(page, scaleFactor); // Add headers only on the first page } let xPosition = tableX; row.forEach((value, index) => { page.drawText(value.toString(), { x: xPosition, y: tableY, font, size: 10 * scaleFactor, // Scale the font size color: rgb(0, 0, 0), }); xPosition += columnWidths[index] * scaleFactor; // Adjust X position based on scaling }); tableY -= rowHeight; // Move down to the next row position }); // Serialize the document to bytes const pdfBytes = await pdfDoc.save(); // Trigger a download of the PDF const blob = new Blob([pdfBytes], { type: 'application/pdf' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `${fileName}.pdf`; link.click(); }; /** * Print the HTML table by accepting the table element or a reference. * @param {HTMLElement} table - The table element (or ref) to print */ export const printTable = (table) => { if (table) { const newWindow = window.open("", "", "width=600,height=600"); // Open a new window // Inject styles for the table and body newWindow.document.write("