diff --git a/src/pages/employee/EmployeeList.jsx b/src/pages/employee/EmployeeList.jsx index 2018afb2..27dd2436 100644 --- a/src/pages/employee/EmployeeList.jsx +++ b/src/pages/employee/EmployeeList.jsx @@ -136,16 +136,53 @@ const EmployeeList = () => { const handleExport = (type) => { if (!currentItems || currentItems.length === 0) return; + // Map and format employee data for export + const exportData = currentItems.map((item) => ({ + "First Name": item.firstName || "", + "Middle Name": item.middleName || "", + "Last Name": item.lastName || "", + "Email": item.email || "", + "Gender": item.gender || "", + "Birth Date": item.birthdate + ? moment(item.birthdate).format("DD-MMM-YYYY") + : "", + "Joining Date": item.joiningDate + ? moment(item.joiningDate).format("DD-MMM-YYYY") + : "", + "Permanent Address": item.permanentAddress || "", + "Current Address": item.currentAddress || "", + "Phone Number": item.phoneNumber || "", + "Emergency Phone Number": item.emergencyPhoneNumber || "", + "Emergency Contact Person": item.emergencyContactPerson || "", + "Is Active": item.isActive ? "Active" : "Inactive", + "Job Role": item.jobRole || "", + })); + switch (type) { case "csv": - exportToCSV(currentItems, "employees"); + exportToCSV(exportData, "employees"); break; case "excel": - exportToExcel(currentItems, "employees"); + exportToExcel(exportData, "employees"); break; case "pdf": - exportToPDF(currentItems, "employees"); + exportToPDF( + currentItems.map((item) => ({ + Name: `${item.firstName || ""} ${item.lastName || ""}`.trim(), + Email: item.email || "", + "Phone Number": item.phoneNumber || "", + "Job Role": item.jobRole || "", + "Joining Date": item.joiningDate + ? moment(item.joiningDate).format("DD-MMM-YYYY") + : "", + "Gender": item.gender || "", + Status: item.isActive ? "Active" : "Inactive", + })), + "employees", + ["Name", "Email", "Phone Number", "Job Role", "Joining Date", "Gender", "Status"] + ); break; + case "print": printTable(tableRef.current); break; diff --git a/src/utils/tableExportUtils.jsx b/src/utils/tableExportUtils.jsx index 90a1306a..768ff5ac 100644 --- a/src/utils/tableExportUtils.jsx +++ b/src/utils/tableExportUtils.jsx @@ -40,112 +40,57 @@ export const exportToExcel = (data, fileName = "data") => { * @param {Array} data - Array of objects to export * @param {string} fileName - File name for the PDF (optional) */ -export const exportToPDF = async (data, fileName = "data") => { +const sanitizeText = (text) => { + if (!text) return ""; + // Replace all non-ASCII characters with "?" or remove them + return text.replace(/[^\x00-\x7F]/g, "?"); +}; + +export const exportToPDF = async (data, fileName = "data", columns = null, options = {}) => { if (!data || data.length === 0) return; - // Create a new PDF document const pdfDoc = await PDFDocument.create(); + const font = await pdfDoc.embedFont(StandardFonts.Helvetica); - // 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] || '')); + // Default options + const { + columnWidths = [], // array of widths per column + fontSizeHeader = 12, + fontSizeRow = 10, + rowHeight = 25, + } = options; - 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)); + const pageWidth = 1000; + const pageHeight = 600; + let page = pdfDoc.addPage([pageWidth, pageHeight]); + const margin = 30; + let y = pageHeight - margin; + + const headers = columns || Object.keys(data[0]); + + // Draw headers + headers.forEach((header, i) => { + const x = margin + (columnWidths[i] ? columnWidths.slice(0, i).reduce((a, b) => a + b, 0) : i * 150); + page.drawText(header, { x, y, font, size: fontSizeHeader }); + }); + y -= rowHeight; + + // Draw rows + data.forEach(row => { + headers.forEach((header, i) => { + const x = margin + (columnWidths[i] ? columnWidths.slice(0, i).reduce((a, b) => a + b, 0) : i * 150); + const text = row[header] || ''; + page.drawText(text, { x, y, font, size: fontSizeRow }); }); - return maxWidth + 10; // Padding for better spacing - }; + y -= rowHeight; - 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 + if (y < margin) { + page = pdfDoc.addPage([pageWidth, pageHeight]); + y = pageHeight - margin; } - - 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); @@ -153,15 +98,110 @@ export const exportToPDF = async (data, fileName = "data") => { link.click(); }; + + + + +/** + * Export JSON data to PDF in a card-style format + * @param {Array} data - Array of objects to export + * @param {string} fileName - File name for the PDF (optional) + */ +export const exportToPDF1 = async (data, fileName = "data") => { + if (!data || data.length === 0) return; + + const pdfDoc = await PDFDocument.create(); + const font = await pdfDoc.embedFont(StandardFonts.Helvetica); + const boldFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold); + + const pageWidth = 600; + const pageHeight = 800; + const margin = 30; + const cardSpacing = 20; + const cardPadding = 10; + let page = pdfDoc.addPage([pageWidth, pageHeight]); + let y = pageHeight - margin; + + for (const item of data) { + const title = item.ContactName || ""; + const subtitle = `by ${item.CreatedBy || ""} on ${item.CreatedAt || ""}`; + const body = item.Note || ""; + + const cardHeight = 80 + (body.length / 60) * 14; // approximate height for body text + + if (y - cardHeight < margin) { + page = pdfDoc.addPage([pageWidth, pageHeight]); + y = pageHeight - margin; + } + + // Draw card border + page.drawRectangle({ + x: margin, + y: y - cardHeight, + width: pageWidth - 2 * margin, + height: cardHeight, + borderColor: rgb(0.7, 0.7, 0.7), + borderWidth: 1, + color: rgb(1, 1, 1), + }); + + // Draw title + page.drawText(title, { + x: margin + cardPadding, + y: y - 20, + font: boldFont, + size: 12, + color: rgb(0.1, 0.1, 0.1), + }); + + // Draw subtitle + page.drawText(subtitle, { + x: margin + cardPadding, + y: y - 35, + font, + size: 10, + color: rgb(0.4, 0.4, 0.4), + }); + + // Draw body text (wrap manually) + const lines = body.match(/(.|[\r\n]){1,80}/g) || []; + lines.forEach((line, i) => { + page.drawText(line, { + x: margin + cardPadding, + y: y - 50 - i * 12, + font, + size: 10, + color: rgb(0.2, 0.2, 0.2), + }); + }); + + y -= cardHeight + cardSpacing; + } + + const pdfBytes = await pdfDoc.save(); + 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 + const clone = table.cloneNode(true); + // Remove last column (Actions) from all rows + clone.querySelectorAll("tr").forEach((row) => { + row.removeChild(row.lastElementChild); + }); - // Inject styles for the table and body + const newWindow = window.open("", "", "width=600,height=600"); newWindow.document.write("