Professor category

This commit is contained in:
2026-05-05 11:55:20 +05:30
parent 7b88426f96
commit 4fc0be9071
2 changed files with 346 additions and 188 deletions
+118 -76
View File
@@ -9,7 +9,10 @@ interface TeamListingProps {
onMemberClick?: (member: TeamMember) => void; onMemberClick?: (member: TeamMember) => void;
} }
const TeamListing: React.FC<TeamListingProps> = ({ const GUIDES_FRIENDS_PATRONS_CATEGORIES = ['GUIDES', 'FRIENDS', 'PATRONS'];
const NON_CLICKABLE_CATEGORIES = ['TRAINEE_FELLOW', 'SUPPORT_TEAM', 'GUIDES', 'FRIENDS', 'PATRONS'];
const TeamListing: React.FC<TeamListingProps> = ({
title = "Our Team", title = "Our Team",
onMemberClick onMemberClick
}) => { }) => {
@@ -35,25 +38,36 @@ const TeamListing: React.FC<TeamListingProps> = ({
loadFacultyData(); loadFacultyData();
}, []); }, []);
// Filter members by category and status // Active faculty members only
const facultyMembers = teamMembers.filter(member => const facultyMembers = teamMembers.filter(member =>
member.category === 'FACULTY' && member.status !== 'RETIRED' member.category === 'FACULTY' && member.status !== 'RETIRED'
); );
const supportTeam = teamMembers.filter(member =>
// Active support team only
const supportTeam = teamMembers.filter(member =>
member.category === 'SUPPORT_TEAM' && member.status !== 'RETIRED' member.category === 'SUPPORT_TEAM' && member.status !== 'RETIRED'
); );
const traineesAndFellows = teamMembers.filter(member =>
// Active trainees and fellows only
const traineesAndFellows = teamMembers.filter(member =>
member.category === 'TRAINEE_FELLOW' && member.status !== 'RETIRED' member.category === 'TRAINEE_FELLOW' && member.status !== 'RETIRED'
); );
const retiredStaff = teamMembers.filter(member =>
member.status === 'RETIRED' // Guides, Friends, Patrons — all three categories in one section
const guidesFriendsPatrons = teamMembers.filter(member =>
GUIDES_FRIENDS_PATRONS_CATEGORIES.includes(member.category) && member.status !== 'RETIRED'
);
// Alumni = RETIRED (any category) + RESIGNED (any status)
const alumniStaff = teamMembers.filter(member =>
member.status === 'RETIRED' || member.category === 'RESIGNED'
); );
const handleMemberClick = (member: TeamMember) => { const handleMemberClick = (member: TeamMember) => {
if (onMemberClick) { if (onMemberClick) {
onMemberClick(member); onMemberClick(member);
} else { } else {
window.location.href = `/faculty/${member.id}`; window.location.href = `/faculty/${member.professorId}`;
} }
}; };
@@ -73,8 +87,8 @@ const TeamListing: React.FC<TeamListingProps> = ({
<div className="min-h-screen flex items-center justify-center"> <div className="min-h-screen flex items-center justify-center">
<div className="text-center"> <div className="text-center">
<p className="text-red-600 mb-4">{error}</p> <p className="text-red-600 mb-4">{error}</p>
<button <button
onClick={() => window.location.reload()} onClick={() => window.location.reload()}
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700" className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
> >
Retry Retry
@@ -87,45 +101,44 @@ const TeamListing: React.FC<TeamListingProps> = ({
const TeamMemberCard: React.FC<{ member: TeamMember }> = ({ member }) => { const TeamMemberCard: React.FC<{ member: TeamMember }> = ({ member }) => {
const [imageError, setImageError] = useState(false); const [imageError, setImageError] = useState(false);
const [imageLoading, setImageLoading] = useState(true); const [imageLoading, setImageLoading] = useState(true);
const isTrainee = member.category === 'TRAINEE_FELLOW';
const isSupportTeam = member.category === 'SUPPORT_TEAM';
const isRetired = member.status === 'RETIRED';
const isNonClickable = isTrainee || isSupportTeam;
// Check if image URL is valid and not a default placeholder
const hasValidImage = member.image &&
member.image.trim() !== '' &&
!member.image.includes('default-avatar') &&
!member.image.includes('placeholder.') &&
!member.image.includes('robot') &&
// Only filter if URL ENDS with /profile-image (backend default endpoint)
!(member.image.endsWith('/profile-image') ||
member.image.includes('/profile-image?') ||
member.image === 'https://via.placeholder.com/400');
// Don't show images for trainees or support team const isNonClickable = NON_CLICKABLE_CATEGORIES.includes(member.category);
const isRetired = member.status === 'RETIRED';
const isResigned = member.category === 'RESIGNED';
// Check if image URL is valid and not a default placeholder
const hasValidImage =
member.image &&
member.image.trim() !== '' &&
!member.image.includes('default-avatar') &&
!member.image.includes('placeholder.') &&
!member.image.includes('robot') &&
!(
member.image.endsWith('/profile-image') ||
member.image.includes('/profile-image?') ||
member.image === 'https://via.placeholder.com/400'
);
// Don't show images for non-clickable categories
const shouldShowImage = !isNonClickable && hasValidImage; const shouldShowImage = !isNonClickable && hasValidImage;
const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => { const handleImageError = () => {
console.error('Image failed to load:', member.image);
console.error('Member:', member.name, 'Professor ID:', member.professorId);
setImageError(true); setImageError(true);
setImageLoading(false); setImageLoading(false);
}; };
const handleImageLoad = () => { const handleImageLoad = () => {
console.log('Image loaded successfully:', member.image);
setImageLoading(false); setImageLoading(false);
}; };
return ( return (
<div <div
className={`bg-white rounded-lg border border-gray-300 overflow-hidden transition-all duration-300 ${ className={`bg-white rounded-lg border border-gray-300 overflow-hidden transition-all duration-300 ${
!isNonClickable ? 'group cursor-pointer hover:shadow-lg' : 'cursor-default' !isNonClickable ? 'group cursor-pointer hover:shadow-lg' : 'cursor-default'
}`} }`}
onClick={() => !isNonClickable && handleMemberClick(member)} onClick={() => !isNonClickable && handleMemberClick(member)}
> >
{/* Only show image section for faculty */} {/* Only show image section for clickable categories (Faculty + Alumni) */}
{!isNonClickable && ( {!isNonClickable && (
<div className="relative aspect-square overflow-hidden bg-gray-50"> <div className="relative aspect-square overflow-hidden bg-gray-50">
{shouldShowImage && !imageError ? ( {shouldShowImage && !imageError ? (
@@ -135,9 +148,8 @@ const TeamListing: React.FC<TeamListingProps> = ({
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div> <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
</div> </div>
)} )}
<img
<img src={member.image}
src={member.image}
alt={member.name} alt={member.name}
className={`w-full h-full object-cover transition-transform duration-300 group-hover:scale-105 ${ className={`w-full h-full object-cover transition-transform duration-300 group-hover:scale-105 ${
imageLoading ? 'opacity-0' : 'opacity-100' imageLoading ? 'opacity-0' : 'opacity-100'
@@ -148,29 +160,41 @@ const TeamListing: React.FC<TeamListingProps> = ({
/> />
</> </>
) : ( ) : (
<div <div
className="w-full h-full flex items-center justify-center" className="w-full h-full flex items-center justify-center"
style={{ backgroundColor: '#e0e5eb' }} style={{ backgroundColor: '#e0e5eb' }}
> >
<svg <svg className="w-32 h-32 text-gray-400" fill="currentColor" viewBox="0 0 24 24">
className="w-32 h-32 text-gray-400" <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg> </svg>
</div> </div>
)} )}
</div> </div>
)} )}
<div className="p-4 sm:p-6"> <div className="p-4 sm:p-6">
<h3 className="text-lg font-medium mb-2 group-hover:opacity-70 transition-opacity" style={{ color: '#012068' }}> {/* Status badge for alumni */}
{(isRetired || isResigned) && (
<div className="mb-2">
<span
className="inline-block px-2 py-0.5 text-xs font-medium rounded-full text-white"
style={{ backgroundColor: isResigned ? '#6b7280' : '#dc2626' }}
>
{isResigned ? 'Resigned' : 'Retired'}
</span>
</div>
)}
<h3
className="text-lg font-medium mb-2 group-hover:opacity-70 transition-opacity"
style={{ color: '#012068' }}
>
{member.name} {member.name}
</h3> </h3>
<p className="text-sm leading-relaxed" style={{ color: '#e64838' }}> <p className="text-sm leading-relaxed" style={{ color: '#e64838' }}>
{member.position} {member.position}
</p> </p>
{!isNonClickable && ( {!isNonClickable && (
<> <>
{member.department && ( {member.department && (
@@ -196,8 +220,8 @@ const TeamListing: React.FC<TeamListingProps> = ({
<section className="py-4" style={{ backgroundColor: '#f4f4f4' }}> <section className="py-4" style={{ backgroundColor: '#f4f4f4' }}>
<div className="max-w-7xl mx-auto px-4"> <div className="max-w-7xl mx-auto px-4">
<nav className="flex items-center space-x-2 text-sm"> <nav className="flex items-center space-x-2 text-sm">
<Link <Link
href="/" href="/"
className="hover:opacity-70 transition-opacity duration-200" className="hover:opacity-70 transition-opacity duration-200"
style={{ color: '#012068' }} style={{ color: '#012068' }}
> >
@@ -208,7 +232,7 @@ const TeamListing: React.FC<TeamListingProps> = ({
Faculty Faculty
</span> </span>
</nav> </nav>
<div className="mt-6"> <div className="mt-6">
<div className="flex items-center mb-4"> <div className="flex items-center mb-4">
<h1 className="text-3xl font-bold" style={{ color: '#012068' }}> <h1 className="text-3xl font-bold" style={{ color: '#012068' }}>
@@ -216,7 +240,9 @@ const TeamListing: React.FC<TeamListingProps> = ({
</h1> </h1>
</div> </div>
<p className="text-base max-w-3xl leading-relaxed" style={{ color: '#333' }}> <p className="text-base max-w-3xl leading-relaxed" style={{ color: '#333' }}>
Meet our dedicated team of medical professionals, researchers, and support staff committed to advancing healthcare, education, and patient outcomes at Christian Medical College, Vellore Meet our dedicated team of medical professionals, researchers, and support staff
committed to advancing healthcare, education, and patient outcomes at Christian
Medical College, Vellore
</p> </p>
</div> </div>
</div> </div>
@@ -243,8 +269,8 @@ const TeamListing: React.FC<TeamListingProps> = ({
</section> </section>
)} )}
{/* Retired Staff Section */} {/* Faculty Alumni Section — RETIRED + RESIGNED */}
{retiredStaff.length > 0 && ( {alumniStaff.length > 0 && (
<section className="py-8" style={{ backgroundColor: '#f9f9f9' }}> <section className="py-8" style={{ backgroundColor: '#f9f9f9' }}>
<div className="max-w-7xl mx-auto px-4"> <div className="max-w-7xl mx-auto px-4">
<div className="mb-8"> <div className="mb-8">
@@ -252,11 +278,11 @@ const TeamListing: React.FC<TeamListingProps> = ({
Faculty Alumni Faculty Alumni
</h2> </h2>
<p className="text-sm mb-2" style={{ color: '#666' }}> <p className="text-sm mb-2" style={{ color: '#666' }}>
Honoring our retired faculty and staff members for their dedicated service Honoring our retired and former faculty members for their dedicated service
</p> </p>
</div> </div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{retiredStaff.map((member) => ( {alumniStaff.map((member) => (
<TeamMemberCard key={member.id} member={member} /> <TeamMemberCard key={member.id} member={member} />
))} ))}
</div> </div>
@@ -273,10 +299,12 @@ const TeamListing: React.FC<TeamListingProps> = ({
Support Team Support Team
</h2> </h2>
<p className="text-base leading-relaxed mb-2" style={{ color: '#012068' }}> <p className="text-base leading-relaxed mb-2" style={{ color: '#012068' }}>
<strong>Clinical Support Staff</strong> - Essential team members providing specialized support services <strong>Clinical Support Staff</strong> — Essential team members providing
specialised support services
</p> </p>
<p className="text-sm mb-1" style={{ color: '#012068' }}> <p className="text-sm mb-1" style={{ color: '#012068' }}>
<strong>Administrative & Technical Support</strong> - Dedicated professionals ensuring smooth operations <strong>Administrative &amp; Technical Support</strong> — Dedicated professionals
ensuring smooth operations
</p> </p>
</div> </div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
@@ -288,16 +316,43 @@ const TeamListing: React.FC<TeamListingProps> = ({
</section> </section>
)} )}
{/* Trainees & Fellows Section */} {/* Guides / Friends / Patrons Section */}
{traineesAndFellows.length > 0 && ( {guidesFriendsPatrons.length > 0 && (
<section className="py-8" style={{ backgroundColor: '#f9f9f9' }}> <section className="py-8" style={{ backgroundColor: '#f9f9f9' }}>
<div className="max-w-7xl mx-auto px-4"> <div className="max-w-7xl mx-auto px-4">
<div className="mb-8"> <div className="mb-8">
<h2 className="text-2xl font-bold mb-4" style={{ color: '#012068' }}> <h2 className="text-2xl font-bold mb-4" style={{ color: '#012068' }}>
Trainees & Fellows Guides / Friends / Patrons
</h2>
<p className="text-base leading-relaxed mb-2" style={{ color: '#012068' }}>
<strong>Guides</strong> — Mentors and senior professionals who have shaped our
department
</p>
<p className="text-sm mb-1" style={{ color: '#012068' }}>
<strong>Friends &amp; Patrons</strong> — Valued supporters and well-wishers of our
institution
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{guidesFriendsPatrons.map((member) => (
<TeamMemberCard key={member.id} member={member} />
))}
</div>
</div>
</section>
)}
{/* Trainees & Fellows Section */}
{traineesAndFellows.length > 0 && (
<section className="py-8" style={{ backgroundColor: '#fff' }}>
<div className="max-w-7xl mx-auto px-4">
<div className="mb-8">
<h2 className="text-2xl font-bold mb-4" style={{ color: '#012068' }}>
Trainees &amp; Fellows
</h2> </h2>
<p className="text-sm mb-2" style={{ color: '#666' }}> <p className="text-sm mb-2" style={{ color: '#666' }}>
Medical trainees, residents, and fellows advancing their skills and contributing to patient care Medical trainees, residents, and fellows advancing their skills and contributing
to patient care
</p> </p>
</div> </div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
@@ -309,7 +364,7 @@ const TeamListing: React.FC<TeamListingProps> = ({
</section> </section>
)} )}
{/* Show message if no faculty data */} {/* No data message */}
{teamMembers.length === 0 && !loading && ( {teamMembers.length === 0 && !loading && (
<section className="py-16 text-center"> <section className="py-16 text-center">
<div className="max-w-2xl mx-auto px-4"> <div className="max-w-2xl mx-auto px-4">
@@ -317,10 +372,11 @@ const TeamListing: React.FC<TeamListingProps> = ({
No Faculty Data Available No Faculty Data Available
</h2> </h2>
<p className="text-gray-600 mb-6"> <p className="text-gray-600 mb-6">
Faculty information is currently being updated. Please check back later or contact administration. Faculty information is currently being updated. Please check back later or contact
administration.
</p> </p>
<button <button
onClick={() => window.location.reload()} onClick={() => window.location.reload()}
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors" className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
> >
Refresh Page Refresh Page
@@ -328,20 +384,6 @@ const TeamListing: React.FC<TeamListingProps> = ({
</div> </div>
</section> </section>
)} )}
{/* Show message if all categories are empty but we have data */}
{teamMembers.length > 0 && facultyMembers.length === 0 && supportTeam.length === 0 && traineesAndFellows.length === 0 && retiredStaff.length === 0 && (
<section className="py-16 text-center">
<div className="max-w-2xl mx-auto px-4">
<h2 className="text-2xl font-bold mb-4" style={{ color: '#012068' }}>
No Categorized Faculty Available
</h2>
<p className="text-gray-600 mb-6">
Faculty members need to be assigned to categories. Please contact administration.
</p>
</div>
</section>
)}
</div> </div>
); );
}; };
+228 -112
View File
@@ -1,9 +1,9 @@
'use client' 'use client'
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import { import {
Phone, Phone,
Mail, Mail,
Share, Share,
ChevronRight, ChevronRight,
Check, Check,
@@ -16,6 +16,8 @@ interface TeamMemberDetailProps {
memberData?: TeamMember; memberData?: TeamMember;
} }
const GUIDES_FRIENDS_PATRONS_CATEGORIES = ['GUIDES', 'FRIENDS', 'PATRONS'];
const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberData }) => { const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberData }) => {
const [member, setMember] = useState<TeamMember | null>(memberData || null); const [member, setMember] = useState<TeamMember | null>(memberData || null);
const [loading, setLoading] = useState(!memberData); const [loading, setLoading] = useState(!memberData);
@@ -25,7 +27,7 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
useEffect(() => { useEffect(() => {
const loadMemberData = async () => { const loadMemberData = async () => {
if (memberData) return; // Already have data if (memberData) return;
try { try {
setLoading(true); setLoading(true);
@@ -62,8 +64,8 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
<div className="min-h-screen flex items-center justify-center"> <div className="min-h-screen flex items-center justify-center">
<div className="text-center"> <div className="text-center">
<p className="text-red-600 mb-4">{error || 'Faculty member not found'}</p> <p className="text-red-600 mb-4">{error || 'Faculty member not found'}</p>
<Link <Link
href="/teamMember" href="/teamMember"
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors" className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
> >
Back to Faculty Back to Faculty
@@ -75,56 +77,87 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
const isTrainee = member.category === 'TRAINEE_FELLOW'; const isTrainee = member.category === 'TRAINEE_FELLOW';
const isRetired = member.status === 'RETIRED'; const isRetired = member.status === 'RETIRED';
const isResigned = member.category === 'RESIGNED';
const isGuidesFriendsPatrons = GUIDES_FRIENDS_PATRONS_CATEGORIES.includes(member.category);
// Check if image URL is valid and not a default placeholder // Check if image URL is valid and not a default placeholder
const hasValidImage = member.image && const hasValidImage =
member.image.trim() !== '' && member.image &&
!member.image.includes('default-avatar') && member.image.trim() !== '' &&
!member.image.includes('placeholder.') && !member.image.includes('default-avatar') &&
!member.image.includes('robot') && !member.image.includes('placeholder.') &&
// Only filter if URL ENDS with /profile-image (backend default endpoint) !member.image.includes('robot') &&
!(member.image.endsWith('/profile-image') || !(
member.image.includes('/profile-image?') || member.image.endsWith('/profile-image') ||
member.image === 'https://via.placeholder.com/400'); member.image.includes('/profile-image?') ||
member.image === 'https://via.placeholder.com/400'
);
const shouldShowImage = !isTrainee && hasValidImage && !imageError; const shouldShowImage = !isTrainee && !isGuidesFriendsPatrons && hasValidImage && !imageError;
// Create a comprehensive description from the member's details
const getFullDescription = () => { const getFullDescription = () => {
return member.description || `${member.name} is a dedicated member of our ${isTrainee ? 'trainee program' : 'faculty'} with expertise in ${member.specialty?.toLowerCase() || 'medical practice'}. They bring valuable experience in ${isTrainee ? 'clinical training' : 'surgical education'}, patient care, and clinical research to Christian Medical College, Vellore.`; return (
member.description ||
`${member.name} is a dedicated member of our ${isTrainee ? 'trainee program' : 'faculty'} with expertise in ${member.specialty?.toLowerCase() || 'medical practice'}. They bring valuable experience in ${isTrainee ? 'clinical training' : 'surgical education'}, patient care, and clinical research to Christian Medical College, Vellore.`
);
}; };
// Parse phone numbers if multiple are provided
const getFormattedPhone = () => { const getFormattedPhone = () => {
if (!member.phone || member.phone === 'Not available') { if (!member.phone || member.phone === 'Not available') {
return 'Contact through main office'; return 'Contact through main office';
} }
return member.phone.includes(',') return member.phone.includes(',')
? member.phone.split(',').map(p => p.trim()).join(' / ') ? member.phone
.split(',')
.map((p) => p.trim())
.join(' / ')
: member.phone; : member.phone;
}; };
const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => { const handleImageError = () => {
console.error('Image failed to load:', member.image);
setImageError(true); setImageError(true);
}; };
// Determine status badge config
const getStatusBadge = () => {
if (isRetired) {
return { label: 'RETIRED', bg: '#dc2626' };
}
if (isResigned) {
return { label: 'RESIGNED', bg: '#6b7280' };
}
if (isTrainee) {
return { label: 'Trainee / Fellow', bg: '#374151' };
}
if (isGuidesFriendsPatrons) {
const labels: Record<string, string> = {
GUIDES: 'Guide',
FRIENDS: 'Friend',
PATRONS: 'Patron',
};
return { label: labels[member.category] || member.category, bg: '#012068' };
}
return null;
};
const statusBadge = getStatusBadge();
return ( return (
<div className="min-h-screen bg-white"> <div className="min-h-screen bg-white">
{/* Breadcrumb Section */} {/* Breadcrumb Section */}
<section className="py-4" style={{ backgroundColor: '#f4f4f4' }}> <section className="py-4" style={{ backgroundColor: '#f4f4f4' }}>
<div className="max-w-7xl mx-auto px-4"> <div className="max-w-7xl mx-auto px-4">
<nav className="flex items-center space-x-2 text-sm"> <nav className="flex items-center space-x-2 text-sm">
<Link <Link
href="/" href="/"
className="hover:opacity-70 transition-opacity duration-200" className="hover:opacity-70 transition-opacity duration-200"
style={{ color: '#012068' }} style={{ color: '#012068' }}
> >
Home Home
</Link> </Link>
<ChevronRight className="w-4 h-4" style={{ color: '#012068' }} /> <ChevronRight className="w-4 h-4" style={{ color: '#012068' }} />
<Link <Link
href="/teamMember" href="/teamMember"
className="hover:opacity-70 transition-opacity duration-200" className="hover:opacity-70 transition-opacity duration-200"
style={{ color: '#012068' }} style={{ color: '#012068' }}
> >
@@ -135,26 +168,25 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
{member.name} {member.name}
</span> </span>
</nav> </nav>
{/* Page Header */} {/* Page Header */}
<div className="mt-6"> <div className="mt-6">
<div className="flex items-center mb-4"> <div className="flex items-center flex-wrap gap-3 mb-4">
<h1 className="text-3xl font-bold" style={{ color: '#012068' }}> <h1 className="text-3xl font-bold" style={{ color: '#012068' }}>
{member.name} {member.name}
</h1> </h1>
{isTrainee && ( {statusBadge && (
<span className="ml-4 px-3 py-1 text-xs font-medium rounded-full bg-gray-200 text-gray-700"> <span
Trainee/Fellow className="px-3 py-1 text-xs font-medium rounded-full text-white"
</span> style={{ backgroundColor: statusBadge.bg }}
)} >
{isRetired && ( {statusBadge.label}
<span className="ml-4 px-3 py-1 text-xs font-medium rounded-full bg-red-600 text-white">
RETIRED
</span> </span>
)} )}
</div> </div>
<p className="text-base max-w-2xl leading-relaxed" style={{ color: '#333' }}> <p className="text-base max-w-2xl leading-relaxed" style={{ color: '#333' }}>
{member.designation || member.position} {member.experience && `with ${member.experience} of experience`} at CMC Vellore {member.designation || member.position}{' '}
{member.experience && `with ${member.experience} of experience`} at CMC Vellore
</p> </p>
</div> </div>
</div> </div>
@@ -169,112 +201,143 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
{/* Profile Image or Avatar */} {/* Profile Image or Avatar */}
<div className="aspect-square relative overflow-hidden bg-gray-50"> <div className="aspect-square relative overflow-hidden bg-gray-50">
{shouldShowImage ? ( {shouldShowImage ? (
<img <img
src={member.image} src={member.image}
alt={member.name} alt={member.name}
className="w-full h-full object-cover transform hover:scale-105 transition-transform duration-300" className="w-full h-full object-cover transform hover:scale-105 transition-transform duration-300"
onError={handleImageError} onError={handleImageError}
/> />
) : ( ) : (
<div <div
className="w-full h-full flex items-center justify-center" className="w-full h-full flex items-center justify-center"
style={{ backgroundColor: '#e0e5eb' }} style={{ backgroundColor: '#e0e5eb' }}
> >
<svg <svg
className="w-48 h-48 text-gray-400" className="w-48 h-48 text-gray-400"
fill="currentColor" fill="currentColor"
viewBox="0 0 24 24" viewBox="0 0 24 24"
> >
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/> <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
</svg> </svg>
</div> </div>
)} )}
</div> </div>
{/* Profile Info */} {/* Profile Info */}
<div className="p-4 sm:p-6"> <div className="p-4 sm:p-6">
<div className="mb-6"> <div className="mb-6">
<div <div
className="inline-flex items-center py-1 text-sm font-medium mb-3" className="inline-flex items-center py-1 text-sm font-medium mb-3"
style={{ color: '#012068' }} style={{ color: '#012068' }}
> >
{member.designation || member.position} {member.designation || member.position}
</div> </div>
<h2 className="text-xl font-bold mb-2" style={{ color: '#012068' }}>{member.name}</h2> <h2 className="text-xl font-bold mb-2" style={{ color: '#012068' }}>
{member.name}
</h2>
</div> </div>
<p className="text-sm mb-6 leading-relaxed" style={{ color: '#333' }}> <p className="text-sm mb-6 leading-relaxed" style={{ color: '#333' }}>
{member.specialty || `${member.name} is a dedicated ${isTrainee ? 'trainee' : 'faculty member'} at CMC Vellore.`} {member.specialty ||
`${member.name} is a dedicated ${isTrainee ? 'trainee' : 'faculty member'} at CMC Vellore.`}
</p> </p>
<div className="space-y-4 mb-6"> <div className="space-y-4 mb-6">
<div className="flex items-start"> <div className="flex items-start">
<Phone className="w-4 h-4 mr-3 mt-0.5 flex-shrink-0" style={{ color: '#e64838' }} /> <Phone
className="w-4 h-4 mr-3 mt-0.5 flex-shrink-0"
style={{ color: '#e64838' }}
/>
<div> <div>
<div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>Phone</div> <div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>
<div className="text-sm" style={{ color: '#333' }}>{getFormattedPhone()}</div> Phone
</div>
<div className="text-sm" style={{ color: '#333' }}>
{getFormattedPhone()}
</div>
</div> </div>
</div> </div>
<div className="flex items-start"> <div className="flex items-start">
<Mail className="w-4 h-4 mr-3 mt-0.5 flex-shrink-0" style={{ color: '#e64838' }} /> <Mail
className="w-4 h-4 mr-3 mt-0.5 flex-shrink-0"
style={{ color: '#e64838' }}
/>
<div> <div>
<div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>Email</div> <div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>
<a href={`mailto:${member.email}`} className="text-sm hover:underline transition-colors" style={{ color: '#e64838' }}> Email
</div>
<a
href={`mailto:${member.email}`}
className="text-sm hover:underline transition-colors"
style={{ color: '#e64838' }}
>
{member.email} {member.email}
</a> </a>
</div> </div>
</div> </div>
{member.experience && ( {member.experience && (
<div className="flex items-start"> <div className="flex items-start">
<div <div
className="w-4 h-4 rounded-full mr-3 mt-0.5 flex-shrink-0 flex items-center justify-center" className="w-4 h-4 rounded-full mr-3 mt-0.5 flex-shrink-0 flex items-center justify-center"
style={{ backgroundColor: '#e64838' }} style={{ backgroundColor: '#e64838' }}
> >
<div className="w-2 h-2 bg-white rounded-full"></div> <div className="w-2 h-2 bg-white rounded-full"></div>
</div> </div>
<div> <div>
<div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>Experience</div> <div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>
<div className="text-sm" style={{ color: '#333' }}>{member.experience}</div> Experience
</div>
<div className="text-sm" style={{ color: '#333' }}>
{member.experience}
</div>
</div> </div>
</div> </div>
)} )}
{member.department && ( {member.department && (
<div className="flex items-start"> <div className="flex items-start">
<div <div
className="w-4 h-4 rounded-full mr-3 mt-0.5 flex-shrink-0 flex items-center justify-center" className="w-4 h-4 rounded-full mr-3 mt-0.5 flex-shrink-0 flex items-center justify-center"
style={{ backgroundColor: '#012068' }} style={{ backgroundColor: '#012068' }}
> >
<div className="w-2 h-2 bg-white rounded-full"></div> <div className="w-2 h-2 bg-white rounded-full"></div>
</div> </div>
<div> <div>
<div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>Department</div> <div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>
<div className="text-sm" style={{ color: '#333' }}>{member.department}</div> Department
</div>
<div className="text-sm" style={{ color: '#333' }}>
{member.department}
</div>
</div> </div>
</div> </div>
)} )}
{member.officeLocation && ( {member.officeLocation && (
<div className="flex items-start"> <div className="flex items-start">
<div <div
className="w-4 h-4 rounded-full mr-3 mt-0.5 flex-shrink-0 flex items-center justify-center" className="w-4 h-4 rounded-full mr-3 mt-0.5 flex-shrink-0 flex items-center justify-center"
style={{ backgroundColor: '#012068' }} style={{ backgroundColor: '#012068' }}
> >
<div className="w-2 h-2 bg-white rounded-full"></div> <div className="w-2 h-2 bg-white rounded-full"></div>
</div> </div>
<div> <div>
<div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>Office Location</div> <div className="text-sm font-medium mb-1" style={{ color: '#012068' }}>
<div className="text-sm" style={{ color: '#333' }}>{member.officeLocation}</div> Office Location
</div>
<div className="text-sm" style={{ color: '#333' }}>
{member.officeLocation}
</div>
</div> </div>
</div> </div>
)} )}
</div> </div>
{/* Social Share */} {/* Social Share */}
<div className="relative"> <div className="relative">
<button <button
onClick={() => setShowSocialShare(!showSocialShare)} onClick={() => setShowSocialShare(!showSocialShare)}
className="flex items-center justify-center w-full px-4 py-3 rounded-lg transition-opacity font-medium text-sm hover:opacity-90" className="flex items-center justify-center w-full px-4 py-3 rounded-lg transition-opacity font-medium text-sm hover:opacity-90"
style={{ backgroundColor: '#f4f4f4', color: '#012068' }} style={{ backgroundColor: '#f4f4f4', color: '#012068' }}
@@ -290,57 +353,84 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
{/* Main Content */} {/* Main Content */}
<div className="xl:col-span-3"> <div className="xl:col-span-3">
<div className="bg-white rounded-md border border-gray-300 overflow-hidden"> <div className="bg-white rounded-md border border-gray-300 overflow-hidden">
{/* Personal Info */}
<div className="p-6 sm:p-8"> <div className="p-6 sm:p-8">
<div className="mb-8"> <div className="mb-8">
<div className="flex items-center mb-6"> <div className="flex items-center mb-6">
<h3 className="text-xl font-semibold" style={{ color: '#012068' }}>About</h3> <h3 className="text-xl font-semibold" style={{ color: '#012068' }}>
About
</h3>
</div> </div>
<div className="prose prose-lg max-w-none mb-8 leading-relaxed"> <div className="prose prose-lg max-w-none mb-8 leading-relaxed">
<p className="text-base text-gray-700"> <p className="text-base text-gray-700">{getFullDescription()}</p>
{getFullDescription()}
</p>
<p className="mt-6 text-base text-gray-700"> <p className="mt-6 text-base text-gray-700">
As a dedicated member of the Department of {member.department || 'Medicine'} at Christian Medical College, Vellore, As a dedicated member of the Department of {member.department || 'Medicine'}{' '}
{member.name.split(' ')[1] || member.name} contributes to advancing medical education, patient care, and at Christian Medical College, Vellore,{' '}
clinical research. Their commitment to excellence in healthcare and medical education makes {member.name.split(' ')[1] || member.name} contributes to advancing medical
them an invaluable asset to the medical community and the patients they serve. education, patient care, and clinical research. Their commitment to excellence
in healthcare and medical education makes them an invaluable asset to the
medical community and the patients they serve.
</p> </p>
</div> </div>
{/* Details Grid */} {/* Details Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-6"> <div className="space-y-6">
<div className="rounded-lg p-4 border border-gray-300" style={{ backgroundColor: '#f4f4f4' }}> <div
<div className="font-medium mb-2 text-sm" style={{ color: '#012068' }}>Education & Certification</div> className="rounded-lg p-4 border border-gray-300"
<div className="text-sm leading-relaxed" style={{ color: '#333' }}>{member.certification || 'Medical certification details available upon request'}</div> style={{ backgroundColor: '#f4f4f4' }}
>
<div className="font-medium mb-2 text-sm" style={{ color: '#012068' }}>
Education &amp; Certification
</div>
<div className="text-sm leading-relaxed" style={{ color: '#333' }}>
{member.certification ||
'Medical certification details available upon request'}
</div>
</div> </div>
</div> </div>
<div className="space-y-6"> <div className="space-y-6">
{/* Only show Training section if NOT retired */} {/* Hide Training section for retired and resigned */}
{!isRetired && ( {!isRetired && !isResigned && (
<div className="rounded-lg p-4 border border-gray-300" style={{ backgroundColor: '#f4f4f4' }}> <div
<div className="font-medium mb-2 text-sm" style={{ color: '#012068' }}>Training & Professional Development</div> className="rounded-lg p-4 border border-gray-300"
<div className="text-sm leading-relaxed" style={{ color: '#333' }}>{member.training || 'Professional training details available upon request'}</div> style={{ backgroundColor: '#f4f4f4' }}
>
<div className="font-medium mb-2 text-sm" style={{ color: '#012068' }}>
Training &amp; Professional Development
</div>
<div className="text-sm leading-relaxed" style={{ color: '#333' }}>
{member.training ||
'Professional training details available upon request'}
</div>
</div> </div>
)} )}
{member.workDays && member.workDays.length > 0 && ( {member.workDays && member.workDays.length > 0 && (
<div className="rounded-lg p-4 border border-gray-300" style={{ backgroundColor: '#f4f4f4' }}> <div
<div className="font-medium mb-3 text-sm" style={{ color: '#012068' }}>Clinical Days</div> className="rounded-lg p-4 border border-gray-300"
style={{ backgroundColor: '#f4f4f4' }}
>
<div className="font-medium mb-3 text-sm" style={{ color: '#012068' }}>
Clinical Days
</div>
<div className="space-y-2"> <div className="space-y-2">
{member.workDays.map((day, index) => ( {member.workDays.map((day, index) => (
<div key={index} className="flex items-center"> <div key={index} className="flex items-center">
<div <div
className="w-4 h-4 rounded flex items-center justify-center mr-3" className="w-4 h-4 rounded flex items-center justify-center mr-3"
style={{ backgroundColor: '#e64838' }} style={{ backgroundColor: '#e64838' }}
> >
<Check className="w-3 h-3 text-white" /> <Check className="w-3 h-3 text-white" />
</div> </div>
<span className="text-sm font-medium" style={{ color: '#012068' }}>{day}</span> <span
className="text-sm font-medium"
style={{ color: '#012068' }}
>
{day}
</span>
</div> </div>
))} ))}
</div> </div>
@@ -356,18 +446,30 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
{member.skills && member.skills.length > 0 && ( {member.skills && member.skills.length > 0 && (
<div> <div>
<div className="flex items-center mb-6"> <div className="flex items-center mb-6">
<h3 className="text-xl font-semibold" style={{ color: '#012068' }}>Research Interests & Expertise</h3> <h3 className="text-xl font-semibold" style={{ color: '#012068' }}>
Research Interests &amp; Expertise
</h3>
</div> </div>
<p className="text-sm mb-6 leading-relaxed" style={{ color: '#333' }}> <p className="text-sm mb-6 leading-relaxed" style={{ color: '#333' }}>
Areas of clinical expertise, research focus, and professional competencies that contribute to advancing medical practice and education at CMC Vellore. Areas of clinical expertise, research focus, and professional competencies
that contribute to advancing medical practice and education at CMC Vellore.
</p> </p>
<div className="space-y-4"> <div className="space-y-4">
{member.skills.map((skill, index) => ( {member.skills.map((skill, index) => (
<div key={index} className="rounded-lg p-4 border border-gray-300" style={{ backgroundColor: '#f4f4f4' }}> <div
key={index}
className="rounded-lg p-4 border border-gray-300"
style={{ backgroundColor: '#f4f4f4' }}
>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<span className="font-medium text-sm" style={{ color: '#012068' }}>{skill.name}</span> <span
className="font-medium text-sm"
style={{ color: '#012068' }}
>
{skill.name}
</span>
{skill.level} {skill.level}
</div> </div>
</div> </div>
@@ -380,19 +482,26 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
{member.awards && member.awards.length > 0 && ( {member.awards && member.awards.length > 0 && (
<div> <div>
<div className="flex items-center mb-6"> <div className="flex items-center mb-6">
<h3 className="text-xl font-semibold" style={{ color: '#012068' }}>Awards and Recognition</h3> <h3 className="text-xl font-semibold" style={{ color: '#012068' }}>
Awards and Recognition
</h3>
</div> </div>
<p className="text-sm mb-6 leading-relaxed" style={{ color: '#333' }}> <p className="text-sm mb-6 leading-relaxed" style={{ color: '#333' }}>
Professional achievements, awards, and recognition received for excellence in medical practice, research, and education. Professional achievements, awards, and recognition received for excellence
in medical practice, research, and education.
</p> </p>
<div className="space-y-6"> <div className="space-y-6">
{member.awards.map((award, index) => ( {member.awards.map((award, index) => (
<div key={index} className="rounded-lg p-4 border border-gray-300" style={{ backgroundColor: '#f4f4f4' }}> <div
key={index}
className="rounded-lg p-4 border border-gray-300"
style={{ backgroundColor: '#f4f4f4' }}
>
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<img <img
src={award.image} src={award.image}
alt={award.title} alt={award.title}
className="w-12 h-12 rounded object-cover border border-gray-300 flex-shrink-0" className="w-12 h-12 rounded object-cover border border-gray-300 flex-shrink-0"
onError={(e) => { onError={(e) => {
@@ -401,14 +510,21 @@ const TeamMemberDetail: React.FC<TeamMemberDetailProps> = ({ memberId, memberDat
}} }}
/> />
<div className="flex-1"> <div className="flex-1">
<div <div
className="inline-flex items-center px-2 py-1 rounded text-xs font-medium mb-2" className="inline-flex items-center px-2 py-1 rounded text-xs font-medium mb-2"
style={{ backgroundColor: '#e64838', color: 'white' }} style={{ backgroundColor: '#e64838', color: 'white' }}
> >
{award.year} {award.year}
</div> </div>
<h4 className="text-base font-medium mb-2" style={{ color: '#012068' }}>{award.title}</h4> <h4
<p className="text-sm leading-relaxed" style={{ color: '#333' }}>{award.description}</p> className="text-base font-medium mb-2"
style={{ color: '#012068' }}
>
{award.title}
</h4>
<p className="text-sm leading-relaxed" style={{ color: '#333' }}>
{award.description}
</p>
</div> </div>
</div> </div>
</div> </div>