From 2aa92edf9e18dd46c69fb1b7c773440357fc4626 Mon Sep 17 00:00:00 2001 From: Harikrishnan Gopal <118685394+hk151109@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:28:52 +0530 Subject: [PATCH] added exam period in frontend and in database --- client/src/Pages/CourseForm.jsx | 155 ++++++++++++++++++----------- client/src/api.js | 1 + server/models/Appointment.js | 9 +- server/routes/appointmentRoutes.js | 15 ++- 4 files changed, 110 insertions(+), 70 deletions(-) diff --git a/client/src/Pages/CourseForm.jsx b/client/src/Pages/CourseForm.jsx index bba7082..1b3490f 100644 --- a/client/src/Pages/CourseForm.jsx +++ b/client/src/Pages/CourseForm.jsx @@ -9,11 +9,8 @@ const CourseForm = () => { const navigate = useNavigate(); const { course } = location.state || {}; - const [options, setOptions] = useState({ - faculties: [], // List of all faculties - }); - - const [suggestions, setSuggestions] = useState({}); // To hold suggestions for each field + const [options, setOptions] = useState({ faculties: [] }); + const [suggestions, setSuggestions] = useState({}); const [formData, setFormData] = useState({ oralsPracticals: "", assessment: "", @@ -32,46 +29,38 @@ const CourseForm = () => { pwdPaperSetter: [], }); + const [examPeriod, setExamPeriod] = useState({ + year: "", + startMonth: "", + endMonth: "", + }); + const [errors, setErrors] = useState({}); - // Fetch faculty list on mount useEffect(() => { const fetchOptionsAndFaculties = async () => { try { - const facultiesData = await fetchFaculties(); // Fetch faculty names from backend + const facultiesData = await fetchFaculties(); setOptions((prev) => ({ ...prev, faculties: facultiesData })); } catch (error) { console.error("Failed to fetch faculties:", error); } }; - fetchOptionsAndFaculties(); }, []); - // Handle input changes for form fields const handleInputChange = (e) => { const { name, value } = e.target; - setFormData({ ...formData, [name]: value }); - if (value.trim() === "") { - // Clear suggestions if input is empty - setSuggestions((prev) => ({ - ...prev, - [name]: [], - })); + setSuggestions((prev) => ({ ...prev, [name]: [] })); return; } - - // Filter suggestions for the current field if (options.faculties.length > 0) { const filteredSuggestions = options.faculties.filter((faculty) => faculty.name.toLowerCase().includes(value.toLowerCase()) ); - setSuggestions((prev) => ({ - ...prev, - [name]: filteredSuggestions, - })); + setSuggestions((prev) => ({ ...prev, [name]: filteredSuggestions })); } }; @@ -79,96 +68,75 @@ const CourseForm = () => { const selectedFaculty = options.faculties.find( (faculty) => faculty.name === formData[field] ); - if (selectedFaculty) { setTempAssignments((prev) => ({ ...prev, [field]: [...prev[field], selectedFaculty], })); - setFormData({ ...formData, [field]: "" }); // Clear input field - setSuggestions((prev) => ({ ...prev, [field]: [] })); // Clear suggestions + setFormData({ ...formData, [field]: "" }); + setSuggestions((prev) => ({ ...prev, [field]: [] })); } }; const handleRemoveFaculty = (field, index) => { setTempAssignments((prev) => { - const updatedAssignments = [...prev[field]]; // Create a shallow copy of the current list for this field - updatedAssignments.splice(index, 1); // Remove the faculty at the specified index - return { ...prev, [field]: updatedAssignments }; // Update the tempAssignments state + const updatedAssignments = [...prev[field]]; + updatedAssignments.splice(index, 1); + return { ...prev, [field]: updatedAssignments }; }); }; const validateForm = () => { const newErrors = {}; - - // Validate that each field in tempAssignments has at least one assigned faculty Object.keys(tempAssignments).forEach((field) => { if (!tempAssignments[field] || tempAssignments[field].length === 0) { newErrors[field] = "At least one faculty must be assigned."; } }); + if (!examPeriod.year || !examPeriod.startMonth || !examPeriod.endMonth) { + newErrors.examPeriod = "Exam period is required."; + } + setErrors(newErrors); - return Object.keys(newErrors).length === 0; // Form is valid if no errors + return Object.keys(newErrors).length === 0; }; - // Handle form submission const handleSubmit = async (e) => { - e.preventDefault(); // Prevent default form submission behavior + e.preventDefault(); - // Validate the form based on tempAssignments if (validateForm()) { try { const groupedTasks = {}; - - // Transform tempAssignments into grouped tasks by facultyId Object.entries(tempAssignments).forEach(([field, facultyList]) => { facultyList.forEach((faculty) => { - // Assuming faculty is an object, not just the faculty name const assignedFaculty = options.faculties.find( (optionFaculty) => optionFaculty.facultyId === faculty.facultyId ); - if (assignedFaculty) { - // Check if the facultyId already exists in groupedTasks if (!groupedTasks[assignedFaculty.facultyId]) { groupedTasks[assignedFaculty.facultyId] = { facultyId: assignedFaculty.facultyId, courseId: course?.courseId || id, tasks: [], + examPeriod: `${examPeriod.year} (${examPeriod.startMonth} - ${examPeriod.endMonth})`, }; } - // Push the task (field) into the tasks array for that faculty groupedTasks[assignedFaculty.facultyId].tasks.push(field); } }); }); - console.log(groupedTasks); - const payload = Object.values(groupedTasks); // Convert grouped tasks into an array - console.log("Saving appointment with payload:", payload); - - if (payload.length === 0) { - throw new Error("No assignments to submit."); - } - - // Call API to save appointments + const payload = Object.values(groupedTasks); await saveAppointment(payload); await updateCourseStatus(course?.courseId || id); - console.log("Form submitted successfully:", payload); - const filteredCourses = JSON.parse(localStorage.getItem("filteredCourses")) || []; - - // Redirect to courses page after successful submission navigate("/courses", { state: { courses: filteredCourses, - updatedCourse: { - ...course, - status: "Submitted", - }, + updatedCourse: { ...course, status: "Submitted" }, }, }); } catch (error) { @@ -227,7 +195,7 @@ const CourseForm = () => { key={faculty.facultyId} onClick={() => { setFormData({ ...formData, [name]: faculty.name }); - setSuggestions((prev) => ({ ...prev, [name]: [] })); // Clear suggestions for this field + setSuggestions((prev) => ({ ...prev, [name]: [] })); }} > {faculty.name} @@ -245,7 +213,7 @@ const CourseForm = () => { onClick={() => handleRemoveFaculty(name, index)} className="remove-faculty-btn" > - ✕ {/* This is the "X" symbol */} + ✕ ))} @@ -256,6 +224,75 @@ const CourseForm = () => { )} ))} +
+ + + + + {errors.examPeriod && ( + {errors.examPeriod} + )} +
diff --git a/client/src/api.js b/client/src/api.js index 826784c..5349583 100644 --- a/client/src/api.js +++ b/client/src/api.js @@ -78,6 +78,7 @@ export const fetchOptions = async () => { } }; + // Save multiple appointments to MongoDB export const saveAppointment = async (appointmentsData) => { console.log("Saving appointments with payload:", appointmentsData); diff --git a/server/models/Appointment.js b/server/models/Appointment.js index 4b19fe9..e3b9efc 100644 --- a/server/models/Appointment.js +++ b/server/models/Appointment.js @@ -2,19 +2,16 @@ const mongoose = require("mongoose"); const { v4: uuidv4 } = require("uuid"); const AppointmentSchema = new mongoose.Schema({ - appointmentId: { - type: String, - required: true, - unique: true, - default: uuidv4 - }, + appointmentId: { type: String, required: true, unique: true, default: uuidv4 }, facultyId: { type: String, required: true }, facultyName: { type: String, required: true }, courseId: { type: String, required: true }, courseName: { type: String, required: true }, task: { type: String, required: true }, + examPeriod: { type: String, required: true }, // New field for exam period }); module.exports = mongoose.model("Appointment", AppointmentSchema); + diff --git a/server/routes/appointmentRoutes.js b/server/routes/appointmentRoutes.js index 8b50f46..683a656 100644 --- a/server/routes/appointmentRoutes.js +++ b/server/routes/appointmentRoutes.js @@ -7,17 +7,22 @@ const Course = require("../models/Course"); // Save multiple appointments router.post("/", async (req, res) => { try { - const { appointments } = req.body; // Expecting an array of appointments + const { appointments } = req.body; if (!appointments || !Array.isArray(appointments)) { return res.status(400).json({ error: "Invalid or missing data" }); } const savedAppointments = []; for (const appointment of appointments) { - const { facultyId, courseId, tasks } = appointment; + const { facultyId, courseId, tasks, examPeriod } = appointment; - // Validate input data - if (!facultyId || !courseId || !Array.isArray(tasks) || tasks.length === 0) { + if ( + !facultyId || + !courseId || + !Array.isArray(tasks) || + tasks.length === 0 || + !examPeriod + ) { return res.status(400).json({ error: "Invalid appointment data" }); } @@ -30,7 +35,6 @@ router.post("/", async (req, res) => { }); } - // Save each task as a separate appointment for (const task of tasks) { const newAppointment = new Appointment({ facultyId, @@ -38,6 +42,7 @@ router.post("/", async (req, res) => { courseId, courseName: course.name, task, + examPeriod, }); const savedAppointment = await newAppointment.save(); savedAppointments.push(savedAppointment);