Service tab update
This commit is contained in:
@ -3,13 +3,14 @@
|
||||
import React, { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
|
||||
const Header = () => {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const [isServicesOpen, setIsServicesOpen] = useState(false);
|
||||
const [isMobileServicesOpen, setIsMobileServicesOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
|
||||
const closeAllMenus = () => {
|
||||
setIsMenuOpen(false);
|
||||
@ -17,7 +18,27 @@ const Header = () => {
|
||||
setIsMobileServicesOpen(false);
|
||||
};
|
||||
|
||||
|
||||
const scrollToSection = (sectionId: string) => {
|
||||
closeAllMenus();
|
||||
|
||||
// If not on services page, navigate to it first
|
||||
if (pathname !== '/services') {
|
||||
router.push('/services');
|
||||
// Wait for navigation to complete, then scroll
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById(sectionId);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}, 100);
|
||||
} else {
|
||||
// Already on services page, just scroll
|
||||
const element = document.getElementById(sectionId);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{ href: "/", label: "Home" },
|
||||
@ -99,6 +120,7 @@ const Header = () => {
|
||||
? "text-white bg-red-600"
|
||||
: "text-white hover:bg-red-600"
|
||||
} flex items-center justify-center gap-1`}
|
||||
onClick={closeAllMenus}
|
||||
>
|
||||
{item.label}
|
||||
<svg
|
||||
@ -114,13 +136,18 @@ const Header = () => {
|
||||
{/* Services Dropdown */}
|
||||
{isServicesOpen && (
|
||||
<div className="absolute top-full left-0 mt-0 w-64 bg-white shadow-lg border border-gray-200 rounded-b-md z-50">
|
||||
<Link
|
||||
href=""
|
||||
className="block px-4 py-3 text-sm font-medium text-blue-900 hover:bg-gray-100 hover:text-red-600 transition-colors"
|
||||
onClick={closeAllMenus}
|
||||
<button
|
||||
onClick={() => scrollToSection('trauma-care')}
|
||||
className="w-full text-left block px-4 py-3 text-sm font-medium text-blue-900 hover:bg-gray-100 hover:text-red-600 transition-colors border-b border-gray-100"
|
||||
>
|
||||
Trauma Care Services
|
||||
</button>
|
||||
<button
|
||||
onClick={() => scrollToSection('acute-care-surgery')}
|
||||
className="w-full text-left block px-4 py-3 text-sm font-medium text-blue-900 hover:bg-gray-100 hover:text-red-600 transition-colors"
|
||||
>
|
||||
Acute Care Surgery Services
|
||||
</Link>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -213,13 +240,20 @@ const Header = () => {
|
||||
{isMobileServicesOpen && (
|
||||
<ul className="ml-4 mt-1 space-y-1">
|
||||
<li>
|
||||
<Link
|
||||
href="/services/acute-care-surgery"
|
||||
className="block py-2.5 px-4 text-sm font-medium text-gray-700 hover:bg-gray-100 hover:text-red-600 rounded transition-colors"
|
||||
onClick={closeAllMenus}
|
||||
<button
|
||||
onClick={() => scrollToSection('trauma-care')}
|
||||
className="w-full text-left block py-2.5 px-4 text-sm font-medium text-gray-700 hover:bg-gray-100 hover:text-red-600 rounded transition-colors"
|
||||
>
|
||||
Trauma Care Services
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
onClick={() => scrollToSection('acute-care-surgery')}
|
||||
className="w-full text-left block py-2.5 px-4 text-sm font-medium text-gray-700 hover:bg-gray-100 hover:text-red-600 rounded transition-colors"
|
||||
>
|
||||
Acute Care Surgery Services
|
||||
</Link>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
|
||||
@ -6,6 +6,7 @@ interface ServiceTile {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
category: 'TRAUMA_CARE' | 'ACUTE_CARE_SURGERY';
|
||||
isActive: boolean;
|
||||
displayOrder: number;
|
||||
createdDate: string;
|
||||
@ -13,7 +14,8 @@ interface ServiceTile {
|
||||
}
|
||||
|
||||
const StatisticsTiles = () => {
|
||||
const [tiles, setTiles] = useState<ServiceTile[]>([]);
|
||||
const [traumaCareTiles, setTraumaCareTiles] = useState<ServiceTile[]>([]);
|
||||
const [acuteCareTiles, setAcuteCareTiles] = useState<ServiceTile[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
@ -25,20 +27,20 @@ const StatisticsTiles = () => {
|
||||
|
||||
if (response.ok) {
|
||||
const data: ServiceTile[] = await response.json();
|
||||
// Filter active tiles and sort by display order
|
||||
const activeTiles = data
|
||||
.filter(tile => tile.isActive)
|
||||
|
||||
// Separate tiles by category
|
||||
const traumaTiles = data
|
||||
.filter(tile => tile.isActive && tile.category === 'TRAUMA_CARE')
|
||||
.sort((a, b) => a.displayOrder - b.displayOrder);
|
||||
|
||||
if (activeTiles.length > 0) {
|
||||
setTiles(activeTiles);
|
||||
setError(false);
|
||||
} else {
|
||||
// No active tiles
|
||||
setError(true);
|
||||
}
|
||||
const acuteTiles = data
|
||||
.filter(tile => tile.isActive && tile.category === 'ACUTE_CARE_SURGERY')
|
||||
.sort((a, b) => a.displayOrder - b.displayOrder);
|
||||
|
||||
setTraumaCareTiles(traumaTiles);
|
||||
setAcuteCareTiles(acuteTiles);
|
||||
setError(false);
|
||||
} else {
|
||||
// API error
|
||||
setError(true);
|
||||
}
|
||||
} catch (err) {
|
||||
@ -54,7 +56,6 @@ const StatisticsTiles = () => {
|
||||
|
||||
// Function to parse description and convert to bullet points (comma-separated)
|
||||
const parseDescription = (description: string) => {
|
||||
// Split by commas and filter out empty strings
|
||||
const points = description
|
||||
.split(',')
|
||||
.map(point => point.trim())
|
||||
@ -66,19 +67,19 @@ const StatisticsTiles = () => {
|
||||
return (
|
||||
<section className="py-12 sm:py-16" style={{ backgroundColor: '#f4f4f4' }}>
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h2
|
||||
className="text-3xl sm:text-4xl font-bold text-center mb-12 sm:mb-16"
|
||||
style={{ color: '#012068' }}
|
||||
>
|
||||
Our Trauma Care Services
|
||||
</h2>
|
||||
|
||||
{loading ? (
|
||||
// Loading state
|
||||
<div className="flex justify-center items-center py-12">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
||||
</div>
|
||||
) : error || tiles.length === 0 ? (
|
||||
) : error ? (
|
||||
// Error state
|
||||
<div className="text-center py-8">
|
||||
<p className="text-gray-600 text-base sm:text-lg">
|
||||
Unable to load services. Please check back later.
|
||||
</p>
|
||||
</div>
|
||||
) : traumaCareTiles.length === 0 && acuteCareTiles.length === 0 ? (
|
||||
// No services available
|
||||
<div className="text-center py-8">
|
||||
<p className="text-gray-600 text-base sm:text-lg">
|
||||
@ -86,34 +87,87 @@ const StatisticsTiles = () => {
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
// Display services one after another
|
||||
<div className="space-y-8">
|
||||
{tiles.map((tile, index) => (
|
||||
<div key={tile.id} className="text-left">
|
||||
<h3
|
||||
className="text-xl sm:text-2xl font-bold mb-4 pb-2 border-b-2 inline-block"
|
||||
style={{ color: '#012068', borderColor: '#012068' }}
|
||||
<>
|
||||
{/* Trauma Care Section */}
|
||||
{traumaCareTiles.length > 0 && (
|
||||
<div id="trauma-care" className="mb-16 scroll-mt-20">
|
||||
<h2
|
||||
className="text-3xl sm:text-4xl font-bold text-center mb-12 sm:mb-16"
|
||||
style={{ color: '#012068' }}
|
||||
>
|
||||
{tile.title}
|
||||
</h3>
|
||||
<ul className="space-y-2.5 mt-4">
|
||||
{parseDescription(tile.description).map((point, idx) => (
|
||||
<li
|
||||
key={idx}
|
||||
className="text-sm sm:text-base leading-relaxed flex items-start"
|
||||
style={{ color: '#333' }}
|
||||
>
|
||||
<span
|
||||
className="inline-block w-1.5 h-1.5 rounded-full mt-2 mr-3 flex-shrink-0"
|
||||
style={{ backgroundColor: '#012068' }}
|
||||
></span>
|
||||
<span>{point}</span>
|
||||
</li>
|
||||
Our Trauma Care Services
|
||||
</h2>
|
||||
|
||||
<div className="space-y-8">
|
||||
{traumaCareTiles.map((tile) => (
|
||||
<div key={tile.id} className="text-left">
|
||||
<h3
|
||||
className="text-xl sm:text-2xl font-bold mb-4 pb-2 border-b-2 inline-block"
|
||||
style={{ color: '#012068', borderColor: '#012068' }}
|
||||
>
|
||||
{tile.title}
|
||||
</h3>
|
||||
<ul className="space-y-2.5 mt-4">
|
||||
{parseDescription(tile.description).map((point, idx) => (
|
||||
<li
|
||||
key={idx}
|
||||
className="text-sm sm:text-base leading-relaxed flex items-start"
|
||||
style={{ color: '#333' }}
|
||||
>
|
||||
<span
|
||||
className="inline-block w-1.5 h-1.5 rounded-full mt-2 mr-3 flex-shrink-0"
|
||||
style={{ backgroundColor: '#012068' }}
|
||||
></span>
|
||||
<span>{point}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Acute Care Surgery Section */}
|
||||
{acuteCareTiles.length > 0 && (
|
||||
<div id="acute-care-surgery" className="scroll-mt-20">
|
||||
<h2
|
||||
className="text-3xl sm:text-4xl font-bold text-center mb-12 sm:mb-16"
|
||||
style={{ color: '#012068' }}
|
||||
>
|
||||
Acute Care Surgery Services
|
||||
</h2>
|
||||
|
||||
<div className="space-y-8">
|
||||
{acuteCareTiles.map((tile) => (
|
||||
<div key={tile.id} className="text-left">
|
||||
<h3
|
||||
className="text-xl sm:text-2xl font-bold mb-4 pb-2 border-b-2 inline-block"
|
||||
style={{ color: '#012068', borderColor: '#012068' }}
|
||||
>
|
||||
{tile.title}
|
||||
</h3>
|
||||
<ul className="space-y-2.5 mt-4">
|
||||
{parseDescription(tile.description).map((point, idx) => (
|
||||
<li
|
||||
key={idx}
|
||||
className="text-sm sm:text-base leading-relaxed flex items-start"
|
||||
style={{ color: '#333' }}
|
||||
>
|
||||
<span
|
||||
className="inline-block w-1.5 h-1.5 rounded-full mt-2 mr-3 flex-shrink-0"
|
||||
style={{ backgroundColor: '#012068' }}
|
||||
></span>
|
||||
<span>{point}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -19,12 +19,14 @@ import { upcomingEventsService, UpcomingEvent } from '../../services/upcomingEve
|
||||
const AcademicResearch: React.FC = () => {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [courses, setCourses] = useState<Course[]>([]);
|
||||
const [pastCourses, setPastCourses] = useState<Course[]>([]);
|
||||
const [upcomingEvents, setUpcomingEvents] = useState<UpcomingEvent[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [selectedCategory, setSelectedCategory] = useState<string>('All');
|
||||
const [searchQuery, setSearchQuery] = useState<string>('');
|
||||
const [activeTab, setActiveTab] = useState<'education' | 'research'>('education');
|
||||
const [courseTab, setCourseTab] = useState<'active' | 'past'>('active');
|
||||
|
||||
const categories = ['All', 'Certification', 'Training', 'Workshop', 'Fellowship'];
|
||||
|
||||
@ -98,12 +100,14 @@ const AcademicResearch: React.FC = () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const [fetchedCourses, fetchedEvents] = await Promise.all([
|
||||
const [fetchedActiveCourses, fetchedPastCourses, fetchedEvents] = await Promise.all([
|
||||
educationService.getActiveCourses(),
|
||||
educationService.getPastCourses(),
|
||||
upcomingEventsService.getActiveUpcomingEvents()
|
||||
]);
|
||||
|
||||
setCourses(fetchedCourses);
|
||||
setCourses(fetchedActiveCourses);
|
||||
setPastCourses(fetchedPastCourses);
|
||||
setUpcomingEvents(fetchedEvents);
|
||||
} catch (err) {
|
||||
setError('Failed to load courses and events. Please try again later.');
|
||||
@ -117,7 +121,7 @@ const AcademicResearch: React.FC = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const filteredCourses = courses.filter(course => {
|
||||
const filteredCourses = (courseTab === 'active' ? courses : pastCourses).filter(course => {
|
||||
const matchesCategory = selectedCategory === 'All' || course.category === selectedCategory;
|
||||
const matchesSearch = !searchQuery.trim() ||
|
||||
course.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
@ -226,15 +230,15 @@ const AcademicResearch: React.FC = () => {
|
||||
{/* Education & Training Tab Content */}
|
||||
{activeTab === 'education' && (
|
||||
<>
|
||||
{/* Upcoming Training Section */}
|
||||
{/* Upcoming Training Section - NO FALLBACK */}
|
||||
<section className="py-12" style={{ backgroundColor: '#fff' }}>
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<h2 className="text-3xl font-bold mb-8 text-center" style={{ color: '#012068' }}>
|
||||
Upcoming Training Programs
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{upcomingEvents.length > 0 ? (
|
||||
upcomingEvents.map((event) => (
|
||||
{upcomingEvents.length > 0 ? (
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{upcomingEvents.map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
className="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300 border-l-4"
|
||||
@ -255,62 +259,13 @@ const AcademicResearch: React.FC = () => {
|
||||
{event.description}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<>
|
||||
<div className="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300 border-l-4" style={{ borderLeftColor: '#012068' }}>
|
||||
<div className="flex items-center mb-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-bold" style={{ color: '#012068' }}>
|
||||
Simulation-based Team Drills
|
||||
</h3>
|
||||
<div className="flex items-center text-sm">
|
||||
<Calendar className="w-4 h-4 mr-1" style={{ color: '#e64838' }} />
|
||||
<span>Q3 2025</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed" style={{ color: '#666' }}>
|
||||
Hands-on simulation training designed to improve team coordination and emergency response in high-pressure trauma situations.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300 border-l-4" style={{ borderLeftColor: '#012068' }}>
|
||||
<div className="flex items-center mb-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-bold" style={{ color: '#012068' }}>
|
||||
Online Webinar Series
|
||||
</h3>
|
||||
<div className="flex items-center text-sm">
|
||||
<Calendar className="w-4 h-4 mr-1" style={{ color: '#e64838' }} />
|
||||
<span>Monthly Sessions</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed" style={{ color: '#666' }}>
|
||||
Monthly online sessions covering trauma ethics, young doctor support, and professional development in emergency medicine.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300 border-l-4" style={{ borderLeftColor: '#012068' }}>
|
||||
<div className="flex items-center mb-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-bold" style={{ color: '#012068' }}>
|
||||
Community Education
|
||||
</h3>
|
||||
<div className="flex items-center text-sm">
|
||||
<Calendar className="w-4 h-4 mr-1" style={{ color: '#e64838' }} />
|
||||
<span>Ongoing</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed" style={{ color: '#666' }}>
|
||||
Road safety fairs and school education sessions to promote trauma prevention and basic first aid awareness in the community.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-gray-500 text-lg">No upcoming training programs at the moment.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -320,6 +275,43 @@ const AcademicResearch: React.FC = () => {
|
||||
<h2 className="text-3xl font-bold mb-8 text-center" style={{ color: '#012068' }}>
|
||||
Available Courses
|
||||
</h2>
|
||||
|
||||
{/* Course Tabs - Active/Past */}
|
||||
<div className="flex justify-center mb-8 border-b-2" style={{ borderColor: '#e5e7eb' }}>
|
||||
<button
|
||||
onClick={() => {
|
||||
setCourseTab('active');
|
||||
setSelectedCategory('All');
|
||||
setSearchQuery('');
|
||||
}}
|
||||
className={`pb-4 px-8 font-semibold transition-all duration-200 relative ${
|
||||
courseTab === 'active' ? 'border-b-4' : ''
|
||||
}`}
|
||||
style={{
|
||||
color: courseTab === 'active' ? '#012068' : '#666',
|
||||
borderColor: courseTab === 'active' ? '#e64838' : 'transparent'
|
||||
}}
|
||||
>
|
||||
Active Courses ({courses.length})
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setCourseTab('past');
|
||||
setSelectedCategory('All');
|
||||
setSearchQuery('');
|
||||
}}
|
||||
className={`pb-4 px-8 font-semibold transition-all duration-200 relative ${
|
||||
courseTab === 'past' ? 'border-b-4' : ''
|
||||
}`}
|
||||
style={{
|
||||
color: courseTab === 'past' ? '#012068' : '#666',
|
||||
borderColor: courseTab === 'past' ? '#e64838' : 'transparent'
|
||||
}}
|
||||
>
|
||||
Past Courses ({pastCourses.length})
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4 mb-8">
|
||||
{/* Category Filter */}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
@ -368,7 +360,7 @@ const AcademicResearch: React.FC = () => {
|
||||
<p className="text-sm text-gray-600">
|
||||
{filteredCourses.length === 0
|
||||
? 'No courses found matching your criteria.'
|
||||
: `Showing ${filteredCourses.length} of ${courses.length} course${courses.length !== 1 ? 's' : ''}`
|
||||
: `Showing ${filteredCourses.length} of ${courseTab === 'active' ? courses.length : pastCourses.length} course${(courseTab === 'active' ? courses.length : pastCourses.length) !== 1 ? 's' : ''}`
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
@ -384,7 +376,9 @@ const AcademicResearch: React.FC = () => {
|
||||
<p className="text-gray-500 text-lg mb-4">
|
||||
{searchQuery.trim() || selectedCategory !== 'All'
|
||||
? 'No courses match your search criteria.'
|
||||
: 'No courses available at the moment.'
|
||||
: courseTab === 'active'
|
||||
? 'No active courses available at the moment.'
|
||||
: 'No past courses available.'
|
||||
}
|
||||
</p>
|
||||
{(searchQuery.trim() || selectedCategory !== 'All') && (
|
||||
@ -407,8 +401,8 @@ const AcademicResearch: React.FC = () => {
|
||||
href={`/education-training/course-detail?id=${course.id}`}
|
||||
className="group bg-white rounded-lg overflow-hidden border border-gray-300 hover:shadow-xl transition-all duration-300 flex flex-col h-full cursor-pointer"
|
||||
>
|
||||
{/* Image */}
|
||||
<div className="relative h-48 overflow-hidden flex-shrink-0">
|
||||
{/* Image - FIXED */}
|
||||
<div className="relative h-48 w-full overflow-hidden flex-shrink-0">
|
||||
<Image
|
||||
src={course.image}
|
||||
alt={course.title}
|
||||
|
||||
@ -335,20 +335,20 @@ const EventDetail = () => {
|
||||
|
||||
<div className="py-6">
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
{/* Image Section */}
|
||||
<div className="bg-white shadow-lg rounded-md overflow-hidden mb-6" style={{ borderColor: '#012068' }}>
|
||||
{/* Image Section - FIXED */}
|
||||
<div className="bg-white shadow-lg rounded-lg overflow-hidden mb-6">
|
||||
<div className="relative">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-1">
|
||||
<div className="md:col-span-2 relative overflow-hidden">
|
||||
<div className="md:col-span-2 relative overflow-hidden h-64 md:h-96">
|
||||
<img
|
||||
src={mainImage}
|
||||
alt={eventData.title}
|
||||
className="w-full h-auto hover:scale-105 transition-transform duration-300"
|
||||
className="w-full h-full object-cover hover:scale-105 transition-transform duration-300"
|
||||
/>
|
||||
</div>
|
||||
<div className="hidden md:flex md:flex-col gap-1">
|
||||
{galleryImages.map((image, index) => (
|
||||
<div key={index} className="relative overflow-hidden flex-1">
|
||||
<div key={index} className="relative overflow-hidden flex-1 min-h-0">
|
||||
<img
|
||||
src={image}
|
||||
alt={`Gallery ${index + 1}`}
|
||||
@ -362,7 +362,7 @@ const EventDetail = () => {
|
||||
</div>
|
||||
|
||||
{/* Event Details Section */}
|
||||
<div className="bg-white shadow-lg rounded-lg overflow-hidden" style={{ borderColor: '#012068' }}>
|
||||
<div className="bg-white shadow-lg rounded-lg overflow-hidden">
|
||||
<div className="p-4 md:p-8">
|
||||
{/* Header Section */}
|
||||
<div className="flex flex-col sm:flex-row justify-between items-start gap-4 mb-6">
|
||||
@ -373,7 +373,7 @@ const EventDetail = () => {
|
||||
<h1 className="text-2xl md:text-3xl font-medium leading-tight mb-3" style={{ color: '#012068' }}>
|
||||
{eventData.title}
|
||||
</h1>
|
||||
{/* Learn More Button - THIS IS THE NEW ADDITION */}
|
||||
{/* Learn More Button */}
|
||||
{eventData.learnMoreLink && eventData.learnMoreLink.trim() !== '' && (
|
||||
<button
|
||||
onClick={handleLearnMore}
|
||||
@ -428,11 +428,11 @@ const EventDetail = () => {
|
||||
{/* About Section */}
|
||||
<div className="space-y-4 mb-8">
|
||||
<h3 className="text-lg font-medium" style={{ color: '#012068' }}>About This Event</h3>
|
||||
<p className="text-md leading-relaxed" style={{ color: '#333' }}>{description.overview}</p>
|
||||
<p className="text-sm leading-relaxed" style={{ color: '#333' }}>{description.overview}</p>
|
||||
|
||||
{description.highlights.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-md font-medium mb-2" style={{ color: '#012068' }}>Event Highlights</h4>
|
||||
<h4 className="text-sm font-medium mb-2" style={{ color: '#012068' }}>Event Highlights</h4>
|
||||
<ul className="text-sm space-y-1" style={{ color: '#333' }}>
|
||||
{description.highlights.map((highlight, index) => (
|
||||
<li key={index}>• {highlight}</li>
|
||||
|
||||
@ -299,7 +299,7 @@ const EventsSection = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right - Past Events List with Scroller */}
|
||||
{/* Right - Past Events List with Scroller - FIXED */}
|
||||
<div className="lg:col-span-1">
|
||||
<h3 className="text-xl font-semibold mb-4" style={{ color: '#012068' }}>Past Events</h3>
|
||||
{pastEvents.length === 0 ? (
|
||||
@ -314,7 +314,8 @@ const EventsSection = () => {
|
||||
className="bg-white border border-gray-100 rounded-lg overflow-hidden cursor-pointer hover:shadow-lg transition-shadow flex-shrink-0"
|
||||
onClick={() => router.push(`/event-detail/${event.id}`)}
|
||||
>
|
||||
<div className="h-24">
|
||||
{/* FIXED: Added explicit height */}
|
||||
<div className="h-24 w-full overflow-hidden">
|
||||
<img
|
||||
src={event.mainImage}
|
||||
alt={event.title}
|
||||
|
||||
@ -76,7 +76,31 @@ class EducationService {
|
||||
return this.transformApiCoursesToCourses(apiCourses);
|
||||
} catch (error) {
|
||||
console.error('Error fetching courses:', error);
|
||||
return this.getFallbackCourses();
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getPastCourses(): Promise<Course[]> {
|
||||
try {
|
||||
const response = await fetch(`${this.apiBaseUrl}/api/courses/past`, {
|
||||
cache: 'no-store'
|
||||
});
|
||||
|
||||
// If endpoint doesn't exist or returns 400/404, return empty array
|
||||
if (!response.ok) {
|
||||
if (response.status === 400 || response.status === 404) {
|
||||
console.log('Past courses endpoint not available, returning empty array');
|
||||
return [];
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const apiCourses: ApiCourse[] = await response.json();
|
||||
return this.transformApiCoursesToCourses(apiCourses);
|
||||
} catch (error) {
|
||||
console.error('Error fetching past courses:', error);
|
||||
// Return empty array instead of throwing error
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,101 +178,6 @@ class EducationService {
|
||||
];
|
||||
return defaultImages[Math.floor(Math.random() * defaultImages.length)];
|
||||
}
|
||||
|
||||
private getFallbackCourses(): Course[] {
|
||||
return [
|
||||
{
|
||||
id: '1',
|
||||
title: "ATLS® (Advanced Trauma Life Support)",
|
||||
description: "Eligibility: MBBS + internship complete. Last Course: Aug 31 – Sep 2, 2023 (60 doctors certified). Next Schedule: [#Incomplete – Date TBD]",
|
||||
duration: "3 Days",
|
||||
seats: 60,
|
||||
category: "Certification",
|
||||
level: "Professional",
|
||||
image: "https://images.unsplash.com/photo-1576091160550-2173dba999ef?w=400&h=200&fit=crop&crop=center",
|
||||
instructor: "Trauma Faculty Team",
|
||||
price: "N/A",
|
||||
startDate: "2023-08-31",
|
||||
eligibility: ["MBBS + internship complete"],
|
||||
objectives: ["Advanced trauma life support skills", "Emergency trauma management"]
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: "ATCN® (Advanced Trauma Care for Nurses)",
|
||||
description: "First Course: Apr 11-13, 2024 (manikin-based training). Participants: 40 critical care nurses from CMC and partner hospitals. Next Batch: [#Incomplete – Date TBD]",
|
||||
duration: "3 Days",
|
||||
seats: 40,
|
||||
category: "Training",
|
||||
level: "Professional",
|
||||
image: "https://images.unsplash.com/photo-1559757175-0eb30cd8c063?w=400&h=300&fit=crop&crop=center",
|
||||
instructor: "Nursing Faculty Team",
|
||||
price: "N/A",
|
||||
startDate: "2024-04-11",
|
||||
eligibility: ["Registered Nurse", "Critical care experience preferred"],
|
||||
objectives: ["Advanced trauma nursing skills", "Manikin-based training proficiency"]
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: "Trauma First Responder Program",
|
||||
description: "Partners: RCPSG Hope Foundation, local colleges. Locations: Walajapet, Auxilium College—250 students trained. Curriculum: CPR, airway support, bleeding control, scene assessment.",
|
||||
duration: "Varies",
|
||||
seats: 250,
|
||||
category: "Workshop",
|
||||
level: "Beginner",
|
||||
image: "https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=400&h=300&fit=crop&crop=center",
|
||||
instructor: "Community Trainers",
|
||||
price: "N/A",
|
||||
startDate: "2023-01-01",
|
||||
eligibility: ["Students", "Community members"],
|
||||
objectives: ["CPR proficiency", "Basic trauma response", "Scene safety assessment"]
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: "FNB in Trauma Surgery",
|
||||
description: "3-year structured training program in acute surgery, ICU management, and research. Open to MS-qualified surgeons seeking specialized trauma surgery expertise.",
|
||||
duration: "3 Years",
|
||||
seats: 8,
|
||||
category: "Certification",
|
||||
level: "Advanced",
|
||||
image: "https://images.unsplash.com/photo-1582750433449-648ed127bb54?w=400&h=300&fit=crop&crop=center",
|
||||
instructor: "Senior Trauma Surgeons",
|
||||
price: "N/A",
|
||||
startDate: "2025-07-01",
|
||||
eligibility: ["MS qualification in Surgery", "Valid medical license"],
|
||||
objectives: ["Advanced trauma surgery skills", "ICU management", "Research methodology"]
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: "Observerships & Electives",
|
||||
description: "4-8 week clinical blocks for national and international residents. Includes ATLS® course access and hands-on trauma experience. Application by email required.",
|
||||
duration: "4-8 Weeks",
|
||||
seats: 20,
|
||||
category: "Training",
|
||||
level: "Intermediate",
|
||||
image: "https://images.unsplash.com/photo-1551601651-2a8555f1a136?w=400&h=300&fit=crop&crop=center",
|
||||
instructor: "Clinical Faculty",
|
||||
price: "N/A",
|
||||
startDate: "2025-01-15",
|
||||
eligibility: ["Medical residency status", "Valid medical credentials"],
|
||||
objectives: ["Clinical observation skills", "Hands-on trauma experience", "ATLS certification"]
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: "Nursing Skills Lab",
|
||||
description: "Trauma-focused skills laboratory sessions open quarterly (Q2, Q4). Includes chest tube insertion, airway management drills, and EFAST simulation training.",
|
||||
duration: "2 Days",
|
||||
seats: 30,
|
||||
category: "Workshop",
|
||||
level: "Intermediate",
|
||||
image: "https://images.unsplash.com/photo-1559757148-5c350d0d3c56?w=400&h=300&fit=crop&crop=center",
|
||||
instructor: "Nursing Skills Faculty",
|
||||
price: "N/A",
|
||||
startDate: "2025-04-01",
|
||||
eligibility: ["Licensed nurse", "Basic trauma knowledge"],
|
||||
objectives: ["Chest tube insertion", "Airway management", "EFAST simulation"]
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export const educationService = new EducationService();
|
||||
Reference in New Issue
Block a user