Update Faculty page, FacultyCard component, types, and constants
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# ─── DATABASE CONNECTION CONFIGURATION ───
|
# ─── DATABASE CONNECTION CONFIGURATION ───
|
||||||
spring.datasource.url=jdbc:postgresql://localhost:5432/rit_freshers_hub?sslmode=disable
|
spring.datasource.url=jdbc:postgresql://localhost:5432/rit_freshers_hub?sslmode=disable
|
||||||
spring.datasource.username=postgres
|
spring.datasource.username=postgres
|
||||||
spring.datasource.password=${DB_PASSWORD:Amudiesh22@.}
|
spring.datasource.password=${DB_PASSWORD:murugan06}
|
||||||
|
|
||||||
# ─── JPA / HIBERNATE SETTINGS ───
|
# ─── JPA / HIBERNATE SETTINGS ───
|
||||||
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
|
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
|
||||||
|
|||||||
@@ -36,6 +36,52 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
{ name: 'Yahoo Mail', url: `https://compose.mail.yahoo.com/?to=${faculty.email}`, icon: Mail, color: 'text-purple-600', bg: 'bg-purple-50' },
|
{ name: 'Yahoo Mail', url: `https://compose.mail.yahoo.com/?to=${faculty.email}`, icon: Mail, color: 'text-purple-600', bg: 'bg-purple-50' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const parseToListItems = (text: string | undefined): string[] => {
|
||||||
|
if (!text) return [];
|
||||||
|
const cleaned = text.replace(/<br\s*\/?>/gi, '\n');
|
||||||
|
const lines = cleaned.split(/\n+/);
|
||||||
|
const items: string[] = [];
|
||||||
|
lines.forEach((line) => {
|
||||||
|
let subParts: string[];
|
||||||
|
if (line.includes(';')) {
|
||||||
|
subParts = line.split(';');
|
||||||
|
} else if (line.includes(',') && !line.includes('(')) {
|
||||||
|
subParts = line.split(',');
|
||||||
|
} else {
|
||||||
|
subParts = [line];
|
||||||
|
}
|
||||||
|
subParts.forEach((part) => {
|
||||||
|
let trimmed = part.trim();
|
||||||
|
trimmed = trimmed.replace(/^[\d+.)\-•\s*]+/, '').trim();
|
||||||
|
if (trimmed && trimmed !== '—' && trimmed !== 'Nil' && trimmed !== 'nil') {
|
||||||
|
items.push(trimmed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderPointList = (value: string | undefined, placeholder: string = 'Not specified') => {
|
||||||
|
const items = parseToListItems(value);
|
||||||
|
if (items.length <= 1) {
|
||||||
|
return (
|
||||||
|
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||||
|
{items[0] || placeholder}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ul className="space-y-1.5 mt-1 text-left">
|
||||||
|
{items.map((item, idx) => (
|
||||||
|
<li key={idx} className="flex items-start gap-2 text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||||
|
<span className="w-1.5 h-1.5 rounded-full bg-[#FF6B00] mt-2 shrink-0" />
|
||||||
|
<span className="leading-tight">{item}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -134,11 +180,11 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="w-32 h-32 rounded-full flex items-center justify-center text-white font-bold text-5xl mb-5 shadow-lg"
|
className="w-32 h-32 rounded-full flex items-center justify-center text-white font-bold text-5xl mb-5 shadow-lg"
|
||||||
style={{ background: `linear-gradient(135deg, ${from}, ${to})`, fontFamily: 'Poppins, sans-serif' }}
|
style={{ background: `linear-gradient(135deg, ${from}, ${to})`, fontFamily: 'Plus Jakarta Sans, sans-serif' }}
|
||||||
>
|
>
|
||||||
{initials}
|
{initials}
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-2xl font-bold text-center text-[#1E293B] mb-1" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
<h2 className="text-2xl font-bold text-center text-[#1E293B] mb-1" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>
|
||||||
{faculty.name}
|
{faculty.name}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-base font-semibold text-[#FF7A00] text-center" style={{ fontFamily: 'Inter, sans-serif' }}>
|
<p className="text-base font-semibold text-[#FF7A00] text-center" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||||
@@ -192,17 +238,13 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
<div className="w-10 h-10 rounded-xl bg-orange-50 flex items-center justify-center shrink-0">
|
<div className="w-10 h-10 rounded-xl bg-orange-50 flex items-center justify-center shrink-0">
|
||||||
<User className="w-5 h-5 text-[#FF7A00]" />
|
<User className="w-5 h-5 text-[#FF7A00]" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>Professional Details</h3>
|
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>Professional Details</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50">
|
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50">
|
||||||
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Department</p>
|
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Department</p>
|
||||||
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.department}</p>
|
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.department}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50">
|
|
||||||
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Specialization</p>
|
|
||||||
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.specialization || 'Not specified'}</p>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50">
|
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50">
|
||||||
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Qualification</p>
|
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Qualification</p>
|
||||||
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.qualification || 'Not specified'}</p>
|
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.qualification || 'Not specified'}</p>
|
||||||
@@ -212,11 +254,15 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.experience || 'Not specified'}</p>
|
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.experience || 'Not specified'}</p>
|
||||||
</div>
|
</div>
|
||||||
{faculty.joinedInstitution && (
|
{faculty.joinedInstitution && (
|
||||||
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50 md:col-span-2">
|
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50">
|
||||||
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Joined Institution</p>
|
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Joined Institution</p>
|
||||||
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.joinedInstitution}</p>
|
<p className="text-sm font-semibold text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.joinedInstitution}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="p-4 rounded-xl bg-gray-50/80 border border-gray-100 transition-colors hover:bg-gray-50 md:col-span-2">
|
||||||
|
<p className="text-xs font-semibold text-[#94A3B8] uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Interest / Domain / Specialization</p>
|
||||||
|
{renderPointList(faculty.interest || faculty.specialization)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -226,17 +272,19 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
<div className="w-10 h-10 rounded-xl bg-indigo-50 flex items-center justify-center shrink-0">
|
<div className="w-10 h-10 rounded-xl bg-indigo-50 flex items-center justify-center shrink-0">
|
||||||
<BookOpen className="w-5 h-5 text-indigo-500" />
|
<BookOpen className="w-5 h-5 text-indigo-500" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>Academic Information</h3>
|
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>Academic Information</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="p-5 rounded-xl bg-indigo-50/30 border border-indigo-100/50">
|
<div className="p-5 rounded-xl bg-indigo-50/30 border border-indigo-100/50">
|
||||||
<p className="text-xs font-bold text-indigo-400 uppercase tracking-wider mb-2" style={{ fontFamily: 'Inter, sans-serif' }}>Subjects Handling</p>
|
<p className="text-xs font-bold text-indigo-400 uppercase tracking-wider mb-2" style={{ fontFamily: 'Inter, sans-serif' }}>Subjects Handling</p>
|
||||||
<p className="text-sm font-medium text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif', lineHeight: '1.6' }}>{faculty.subjectsHandling || 'Not specified'}</p>
|
{renderPointList(faculty.subjectsHandling)}
|
||||||
</div>
|
</div>
|
||||||
|
{faculty.researchAreas && (
|
||||||
<div className="p-5 rounded-xl bg-teal-50/30 border border-teal-100/50">
|
<div className="p-5 rounded-xl bg-teal-50/30 border border-teal-100/50">
|
||||||
<p className="text-xs font-bold text-teal-500 uppercase tracking-wider mb-2" style={{ fontFamily: 'Inter, sans-serif' }}>Research Areas</p>
|
<p className="text-xs font-bold text-teal-500 uppercase tracking-wider mb-2" style={{ fontFamily: 'Inter, sans-serif' }}>Research Areas</p>
|
||||||
<p className="text-sm font-medium text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif', lineHeight: '1.6' }}>{faculty.researchAreas || 'Not specified'}</p>
|
<p className="text-sm font-medium text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif', lineHeight: '1.6' }}>{faculty.researchAreas}</p>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
{faculty.studentsGuided && (
|
{faculty.studentsGuided && (
|
||||||
<div className="p-5 rounded-xl bg-blue-50/30 border border-blue-100/50">
|
<div className="p-5 rounded-xl bg-blue-50/30 border border-blue-100/50">
|
||||||
<p className="text-xs font-bold text-blue-500 uppercase tracking-wider mb-3" style={{ fontFamily: 'Inter, sans-serif' }}>Students Guided</p>
|
<p className="text-xs font-bold text-blue-500 uppercase tracking-wider mb-3" style={{ fontFamily: 'Inter, sans-serif' }}>Students Guided</p>
|
||||||
@@ -266,7 +314,7 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
<div className="w-10 h-10 rounded-xl bg-pink-50 flex items-center justify-center shrink-0">
|
<div className="w-10 h-10 rounded-xl bg-pink-50 flex items-center justify-center shrink-0">
|
||||||
<GraduationCap className="w-5 h-5 text-pink-500" />
|
<GraduationCap className="w-5 h-5 text-pink-500" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>Achievements</h3>
|
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>Achievements</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
{faculty.achievements && faculty.achievements.length > 0 && (
|
{faculty.achievements && faculty.achievements.length > 0 && (
|
||||||
@@ -294,30 +342,36 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Section 4: Office Info */}
|
{/* Section 4: Office Info */}
|
||||||
|
{(faculty.office || faculty.officeHours) && (
|
||||||
<div className="bg-white rounded-[20px] shadow-sm border border-[#E8ECF4] p-6 sm:p-8">
|
<div className="bg-white rounded-[20px] shadow-sm border border-[#E8ECF4] p-6 sm:p-8">
|
||||||
<div className="flex items-center gap-3 mb-6">
|
<div className="flex items-center gap-3 mb-6">
|
||||||
<div className="w-10 h-10 rounded-xl bg-emerald-50 flex items-center justify-center shrink-0">
|
<div className="w-10 h-10 rounded-xl bg-emerald-50 flex items-center justify-center shrink-0">
|
||||||
<Clock className="w-5 h-5 text-emerald-500" />
|
<Clock className="w-5 h-5 text-emerald-500" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>Office Information</h3>
|
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>Office Information</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
{faculty.officeHours && (
|
||||||
<div className="p-5 rounded-xl bg-emerald-50/50 border border-emerald-100 flex items-start gap-4">
|
<div className="p-5 rounded-xl bg-emerald-50/50 border border-emerald-100 flex items-start gap-4">
|
||||||
<Clock className="w-6 h-6 text-emerald-500 shrink-0 mt-0.5" />
|
<Clock className="w-6 h-6 text-emerald-500 shrink-0 mt-0.5" />
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-bold text-emerald-600 uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Office Hours</p>
|
<p className="text-xs font-bold text-emerald-600 uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Office Hours</p>
|
||||||
<p className="text-sm font-medium text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.officeHours || 'Not specified'}</p>
|
<p className="text-sm font-medium text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.officeHours}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{faculty.office && (
|
||||||
<div className="p-5 rounded-xl bg-blue-50/30 border border-blue-100/50 flex items-start gap-4">
|
<div className="p-5 rounded-xl bg-blue-50/30 border border-blue-100/50 flex items-start gap-4">
|
||||||
<Building2 className="w-6 h-6 text-blue-500 shrink-0 mt-0.5" />
|
<Building2 className="w-6 h-6 text-blue-500 shrink-0 mt-0.5" />
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-bold text-blue-500 uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Office Location</p>
|
<p className="text-xs font-bold text-blue-500 uppercase tracking-wider mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Office Location</p>
|
||||||
<p className="text-sm font-medium text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.office || 'Not specified'}</p>
|
<p className="text-sm font-medium text-[#1E293B]" style={{ fontFamily: 'Inter, sans-serif' }}>{faculty.office}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -348,7 +402,7 @@ export default function FacultyCard({ faculty }: FacultyCardProps) {
|
|||||||
>
|
>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>Choose Mail App</h3>
|
<h3 className="text-lg font-bold text-[#1E293B]" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>Choose Mail App</h3>
|
||||||
<p className="text-xs text-[#64748B] mt-0.5" style={{ fontFamily: 'Inter, sans-serif' }}>Compose email to {faculty.name}</p>
|
<p className="text-xs text-[#64748B] mt-0.5" style={{ fontFamily: 'Inter, sans-serif' }}>Compose email to {faculty.name}</p>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={() => setShowEmailOptions(false)} className="p-2 rounded-full hover:bg-gray-100 transition-colors">
|
<button onClick={() => setShowEmailOptions(false)} className="p-2 rounded-full hover:bg-gray-100 transition-colors">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,23 @@ import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/An
|
|||||||
import { FACULTY_DATA, DEPARTMENTS } from '@/constants';
|
import { FACULTY_DATA, DEPARTMENTS } from '@/constants';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
const DEPT_MAP: Record<string, { abrv: string; full: string }> = {
|
||||||
|
'Computer Science & Engineering': { abrv: 'CSE', full: 'Computer Science and Engineering' },
|
||||||
|
'Computer Science & Business Systems': { abrv: 'CSBS', full: 'Computer Science and Business Systems' },
|
||||||
|
'Artificial Intelligence & Machine Learning': { abrv: 'AIML', full: 'Artificial Intelligence and Machine Learning' },
|
||||||
|
'Electronics & Communication Engineering': { abrv: 'ECE', full: 'Electronics and Communication Engineering' },
|
||||||
|
'Mechanical Engineering': { abrv: 'MECH', full: 'Mechanical Engineering' },
|
||||||
|
'Civil Engineering': { abrv: 'CIVIL', full: 'Civil Engineering' },
|
||||||
|
'Artificial Intelligence & Data Science': { abrv: 'AI&DS', full: 'Artificial Intelligence and Data Science' },
|
||||||
|
'Electrical & Electronics Engineering': { abrv: 'EEE', full: 'Electrical and Electronics Engineering' },
|
||||||
|
'Communication and Computer Engineering': { abrv: 'CCE', full: 'Communication and Computer Engineering' },
|
||||||
|
'Electronics Engineering VLSI (Design and Technology)': { abrv: 'EE VLSI (D&T)', full: 'Electronics Engineering (VLSI Design and Technology)' },
|
||||||
|
'Humanities & Sciences': { abrv: 'H&S', full: 'Humanities and Sciences' },
|
||||||
|
'M.Tech (Data Science)': { abrv: 'M.TECH-DS', full: 'M.Tech (Data Science)' },
|
||||||
|
'Mathematics': { abrv: 'MATHS', full: 'Mathematics' },
|
||||||
|
'M.E. (VLSI Design)': { abrv: 'MEVLSI', full: 'M.E. (VLSI Design)' },
|
||||||
|
};
|
||||||
|
|
||||||
export default function Faculty() {
|
export default function Faculty() {
|
||||||
const [searchFaculty, setSearchFaculty] = useState('');
|
const [searchFaculty, setSearchFaculty] = useState('');
|
||||||
const [selectedDept, setSelectedDept] = useState('All Departments');
|
const [selectedDept, setSelectedDept] = useState('All Departments');
|
||||||
@@ -15,23 +32,39 @@ export default function Faculty() {
|
|||||||
const filtered = FACULTY_DATA.filter((f) => {
|
const filtered = FACULTY_DATA.filter((f) => {
|
||||||
const searchLower = searchFaculty.trim().toLowerCase();
|
const searchLower = searchFaculty.trim().toLowerCase();
|
||||||
const matchSearch =
|
const matchSearch =
|
||||||
f.name.toLowerCase().includes(searchLower) ||
|
(f.name && f.name.toLowerCase().includes(searchLower)) ||
|
||||||
f.department.toLowerCase().includes(searchLower) ||
|
(f.department && f.department.toLowerCase().includes(searchLower)) ||
|
||||||
f.designation.toLowerCase().includes(searchLower) ||
|
(f.designation && f.designation.toLowerCase().includes(searchLower)) ||
|
||||||
(f.specialization && f.specialization.toLowerCase().includes(searchLower));
|
(f.specialization && f.specialization.toLowerCase().includes(searchLower)) ||
|
||||||
|
(f.interest && f.interest.toLowerCase().includes(searchLower));
|
||||||
|
|
||||||
const matchDept = selectedDept === 'All Departments' || f.department === selectedDept;
|
const matchDept = selectedDept === 'All Departments' || f.department === selectedDept;
|
||||||
return matchSearch && matchDept;
|
return matchSearch && matchDept;
|
||||||
});
|
});
|
||||||
|
|
||||||
return filtered.sort((a, b) => {
|
return filtered.sort((a, b) => {
|
||||||
if (sortBy === 'Name A-Z') return a.name.localeCompare(b.name);
|
if (sortBy === 'Name A-Z') return (a.name || '').localeCompare(b.name || '');
|
||||||
if (sortBy === 'Department') return a.department.localeCompare(b.department);
|
if (sortBy === 'Department') return (a.department || '').localeCompare(b.department || '');
|
||||||
if (sortBy === 'Designation') return a.designation.localeCompare(b.designation);
|
if (sortBy === 'Designation') return (a.designation || '').localeCompare(b.designation || '');
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
}, [searchFaculty, selectedDept, sortBy]);
|
}, [searchFaculty, selectedDept, sortBy]);
|
||||||
|
|
||||||
|
const groupedFaculty = useMemo(() => {
|
||||||
|
const groups: Record<string, typeof filteredAndSortedFaculty> = {};
|
||||||
|
filteredAndSortedFaculty.forEach((faculty) => {
|
||||||
|
if (!groups[faculty.department]) {
|
||||||
|
groups[faculty.department] = [];
|
||||||
|
}
|
||||||
|
groups[faculty.department].push(faculty);
|
||||||
|
});
|
||||||
|
return groups;
|
||||||
|
}, [filteredAndSortedFaculty]);
|
||||||
|
|
||||||
|
const departmentOrder = useMemo(() => {
|
||||||
|
return DEPARTMENTS.filter(d => d !== 'All Departments');
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen relative overflow-hidden bg-[#F8FAFC]">
|
<div className="min-h-screen relative overflow-hidden bg-[#F8FAFC]">
|
||||||
{/* Background decorations */}
|
{/* Background decorations */}
|
||||||
@@ -112,15 +145,21 @@ export default function Faculty() {
|
|||||||
{ abrv: 'CIVIL', full: 'Civil Engineering', color: 'emerald' },
|
{ abrv: 'CIVIL', full: 'Civil Engineering', color: 'emerald' },
|
||||||
{ abrv: 'AI & DS', full: 'Artificial Intelligence & Data Science', color: 'pink' },
|
{ abrv: 'AI & DS', full: 'Artificial Intelligence & Data Science', color: 'pink' },
|
||||||
{ abrv: 'EEE', full: 'Electrical & Electronics Engineering', color: 'yellow' },
|
{ abrv: 'EEE', full: 'Electrical & Electronics Engineering', color: 'yellow' },
|
||||||
].map(d => {
|
{ abrv: 'CCE', full: 'Communication and Computer Engineering', color: 'rose' },
|
||||||
|
{ abrv: 'EE VLSI (D&T)', full: 'Electronics Engineering VLSI (Design and Technology)', color: 'teal' },
|
||||||
|
{ abrv: 'H&S', full: 'Humanities & Sciences', color: 'indigo' },
|
||||||
|
{ abrv: 'M.TECH-DS', full: 'M.Tech (Data Science)', color: 'fuchsia' },
|
||||||
|
{ abrv: 'MATHS', full: 'Mathematics', color: 'blue' },
|
||||||
|
{ abrv: 'MEVLSI', full: 'M.E. (VLSI Design)', color: 'rose' },
|
||||||
|
].filter(d => FACULTY_DATA.filter(f => f.department === d.full).length > 0).map(d => {
|
||||||
const count = FACULTY_DATA.filter(f => f.department === d.full).length;
|
const count = FACULTY_DATA.filter(f => f.department === d.full).length;
|
||||||
return (
|
return (
|
||||||
<div key={d.abrv} className={`p-4 rounded-2xl bg-${d.color}-50 border border-${d.color}-100 flex flex-col gap-1 transition-transform hover:scale-105 cursor-default`}>
|
<div key={d.abrv} className={`p-4 rounded-2xl bg-${d.color}-50 border border-${d.color}-100 flex flex-col gap-1 transition-transform hover:scale-105 cursor-default`}>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className={`text-xs font-bold text-${d.color}-700`} style={{ fontFamily: 'Poppins, sans-serif' }}>{d.abrv}</span>
|
<span className={`text-xs font-bold text-${d.color}-700`} style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>{d.abrv}</span>
|
||||||
<BookOpen className={`w-3.5 h-3.5 text-${d.color}-400`} />
|
<BookOpen className={`w-3.5 h-3.5 text-${d.color}-400`} />
|
||||||
</div>
|
</div>
|
||||||
<span className="text-2xl font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>{count}</span>
|
<span className="text-2xl font-bold text-[#1E293B]" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>{count}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -134,7 +173,7 @@ export default function Faculty() {
|
|||||||
<Search className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-[#94A3B8]" />
|
<Search className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-[#94A3B8]" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search by faculty name, department, designation or specialization..."
|
placeholder="Search by faculty name, department, designation or interest..."
|
||||||
value={searchFaculty}
|
value={searchFaculty}
|
||||||
onChange={(e) => setSearchFaculty(e.target.value)}
|
onChange={(e) => setSearchFaculty(e.target.value)}
|
||||||
className="w-full pl-12 pr-4 py-3.5 rounded-2xl bg-[#F8FAFC] border-none text-sm text-[#1E293B] placeholder-[#94A3B8] focus:ring-2 focus:ring-[#FF7A00]/20 focus:outline-none transition-all"
|
className="w-full pl-12 pr-4 py-3.5 rounded-2xl bg-[#F8FAFC] border-none text-sm text-[#1E293B] placeholder-[#94A3B8] focus:ring-2 focus:ring-[#FF7A00]/20 focus:outline-none transition-all"
|
||||||
@@ -150,7 +189,7 @@ export default function Faculty() {
|
|||||||
className="h-full pl-10 pr-10 py-3.5 rounded-2xl bg-[#F8FAFC] border-none text-sm font-medium text-[#475569] focus:ring-2 focus:ring-[#FF7A00]/20 focus:outline-none transition-all appearance-none cursor-pointer min-w-[200px]"
|
className="h-full pl-10 pr-10 py-3.5 rounded-2xl bg-[#F8FAFC] border-none text-sm font-medium text-[#475569] focus:ring-2 focus:ring-[#FF7A00]/20 focus:outline-none transition-all appearance-none cursor-pointer min-w-[200px]"
|
||||||
style={{ fontFamily: 'Inter, sans-serif', backgroundImage: 'url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%2394A3B8%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E")', backgroundRepeat: 'no-repeat', backgroundPosition: 'right 1rem top 50%', backgroundSize: '0.65rem auto' }}
|
style={{ fontFamily: 'Inter, sans-serif', backgroundImage: 'url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%2394A3B8%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E")', backgroundRepeat: 'no-repeat', backgroundPosition: 'right 1rem top 50%', backgroundSize: '0.65rem auto' }}
|
||||||
>
|
>
|
||||||
{DEPARTMENTS.map((dept) => {
|
{DEPARTMENTS.filter(dept => dept === 'All Departments' || FACULTY_DATA.filter((f) => f.department === dept).length > 0).map((dept) => {
|
||||||
const count = dept === 'All Departments' ? FACULTY_DATA.length : FACULTY_DATA.filter((f) => f.department === dept).length;
|
const count = dept === 'All Departments' ? FACULTY_DATA.length : FACULTY_DATA.filter((f) => f.department === dept).length;
|
||||||
return <option key={dept} value={dept}>{dept} ({count})</option>;
|
return <option key={dept} value={dept}>{dept} ({count})</option>;
|
||||||
})}
|
})}
|
||||||
@@ -172,15 +211,38 @@ export default function Faculty() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Grid */}
|
{/* Grouped Grid */}
|
||||||
{filteredAndSortedFaculty.length > 0 ? (
|
{filteredAndSortedFaculty.length > 0 ? (
|
||||||
<StaggerContainer key={`${searchFaculty}-${selectedDept}-${sortBy}`} className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 pb-20">
|
<div className="space-y-12 pb-20">
|
||||||
{filteredAndSortedFaculty.map((faculty) => (
|
{departmentOrder.map((deptName) => {
|
||||||
|
const facultyInDept = groupedFaculty[deptName];
|
||||||
|
if (!facultyInDept || facultyInDept.length === 0) return null;
|
||||||
|
const deptInfo = DEPT_MAP[deptName] || { abrv: deptName, full: deptName };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={deptName} className="space-y-6">
|
||||||
|
{/* Department Header */}
|
||||||
|
<div className="border-l-4 border-[#FF6B00] pl-4 py-1">
|
||||||
|
<h2 className="text-xl font-bold text-[#1A0B2E]" style={{ fontFamily: 'Plus Jakarta Sans, sans-serif' }}>
|
||||||
|
{deptInfo.abrv}
|
||||||
|
</h2>
|
||||||
|
<p className="text-xs text-[#9E91B6] font-semibold mt-0.5" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||||
|
{deptInfo.full}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Department Grid */}
|
||||||
|
<StaggerContainer key={`${deptName}-${searchFaculty}-${selectedDept}-${sortBy}`} className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{facultyInDept.map((faculty) => (
|
||||||
<StaggerItem key={faculty.id}>
|
<StaggerItem key={faculty.id}>
|
||||||
<FacultyCard faculty={faculty} />
|
<FacultyCard faculty={faculty} />
|
||||||
</StaggerItem>
|
</StaggerItem>
|
||||||
))}
|
))}
|
||||||
</StaggerContainer>
|
</StaggerContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="py-20 text-center flex flex-col items-center justify-center bg-white rounded-3xl border border-[#E8ECF4] shadow-sm">
|
<div className="py-20 text-center flex flex-col items-center justify-center bg-white rounded-3xl border border-[#E8ECF4] shadow-sm">
|
||||||
<Users className="w-12 h-12 text-[#CBD5E1] mb-4" />
|
<Users className="w-12 h-12 text-[#CBD5E1] mb-4" />
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ export interface Stat {
|
|||||||
export interface Faculty {
|
export interface Faculty {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
designation: string;
|
designation?: string;
|
||||||
department: string;
|
department: string;
|
||||||
email: string;
|
email: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
office?: string;
|
office?: string;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
specialization?: string;
|
specialization?: string;
|
||||||
|
interest?: string;
|
||||||
qualification?: string;
|
qualification?: string;
|
||||||
experience?: string;
|
experience?: string;
|
||||||
subjectsHandling?: string;
|
subjectsHandling?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user