const BASE_URL = "http://localhost:8080/api"; const XLSX = require("xlsx-js-style"); // Helper function for handling fetch requests const fetchData = async (url, options) => { try { const response = await fetch(url, options); // Check if response is OK (status 200-299) if (!response.ok) { let errorDetails = {}; try { errorDetails = await response.json(); // Attempt to parse error response } catch (err) { console.warn("Failed to parse error details:", err); } throw new Error( `Error: ${response.statusText} (${response.status}) - ${ errorDetails.message || "No details available" }` ); } // Return JSON response if successful return await response.json(); } catch (error) { console.error(`Request failed for ${url}:`, error.message); throw error; // Re-throw for the caller to handle } }; // Fetch courses with optional filters export const fetchCourses = async (filterData = {}) => { try { const queryString = new URLSearchParams(filterData).toString(); const url = `${BASE_URL}/courses?${queryString}`; return fetchData(url, { method: "GET", headers: { "Content-Type": "application/json", }, }); } catch (error) { console.error("Error fetching courses:", error.message); throw error; } }; // Fetch list of faculties export const fetchFaculties = async () => { try { const url = `${BASE_URL}/faculty`; return fetchData(url, { method: "GET", headers: { "Content-Type": "application/json", }, }); } catch (error) { console.error("Error fetching faculties:", error.message); throw error; } }; // Fetch available options for form dropdowns export const fetchOptions = async () => { try { const url = `${BASE_URL}/options`; return fetchData(url, { method: "GET", headers: { "Content-Type": "application/json", }, }); } catch (error) { console.error("Error fetching options:", error.message); throw error; } }; export const fetchAppointments = async (academicYear) => { try { const response = await fetch(`${BASE_URL}/appointments?academicYear=${academicYear}`); if (!response.ok) { throw new Error("Failed to fetch appointments"); } return await response.json(); } catch (error) { console.error(error); return []; } }; // Save multiple appointments to MongoDB export const saveAppointment = async (appointmentsData) => { console.log("Saving appointments with payload:", appointmentsData); // Validate input format if (!Array.isArray(appointmentsData) || appointmentsData.length === 0) { const errorMessage = "Invalid or missing appointment data: expected a non-empty array"; console.error(errorMessage); throw new Error(errorMessage); } // Validate each appointment's structure const invalidEntries = appointmentsData.filter( (appointment) => !appointment.facultyId || !appointment.courseId || !Array.isArray(appointment.tasks) ); if (invalidEntries.length > 0) { const errorMessage = `Invalid appointments detected: ${JSON.stringify( invalidEntries )}`; console.error(errorMessage); throw new Error(errorMessage); } try { const url = `${BASE_URL}/appointments`; const response = await fetchData(url, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ appointments: appointmentsData }), // Send appointments as an array }); console.log("Appointments saved successfully:", response); return response; } catch (error) { console.error("Error saving appointments:", error.message); throw error; } }; // Update course status export const updateCourseStatus = async (courseId) => { if (!courseId) { throw new Error("Course ID is required to update the status"); } const url = `${BASE_URL}/courses/${courseId}`; return fetchData(url, { method: "PATCH", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ status: "submitted" }), // Update status to "Submitted" }); }; export const sendEmail = async (formData, type) => { try { const url = `${BASE_URL}/send-email/${type}`; const response = await fetch(url, { method: "POST", body: formData, // Directly pass FormData }); if (!response.ok) { let errorDetails = {}; try { errorDetails = await response.json(); } catch (err) { console.warn("Failed to parse error details:", err); } throw new Error( `Error: ${response.statusText} (${response.status}) - ${ errorDetails.message || "No details available" }` ); } return await response.json(); } catch (error) { console.error( error.message); throw error; } }; export const createExcelBook = (teacherData, teacher) => { const workbook = XLSX.utils.book_new(); // Extract academicYear and examPeriod from the first entry in the teacherData array const { academicYear, examPeriod } = teacherData[0] || {}; // Define header information const headerInfo = [ ["Somaiya Vidyavihar University"], ["K. J. SOMAIYA COLLEGE OF ENGINEERING"], [`Examination: ${examPeriod} ${academicYear}`], [ "Appointment of Internal Examiners for Paper Setting / OR/PR/Assessment/Reassessment", ], ["Class: B Tech/M Tech/Honour/Minor"], ["Department - Computer Engineering"], [], ]; const tableHeaders = [ [ "Sr No", "Semester", "Program", "Course Code", "Course Name", "Exam Type", "Year", "Marks", "Name", "Affiliation/College", "Highest Qualification", "Career Experience", "Oral/Practical", "Assessment", "Reassessment", "Paper Setting", "Moderation", "PwD Paper Setting", ], ]; const dataRows = teacherData.map((row, index) => [ index + 1, row.semester, row.program, row.courseCode, row.courseName, row.examType, Math.ceil(row.semester/2), row.marks, row.Name, row.affiliation, row.qualification, row.experience, row.oralPractical, row.assessment, row.reassessment, row.paperSetting, row.moderation, row.pwdPaperSetting, ]); const sheetData = [...headerInfo, ...tableHeaders, ...dataRows]; const worksheet = XLSX.utils.aoa_to_sheet(sheetData); // Add merged cells worksheet["!merges"] = [ { s: { r: 0, c: 0 }, e: { r: 0, c: 18 } }, { s: { r: 1, c: 0 }, e: { r: 1, c: 18 } }, { s: { r: 2, c: 0 }, e: { r: 2, c: 18 } }, { s: { r: 3, c: 0 }, e: { r: 3, c: 18 } }, { s: { r: 4, c: 0 }, e: { r: 4, c: 18 } }, ]; // Define styles const boldStyle = { font: { bold: true, name: "Times New Roman", sz: 14 }, alignment: { horizontal: "center", vertical: "center" }, }; const redStyle = { font: { bold: true, color: { rgb: "FF0000" }, name: "Times New Roman", sz: 14, }, alignment: { horizontal: "center", vertical: "center" }, }; const normalStyle = { font: { name: "Times New Roman", sz: 12 }, }; // Apply styles to headers const headerRanges = [ { row: 0, style: boldStyle }, { row: 1, style: boldStyle }, { row: 2, style: boldStyle }, { row: 3, style: boldStyle }, { row: 4, style: redStyle }, ]; headerRanges.forEach(({ row, style }) => { for (let col = 0; col <= 18; col++) { const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); if (!worksheet[cellAddress]) continue; // Skip empty cells worksheet[cellAddress].s = style; } }); // Set column widths for better readability worksheet["!cols"] = [ { wch: 10 }, // Sr No { wch: 12 }, // Semester { wch: 15 }, // Course Code { wch: 25 }, // Course Name { wch: 15 }, // Exam Type { wch: 10 }, // Year { wch: 10 }, // Marks { wch: 15 }, // Surname { wch: 15 }, // First Name { wch: 15 }, // Middle Name { wch: 20 }, // Affiliation { wch: 20 }, // Qualification { wch: 15 }, // Career Experience { wch: 15 }, // Oral/Practical { wch: 15 }, // Assessment { wch: 15 }, // Reassessment { wch: 15 }, // Paper Setting { wch: 15 }, // Moderation { wch: 15 }, // PwD Paper Setting ]; // Apply normal font style to all cells Object.keys(worksheet).forEach((key) => { if (worksheet[key] && key[0] !== "!") { worksheet[key].s = worksheet[key].s || normalStyle; } }); // Add worksheet to workbook and save file XLSX.utils.book_append_sheet(workbook, worksheet, teacher); return workbook; }