From bf1bdd935c875471b49e2702f034b8ac0affc8d0 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Sun, 18 Aug 2024 21:25:18 +0100 Subject: [PATCH] Improvements on excel rendering --- .../api/assignments/[id]/[export]/excel.ts | 176 +++++++++++++++--- 1 file changed, 150 insertions(+), 26 deletions(-) diff --git a/src/pages/api/assignments/[id]/[export]/excel.ts b/src/pages/api/assignments/[id]/[export]/excel.ts index 2d4cbf23..25a96d4a 100644 --- a/src/pages/api/assignments/[id]/[export]/excel.ts +++ b/src/pages/api/assignments/[id]/[export]/excel.ts @@ -46,6 +46,15 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === "POST") return await post(req, res); } +function logWorksheetData(worksheet: any) { + worksheet.eachRow((row: any, rowNumber: number) => { + console.log(`Row ${rowNumber}:`); + row.eachCell((cell: any, colNumber: number) => { + console.log(` Cell ${colNumber}: ${cell.value}`); + }); + }); +} + async function post(req: NextApiRequest, res: NextApiResponse) { // verify if it's a logged user that is trying to export if (req.session.user) { @@ -68,17 +77,17 @@ async function post(req: NextApiRequest, res: NextApiResponse) { return; } - if ( - data.excel && - data.excel.path && - data.excel.version === process.env.EXCEL_VERSION - ) { - // if it does, return the excel url - const fileRef = ref(storage, data.excel.path); - const url = await getDownloadURL(fileRef); - res.status(200).end(url); - return; - } + // if ( + // data.excel && + // data.excel.path && + // data.excel.version === process.env.EXCEL_VERSION + // ) { + // // if it does, return the excel url + // const fileRef = ref(storage, data.excel.path); + // const url = await getDownloadURL(fileRef); + // res.status(200).end(url); + // return; + // } const docsSnap = await getDocs( query(collection(db, "users"), where(documentId(), "in", data.assignees)) @@ -106,20 +115,29 @@ async function post(req: NextApiRequest, res: NextApiResponse) { const firstSectionData = [ { label: "Corporate Name :", - value: user.corporateInformation.companyInformation.name, + value: user.corporateInformation?.companyInformation?.name || "", }, { label: "Report Download date :", value: moment().format("DD/MM/YYYY"), }, { label: "Test Information :", value: "TODO" }, - { label: "Date of Test :", value: moment(data.startDate).format("DD/MM/YYYY") }, + { + label: "Date of Test :", + value: moment(data.startDate).format("DD/MM/YYYY"), + }, { label: "Number of Candidates :", value: data.assignees.length }, { label: "Highest score :", value: highestScore }, { label: "Lowest score :", value: lowestScore }, { label: "", value: "" }, - { label: "Date and time of First submission :", value: firstDate.format("DD/MM/YYYY") }, - { label: "Date and time of Last submission :", value: lastDate.format("DD/MM/YYYY") }, + { + label: "Date and time of First submission :", + value: firstDate.format("DD/MM/YYYY"), + }, + { + label: "Date and time of Last submission :", + value: lastDate.format("DD/MM/YYYY"), + }, ]; // Create a new workbook and add a worksheet @@ -132,19 +150,125 @@ async function post(req: NextApiRequest, res: NextApiResponse) { worksheet.getCell(`B${index + 1}`).value = value; // Second column (values) }); - // Set the response headers for downloading an Excel file - res.setHeader( - "Content-Type", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" - ); - res.setHeader( - "Content-Disposition", - "attachment; filename=ReportData.xlsx" + logWorksheetData(worksheet); + + const testSectionsArray = [1, 2, 3, 4, 5]; + + // Define the static part of the headers (before "Test Sections") + const staticHeaders = [ + "Sr N", + "Candidate ID", + "First and Last Name", + "Passport/ID", + "Email ID", + "Gender", + ]; + + // Define additional headers after "Test Sections" + const additionalHeaders = ["Time Spent", "Score", "Level"]; + + // Calculate the dynamic columns based on the testSectionsArray + const numberOfTestSections = testSectionsArray.length; + const testSectionHeaders = testSectionsArray.map( + (section, index) => `Part ${index + 1}` ); - // Write the workbook to the response - await workbook.xlsx.write(res); - res.end(); + // Add the main header row, merging static columns and "Test Sections" + worksheet.addRow([ + ...staticHeaders, + ...testSectionsArray.map((a) => "Test Sections"), + ...additionalHeaders, + ]); + + // 1 headers rows + const startIndexTable = firstSectionData.length + 1; + + logWorksheetData(worksheet); + + // // Merge "Test Sections" over dynamic number of columns + // const tableColumns = staticHeaders.length + numberOfTestSections; + // worksheet.mergeCells(1, staticHeaders.length + 1, 1, tableColumns); + + // logWorksheetData(worksheet); + // worksheet.mergeCells(`G1:G3`); // Time Spent + // worksheet.mergeCells(`H1:H3`); // Score + // worksheet.mergeCells(`I1:I3`); // Level + + // Add the dynamic second and third header rows for test sections and sub-columns + worksheet.addRow([ + ...Array(staticHeaders.length).fill(""), + ...testSectionHeaders, + "", + "", + "", + ]); + worksheet.addRow([ + ...Array(staticHeaders.length).fill(""), + ...testSectionsArray.map(() => "Grammar"), + "", + "", + "", + ]); + + // Merging static headers and "Test Sections" over dynamic columns + worksheet.mergeCells(`A${startIndexTable}:A${startIndexTable + 2}`); // "Sr N" + worksheet.mergeCells(`B${startIndexTable}:B${startIndexTable + 2}`); // "Candidate ID" + worksheet.mergeCells(`C${startIndexTable}:C${startIndexTable + 2}`); // "First and Last Name" + worksheet.mergeCells(`D${startIndexTable}:D${startIndexTable + 2}`); // "Passport/ID" + worksheet.mergeCells(`E${startIndexTable}:E${startIndexTable + 2}`); // "Email ID" + worksheet.mergeCells(`F${startIndexTable}:F${startIndexTable + 2}`); // "Gender" + + // worksheet.addRow(users.map((a) => { + // })) + + for ( + let i = 0; + i < staticHeaders.length + additionalHeaders.length + 1; + i++ + ) { + worksheet.getColumn(i + 1).width = 30; + } + + // Apply styles to the headers + [startIndexTable].forEach((rowNumber) => { + worksheet.getRow(rowNumber).eachCell((cell) => { + if (cell.value) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "FFBFBFBF" }, // Grey color for headers + }; + cell.font = { bold: true }; + cell.alignment = { vertical: "middle", horizontal: "center" }; + } + }); + }); + + worksheet.addRow(["Printed by: Confidential Information"]); + worksheet.addRow(["info@encoach.com"]); + + // Convert workbook to Buffer (Node.js) or Blob (Browser) + const buffer = await workbook.xlsx.writeBuffer(); + // generate the file ref for storage + const fileName = `${Date.now().toString()}.xlsx`; + const refName = `assignment_report/${fileName}`; + const fileRef = ref(storage, refName); + + // upload the pdf to storage + const snapshot = await uploadBytes(fileRef, buffer, { + contentType: + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + + // update the stats entries with the pdf url to prevent duplication + await updateDoc(docSnap.ref, { + excel: { + path: refName, + version: process.env.EXCEL_VERSION, + }, + }); + const url = await getDownloadURL(fileRef); + res.status(200).end(url); return; }