academicYear logic
This commit is contained in:
@@ -14,7 +14,7 @@ import "react-toastify/dist/ReactToastify.css";
|
||||
import CourseTable from "./Pages/CourseTable";
|
||||
import GenerateCSV from "./Pages/GenerateCSV";
|
||||
import ConsolidatedTable from "./Pages/ConsolidatedTable";
|
||||
import CourseConsolidated from "./Pages/courseConsolidated";
|
||||
import CourseConsolidated from "./Pages/CourseConsolidated";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useLocation, useParams, useNavigate } from "react-router-dom";
|
||||
import { fetchFaculties, saveAppointment, updateCourseStatus } from "../api";
|
||||
import { fetchFaculties, saveAppointment } from "../api";
|
||||
import "./CourseForm.css";
|
||||
import "./Navbar.jsx";
|
||||
import Navbar from "./Navbar.jsx";
|
||||
@@ -9,7 +9,7 @@ const CourseForm = () => {
|
||||
const { id } = useParams();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { course } = location.state || {};
|
||||
const { course, academicYear } = location.state || {};
|
||||
|
||||
const [options, setOptions] = useState({ faculties: [] });
|
||||
const [suggestions, setSuggestions] = useState({});
|
||||
@@ -32,7 +32,7 @@ const CourseForm = () => {
|
||||
});
|
||||
|
||||
const [examPeriod, setExamPeriod] = useState({
|
||||
year: "",
|
||||
year: academicYear || "",
|
||||
startMonth: "",
|
||||
endMonth: "",
|
||||
});
|
||||
@@ -110,6 +110,7 @@ const CourseForm = () => {
|
||||
if (validateForm()) {
|
||||
try {
|
||||
const groupedTasks = {};
|
||||
const academicYear = course?.academicYear || examPeriod.year;
|
||||
Object.entries(tempAssignments).forEach(([field, facultyList]) => {
|
||||
facultyList.forEach((faculty) => {
|
||||
const assignedFaculty = options.faculties.find(
|
||||
@@ -121,7 +122,8 @@ const CourseForm = () => {
|
||||
facultyId: assignedFaculty.facultyId,
|
||||
courseId: course?.courseId || id,
|
||||
tasks: [],
|
||||
examPeriod: `${examPeriod.year} (${examPeriod.startMonth} - ${examPeriod.endMonth})`,
|
||||
examPeriod: `${examPeriod.startMonth} - ${examPeriod.endMonth}`,
|
||||
academicYear,
|
||||
};
|
||||
}
|
||||
groupedTasks[assignedFaculty.facultyId].tasks.push(field);
|
||||
@@ -131,14 +133,14 @@ const CourseForm = () => {
|
||||
|
||||
const payload = Object.values(groupedTasks);
|
||||
await saveAppointment(payload);
|
||||
await updateCourseStatus(course?.courseId || id);
|
||||
// await updateCourseStatus(course?.courseId || id);
|
||||
|
||||
const filteredCourses =
|
||||
JSON.parse(localStorage.getItem("filteredCourses")) || [];
|
||||
navigate("/courses", {
|
||||
state: {
|
||||
courses: filteredCourses,
|
||||
updatedCourse: { ...course, status: "Submitted" },
|
||||
academicYear: academicYear,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -169,16 +171,12 @@ const CourseForm = () => {
|
||||
</div>
|
||||
<div className={errors.examPeriod ? "courseFormErrorSelect" : ""}>
|
||||
<label className="courseFormLabel">Exam Period:</label>
|
||||
<select
|
||||
className="courseFormSelect"
|
||||
<input
|
||||
type="text"
|
||||
className="courseFormInput courseFormReadOnly"
|
||||
value={examPeriod.year}
|
||||
onChange={(e) => setExamPeriod({ ...examPeriod, year: e.target.value })}
|
||||
>
|
||||
<option value="">Year</option>
|
||||
{[2025, 2026, 2027].map(year => (
|
||||
<option key={year} value={year}>{year}</option>
|
||||
))}
|
||||
</select>
|
||||
readOnly
|
||||
/>
|
||||
<select
|
||||
className="courseFormSelect"
|
||||
value={examPeriod.startMonth}
|
||||
|
||||
@@ -1,52 +1,51 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import "./CourseTable.css";
|
||||
import { fetchCourses } from "../api";
|
||||
import { fetchCourses, fetchAppointments } from "../api";
|
||||
import Navbar from "./Navbar";
|
||||
|
||||
const CourseTable = () => {
|
||||
const { state } = useLocation();
|
||||
const [courses, setCourses] = useState(state?.courses || []);
|
||||
const [appointments, setAppointments] = useState([]);
|
||||
const [loading, setLoading] = useState(!state?.courses);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAllCourses = async () => {
|
||||
if (!state?.courses) {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const fetchedCourses = await fetchCourses(); // Fetch courses from API
|
||||
setCourses(fetchedCourses);
|
||||
const academicYear = state?.academicYear;
|
||||
const [fetchedAppointments, fetchedCourses] = await Promise.all([
|
||||
fetchAppointments(academicYear),
|
||||
state?.courses ? Promise.resolve(state.courses) : fetchCourses(),
|
||||
]);
|
||||
setAppointments(fetchedAppointments);
|
||||
if (!state?.courses) setCourses(fetchedCourses);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch courses:", error);
|
||||
console.error("Failed to fetch data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchAllCourses();
|
||||
}, [state?.courses]);
|
||||
|
||||
useEffect(() => {
|
||||
if (state?.updatedCourse) {
|
||||
setCourses((prevCourses) =>
|
||||
prevCourses.map((course) =>
|
||||
course.courseId === state.updatedCourse.courseId
|
||||
? { ...course, status: "Submitted" } // Update the status for the specific course
|
||||
: course
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [state?.updatedCourse]);
|
||||
|
||||
fetchData();
|
||||
}, [state?.courses, state?.academicYear]);
|
||||
|
||||
const getStatus = (courseId) => {
|
||||
// Check if there's an appointment for the given courseId
|
||||
return appointments.some((appointment) => appointment.courseId === courseId)
|
||||
? "Submitted"
|
||||
: "Not Submitted";
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
const handleRowClick = (course) => {
|
||||
navigate(`/course-form/${course.courseId}`, { state: { course } });
|
||||
navigate(`/course-form/${course.courseId}`, {
|
||||
state: { course, academicYear: state?.academicYear },
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -66,7 +65,7 @@ const CourseTable = () => {
|
||||
<tr key={course.courseId} onClick={() => handleRowClick(course)}>
|
||||
<td>{course.courseId}</td>
|
||||
<td>{course.name}</td>
|
||||
<td>{course.status}</td>
|
||||
<td>{getStatus(course.courseId)}</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
|
||||
@@ -5,11 +5,13 @@ import { fetchCourses } from "../api";
|
||||
import Navbar from "./Navbar";
|
||||
|
||||
const FilterPage = () => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const [formData, setFormData] = useState({
|
||||
scheme: "",
|
||||
semester: "",
|
||||
department: "",
|
||||
program: "",
|
||||
academicYear: `${currentYear}-${(currentYear + 1).toString().slice(-2)}`,
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
@@ -25,19 +27,32 @@ const FilterPage = () => {
|
||||
};
|
||||
|
||||
const handleApplyFilter = async () => {
|
||||
if (!formData.scheme || !formData.semester || !formData.department || !formData.program) {
|
||||
if (
|
||||
!formData.scheme ||
|
||||
!formData.semester ||
|
||||
!formData.department ||
|
||||
!formData.program ||
|
||||
!formData.academicYear
|
||||
) {
|
||||
alert("Please fill all the fields before applying the filter.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const filteredCourses = await fetchCourses(formData);
|
||||
console.log(formData);
|
||||
if (filteredCourses.length > 0) {
|
||||
// Save filteredCourses in localStorage
|
||||
localStorage.setItem("filteredCourses", JSON.stringify(filteredCourses));
|
||||
localStorage.setItem(
|
||||
"filteredCourses",
|
||||
JSON.stringify(filteredCourses)
|
||||
);
|
||||
|
||||
navigate("/courses", { state: { courses: filteredCourses } });
|
||||
navigate("/courses", {
|
||||
state: {
|
||||
courses: filteredCourses,
|
||||
academicYear: formData.academicYear,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
alert("No courses found for the selected filters.");
|
||||
}
|
||||
@@ -47,7 +62,6 @@ const FilterPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getSemesters = () => {
|
||||
if (!formData.program) return [];
|
||||
if (formData.program === "B.Tech") {
|
||||
@@ -59,6 +73,14 @@ const FilterPage = () => {
|
||||
return [];
|
||||
};
|
||||
|
||||
const getAcademicYears = () => {
|
||||
return Array.from({ length: 6 }, (_, i) => {
|
||||
const startYear = currentYear - i;
|
||||
const endYear = startYear + 1;
|
||||
return `${startYear}-${endYear.toString().slice(-2)}`;
|
||||
}); // Generate in YYYY-YY format
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
@@ -100,8 +122,20 @@ const FilterPage = () => {
|
||||
onChange={handleInputChange}
|
||||
>
|
||||
<option value="">Select Scheme</option>
|
||||
<option value="2020">SVU 2020</option>
|
||||
<option value="2023">SVU 2023</option>
|
||||
<option value="SVU 2020">SVU 2020</option>
|
||||
<option value="SVU 2023">SVU 2023</option>
|
||||
</select>
|
||||
<select
|
||||
name="academicYear"
|
||||
value={formData.academicYear}
|
||||
onChange={handleInputChange}
|
||||
>
|
||||
<option value="">Select Academic Year</option>
|
||||
{getAcademicYears().map((year) => (
|
||||
<option key={year} value={year}>
|
||||
{year}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button onClick={handleApplyFilter}>Apply Filter</button>
|
||||
</div>
|
||||
|
||||
@@ -5,20 +5,21 @@ import "./Navbar.css"; // Navbar-specific styles
|
||||
|
||||
const Navbar = () => {
|
||||
return (
|
||||
<header className="navbar mb-10">
|
||||
<header className="navbar">
|
||||
<div className="navbar-container">
|
||||
<NavLink to="/Welcom">
|
||||
<FaUserCircle className="user-icon" />
|
||||
Appointment To Examiner
|
||||
</NavLink>
|
||||
<div className="button-container">
|
||||
<NavLink to="/consolidated" className="consolidated-button">
|
||||
Faculty Form
|
||||
Faculty Consolidated
|
||||
</NavLink>
|
||||
<NavLink to="/course-form" className="course-form-button">
|
||||
Course Form
|
||||
<NavLink to="/courseConsolidated" className="consolidated-button">
|
||||
Course Consolidated
|
||||
</NavLink>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import * as XLSX from "xlsx-js-style";
|
||||
import { jsPDF } from "jspdf";
|
||||
import autoTable from "jspdf-autotable";
|
||||
import Navbar from "./Navbar";
|
||||
|
||||
|
||||
const CourseConsolidated = () => {
|
||||
@@ -186,6 +186,8 @@ const CourseConsolidated = () => {
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar/>
|
||||
<div>
|
||||
<h1 style={{ textAlign: "center" }}>
|
||||
Course Tables with Download Options
|
||||
@@ -392,6 +394,7 @@ const CourseConsolidated = () => {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -78,6 +78,18 @@ export const fetchOptions = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
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) => {
|
||||
|
||||
@@ -8,7 +8,8 @@ const AppointmentSchema = new mongoose.Schema({
|
||||
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
|
||||
examPeriod: { type: String, required: true },
|
||||
academicYear: {type: String, required: true},
|
||||
});
|
||||
|
||||
module.exports = mongoose.model("Appointment", AppointmentSchema);
|
||||
|
||||
@@ -14,7 +14,7 @@ router.post("/", async (req, res) => {
|
||||
|
||||
const savedAppointments = [];
|
||||
for (const appointment of appointments) {
|
||||
const { facultyId, courseId, tasks, examPeriod } = appointment;
|
||||
const { facultyId, courseId, tasks, examPeriod, academicYear } = appointment;
|
||||
|
||||
if (
|
||||
!facultyId ||
|
||||
@@ -43,6 +43,7 @@ router.post("/", async (req, res) => {
|
||||
courseName: course.name,
|
||||
task,
|
||||
examPeriod,
|
||||
academicYear,
|
||||
});
|
||||
const savedAppointment = await newAppointment.save();
|
||||
savedAppointments.push(savedAppointment);
|
||||
@@ -58,8 +59,9 @@ router.post("/", async (req, res) => {
|
||||
|
||||
// Get all appointments
|
||||
router.get("/", async (req, res) => {
|
||||
const { academicYear } = req.query;
|
||||
try {
|
||||
const appointments = await Appointment.find();
|
||||
const appointments = await Appointment.find({ academicYear });
|
||||
res.json(appointments);
|
||||
} catch (error) {
|
||||
console.error("Error fetching appointments:", error);
|
||||
|
||||
Reference in New Issue
Block a user