diff --git a/src/components/Activities/AttendcesLogs.jsx b/src/components/Activities/AttendcesLogs.jsx index d5134f7b..949ad7bd 100644 --- a/src/components/Activities/AttendcesLogs.jsx +++ b/src/components/Activities/AttendcesLogs.jsx @@ -305,8 +305,7 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => { ) : (
No Result Found
+No Result Found
- {selectedProject ? " No images match the selected filters.":"Please Select Project!"} -
- ); - } + if (!data?.data?.length && !isLoading) { + return ( +Service not assigned
diff --git a/src/pages/employee/EmployeeList.jsx b/src/pages/employee/EmployeeList.jsx index 644640ee..10db6786 100644 --- a/src/pages/employee/EmployeeList.jsx +++ b/src/pages/employee/EmployeeList.jsx @@ -38,6 +38,7 @@ import usePagination from "../../hooks/usePagination"; import { setProjectId } from "../../slices/localVariablesSlice"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import Pagination from "../../components/common/Pagination"; +import handleEmployeeExport from "../../components/Employee/handleEmployeeExport"; const EmployeeList = () => { const selectedProjectId = useSelector( @@ -134,26 +135,11 @@ const EmployeeList = () => { const tableRef = useRef(null); const handleExport = (type) => { - if (!currentItems || currentItems.length === 0) return; - - switch (type) { - case "csv": - exportToCSV(currentItems, "employees"); - break; - case "excel": - exportToExcel(currentItems, "employees"); - break; - case "pdf": - exportToPDF(currentItems, "employees"); - break; - case "print": - printTable(tableRef.current); - break; - default: - break; - } + handleEmployeeExport(type, employeeList, filteredData, searchText, tableRef); }; + + const handleAllEmployeesToggle = (e) => { const isChecked = e.target.checked; setShowInactive(false); 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("