Changes on 19-11-2025
This commit is contained in:
@ -7,18 +7,24 @@ import { usePathname } from "next/navigation";
|
||||
|
||||
const Header = () => {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const [isServicesOpen, setIsServicesOpen] = useState(false);
|
||||
const [isMobileServicesOpen, setIsMobileServicesOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
const closeAllMenus = () => {
|
||||
setIsMenuOpen(false);
|
||||
setIsServicesOpen(false);
|
||||
setIsMobileServicesOpen(false);
|
||||
};
|
||||
|
||||
|
||||
|
||||
const menuItems = [
|
||||
{ href: "/", label: "Home" },
|
||||
{ href: "/about", label: "About" },
|
||||
{ href: "/teamMember", label: "Our Team" },
|
||||
{ href: "/education-training", label: "Academics & Research" },
|
||||
{ href: "/services", label: "Services" },
|
||||
{ href: "/services", label: "Services", hasDropdown: true },
|
||||
{ href: "/events", label: "Events" },
|
||||
{ href: "/blogs", label: "Blogs" },
|
||||
{ href: "/career", label: "Career" },
|
||||
@ -77,6 +83,50 @@ const Header = () => {
|
||||
{menuItems.map((item, idx) => {
|
||||
const isActive = pathname === item.href ||
|
||||
(item.href !== "/" && pathname.startsWith(item.href));
|
||||
|
||||
if (item.hasDropdown) {
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className="relative flex-1"
|
||||
onMouseEnter={() => setIsServicesOpen(true)}
|
||||
onMouseLeave={() => setIsServicesOpen(false)}
|
||||
>
|
||||
<Link
|
||||
href="/services"
|
||||
className={`font-medium text-sm xl:text-[15px] whitespace-nowrap px-4 xl:px-5 py-3.5 transition-colors w-full ${
|
||||
isActive
|
||||
? "text-white bg-red-600"
|
||||
: "text-white hover:bg-red-600"
|
||||
} flex items-center justify-center gap-1`}
|
||||
>
|
||||
{item.label}
|
||||
<svg
|
||||
className={`w-4 h-4 transition-transform ${isServicesOpen ? "rotate-180" : ""}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</Link>
|
||||
|
||||
{/* 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="/services/acute-care-surgery"
|
||||
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}
|
||||
>
|
||||
Acute Care Surgery Services
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={idx}
|
||||
@ -95,7 +145,7 @@ const Header = () => {
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Mobile menu button - More visible */}
|
||||
{/* Mobile menu button */}
|
||||
<button
|
||||
className="lg:hidden p-3 text-white hover:bg-red-600 transition-colors w-full flex items-center justify-between"
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
@ -136,6 +186,47 @@ const Header = () => {
|
||||
{menuItems.map((item, idx) => {
|
||||
const isActive = pathname === item.href ||
|
||||
(item.href !== "/" && pathname.startsWith(item.href));
|
||||
|
||||
if (item.hasDropdown) {
|
||||
return (
|
||||
<li key={idx}>
|
||||
<button
|
||||
className={`w-full text-left font-medium py-3 px-4 transition-colors rounded text-sm sm:text-base flex items-center justify-between ${
|
||||
isActive
|
||||
? "bg-red-600 text-white"
|
||||
: "text-blue-900 hover:bg-gray-100 hover:text-red-600"
|
||||
}`}
|
||||
onClick={() => setIsMobileServicesOpen(!isMobileServicesOpen)}
|
||||
>
|
||||
{item.label}
|
||||
<svg
|
||||
className={`w-4 h-4 transition-transform ${isMobileServicesOpen ? "rotate-180" : ""}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Mobile Services Submenu */}
|
||||
{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}
|
||||
>
|
||||
Acute Care Surgery Services
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<li key={idx}>
|
||||
<Link
|
||||
|
||||
@ -64,10 +64,10 @@ const StatisticsTiles = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="py-8 sm:py-12" style={{ backgroundColor: '#f4f4f4' }}>
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<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-2xl sm:text-3xl font-semibold text-center mb-8 sm:mb-12"
|
||||
className="text-3xl sm:text-4xl font-bold text-center mb-12 sm:mb-16"
|
||||
style={{ color: '#012068' }}
|
||||
>
|
||||
Our Trauma Care Services
|
||||
@ -86,33 +86,31 @@ const StatisticsTiles = () => {
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
// Display tiles
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 lg:gap-6">
|
||||
// Display services one after another
|
||||
<div className="space-y-8">
|
||||
{tiles.map((tile, index) => (
|
||||
<div
|
||||
key={tile.id}
|
||||
className="border border-gray-300 rounded-lg p-5 h-full hover:shadow-lg transition-shadow duration-300"
|
||||
style={{ backgroundColor: '#ffffff' }}
|
||||
>
|
||||
<div className="flex flex-col h-full">
|
||||
<h3
|
||||
className="text-base sm:text-lg font-semibold mb-3 text-left"
|
||||
style={{ color: '#012068' }}
|
||||
>
|
||||
{tile.title}
|
||||
</h3>
|
||||
<ul className="list-disc pl-5 space-y-2 flex-grow text-left">
|
||||
{parseDescription(tile.description).map((point, idx) => (
|
||||
<li
|
||||
key={idx}
|
||||
className="text-sm sm:text-base leading-relaxed text-left"
|
||||
style={{ color: '#333' }}
|
||||
>
|
||||
{point}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
@ -116,20 +116,6 @@ const BlogDetail: React.FC = () => {
|
||||
target.src = '/images/default-blog-image.jpg';
|
||||
};
|
||||
|
||||
const getAuthorName = (blog: Blog) => {
|
||||
if (blog.professors && blog.professors.length > 0) {
|
||||
return blog.professors.map(prof => prof.firstName || prof.name).join(', ');
|
||||
}
|
||||
return 'Medical Team';
|
||||
};
|
||||
|
||||
const getAuthorBio = (blog: Blog) => {
|
||||
if (blog.professors && blog.professors.length > 0) {
|
||||
return `Medical professional${blog.professors.length > 1 ? 's' : ''} specializing in trauma care and mental health support.`;
|
||||
}
|
||||
return 'Our medical team consists of experienced professionals dedicated to trauma care and mental health support.';
|
||||
};
|
||||
|
||||
if (!mounted) {
|
||||
return null;
|
||||
}
|
||||
@ -286,23 +272,6 @@ const BlogDetail: React.FC = () => {
|
||||
<span>{blogData.readTime}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Author Info */}
|
||||
<div className="flex items-start space-x-4 mt-6 p-4 rounded-lg" style={{ backgroundColor: '#f4f4f4' }}>
|
||||
<div className="w-15 h-15 bg-gray-300 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span className="text-2xl font-medium" style={{ color: '#012068' }}>
|
||||
{getAuthorName(blogData).charAt(0)}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium" style={{ color: '#012068' }}>
|
||||
{getAuthorName(blogData)}
|
||||
</h3>
|
||||
<p className="text-sm mt-1" style={{ color: '#666' }}>
|
||||
{getAuthorBio(blogData)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Share Buttons */}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Calendar, MapPin, Clock, Users, Star, Share2, ArrowLeft, ChevronRight } from 'lucide-react';
|
||||
import { Calendar, MapPin, Clock, Users, Star, Share2, ArrowLeft, ChevronRight, ExternalLink } from 'lucide-react';
|
||||
import { useRouter, useParams } from 'next/navigation';
|
||||
import Link from "next/link";
|
||||
import { eventAPI, Event } from '../../lib/api'; // Adjust path as needed
|
||||
@ -75,7 +75,7 @@ const EventDetail = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// NEW FUNCTION: Handle book seat click - redirects to admin-provided link
|
||||
// Handle book seat click - redirects to admin-provided link
|
||||
const handleBookSeat = () => {
|
||||
if (!eventData) return;
|
||||
|
||||
@ -100,6 +100,28 @@ const EventDetail = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Handle learn more click - redirects to admin-provided learn more link
|
||||
const handleLearnMore = () => {
|
||||
if (!eventData) return;
|
||||
|
||||
// Check if admin has provided a custom learn more link
|
||||
if (eventData.learnMoreLink && eventData.learnMoreLink.trim() !== '') {
|
||||
// Validate if it's a proper URL
|
||||
try {
|
||||
// If the URL doesn't start with http:// or https://, add https://
|
||||
let url = eventData.learnMoreLink;
|
||||
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||
url = 'https://' + url;
|
||||
}
|
||||
// Open in new tab
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
} catch (error) {
|
||||
console.error('Invalid learn more link:', error);
|
||||
alert('Invalid information link. Please contact the organizers.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleShare = async () => {
|
||||
if (!eventData || typeof window === 'undefined') return;
|
||||
|
||||
@ -348,9 +370,20 @@ const EventDetail = () => {
|
||||
<div className="text-xs font-medium mb-2" style={{ color: '#e64838' }}>
|
||||
{eventData.date}
|
||||
</div>
|
||||
<h1 className="text-2xl md:text-3xl font-medium leading-tight" style={{ color: '#012068' }}>
|
||||
<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 */}
|
||||
{eventData.learnMoreLink && eventData.learnMoreLink.trim() !== '' && (
|
||||
<button
|
||||
onClick={handleLearnMore}
|
||||
className="inline-flex items-center text-xs hover:underline transition-all duration-200"
|
||||
style={{ color: '#012068', opacity: 0.7 }}
|
||||
>
|
||||
<ExternalLink className="w-3 h-3 mr-1" />
|
||||
Learn More
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-left sm:text-right w-full sm:w-auto">
|
||||
<div className="text-xs mb-1" style={{ color: '#012068', opacity: 0.8 }}>From</div>
|
||||
|
||||
@ -3,68 +3,130 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import Link from "next/link";
|
||||
import { eventAPI, Event } from '../../lib/api'; // Adjust path as needed
|
||||
import { eventAPI, Event } from '../../lib/api';
|
||||
import { educationService, Course } from '../../services/educationService';
|
||||
|
||||
// Combined type for events and training programs
|
||||
type DisplayItem =
|
||||
| (Event & { type: 'event'; itemDate: Date })
|
||||
| (Course & {
|
||||
type: 'training';
|
||||
itemDate: Date;
|
||||
mainImage: string;
|
||||
date: string; // Add this field
|
||||
detail: string;
|
||||
galleryImages?: string[];
|
||||
venue?: any[]
|
||||
});
|
||||
|
||||
const MedicalEventsComponent = () => {
|
||||
const [selectedPeriod, setSelectedPeriod] = useState('Upcoming Events');
|
||||
const [activeTab, setActiveTab] = useState('Upcoming Events');
|
||||
const [upcomingEvents, setUpcomingEvents] = useState<Event[]>([]);
|
||||
const [pastEvents, setPastEvents] = useState<Event[]>([]);
|
||||
const [nextEvent, setNextEvent] = useState<Event | null>(null);
|
||||
const [upcomingItems, setUpcomingItems] = useState<DisplayItem[]>([]);
|
||||
const [pastItems, setPastItems] = useState<DisplayItem[]>([]);
|
||||
const [nextItem, setNextItem] = useState<DisplayItem | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
loadEvents();
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
const loadEvents = async () => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const [upcoming, past] = await Promise.all([
|
||||
eventAPI.getUpcomingEvents(),
|
||||
eventAPI.getPastEvents()
|
||||
const [events, trainingPrograms] = await Promise.all([
|
||||
eventAPI.getAllEvents(), // Get all events (both upcoming and past)
|
||||
educationService.getActiveCourses() // Get all training programs
|
||||
]);
|
||||
|
||||
setUpcomingEvents(upcoming);
|
||||
setPastEvents(past);
|
||||
const currentDate = new Date();
|
||||
currentDate.setHours(0, 0, 0, 0); // Set to start of day for accurate comparison
|
||||
|
||||
// Set the next event (first upcoming event)
|
||||
// Transform events with type
|
||||
const eventsWithType: DisplayItem[] = events.map(event => {
|
||||
const eventDate = new Date(event.date);
|
||||
return {
|
||||
...event,
|
||||
type: 'event' as const,
|
||||
itemDate: eventDate
|
||||
};
|
||||
});
|
||||
|
||||
// Transform training programs (courses) with type
|
||||
const trainingWithType: DisplayItem[] = trainingPrograms.map(course => {
|
||||
const courseDate = course.startDate ? new Date(course.startDate) : new Date();
|
||||
return {
|
||||
...course,
|
||||
type: 'training' as const,
|
||||
itemDate: courseDate,
|
||||
mainImage: course.image,
|
||||
detail: `${course.duration} | ${course.seats} seats available | Led by ${course.instructor}`,
|
||||
galleryImages: [], // Training programs don't have gallery images
|
||||
date: course.startDate || 'Date TBD'
|
||||
};
|
||||
});
|
||||
|
||||
// Combine all items (events + training programs)
|
||||
const allItems = [...eventsWithType, ...trainingWithType];
|
||||
|
||||
// Separate into upcoming and past based on date
|
||||
const upcoming = allItems
|
||||
.filter(item => item.itemDate >= currentDate)
|
||||
.sort((a, b) => a.itemDate.getTime() - b.itemDate.getTime());
|
||||
|
||||
const past = allItems
|
||||
.filter(item => item.itemDate < currentDate)
|
||||
.sort((a, b) => b.itemDate.getTime() - a.itemDate.getTime()); // Most recent first
|
||||
|
||||
setUpcomingItems(upcoming);
|
||||
setPastItems(past);
|
||||
|
||||
// Set the next item (first upcoming item)
|
||||
if (upcoming.length > 0) {
|
||||
setNextEvent(upcoming[0]);
|
||||
setNextItem(upcoming[0]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading events:', error);
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Filter events based on search term
|
||||
const filteredEvents = () => {
|
||||
const events = activeTab === 'Upcoming Events' ? upcomingEvents : pastEvents;
|
||||
if (!searchTerm) return events;
|
||||
// Filter items based on search term and active tab
|
||||
const filteredItems = () => {
|
||||
const items = activeTab === 'Upcoming Events' ? upcomingItems : pastItems;
|
||||
if (!searchTerm) return items;
|
||||
|
||||
return events.filter(event =>
|
||||
event.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
event.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
event.subject.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
return items.filter(item =>
|
||||
item.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
item.description.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
};
|
||||
|
||||
// Navigation function for App Router
|
||||
const navigateToEventDetail = (eventId: string | number) => {
|
||||
router.push(`/event-detail/${eventId}`);
|
||||
// Navigation function
|
||||
const navigateToDetail = (item: DisplayItem) => {
|
||||
if (item.type === 'event') {
|
||||
router.push(`/event-detail/${item.id}`);
|
||||
} else {
|
||||
// For training programs, navigate to course detail
|
||||
router.push(`/education-training/course-detail?id=${item.id}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Format price display from fees
|
||||
const formatPrice = (event: Event) => {
|
||||
if (event.fee && event.fee.length > 0) {
|
||||
return `₹${event.fee[0].cost} per seat`;
|
||||
// Format price display
|
||||
const formatPrice = (item: DisplayItem) => {
|
||||
if (item.type === 'event') {
|
||||
if (item.fee && item.fee.length > 0) {
|
||||
return `₹${item.fee[0].cost} per seat`;
|
||||
}
|
||||
return '₹1,800 per seat';
|
||||
} else {
|
||||
// Training program
|
||||
return item.price !== 'N/A' ? item.price : 'Contact for pricing';
|
||||
}
|
||||
return '₹1,800 per seat'; // fallback price
|
||||
};
|
||||
|
||||
// Get safe image URL with fallback
|
||||
@ -72,8 +134,8 @@ const MedicalEventsComponent = () => {
|
||||
return imageUrl && imageUrl.trim() !== '' ? imageUrl : fallback;
|
||||
};
|
||||
|
||||
// Get gallery images with fallbacks
|
||||
const getGalleryImages = (galleryImages: string[] | undefined) => {
|
||||
// Get gallery images with fallbacks - only for events, not training programs
|
||||
const getGalleryImages = (item: DisplayItem) => {
|
||||
const fallbackImages = [
|
||||
'https://images.unsplash.com/photo-1551601651-2a8555f1a136?w=200&h=100&fit=crop',
|
||||
'https://images.unsplash.com/photo-1582750433449-648ed127bb54?w=200&h=100&fit=crop',
|
||||
@ -81,6 +143,13 @@ const MedicalEventsComponent = () => {
|
||||
'https://images.unsplash.com/photo-1551601651-2a8555f1a136?w=200&h=100&fit=crop'
|
||||
];
|
||||
|
||||
if (item.type === 'training') {
|
||||
// Training programs don't have gallery images
|
||||
return [];
|
||||
}
|
||||
|
||||
const galleryImages = item.galleryImages;
|
||||
|
||||
if (!galleryImages || galleryImages.length === 0) {
|
||||
return fallbackImages;
|
||||
}
|
||||
@ -97,7 +166,7 @@ const MedicalEventsComponent = () => {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="text-lg" style={{ color: '#012068' }}>Loading events...</div>
|
||||
<div className="text-lg" style={{ color: '#012068' }}>Loading events and training programs...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -129,7 +198,7 @@ const MedicalEventsComponent = () => {
|
||||
</h1>
|
||||
</div>
|
||||
<p className="text-sm md:text-base max-w-2xl leading-relaxed" style={{ color: '#333' }}>
|
||||
Discover upcoming medical conferences, workshops, and professional development events
|
||||
Discover upcoming medical conferences, workshops, training programs and professional development events
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -164,7 +233,7 @@ const MedicalEventsComponent = () => {
|
||||
<div className="relative w-full sm:w-64">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search an event..."
|
||||
placeholder="Search events or training programs..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="border rounded-lg px-4 py-2 pl-4 pr-10 text-sm focus:outline-none w-full"
|
||||
@ -184,20 +253,34 @@ const MedicalEventsComponent = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Next Event Hero Section */}
|
||||
{nextEvent && (
|
||||
{/* Next Item Hero Section */}
|
||||
{nextItem && (
|
||||
<div className="mb-8">
|
||||
<h2 className="text-lg font-medium mb-4" style={{ color: '#012068' }}>Next Event</h2>
|
||||
<h2 className="text-lg font-medium mb-4" style={{ color: '#012068' }}>
|
||||
Next {nextItem.type === 'training' ? 'Training Program' : 'Event'}
|
||||
</h2>
|
||||
<div
|
||||
className="bg-white border border-gray-100 rounded-lg overflow-hidden cursor-pointer hover:shadow-lg transition-shadow"
|
||||
onClick={() => navigateToEventDetail(nextEvent.id)}
|
||||
onClick={() => navigateToDetail(nextItem)}
|
||||
>
|
||||
<div className="relative h-48 md:h-64">
|
||||
<img
|
||||
src={getSafeImageUrl(nextEvent.mainImage, "https://images.unsplash.com/photo-1576091160550-2173dba999ef?w=800&h=300&fit=crop")}
|
||||
alt={nextEvent.title}
|
||||
src={getSafeImageUrl(nextItem.mainImage, "https://images.unsplash.com/photo-1576091160550-2173dba999ef?w=800&h=300&fit=crop")}
|
||||
alt={nextItem.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
{/* Type Badge */}
|
||||
<div className="absolute top-4 right-4">
|
||||
<span
|
||||
className="px-3 py-1 rounded text-xs font-medium"
|
||||
style={{
|
||||
backgroundColor: nextItem.type === 'event' ? '#e64838' : '#012068',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
{nextItem.type === 'event' ? 'Event' : 'Training Program'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2">
|
||||
<div className="w-2 h-2 bg-white rounded-full shadow"></div>
|
||||
<div className="w-2 h-2 bg-gray-400 rounded-full"></div>
|
||||
@ -207,26 +290,30 @@ const MedicalEventsComponent = () => {
|
||||
<div className="p-4 md:p-6">
|
||||
<div className="flex flex-col lg:flex-row lg:justify-between gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="text-xs font-medium mb-3" style={{ color: '#e64838' }}>{nextEvent.date}</div>
|
||||
<div className="text-xs font-medium mb-3" style={{ color: '#e64838' }}>
|
||||
{nextItem.type === 'event' ? nextItem.date : (nextItem.date || 'Date TBD')}
|
||||
</div>
|
||||
<div className="text-lg md:text-xl font-medium mb-2" style={{ color: '#012068' }}>
|
||||
{nextEvent.title}
|
||||
{nextItem.title}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-1" style={{ color: '#333' }}>
|
||||
{nextEvent.description}
|
||||
{nextItem.description}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-4" style={{ color: '#333' }}>
|
||||
{nextEvent.detail}
|
||||
{nextItem.detail || (nextItem.type === 'event' ? nextItem.detail : '')}
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<div
|
||||
className="text-xs cursor-pointer hover:underline"
|
||||
style={{ color: '#012068' }}
|
||||
>
|
||||
Share Event
|
||||
</div>
|
||||
<div className="text-xs" style={{ color: '#012068' }}>
|
||||
📍 {nextEvent.venue?.[0]?.address || 'Convention Center, Medical District'}
|
||||
Share {nextItem.type === 'training' ? 'Training Program' : 'Event'}
|
||||
</div>
|
||||
{nextItem.type === 'event' && (
|
||||
<div className="text-xs" style={{ color: '#012068' }}>
|
||||
📍 {nextItem.venue?.[0]?.address || 'Convention Center, Medical District'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-left lg:text-right">
|
||||
@ -238,15 +325,17 @@ const MedicalEventsComponent = () => {
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
console.log('Book seat clicked');
|
||||
navigateToDetail(nextItem);
|
||||
}}
|
||||
>
|
||||
Book Your Seat
|
||||
{nextItem.type === 'training' ? 'Register Now' : 'Book Your Seat'}
|
||||
</button>
|
||||
<div className="text-sm font-medium" style={{ color: '#e64838' }}>{formatPrice(nextEvent)}</div>
|
||||
<div className="text-xs mt-1" style={{ color: '#333' }}>
|
||||
Early bird discount available
|
||||
</div>
|
||||
<div className="text-sm font-medium" style={{ color: '#e64838' }}>{formatPrice(nextItem)}</div>
|
||||
{nextItem.type === 'event' && (
|
||||
<div className="text-xs mt-1" style={{ color: '#333' }}>
|
||||
Early bird discount available
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -272,7 +361,7 @@ const MedicalEventsComponent = () => {
|
||||
color: activeTab === 'Upcoming Events' ? '#012068' : '#012068'
|
||||
}}
|
||||
>
|
||||
Upcoming Events ({upcomingEvents.length})
|
||||
Upcoming Events ({upcomingItems.length})
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('Past Events')}
|
||||
@ -286,84 +375,103 @@ const MedicalEventsComponent = () => {
|
||||
color: activeTab === 'Past Events' ? '#012068' : '#012068'
|
||||
}}
|
||||
>
|
||||
Past Events ({pastEvents.length})
|
||||
Past Events ({pastItems.length})
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Event Rows */}
|
||||
{/* Item Rows */}
|
||||
<div className="space-y-6">
|
||||
{filteredEvents().length === 0 ? (
|
||||
{filteredItems().length === 0 ? (
|
||||
<div className="text-center py-8">
|
||||
<p className="text-gray-500">No events found.</p>
|
||||
<p className="text-gray-500">No items found.</p>
|
||||
</div>
|
||||
) : (
|
||||
filteredEvents().map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
className="bg-white border border-gray-100 rounded-lg p-4 md:p-6 cursor-pointer hover:shadow-lg transition-shadow"
|
||||
onClick={() => navigateToEventDetail(event.id)}
|
||||
>
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
{/* Images Section */}
|
||||
<div className="flex flex-col sm:flex-row gap-1 md:w-auto">
|
||||
{/* Main image */}
|
||||
<div className="w-full sm:w-48 h-32 md:h-30 flex-shrink-0 rounded-xs overflow-hidden">
|
||||
<img
|
||||
src={getSafeImageUrl(event.mainImage, "https://images.unsplash.com/photo-1559757148-5c350d0d3c56?w=400&h=200&fit=crop")}
|
||||
alt={event.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
filteredItems().map((item) => {
|
||||
const galleryImages = getGalleryImages(item);
|
||||
const showGallery = item.type === 'event' && galleryImages.length > 0;
|
||||
|
||||
{/* Gallery grid */}
|
||||
<div className="grid grid-cols-2 gap-1 w-full sm:w-60 h-32 md:h-30">
|
||||
{getGalleryImages(event.galleryImages).map((img, index) => (
|
||||
<div key={index} className="rounded-xs overflow-hidden">
|
||||
<img
|
||||
src={img}
|
||||
alt={`${event.title} gallery ${index + 1}`}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
return (
|
||||
<div
|
||||
key={`${item.type}-${item.id}`}
|
||||
className="bg-white border border-gray-100 rounded-lg p-4 md:p-6 cursor-pointer hover:shadow-lg transition-shadow"
|
||||
onClick={() => navigateToDetail(item)}
|
||||
>
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
{/* Images Section */}
|
||||
<div className="flex flex-col sm:flex-row gap-1 md:w-auto">
|
||||
{/* Main image */}
|
||||
<div className="w-full sm:w-48 h-32 md:h-30 flex-shrink-0 rounded-xs overflow-hidden relative">
|
||||
<img
|
||||
src={getSafeImageUrl(item.mainImage, "https://images.unsplash.com/photo-1559757148-5c350d0d3c56?w=400&h=200&fit=crop")}
|
||||
alt={item.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
{/* Type Badge */}
|
||||
<div className="absolute top-2 right-2">
|
||||
<span
|
||||
className="px-2 py-1 rounded text-xs font-medium"
|
||||
style={{
|
||||
backgroundColor: item.type === 'event' ? '#e64838' : '#012068',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
{item.type === 'event' ? 'Event' : 'Training'}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Event details */}
|
||||
<div className="flex-1 text-sm">
|
||||
<div className="mb-1 font-medium text-xs" style={{ color: '#e64838' }}>
|
||||
{event.date}
|
||||
{/* Gallery grid - only for events */}
|
||||
{showGallery && (
|
||||
<div className="grid grid-cols-2 gap-1 w-full sm:w-60 h-32 md:h-30">
|
||||
{galleryImages.map((img, index) => (
|
||||
<div key={index} className="rounded-xs overflow-hidden">
|
||||
<img
|
||||
src={img}
|
||||
alt={`${item.title} gallery ${index + 1}`}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="font-medium mb-2 text-lg md:text-xl" style={{ color: '#012068' }}>
|
||||
{event.title}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-1" style={{ color: '#333' }}>
|
||||
{event.description}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-4" style={{ color: '#333' }}>
|
||||
{event.detail}
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<button
|
||||
className="text-xs hover:underline text-left"
|
||||
style={{ color: '#012068' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
navigateToEventDetail(event.id);
|
||||
}}
|
||||
>
|
||||
View Details
|
||||
</button>
|
||||
<span className="text-gray-400 hidden sm:inline">|</span>
|
||||
<span className="text-xs font-medium" style={{ color: '#e64838' }}>
|
||||
{formatPrice(event)}
|
||||
</span>
|
||||
|
||||
{/* Item details */}
|
||||
<div className="flex-1 text-sm">
|
||||
<div className="mb-1 font-medium text-xs" style={{ color: '#e64838' }}>
|
||||
{item.type === 'event' ? item.date : item.date}
|
||||
</div>
|
||||
<div className="font-medium mb-2 text-lg md:text-xl" style={{ color: '#012068' }}>
|
||||
{item.title}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-1" style={{ color: '#333' }}>
|
||||
{item.description}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-4" style={{ color: '#333' }}>
|
||||
{item.type === 'event' ? item.detail : item.detail}
|
||||
</div>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<button
|
||||
className="text-xs hover:underline text-left"
|
||||
style={{ color: '#012068' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
navigateToDetail(item);
|
||||
}}
|
||||
>
|
||||
View Details
|
||||
</button>
|
||||
<span className="text-gray-400 hidden sm:inline">|</span>
|
||||
<span className="text-xs font-medium" style={{ color: '#e64838' }}>
|
||||
{formatPrice(item)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@ -374,35 +482,38 @@ const MedicalEventsComponent = () => {
|
||||
Recent Past Events
|
||||
</h3>
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-1 gap-6">
|
||||
{pastEvents.slice(0, 2).map((event) => (
|
||||
<div
|
||||
key={event.id}
|
||||
className="cursor-pointer hover:bg-gray-50 p-2 rounded-lg transition-colors"
|
||||
onClick={() => navigateToEventDetail(event.id)}
|
||||
>
|
||||
<div className="w-full h-32 lg:h-28 mb-3 overflow-hidden rounded-xs">
|
||||
<img
|
||||
src={getSafeImageUrl(event.mainImage, "https://images.unsplash.com/photo-1551601651-2a8555f1a136?w=300&h=200&fit=crop")}
|
||||
alt={event.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
<div className="mb-1 font-medium text-xs" style={{ color: '#e64838' }}>
|
||||
{event.date}
|
||||
{pastItems.filter(item => item.type === 'event').slice(0, 2).map((item) => {
|
||||
const event = item as Event & { type: 'event'; itemDate: Date };
|
||||
return (
|
||||
<div
|
||||
key={event.id}
|
||||
className="cursor-pointer hover:bg-gray-50 p-2 rounded-lg transition-colors"
|
||||
onClick={() => router.push(`/event-detail/${event.id}`)}
|
||||
>
|
||||
<div className="w-full h-32 lg:h-28 mb-3 overflow-hidden rounded-xs">
|
||||
<img
|
||||
src={getSafeImageUrl(event.mainImage, "https://images.unsplash.com/photo-1551601651-2a8555f1a136?w=300&h=200&fit=crop")}
|
||||
alt={event.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="font-medium mb-1" style={{ color: '#012068' }}>
|
||||
{event.title}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-1" style={{ color: '#333' }}>
|
||||
{event.description}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed" style={{ color: '#333' }}>
|
||||
{event.detail}
|
||||
<div className="text-sm">
|
||||
<div className="mb-1 font-medium text-xs" style={{ color: '#e64838' }}>
|
||||
{event.date}
|
||||
</div>
|
||||
<div className="font-medium mb-1" style={{ color: '#012068' }}>
|
||||
{event.title}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-1" style={{ color: '#333' }}>
|
||||
{event.description}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed" style={{ color: '#333' }}>
|
||||
{event.detail}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -249,7 +249,7 @@ const TeamListing: React.FC<TeamListingProps> = ({
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<div className="mb-8">
|
||||
<h2 className="text-2xl font-bold mb-4" style={{ color: '#012068' }}>
|
||||
Retired Staff
|
||||
FACULTY ALUMNI
|
||||
</h2>
|
||||
<p className="text-sm mb-2" style={{ color: '#666' }}>
|
||||
Honoring our retired faculty and staff members for their dedicated service
|
||||
|
||||
@ -2,60 +2,113 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { eventAPI, Event } from '../../lib/api';
|
||||
import { educationService, Course } from '../../services/educationService';
|
||||
|
||||
// Combined type for events and courses
|
||||
type EventOrCourse = (Event & { type: 'event' }) | (Course & { type: 'course', date: string, mainImage: string });
|
||||
|
||||
const EventsSection = () => {
|
||||
const router = useRouter();
|
||||
const [upcomingEvents, setUpcomingEvents] = useState<Event[]>([]);
|
||||
const [pastEvents, setPastEvents] = useState<Event[]>([]);
|
||||
const [courses, setCourses] = useState<Course[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [combinedUpcoming, setCombinedUpcoming] = useState<EventOrCourse[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
loadEvents();
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
const loadEvents = async () => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const [upcoming, past] = await Promise.all([
|
||||
const [upcoming, past, activeCourses] = await Promise.all([
|
||||
eventAPI.getUpcomingEvents(),
|
||||
eventAPI.getPastEvents()
|
||||
eventAPI.getPastEvents(),
|
||||
educationService.getActiveCourses()
|
||||
]);
|
||||
|
||||
setUpcomingEvents(upcoming);
|
||||
setPastEvents(past);
|
||||
setCourses(activeCourses);
|
||||
|
||||
// Combine events and courses for display
|
||||
const eventsWithType: EventOrCourse[] = upcoming.map(event => ({
|
||||
...event,
|
||||
type: 'event' as const
|
||||
}));
|
||||
|
||||
const coursesWithType: EventOrCourse[] = activeCourses.map(course => ({
|
||||
...course,
|
||||
type: 'course' as const,
|
||||
date: course.startDate || 'Date TBD',
|
||||
mainImage: course.image
|
||||
}));
|
||||
|
||||
// Combine and sort by date
|
||||
const combined = [...eventsWithType, ...coursesWithType].sort((a, b) => {
|
||||
const dateA = new Date(a.date);
|
||||
const dateB = new Date(b.date);
|
||||
return dateA.getTime() - dateB.getTime();
|
||||
});
|
||||
|
||||
setCombinedUpcoming(combined);
|
||||
} catch (error) {
|
||||
console.error('Error loading events:', error);
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Navigation function for App Router
|
||||
const navigateToEventDetail = (eventId: string | number) => {
|
||||
router.push(`/event-detail/${eventId}`);
|
||||
// Navigation functions
|
||||
const navigateToDetail = (item: EventOrCourse) => {
|
||||
if (item.type === 'event') {
|
||||
router.push(`/event-detail/${item.id}`);
|
||||
} else {
|
||||
router.push(`/education-training/course-detail?id=${item.id}`);
|
||||
}
|
||||
};
|
||||
|
||||
const navigateToAllEvents = () => {
|
||||
router.push('/events');
|
||||
};
|
||||
|
||||
// Format price display from fees
|
||||
const formatPrice = (event: Event) => {
|
||||
if (event.fee && event.fee.length > 0) {
|
||||
return `₹${event.fee[0].cost} per ticket`;
|
||||
// Format price display
|
||||
const formatPrice = (item: EventOrCourse) => {
|
||||
if (item.type === 'event') {
|
||||
if (item.fee && item.fee.length > 0) {
|
||||
return `₹${item.fee[0].cost} per ticket`;
|
||||
}
|
||||
return '₹1,800 per ticket';
|
||||
} else {
|
||||
return item.price !== 'N/A' ? item.price : 'Contact for pricing';
|
||||
}
|
||||
return '₹1,800 per ticket';
|
||||
};
|
||||
|
||||
// Top section events (first 4 events for the grid)
|
||||
const topEvents = upcomingEvents.slice(0, 4);
|
||||
// Get title for the item
|
||||
const getTitle = (item: EventOrCourse) => {
|
||||
return item.title;
|
||||
};
|
||||
|
||||
// Featured event (first event)
|
||||
const featuredEvent = upcomingEvents.length > 0 ? upcomingEvents[0] : null;
|
||||
// Get description for the item
|
||||
const getDescription = (item: EventOrCourse) => {
|
||||
if (item.type === 'event') {
|
||||
return item.description;
|
||||
} else {
|
||||
return item.description;
|
||||
}
|
||||
};
|
||||
|
||||
// Top section items (first 4 for the grid)
|
||||
const topItems = combinedUpcoming.slice(0, 4);
|
||||
|
||||
// Featured item (first item)
|
||||
const featuredItem = combinedUpcoming.length > 0 ? combinedUpcoming[0] : null;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="py-12 px-6 sm:px-8 md:px-6 lg:px-6 xl:px-6 bg-white max-w-7xl mx-auto">
|
||||
<div className="text-center" style={{ color: '#012068' }}>Loading events...</div>
|
||||
<div className="text-center" style={{ color: '#012068' }}>Loading events and courses...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -65,7 +118,7 @@ const EventsSection = () => {
|
||||
{/* Section Header */}
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<h2 className="text-2xl md:text-3xl font-bold" style={{ color: '#012068' }}>
|
||||
Our Events
|
||||
Our Events & Courses
|
||||
</h2>
|
||||
<button
|
||||
className="text-sm font-medium hover:opacity-70 transition-opacity duration-200"
|
||||
@ -76,39 +129,52 @@ const EventsSection = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Events Grid - Top Section with Event Details */}
|
||||
{topEvents.length === 0 ? (
|
||||
{/* Events/Courses Grid - Top Section with Details */}
|
||||
{topItems.length === 0 ? (
|
||||
<div className="text-center py-8 mb-12">
|
||||
<p className="text-gray-500">No upcoming events.</p>
|
||||
<p className="text-gray-500">No upcoming events or courses.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-12">
|
||||
{topEvents.map((event, index) => (
|
||||
{topItems.map((item, index) => (
|
||||
<div
|
||||
key={event.id}
|
||||
key={`${item.type}-${item.id}`}
|
||||
className={`relative rounded-lg h-48 overflow-hidden cursor-pointer hover:shadow-lg transition-shadow ${
|
||||
index === 2 ? 'lg:hidden xl:block' : ''
|
||||
} ${index === 3 ? 'md:col-span-2 lg:col-span-1' : ''}`}
|
||||
onClick={() => navigateToEventDetail(event.id)}
|
||||
onClick={() => navigateToDetail(item)}
|
||||
>
|
||||
<img
|
||||
src={event.mainImage}
|
||||
alt={event.title}
|
||||
src={item.mainImage}
|
||||
alt={getTitle(item)}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
{/* Gradient overlay for better text readability */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent"></div>
|
||||
|
||||
{/* Event details overlay */}
|
||||
{/* Item type badge */}
|
||||
<div className="absolute top-3 right-3">
|
||||
<span
|
||||
className="text-xs font-medium px-2 py-1 rounded"
|
||||
style={{
|
||||
backgroundColor: item.type === 'event' ? '#e64838' : '#012068',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
{item.type === 'event' ? 'Event' : 'Course'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Item details overlay */}
|
||||
<div className="absolute bottom-0 left-0 right-0 p-4 text-white">
|
||||
<div className="text-xs font-medium mb-1" style={{ color: '#e64838' }}>
|
||||
{event.date}
|
||||
{item.date}
|
||||
</div>
|
||||
<h4 className="font-medium mb-2 text-sm leading-tight">
|
||||
{event.title}
|
||||
<h4 className="font-medium mb-2 text-sm leading-tight line-clamp-2">
|
||||
{getTitle(item)}
|
||||
</h4>
|
||||
<div className="text-xs font-medium">
|
||||
{formatPrice(event)}
|
||||
{formatPrice(item)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -116,26 +182,40 @@ const EventsSection = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Featured Events Section */}
|
||||
{/* Featured Section */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Left - Large Featured Event */}
|
||||
{/* Left - Large Featured Item */}
|
||||
<div className="lg:col-span-2 px-4 py-4 rounded-lg" style={{ backgroundColor: '#f4f4f4' }}>
|
||||
<h3 className="text-xl font-semibold mb-4" style={{ color: '#012068' }}>Upcoming Events</h3>
|
||||
{!featuredEvent ? (
|
||||
<h3 className="text-xl font-semibold mb-4" style={{ color: '#012068' }}>
|
||||
Featured {featuredItem?.type === 'course' ? 'Course' : 'Event'}
|
||||
</h3>
|
||||
{!featuredItem ? (
|
||||
<div className="text-center py-8">
|
||||
<p className="text-gray-500">No upcoming events.</p>
|
||||
<p className="text-gray-500">No upcoming events or courses.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className="bg-white border border-gray-100 rounded-lg overflow-hidden cursor-pointer hover:shadow-lg transition-shadow"
|
||||
onClick={() => navigateToEventDetail(featuredEvent.id)}
|
||||
onClick={() => navigateToDetail(featuredItem)}
|
||||
>
|
||||
<div className="relative h-48 md:h-64">
|
||||
<img
|
||||
src={featuredEvent.mainImage}
|
||||
alt={featuredEvent.title}
|
||||
src={featuredItem.mainImage}
|
||||
alt={getTitle(featuredItem)}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
{/* Item type badge */}
|
||||
<div className="absolute top-4 right-4">
|
||||
<span
|
||||
className="text-xs font-medium px-3 py-1 rounded"
|
||||
style={{
|
||||
backgroundColor: featuredItem.type === 'event' ? '#e64838' : '#012068',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
{featuredItem.type === 'event' ? 'Event' : 'Course'}
|
||||
</span>
|
||||
</div>
|
||||
{/* Pagination dots */}
|
||||
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2">
|
||||
<div className="w-2 h-2 bg-white rounded-full shadow"></div>
|
||||
@ -147,27 +227,47 @@ const EventsSection = () => {
|
||||
<div className="flex flex-col lg:flex-row lg:justify-between gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="text-xs font-medium mb-3" style={{ color: '#e64838' }}>
|
||||
{featuredEvent.date}
|
||||
{featuredItem.date}
|
||||
</div>
|
||||
<h4 className="text-lg md:text-xl font-medium mb-2" style={{ color: '#012068' }}>
|
||||
{featuredEvent.title}
|
||||
{getTitle(featuredItem)}
|
||||
</h4>
|
||||
<div className="text-xs leading-relaxed mb-1" style={{ color: '#333' }}>
|
||||
{featuredEvent.description}
|
||||
</div>
|
||||
<div className="text-xs leading-relaxed mb-4" style={{ color: '#333' }}>
|
||||
{featuredEvent.detail}
|
||||
{getDescription(featuredItem)}
|
||||
</div>
|
||||
{featuredItem.type === 'event' && (
|
||||
<div className="text-xs leading-relaxed mb-4" style={{ color: '#333' }}>
|
||||
{featuredItem.detail}
|
||||
</div>
|
||||
)}
|
||||
{featuredItem.type === 'course' && (
|
||||
<div className="flex items-center gap-4 mb-4 text-xs" style={{ color: '#012068' }}>
|
||||
<div className="flex items-center">
|
||||
<span className="mr-1">⏱️</span>
|
||||
<span>{featuredItem.duration}</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="mr-1">👥</span>
|
||||
<span>{featuredItem.seats} seats</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="mr-1">👨🏫</span>
|
||||
<span>{featuredItem.instructor}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
||||
<div
|
||||
className="text-xs cursor-pointer hover:underline"
|
||||
style={{ color: '#012068' }}
|
||||
>
|
||||
Share Event
|
||||
</div>
|
||||
<div className="text-xs" style={{ color: '#012068' }}>
|
||||
📍 {featuredEvent.venue?.[0]?.address || 'Convention Center, Medical District'}
|
||||
Share {featuredItem.type === 'course' ? 'Course' : 'Event'}
|
||||
</div>
|
||||
{featuredItem.type === 'event' && (
|
||||
<div className="text-xs" style={{ color: '#012068' }}>
|
||||
📍 {featuredItem.venue?.[0]?.address || 'Convention Center, Medical District'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-left lg:text-right">
|
||||
@ -179,17 +279,19 @@ const EventsSection = () => {
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
console.log('Book seat clicked');
|
||||
navigateToDetail(featuredItem);
|
||||
}}
|
||||
>
|
||||
Book Your Seat
|
||||
{featuredItem.type === 'course' ? 'Apply Now' : 'Book Your Seat'}
|
||||
</button>
|
||||
<div className="text-sm font-medium" style={{ color: '#e64838' }}>
|
||||
{formatPrice(featuredEvent)}
|
||||
</div>
|
||||
<div className="text-xs mt-1" style={{ color: '#012068', opacity: 0.8 }}>
|
||||
Early bird discount available
|
||||
{formatPrice(featuredItem)}
|
||||
</div>
|
||||
{featuredItem.type === 'event' && (
|
||||
<div className="text-xs mt-1" style={{ color: '#012068', opacity: 0.8 }}>
|
||||
Early bird discount available
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -197,7 +299,7 @@ const EventsSection = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right - Event List with Scroller */}
|
||||
{/* Right - Past Events List with Scroller */}
|
||||
<div className="lg:col-span-1">
|
||||
<h3 className="text-xl font-semibold mb-4" style={{ color: '#012068' }}>Past Events</h3>
|
||||
{pastEvents.length === 0 ? (
|
||||
@ -210,7 +312,7 @@ const EventsSection = () => {
|
||||
<div
|
||||
key={event.id}
|
||||
className="bg-white border border-gray-100 rounded-lg overflow-hidden cursor-pointer hover:shadow-lg transition-shadow flex-shrink-0"
|
||||
onClick={() => navigateToEventDetail(event.id)}
|
||||
onClick={() => router.push(`/event-detail/${event.id}`)}
|
||||
>
|
||||
<div className="h-24">
|
||||
<img
|
||||
@ -226,7 +328,7 @@ const EventsSection = () => {
|
||||
<h4 className="font-medium mb-1 text-sm" style={{ color: '#012068' }}>
|
||||
{event.title}
|
||||
</h4>
|
||||
<p className="text-xs leading-relaxed" style={{ color: '#333' }}>
|
||||
<p className="text-xs leading-relaxed line-clamp-2" style={{ color: '#333' }}>
|
||||
{event.description}
|
||||
</p>
|
||||
<div className="mt-2 flex justify-between items-center">
|
||||
@ -235,14 +337,11 @@ const EventsSection = () => {
|
||||
style={{ color: '#012068' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
navigateToEventDetail(event.id);
|
||||
router.push(`/event-detail/${event.id}`);
|
||||
}}
|
||||
>
|
||||
View Details
|
||||
</button>
|
||||
{/* <span className="text-xs font-medium" style={{ color: '#e64838' }}>
|
||||
{formatPrice(event)}
|
||||
</span> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -18,7 +18,8 @@ export interface Event {
|
||||
phone: string;
|
||||
email: string;
|
||||
isActive: boolean;
|
||||
bookSeatLink?: string; // NEW FIELD
|
||||
bookSeatLink?: string; // Registration/booking link
|
||||
learnMoreLink?: string; // Additional information link
|
||||
professors?: Professor[];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user