- {currentCourses.map((courseCode, index) => {
- const courseData = data.filter(
- (row) => row.courseCode === courseCode
- );
- const courseName = courseData[0]?.courseName; // Get course name from first item
- return (
-
-
- setExpandedCourse(
- expandedCourse === courseCode ? null : courseCode
- )
- }
- >
-
{courseName}'s Table
-
- {/* Pagination controls */}
-
-
- Previous
-
-
- Page {currentPage} of {totalPages}
-
-
- Next
-
+ {/* Pagination controls */}
+
+
+ Previous
+
+
+ Page {currentPage} of {totalPages}
+
+
+ Next
+
+
-
>
);
};
diff --git a/client/src/api.js b/client/src/api.js
index fae21de..f9bec06 100644
--- a/client/src/api.js
+++ b/client/src/api.js
@@ -151,9 +151,9 @@ export const updateCourseStatus = async (courseId) => {
});
};
-export const sendEmail = async (formData) => {
+export const sendEmail = async (formData, type) => {
try {
- const url = `${BASE_URL}/send-email`;
+ const url = `${BASE_URL}/send-email/${type}`;
const response = await fetch(url, {
method: "POST",
body: formData, // Directly pass FormData
diff --git a/server/models/Faculty.js b/server/models/Faculty.js
index 9e77a43..35e89b2 100644
--- a/server/models/Faculty.js
+++ b/server/models/Faculty.js
@@ -6,6 +6,7 @@ const FacultySchema = new mongoose.Schema({
email: { type: String, required: true },
department: { type: String, required: true },
program: { type: String, required: true },
+ courses: [{ type: String }],
});
module.exports = mongoose.model("Faculty", FacultySchema);
diff --git a/server/routes/consolidatedRoutes.js b/server/routes/consolidatedRoutes.js
index 815f224..8a7b784 100644
--- a/server/routes/consolidatedRoutes.js
+++ b/server/routes/consolidatedRoutes.js
@@ -108,7 +108,7 @@ router.get("/course-consolidated", async (req, res) => {
// Add the faculty name to the appropriate task
if (appointment.task && groupedByCourse[courseId].tasks[appointment.task]) {
- groupedByCourse[courseId].tasks[appointment.task].add(appointment.facultyName);
+ groupedByCourse[courseId].tasks[appointment.task].add(JSON.stringify({ facultyId: appointment.facultyId, facultyName: appointment.facultyName }));
}
});
@@ -130,12 +130,12 @@ router.get("/course-consolidated", async (req, res) => {
semester: course.semester,
examType: course.examType,
year: course.year,
- oralPracticalTeachers: Array.from(course.tasks.oralsPracticals),
- assessmentTeachers: Array.from(course.tasks.assessment),
- reassessmentTeachers: Array.from(course.tasks.reassessment),
- paperSettingTeachers: Array.from(course.tasks.paperSetting),
- moderationTeachers: Array.from(course.tasks.moderation),
- pwdPaperSettingTeachers: Array.from(course.tasks.pwdPaperSetter),
+ oralPracticalTeachers: Array.from(course.tasks.oralsPracticals).map((data) => JSON.parse(data)),
+ assessmentTeachers: Array.from(course.tasks.assessment).map((data) => JSON.parse(data)),
+ reassessmentTeachers: Array.from(course.tasks.reassessment).map((data) => JSON.parse(data)),
+ paperSettingTeachers: Array.from(course.tasks.paperSetting).map((data) => JSON.parse(data)),
+ moderationTeachers: Array.from(course.tasks.moderation).map((data) => JSON.parse(data)),
+ pwdPaperSettingTeachers: Array.from(course.tasks.pwdPaperSetter).map((data) => JSON.parse(data)),
}));
res.status(200).json(consolidatedData);
@@ -215,5 +215,37 @@ router.get("/department-consolidated", async (req, res) => {
}
});
+router.get("/panel-consolidated", async (req, res) => {
+ try {
+ const courses = await Course.find();
+ const faculties = await Faculty.find();
+
+ // Create a structure where each course has its associated faculty
+ const consolidatedData = courses.map((course) => {
+ return {
+ courseId: course.courseId,
+ courseName: course.courseName,
+ semester: course.semester,
+ examType: course.scheme,
+ program: course.program,
+ faculty: faculties
+ .filter((faculty) => faculty.courses.includes(course.courseId))
+ .map((faculty) => ({
+ facultyId: faculty.facultyId,
+ name: faculty.name,
+ email: faculty.email,
+ qualification: faculty.qualification,
+ experience: faculty.experience,
+ })),
+ };
+ });
+
+ res.status(200).json(consolidatedData);
+ } catch (error) {
+ console.error("Error fetching panel consolidated data:", error);
+ res.status(500).json({ message: "Failed to fetch panel consolidated data" });
+ }
+});
+
module.exports = router;
diff --git a/server/routes/emailRoutes.js b/server/routes/emailRoutes.js
index e6eabc1..bb3ebfd 100644
--- a/server/routes/emailRoutes.js
+++ b/server/routes/emailRoutes.js
@@ -17,7 +17,7 @@ const storage = multer.diskStorage({
const upload = multer({ storage });
// Route to handle email sending with file attachment
-router.post("/", upload.single("file"), async (req, res) => {
+router.post("/excel", upload.single("file"), async (req, res) => {
const { teacher, fileName, recipientEmail } = req.body;
if (!teacher || !fileName || !recipientEmail || !req.file) {
@@ -31,9 +31,12 @@ router.post("/", upload.single("file"), async (req, res) => {
user: "swdc.ate@gmail.com", // Replace with your email
pass: "umlc hbkr dpga iywd", // Replace with your app-specific password or token
},
+ tls: {
+ rejectUnauthorized: false, // Ignore self-signed certificate errors
+ },
connectionTimeout: 15000,
- greetingTimeout: 15000,
- socketTimeout: 15000,
+ greetingTimeout: 15000,
+ socketTimeout: 15000,
});
// Email options
@@ -52,17 +55,18 @@ If you have any queries, please contact the H.O.D or the Examination In-charge.
Your cooperation regarding the upcoming examination duties is highly solicited.`,
attachments: [
- {
- filename: fileName,
- path: req.file.path, // Use the uploaded file's path
- },
+ {
+ filename: fileName,
+ path: req.file.path, // Use the uploaded file's path
+ },
],
-};
+ };
try {
// Send email
await transporter.sendMail(mailOptions);
+ transporter.close();
// Delete the temporary file after sending the email
fs.unlinkSync(req.file.path);
@@ -74,4 +78,64 @@ Your cooperation regarding the upcoming examination duties is highly solicited.`
}
});
+// Route to send emails with PDF attachments
+router.post("/pdf", upload.single("pdfFile"), async (req, res) => {
+ const { fileName, recipientEmail, role, courseName } = req.body;
+
+ if (!fileName || !recipientEmail || !role || !courseName || !req.file) {
+ return res.status(400).json({ error: "Missing required fields or file" });
+ }
+
+ // Configure Nodemailer transporter
+ const transporter = nodemailer.createTransport({
+ service: "gmail",
+ auth: {
+ user: "swdc.ate@gmail.com", // Replace with your email
+ pass: "umlc hbkr dpga iywd", // Replace with your app-specific password
+ },
+ tls: {
+ rejectUnauthorized: false,
+ },
+ connectionTimeout: 15000,
+ greetingTimeout: 15000,
+ socketTimeout: 15000,
+ });
+
+ // Email options
+ const mailOptions = {
+ from: "SWDC Admin
",
+ to: recipientEmail,
+ subject: `Appointment as ${role} - ${courseName}`,
+ text: `Dear teacher,
+
+You have been appointed as a ${role} for the course "${courseName}".
+Please find your appointment letter attached.
+
+If you have any queries, please contact the Examination In-charge.
+
+Best regards,
+Examination Department`,
+ attachments: [
+ {
+ filename: fileName,
+ path: req.file.path, // Path to the uploaded PDF
+ },
+ ],
+ };
+
+ try {
+ // Send email
+ await transporter.sendMail(mailOptions);
+ transporter.close();
+
+ // Delete the PDF file after sending
+ // fs.unlinkSync(req.file.path);
+
+ res.status(200).json({ message: "Email sent successfully" });
+ } catch (error) {
+ console.error("Error sending email:", error);
+ res.status(500).json({ error: "Failed to send email" });
+ }
+});
+
module.exports = router;