Files
appointment_to_examiner/client/src/api.js
2025-03-07 02:09:15 +05:30

328 lines
8.6 KiB
JavaScript

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;
}