Files
appointment_to_examiner/client/src/Pages/AdminFacultyPage.jsx
2025-03-29 15:40:41 +05:30

458 lines
13 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Navbar from './Navbar';
import { toast, ToastContainer } from "react-toastify";
import 'react-toastify/dist/ReactToastify.css';
import { useNavigate } from 'react-router-dom';
export const AdminFacultyPage = () => {
const [faculties, setFaculties] = useState([]);
const [showForm, setShowForm] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [isLoading, setIsLoading] = useState(true);
const [currentFaculty, setCurrentFaculty] = useState({
facultyId: '',
name: '',
email: '',
department: '',
program: '',
courses: [''],
});
const [courses, setcourses] = useState({});
const navigate = useNavigate();
// Fetch all faculties
useEffect(() => {
const checkAdmin = async () => {
try {
const res = await axios.get("http://localhost:8080/api/me", { withCredentials: true });
console.log(res.data);
if (!res.data.isAdmin) {
handleUnauthorizedAccess();
} else {
setIsLoading(false);
}
} catch (error) {
console.error("Unauthorized access:", error);
handleUnauthorizedAccess();
}
};
fetchFaculties();
fetchCourses();
checkAdmin();
}, []);
const handleUnauthorizedAccess = async () => {
try {
toast.warning("Unauthorized access. Logging out...", { position: "top-center" });
// Attempt to log out
await axios.get("http://localhost:8080/auth/logout", { withCredentials: true });
// Delay redirection to show the toast message
setTimeout(() => {
navigate("/"); // Redirect to login
}, 1500);
} catch (error) {
console.error("Error during unauthorized access handling:", error);
}
};
useEffect(() => {
if (!isLoading) {
fetchCourses();
}
}, [isLoading]);
const fetchFaculties = async () => {
const res = await axios.get('http://localhost:8080/api/faculty');
setFaculties(res.data);
};
const fetchCourses = async () => {
try {
const res = await axios.get("http://localhost:8080/api/courses");
const courseMap = res.data.reduce((acc, course) => {
acc[course.courseId] = course.name;
return acc;
}, {});
setcourses(courseMap);
} catch (error) {
console.error("Error fetching courses: ", error);
}
};
// Add or Update Faculty
const handleAddOrUpdateFaculty = async (e) => {
e.preventDefault();
if (isEditMode) {
// Update Faculty (PUT request)
await axios.put(`http://localhost:8080/api/faculty/${currentFaculty._id}`, currentFaculty);
toast.success('Faculty updated successfully!', { position: 'top-center' });
} else {
// Add Faculty (POST request)
await axios.post('http://localhost:8080/api/faculty', currentFaculty);
toast.success('Faculty added successfully!', { position: 'top-center' });
}
// Reset form and refresh data
resetForm();
fetchFaculties();
};
// Delete Faculty
const handleDeleteFaculty = async (id) => {
const confirm = window.confirm('⚠️ Are you sure you want to delete this faculty?');
if (confirm) {
await axios.delete(`http://localhost:8080/api/faculty/${id}`);
fetchFaculties();
toast.success('Faculty deleted successfully!', { position: 'top-center' });
}
};
// Open Form for Edit
const handleOpenEditForm = (faculty) => {
setCurrentFaculty(faculty);
setIsEditMode(true);
setShowForm(true);
};
// Open Form for Add
const handleOpenAddForm = () => {
resetForm();
setIsEditMode(false);
setShowForm(true);
};
// Handle Course Input Change
const handleCourseChange = (index, value) => {
const newCourses = [...currentFaculty.courses];
newCourses[index] = value;
setCurrentFaculty({ ...currentFaculty, courses: newCourses });
};
// Add a new course field
const handleAddCourse = () => {
setCurrentFaculty({
...currentFaculty,
courses: [...currentFaculty.courses, ''],
});
};
// Remove a course field
const handleRemoveCourse = (index) => {
const newCourses = currentFaculty.courses.filter((_, i) => i !== index);
setCurrentFaculty({ ...currentFaculty, courses: newCourses });
};
// Reset form
const resetForm = () => {
setCurrentFaculty({
facultyId: '',
name: '',
email: '',
department: '',
program: '',
courses: [''],
});
setShowForm(false);
};
const filteredFaculties = faculties.filter((faculty) =>
faculty.name.toLowerCase().includes(searchQuery.toLowerCase())
);
if (isLoading) {
return <p style={{ textAlign: 'center', marginTop: '50px', fontSize: '18px' }}>Loading...</p>;
}
return (
<>
<Navbar />
<div style={{ fontFamily: 'Arial, sans-serif', backgroundColor: '#f4f6f9', padding: '20px' }}>
<h2 style={{ textAlign: 'center', color: '#333', marginBottom: '20px' }}>Faculty Management</h2>
<div style={{ textAlign: 'center', marginBottom: '20px' }}></div>
<input
type="text"
placeholder="Search faculty by name..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
style={{
padding: '10px',
width: '300px',
borderRadius: '5px',
border: '1px solid #ddd',
outline: 'none',
fontSize: '16px',
}}
/>
<button onClick={handleOpenAddForm} style={{
backgroundColor: '#4CAF50',
color: '#fff',
padding: '10px 15px',
borderRadius: '5px',
marginLeft: '10px',
border: 'none',
cursor: 'pointer',
transition: '0.3s',
}}
onMouseEnter={(e) => (e.target.style.backgroundColor = '#800000')}
onMouseLeave={(e) => (e.target.style.backgroundColor = '#4CAF50')}>
+ Add New Faculty</button>
</div>
{showForm && (
<div style={{
backgroundColor: '#fff',
borderRadius: '10px',
padding: '20px',
boxShadow: '0 5px 20px rgba(0,0,0,0.1)',
marginBottom: '20px',
}}>
<h3>{isEditMode ? 'Edit Faculty' : 'Add New Faculty'}</h3>
<form onSubmit={handleAddOrUpdateFaculty} style={formStyle}>
<div style={inputContainer}>
<input
placeholder="Faculty ID"
value={currentFaculty.facultyId}
onChange={(e) => setCurrentFaculty({ ...currentFaculty, facultyId: e.target.value })}
style={inputStyle}
/>
<input
placeholder="Name"
value={currentFaculty.name}
onChange={(e) => setCurrentFaculty({ ...currentFaculty, name: e.target.value })}
style={inputStyle}
/>
</div>
<div style={inputContainer}>
<input
placeholder="Email"
value={currentFaculty.email}
onChange={(e) => setCurrentFaculty({ ...currentFaculty, email: e.target.value })}
style={inputStyle}
/>
<input
placeholder="Department"
value={currentFaculty.department}
onChange={(e) => setCurrentFaculty({ ...currentFaculty, department: e.target.value })}
style={inputStyle}
/>
</div>
<div style={inputContainer}>
<input
placeholder="Program"
value={currentFaculty.program}
onChange={(e) => setCurrentFaculty({ ...currentFaculty, program: e.target.value })}
style={inputStyle}
/>
</div>
{currentFaculty.courses.map((course, index) => (
<div key={index} style={courseContainerStyle}>
<select
value={course}
onChange={(e) => handleCourseChange(index, e.target.value)}
style={{ ...inputStyle, flex: 1 }}
>
<option value="">Select Course</option>
{Object.entries(courses).map(([courseId, courseName]) => (
<option key={courseId} value={courseId}>
{courseName}
</option>
))}
</select>
<button type="button" onClick={() => handleRemoveCourse(index)} style={removeButtonStyle}></button>
</div>
))}
<button type="button" onClick={handleAddCourse} style={addCourseButtonStyle}>+ Add Course</button>
<div style={formButtonContainer}>
<button type="submit" style={submitButtonStyle}>
{isEditMode ? 'Update Faculty' : 'Add Faculty'}
</button>
<button type="button" onClick={() => setShowForm(false)} style={cancelButtonStyle}>Cancel</button>
</div>
</form>
</div>
)}
{/* TABLE DATA */}
<table style={tableStyle}>
<thead>
<tr>
<th>Faculty ID</th>
<th>Name</th>
<th>Email</th>
<th>Department</th>
<th>Program</th>
<th>Courses</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{filteredFaculties.length > 0 ? (
filteredFaculties.map((f) => (
<tr key={f._id}>
<td style={tdStyle}>{f.facultyId}</td>
<td style={{
maxWidth: '150px',
wordWrap: 'break-word',
whiteSpace: 'normal'
}}>{f.name}</td>
<td style={tdStyle}>{f.email}</td>
<td style={tdStyle}>{f.department}</td>
<td style={tdStyle}>{f.program}</td>
<td style={tdStyle}><ul style={{ padding: 0, margin: 0, listStyleType: 'none' }}>
{f.courses.map((courseId, index) => (
<li key={index} style={{ marginBottom: '5px' }}>
{courses[courseId] || courseId}
</li>
))}
</ul></td>
<td style={tdStyle}>
<button style={{
backgroundColor: '#4CAF50',
color: 'white',
padding: '8px 12px',
border: 'none',
borderRadius: '5px',
marginRight: '10px',
cursor: 'pointer',
transition: '0.3s',
}}
onMouseEnter={(e) => (e.target.style.backgroundColor = '#2e7d32')}
onMouseLeave={(e) => (e.target.style.backgroundColor = '#4CAF50')}
onClick={() => handleOpenEditForm(f)}>Edit</button>
<button style={{
backgroundColor: '#f44336',
color: 'white',
padding: '8px 12px',
border: 'none',
borderRadius: '5px',
marginLeft: '10px',
cursor: 'pointer',
transition: '0.3s',
}}
onMouseEnter={(e) => (e.target.style.backgroundColor = '#d32f2f')}
onMouseLeave={(e) => (e.target.style.backgroundColor = '#f44336')}
onClick={() => handleDeleteFaculty(f._id)}>Delete</button>
</td>
</tr>
))
) : (
<tr>
<td colSpan="7" style={{ textAlign: 'center', color: 'red' }}>
No faculty found
</td>
</tr>
)}
</tbody>
</table >
</>
);
};
const tableStyle = {
width: '100%',
borderCollapse: 'collapse',
marginTop: '20px',
};
const tdStyle = {
maxWidth: '350px',
wordWrap: 'break-word',
whiteSpace: 'normal'
}
const formStyle = {
backgroundColor: '#f9f9f9',
padding: '20px',
borderRadius: '10px',
boxShadow: '0 5px 20px rgba(0, 0, 0, 0.1)',
maxWidth: '700px',
margin: '0 auto',
};
const inputContainer = {
display: 'flex',
gap: '10px',
marginBottom: '10px',
};
const inputStyle = {
flex: 1,
padding: '10px 15px',
border: '1px solid #ddd',
borderRadius: '5px',
fontSize: '14px',
};
const courseContainerStyle = {
display: 'flex',
alignItems: 'center',
gap: '10px',
marginBottom: '8px',
};
const removeButtonStyle = {
backgroundColor: '#ffffff',
color: 'white',
border: 'none',
padding: '5px 10px',
borderRadius: '5px',
cursor: 'pointer',
fontSize: '14px',
transition: '0.3s',
};
const addCourseButtonStyle = {
backgroundColor: '#4CAF50',
color: 'white',
border: 'none',
padding: '8px 15px',
borderRadius: '5px',
cursor: 'pointer',
transition: '0.3s',
};
const formButtonContainer = {
display: 'flex',
justifyContent: 'space-between',
marginTop: '20px',
};
const submitButtonStyle = {
backgroundColor: '#4CAF50',
color: 'white',
border: 'none',
padding: '10px 20px',
borderRadius: '5px',
cursor: 'pointer',
fontSize: '14px',
};
const cancelButtonStyle = {
backgroundColor: '#f44336',
color: 'white',
border: 'none',
padding: '10px 20px',
borderRadius: '5px',
cursor: 'pointer',
fontSize: '14px',
};
const subHeadingStyle = {
fontSize: '18px',
marginBottom: '10px',
};