@@ -241,17 +262,31 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
{showActive ? "Active Contacts" : "Inactive Contacts"}
)}
+
+
+
+
+
+
+
+
+
+
+ {/* Divider */}
+ {activeTab === "contacts" &&
}
-
-
-
-
}>
{activeTab === "notes" && (
diff --git a/src/pages/Directory/NotesPage.jsx b/src/pages/Directory/NotesPage.jsx
index 58790562..3f0d4348 100644
--- a/src/pages/Directory/NotesPage.jsx
+++ b/src/pages/Directory/NotesPage.jsx
@@ -42,7 +42,7 @@ const NotesPage = ({ projectId, searchText, onExport }) => {
};
}, []);
- // 🔹 Format data for export
+ // Format data for export
const formatExportData = (notes) => {
return notes.map((n) => ({
ContactName: n.contactName || "",
@@ -59,7 +59,7 @@ const NotesPage = ({ projectId, searchText, onExport }) => {
}));
};
- // 🔹 Pass formatted notes to parent for export
+ // Pass formatted notes to parent for export
useEffect(() => {
if (data?.data && onExport) {
onExport(formatExportData(data.data));
diff --git a/src/utils/tableExportUtils.jsx b/src/utils/tableExportUtils.jsx
index 57af704f..768ff5ac 100644
--- a/src/utils/tableExportUtils.jsx
+++ b/src/utils/tableExportUtils.jsx
@@ -40,39 +40,52 @@ 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", columns = null) => {
+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;
const pdfDoc = await PDFDocument.create();
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
- // Landscape dimensions
- const pageWidth = 1000; // wider for more space
+ // Default options
+ const {
+ columnWidths = [], // array of widths per column
+ fontSizeHeader = 12,
+ fontSizeRow = 10,
+ rowHeight = 25,
+ } = options;
+
+ 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]);
- const rowHeight = 25; // slightly taller rows for readability
- const columnSpacing = 150; // increase space between columns
// Draw headers
headers.forEach((header, i) => {
- page.drawText(header, { x: margin + i * columnSpacing, y, font, size: 12 });
+ 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 text = row[header] ? row[header].toString() : '';
- page.drawText(text, { x: margin + i * columnSpacing, y, font, size: 10 });
+ 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 });
});
y -= rowHeight;
if (y < margin) {
- page = pdfDoc.addPage([pageWidth, pageHeight]); // landscape for new page
+ page = pdfDoc.addPage([pageWidth, pageHeight]);
y = pageHeight - margin;
}
});
@@ -87,6 +100,95 @@ export const exportToPDF = async (data, fileName = "data", columns = null) => {
+
+
+/**
+ * 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