Files
Event-Management-System/RIT-EVENT-MANAGEMENT--main/components/EventsHeroSlider.tsx

180 lines
7.8 KiB
TypeScript

import React, { useState, useEffect, useMemo, useCallback } from 'react';
import { Event } from '../types';
interface EventsHeroSliderProps {
events: Event[];
}
const EventsHeroSlider: React.FC<EventsHeroSliderProps> = ({ events }) => {
const sortedEvents = useMemo(() => {
return [...events]
.filter(e => e.status !== 'Completed')
.sort((a, b) => {
return new Date(a.date).getTime() - new Date(b.date).getTime();
});
}, [events]);
const [currentIndex, setCurrentIndex] = useState(0);
const [timeLeft, setTimeLeft] = useState({ d: '00', h: '00', m: '00', s: '00' });
const nextSlide = useCallback(() => {
setCurrentIndex((prev) => (prev + 1) % sortedEvents.length);
}, [sortedEvents.length]);
const prevSlide = useCallback(() => {
setCurrentIndex((prev) => (prev - 1 + sortedEvents.length) % sortedEvents.length);
}, [sortedEvents.length]);
useEffect(() => {
if (sortedEvents.length === 0) return;
const interval = setInterval(nextSlide, 5000);
return () => clearInterval(interval);
}, [sortedEvents.length, nextSlide]);
const updateTimer = useCallback(() => {
const activeEvent = sortedEvents[currentIndex];
if (!activeEvent) {
setTimeLeft({ d: '00', h: '00', m: '00', s: '00' });
return;
}
const targetDate = new Date(activeEvent.date).getTime();
const now = new Date().getTime();
const distance = targetDate - now;
if (isNaN(targetDate) || distance < 0) {
setTimeLeft({ d: '00', h: '00', m: '00', s: '00' });
return;
}
setTimeLeft(prev => {
const newD = Math.floor(distance / (1000 * 60 * 60 * 24)).toString().padStart(2, '0');
const newH = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)).toString().padStart(2, '0');
const newM = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)).toString().padStart(2, '0');
const newS = Math.floor((distance % (1000 * 60)) / 1000).toString().padStart(2, '0');
if (prev.d === newD && prev.h === newH && prev.m === newM && prev.s === newS) {
return prev;
}
return { d: newD, h: newH, m: newM, s: newS };
});
}, [sortedEvents, currentIndex]);
useEffect(() => {
updateTimer();
const timerId = setInterval(updateTimer, 1000);
return () => clearInterval(timerId);
}, [updateTimer]);
if (sortedEvents.length === 0) return null;
const activeEvent = sortedEvents[currentIndex];
return (
<div className="relative w-full h-screen bg-[#1A202C] overflow-hidden group">
{/* Background Images & Content */}
{sortedEvents.map((event, idx) => {
const isActive = idx === currentIndex;
return (
<div
key={event.id}
className={`absolute inset-0 transition-opacity duration-1000 ease-in-out ${isActive ? 'opacity-100 z-10' : 'opacity-0 z-0'}`}
>
{/* Background Image */}
<div className="absolute inset-0 bg-black">
<img
src={event.image}
alt={event.title}
className={`w-full h-full object-cover opacity-50 transition-transform duration-[5000ms] ${isActive ? 'scale-100' : 'scale-105'}`}
/>
</div>
{/* Top Right Location Button */}
<div className="absolute top-24 right-12 z-20">
<div className="bg-white px-6 py-3 rounded-full flex items-center gap-3 shadow-2xl shadow-gray-200/50">
<i className="fas fa-location-dot text-[#f97316]"></i>
<span className="text-[#1A202C] text-xs font-bold tracking-widest uppercase">{event.location}</span>
</div>
</div>
{/* Main Content */}
<div className="absolute inset-0 z-10 flex flex-col justify-center pb-[15vh] px-12 md:px-24">
<div className={`max-w-5xl transition-all duration-1000 transform ${isActive ? 'translate-y-0 opacity-100' : 'translate-y-8 opacity-0'}`}>
<div className="flex items-center gap-4 mb-6">
<div className="w-12 h-[2px] bg-[#f97316]"></div>
<span className="text-white font-bold tracking-[0.3em] uppercase text-sm">
JOIN US <span className="text-[#f97316] ml-2">{event.date}</span>
</span>
</div>
<h1 className="text-white text-5xl md:text-[6rem] lg:text-[8rem] font-black leading-[0.9] tracking-tighter uppercase break-words drop-shadow-lg">
{event.title}
</h1>
</div>
</div>
</div>
);
})}
{/* Countdown Timer Block (Slanted Orange Design) */}
<div
className="absolute bottom-0 left-0 z-20 bg-[#f97316] h-[140px] md:h-[160px] flex items-center px-8 md:px-16"
style={{
clipPath: 'polygon(0 0, 85% 0, 100% 100%, 0% 100%)',
width: '100%',
maxWidth: '800px'
}}
>
<div className="flex items-center gap-6 md:gap-12 relative z-10 w-full pr-12 md:pr-24">
<div className="flex flex-col items-center flex-1">
<span className="text-5xl md:text-6xl font-black leading-none text-white tracking-tighter">{timeLeft.d}</span>
<span className="text-[10px] md:text-xs font-bold uppercase tracking-widest mt-2 text-white">Days</span>
</div>
<div className="w-px h-16 bg-white/30"></div>
<div className="flex flex-col items-center flex-1">
<span className="text-5xl md:text-6xl font-black leading-none text-white tracking-tighter">{timeLeft.h}</span>
<span className="text-[10px] md:text-xs font-bold uppercase tracking-widest mt-2 text-white">Hrs</span>
</div>
<div className="w-px h-16 bg-white/30"></div>
<div className="flex flex-col items-center flex-1">
<span className="text-5xl md:text-6xl font-black leading-none text-white tracking-tighter">{timeLeft.m}</span>
<span className="text-[10px] md:text-xs font-bold uppercase tracking-widest mt-2 text-white">Min</span>
</div>
<div className="w-px h-16 bg-white/30"></div>
<div className="flex flex-col items-center flex-1">
<span className="text-5xl md:text-6xl font-black leading-none text-white tracking-tighter">{timeLeft.s}</span>
<span className="text-[10px] md:text-xs font-bold uppercase tracking-widest mt-2 text-white">Sec</span>
</div>
</div>
</div>
{/* Navigation Arrows */}
<button
onClick={prevSlide}
className="absolute left-8 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-white/10 backdrop-blur-md flex items-center justify-center text-white/50 hover:text-white hover:bg-white/20 transition-all duration-300 z-20 opacity-0 group-hover:opacity-100 hover:scale-110 border border-white/10"
>
<i className="fas fa-chevron-left text-lg"></i>
</button>
<button
onClick={nextSlide}
className="absolute right-8 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-white/10 backdrop-blur-md flex items-center justify-center text-white/50 hover:text-white hover:bg-white/20 transition-all duration-300 z-20 opacity-0 group-hover:opacity-100 hover:scale-110 border border-white/10"
>
<i className="fas fa-chevron-right text-lg"></i>
</button>
{/* Slider Dots */}
<div className="absolute bottom-12 right-12 z-20 flex gap-3">
{sortedEvents.map((_, idx) => (
<button
key={idx}
onClick={() => setCurrentIndex(idx)}
className={`h-1 transition-all duration-500 ${currentIndex === idx ? 'w-12 bg-[#f97316]' : 'w-6 bg-gray-200 hover:bg-gray-400'}`}
></button>
))}
</div>
</div>
);
};
export default EventsHeroSlider;