Files
KLC-Website-Frontend/src/components/ReusableCarousel.tsx
priyanshuvish b9bf8ce99e first commit
2025-08-28 13:14:51 +05:30

298 lines
9.7 KiB
TypeScript

import React, { useState } from 'react';
import { navigateTo } from './Router';
import { Card, CardContent } from './ui/card';
import { PrimaryCTAButton } from './PrimaryCTAButton';
import { CheckCircle, Target, ChevronLeft, ChevronRight } from 'lucide-react';
// Types for the reusable carousel
export interface CarouselItem {
title: string;
description: string;
icon: React.ComponentType<any>;
features?: string[];
outcome?: string;
// Additional flexible properties for different content types
[key: string]: any;
}
export interface CarouselConfig {
eyebrowText: string;
title: string;
description: string;
ctaText: string;
ctaAction: () => void;
ctaAriaLabel: string;
}
export interface ReusableCarouselProps {
items: CarouselItem[];
config: CarouselConfig;
className?: string;
cardWidth?: string; // Default: "70%"
cardSpacing?: string; // Default: "mr-7" (28px)
featuresTitle?: string; // Default: "Key Features & Benefits:"
outcomesTitle?: string; // Default: "Expected Outcomes:"
customCardRenderer?: (item: CarouselItem, index: number) => React.ReactNode;
}
export function ReusableCarousel({
items,
config,
className = "",
cardWidth = "70%",
cardSpacing = "mr-7",
featuresTitle = "Key Features & Benefits:",
outcomesTitle = "Expected Outcomes:",
customCardRenderer
}: ReusableCarouselProps) {
const [currentIndex, setCurrentIndex] = useState(0);
const nextSlide = () => {
setCurrentIndex((prev) => (prev + 1) % items.length);
};
const prevSlide = () => {
setCurrentIndex((prev) => (prev - 1 + items.length) % items.length);
};
const renderDefaultCard = (item: CarouselItem, index: number) => (
<Card
className="border border-gray-200 h-full overflow-hidden"
style={{ backgroundColor: '#FFFFFF' }}
>
<CardContent className="p-6">
{/* Service Icon & Header - Inline Layout */}
<div className="flex items-center gap-4 mb-4">
<div
className="w-14 h-14 rounded-xl flex items-center justify-center flex-shrink-0"
style={{ backgroundColor: 'rgba(4, 4, 91, 0.1)' }}
>
{React.createElement(item.icon, {
className: "w-7 h-7 text-primary"
})}
</div>
<h3 className="text-h4 text-black leading-tight">
{item.title}
</h3>
</div>
{/* Divider Line */}
<div
className="w-full h-px mb-4"
style={{ backgroundColor: 'rgba(0, 0, 0, 0.1)' }}
></div>
{/* Description */}
<p className="text-body text-muted leading-relaxed mb-6">
{item.description}
</p>
{/* Key Features */}
{item.features && item.features.length > 0 && (
<div className="mb-6">
<h4 className="text-subhead text-black mb-4 font-medium">
{featuresTitle}
</h4>
<div className="grid md:grid-cols-2 gap-3">
{item.features.map((feature: string, featureIndex: number) => (
<div key={featureIndex} className="flex items-start gap-2">
<CheckCircle className="w-4 h-4 flex-shrink-0 mt-0.5 text-primary" />
<span className="text-small text-muted leading-relaxed">
{feature}
</span>
</div>
))}
</div>
</div>
)}
{/* Expected Outcomes */}
{item.outcome && (
<div
className="rounded-lg p-4"
style={{ backgroundColor: 'rgba(247, 247, 253, 0.5)' }}
>
<h4 className="text-subhead text-black mb-3 font-medium">
{outcomesTitle}
</h4>
<div className="flex items-start gap-3">
<Target className="w-4 h-4 flex-shrink-0 mt-0.5 text-primary" />
<span className="text-small text-muted leading-relaxed">
{item.outcome}
</span>
</div>
</div>
)}
</CardContent>
</Card>
);
return (
<div className={`max-w-7xl mx-auto mb-16 ${className}`}>
{/* Header Section */}
<div className="mb-12 relative">
{/* Left Side - Eyebrow Text, Header & Subtext */}
<div className="flex-1 max-w-2xl">
<div className="branded-tag-system mb-6">
<div className="dot"></div>
<span className="text">{config.eyebrowText}</span>
</div>
<h2 className="text-h2 mb-4 leading-tight">{config.title}</h2>
<p className="text-body-lg text-muted leading-relaxed">
{config.description}
</p>
</div>
{/* Navigation Controls - Bottom Right of Header */}
<div className="absolute bottom-0 right-0 flex items-center gap-4">
<span className="text-body text-muted font-medium">
{String(currentIndex + 1).padStart(2, '0')} / {String(items.length).padStart(2, '0')}
</span>
<div className="flex gap-2">
<button
onClick={prevSlide}
className="w-12 h-12 rounded-lg border-2 border-gray-200 flex items-center justify-center hover:border-primary hover:bg-primary hover:text-white transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed"
disabled={currentIndex === 0}
aria-label="Previous item"
>
<ChevronLeft className="w-5 h-5" />
</button>
<button
onClick={nextSlide}
className="w-12 h-12 rounded-lg border-2 border-gray-200 flex items-center justify-center hover:border-primary hover:bg-primary hover:text-white transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed"
disabled={currentIndex === items.length - 1}
aria-label="Next item"
>
<ChevronRight className="w-5 h-5" />
</button>
</div>
</div>
</div>
{/* Main Carousel Content */}
<div className="relative">
{/* Carousel Container */}
<div className="overflow-hidden">
<div
className="flex transition-transform duration-700 ease-in-out"
style={{ transform: `translateX(-${currentIndex * 75}%)` }}
>
{items.map((item, index) => (
<div
key={`${item.title}-${index}`}
className={`flex-shrink-0 w-[${cardWidth}] ${cardSpacing}`}
>
{customCardRenderer ? customCardRenderer(item, index) : renderDefaultCard(item, index)}
</div>
))}
</div>
</div>
</div>
{/* CTA Button - Right Bottom with 40px spacing */}
<div className="flex justify-end" style={{ marginTop: '40px' }}>
<PrimaryCTAButton
text={config.ctaText}
onClick={config.ctaAction}
ariaLabel={config.ctaAriaLabel}
/>
</div>
</div>
);
}
// Pre-configured carousel variants for common use cases
export function ConsultingServicesCarousel({
consultingServices
}: {
consultingServices: CarouselItem[]
}) {
const config: CarouselConfig = {
eyebrowText: "CONSULTING & ADVISORY SERVICES",
title: "Our Services",
description: "Comprehensive consulting solutions designed to drive organizational transformation and leadership excellence across all levels of your business.",
ctaText: "Explore Consulting Services",
ctaAction: () => navigateTo('/services/consulting'),
ctaAriaLabel: "Explore our consulting services"
};
return (
<ReusableCarousel
items={consultingServices}
config={config}
/>
);
}
export function LeadershipProgramsCarousel({
leadershipPrograms
}: {
leadershipPrograms: CarouselItem[]
}) {
const config: CarouselConfig = {
eyebrowText: "LEADERSHIP DEVELOPMENT PROGRAMS",
title: "Our Programs",
description: "Comprehensive leadership development programs designed to build capabilities and drive organizational transformation with measurable impact.",
ctaText: "Explore Leadership Programs",
ctaAction: () => navigateTo('/services/leadership-development'),
ctaAriaLabel: "Explore our leadership development programs"
};
return (
<ReusableCarousel
items={leadershipPrograms}
config={config}
featuresTitle="Program Features:"
outcomesTitle="Program Outcomes:"
/>
);
}
export function ExpertServicesCarousel({
expertServices
}: {
expertServices: CarouselItem[]
}) {
const config: CarouselConfig = {
eyebrowText: "EXPERT CONSULTATION & SERVICES",
title: "Expert Services",
description: "Personalized guidance from industry thought leaders and senior practitioners who bring decades of real-world experience.",
ctaText: "Connect with Experts",
ctaAction: () => navigateTo('/services/executive-coaching'),
ctaAriaLabel: "Connect with our expert consultants"
};
return (
<ReusableCarousel
items={expertServices}
config={config}
featuresTitle="Service Features:"
outcomesTitle="Expected Results:"
/>
);
}
export function PlatformFeaturesCarousel({
platformFeatures
}: {
platformFeatures: CarouselItem[]
}) {
const config: CarouselConfig = {
eyebrowText: "DIGITAL PLATFORM FEATURES",
title: "Platform Capabilities",
description: "State-of-the-art digital learning platform with cutting-edge technology and interactive experiences for modern learning.",
ctaText: "Explore Platform",
ctaAction: () => navigateTo('/learning-online'),
ctaAriaLabel: "Explore our online learning platform"
};
return (
<ReusableCarousel
items={platformFeatures}
config={config}
featuresTitle="Platform Features:"
outcomesTitle="Learning Benefits:"
/>
);
}