883 lines
37 KiB
TypeScript
883 lines
37 KiB
TypeScript
|
|
import React, { useState, useRef, useEffect } from 'react';
|
||
|
|
import { Button } from './ui/button';
|
||
|
|
import { Card, CardContent } from './ui/card';
|
||
|
|
import { Badge } from './ui/badge';
|
||
|
|
import { Input } from './ui/input';
|
||
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select';
|
||
|
|
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||
|
|
import { PrimaryCTAButton } from './PrimaryCTAButton';
|
||
|
|
import { navigateTo } from './Router';
|
||
|
|
import {
|
||
|
|
Search,
|
||
|
|
Calendar,
|
||
|
|
Clock,
|
||
|
|
Users,
|
||
|
|
Play,
|
||
|
|
Filter,
|
||
|
|
Grid,
|
||
|
|
List,
|
||
|
|
ChevronLeft,
|
||
|
|
ChevronRight,
|
||
|
|
X,
|
||
|
|
TrendingUp,
|
||
|
|
Award,
|
||
|
|
Globe
|
||
|
|
} from 'lucide-react';
|
||
|
|
|
||
|
|
// Comprehensive webinar data
|
||
|
|
const webinarsData = [
|
||
|
|
{
|
||
|
|
id: '1',
|
||
|
|
slug: 'leadership-in-digital-age',
|
||
|
|
title: 'Leadership in the Digital Age: Navigating Change and Innovation',
|
||
|
|
description: 'Discover how modern leaders can adapt and thrive in an increasingly digital world. This comprehensive webcast covers digital transformation strategies, leading remote teams, and fostering innovation.',
|
||
|
|
presenter: 'Dr. Sarah Mitchell',
|
||
|
|
presenterTitle: 'Chief Digital Transformation Officer',
|
||
|
|
company: 'Global Leadership Institute',
|
||
|
|
date: '2024-02-15',
|
||
|
|
time: '2:00 PM EST',
|
||
|
|
duration: '90 minutes',
|
||
|
|
attendees: '2,400+',
|
||
|
|
category: 'Digital Transformation',
|
||
|
|
tags: ['Leadership', 'Digital Strategy', 'Innovation', 'Change Management'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1560472355-536de3962603?w=600&h=400&fit=crop',
|
||
|
|
status: 'Available',
|
||
|
|
featured: true,
|
||
|
|
level: 'Advanced',
|
||
|
|
format: 'Hybrid',
|
||
|
|
rating: 4.8,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '2',
|
||
|
|
slug: 'building-resilient-teams',
|
||
|
|
title: 'Building Resilient Teams: Strategies for Sustainable Performance',
|
||
|
|
description: 'Learn proven methodologies for creating teams that can withstand challenges and maintain high performance under pressure.',
|
||
|
|
presenter: 'Marcus Rodriguez',
|
||
|
|
presenterTitle: 'Director of Organizational Development',
|
||
|
|
company: 'Excellence Consulting',
|
||
|
|
date: '2024-02-08',
|
||
|
|
time: '1:00 PM EST',
|
||
|
|
duration: '75 minutes',
|
||
|
|
attendees: '1,850+',
|
||
|
|
category: 'Team Development',
|
||
|
|
tags: ['Team Building', 'Resilience', 'Performance', 'Leadership'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=600&h=400&fit=crop',
|
||
|
|
status: 'Available',
|
||
|
|
featured: true,
|
||
|
|
level: 'Intermediate',
|
||
|
|
format: 'In Person',
|
||
|
|
rating: 4.9,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '3',
|
||
|
|
slug: 'strategic-decision-making',
|
||
|
|
title: 'Strategic Decision Making: Tools and Frameworks for Leaders',
|
||
|
|
description: 'Master the art of strategic thinking and decision-making with proven frameworks and methodologies used by top executives.',
|
||
|
|
presenter: 'Dr. Emily Chen',
|
||
|
|
presenterTitle: 'Strategic Leadership Consultant',
|
||
|
|
company: 'Strategy First',
|
||
|
|
date: '2024-01-25',
|
||
|
|
time: '3:00 PM EST',
|
||
|
|
duration: '60 minutes',
|
||
|
|
attendees: '3,200+',
|
||
|
|
category: 'Strategy',
|
||
|
|
tags: ['Strategic Thinking', 'Decision Making', 'Leadership', 'Planning'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=600&h=400&fit=crop',
|
||
|
|
status: 'Available',
|
||
|
|
featured: false,
|
||
|
|
level: 'Advanced',
|
||
|
|
format: 'Virtual',
|
||
|
|
rating: 4.7,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '4',
|
||
|
|
slug: 'emotional-intelligence-workplace',
|
||
|
|
title: 'Emotional Intelligence in the Workplace: Leading with Empathy',
|
||
|
|
description: 'Explore the critical role of emotional intelligence in effective leadership and learn practical techniques for developing empathy and emotional awareness.',
|
||
|
|
presenter: 'Jennifer Adams',
|
||
|
|
presenterTitle: 'Executive Coach & EQ Specialist',
|
||
|
|
company: 'Empathy Leadership Group',
|
||
|
|
date: '2024-01-18',
|
||
|
|
time: '2:30 PM EST',
|
||
|
|
duration: '85 minutes',
|
||
|
|
attendees: '2,100+',
|
||
|
|
category: 'Personal Development',
|
||
|
|
tags: ['Emotional Intelligence', 'Empathy', 'Communication', 'Leadership'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1559027615-cd4628902d4a?w=600&h=400&fit=crop',
|
||
|
|
status: 'Recorded',
|
||
|
|
featured: false,
|
||
|
|
level: 'Intermediate',
|
||
|
|
format: 'Hybrid',
|
||
|
|
rating: 4.6,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '5',
|
||
|
|
slug: 'crisis-leadership-management',
|
||
|
|
title: 'Crisis Leadership: Managing Through Uncertainty and Change',
|
||
|
|
description: 'Learn essential crisis leadership skills and strategies for guiding organizations through challenging times and uncertainty.',
|
||
|
|
presenter: 'David Park',
|
||
|
|
presenterTitle: 'Crisis Management Expert',
|
||
|
|
company: 'Risk Management Solutions',
|
||
|
|
date: '2024-01-10',
|
||
|
|
time: '1:30 PM EST',
|
||
|
|
duration: '70 minutes',
|
||
|
|
attendees: '2,800+',
|
||
|
|
category: 'Crisis Management',
|
||
|
|
tags: ['Crisis Leadership', 'Change Management', 'Communication', 'Strategy'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=600&h=400&fit=crop',
|
||
|
|
status: 'Live',
|
||
|
|
featured: false,
|
||
|
|
level: 'Advanced',
|
||
|
|
format: 'Virtual',
|
||
|
|
rating: 4.8,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '6',
|
||
|
|
slug: 'future-workplace-trends',
|
||
|
|
title: 'The Future of Work: Preparing for Tomorrow\'s Workplace',
|
||
|
|
description: 'Discover emerging workplace trends and learn how to prepare your organization and teams for the future of work.',
|
||
|
|
presenter: 'Lisa Thompson',
|
||
|
|
presenterTitle: 'Future of Work Analyst',
|
||
|
|
company: 'Tomorrow Institute',
|
||
|
|
date: '2024-01-05',
|
||
|
|
time: '4:00 PM EST',
|
||
|
|
duration: '80 minutes',
|
||
|
|
attendees: '1,950+',
|
||
|
|
category: 'Future of Work',
|
||
|
|
tags: ['Future Trends', 'Workplace Evolution', 'Technology', 'Leadership'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1600880292203-757bb62b4baf?w=600&h=400&fit=crop',
|
||
|
|
status: 'Upcoming',
|
||
|
|
featured: false,
|
||
|
|
level: 'Beginner',
|
||
|
|
format: 'Hybrid',
|
||
|
|
rating: 4.5,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '7',
|
||
|
|
slug: 'ai-leadership-transformation',
|
||
|
|
title: 'AI-Powered Leadership: Transforming Decision Making',
|
||
|
|
description: 'Explore how artificial intelligence is reshaping leadership practices and learn to leverage AI tools for better decision-making.',
|
||
|
|
presenter: 'Dr. Alex Kim',
|
||
|
|
presenterTitle: 'AI Strategy Director',
|
||
|
|
company: 'AI Leadership Labs',
|
||
|
|
date: '2024-03-15',
|
||
|
|
time: '2:00 PM EST',
|
||
|
|
duration: '75 minutes',
|
||
|
|
attendees: '3,500+',
|
||
|
|
category: 'Technology Leadership',
|
||
|
|
tags: ['Artificial Intelligence', 'Decision Making', 'Technology', 'Innovation'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1677442136019-21780ecad995?w=600&h=400&fit=crop',
|
||
|
|
status: 'Upcoming',
|
||
|
|
featured: true,
|
||
|
|
level: 'Advanced',
|
||
|
|
format: 'Virtual',
|
||
|
|
rating: 4.9,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '8',
|
||
|
|
slug: 'sustainable-leadership-live',
|
||
|
|
title: 'Sustainable Leadership: Building for the Future - LIVE SESSION',
|
||
|
|
description: 'Join us LIVE as we discuss sustainable leadership practices and environmental responsibility in business leadership.',
|
||
|
|
presenter: 'Maria Santos',
|
||
|
|
presenterTitle: 'Sustainability Leadership Expert',
|
||
|
|
company: 'Green Leadership Council',
|
||
|
|
date: '2024-02-20',
|
||
|
|
time: '1:00 PM EST',
|
||
|
|
duration: '90 minutes',
|
||
|
|
attendees: '2,200+',
|
||
|
|
category: 'Sustainable Leadership',
|
||
|
|
tags: ['Sustainability', 'Environmental Leadership', 'Future Business', 'Corporate Responsibility'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1542601906990-b4d3fb778b09?w=600&h=400&fit=crop',
|
||
|
|
status: 'Live',
|
||
|
|
featured: true,
|
||
|
|
level: 'Intermediate',
|
||
|
|
format: 'Virtual',
|
||
|
|
rating: 4.7,
|
||
|
|
price: 'Free'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: '9',
|
||
|
|
slug: 'cross-cultural-leadership',
|
||
|
|
title: 'Cross-Cultural Leadership: Leading Global Teams Effectively',
|
||
|
|
description: 'Develop the skills needed to lead diverse, multicultural teams across different time zones and cultural contexts.',
|
||
|
|
presenter: 'Dr. Raj Patel',
|
||
|
|
presenterTitle: 'Global Leadership Specialist',
|
||
|
|
company: 'International Business Academy',
|
||
|
|
date: '2024-02-25',
|
||
|
|
time: '11:00 AM EST',
|
||
|
|
duration: '65 minutes',
|
||
|
|
attendees: '1,750+',
|
||
|
|
category: 'Global Leadership',
|
||
|
|
tags: ['Cross-Cultural', 'Global Teams', 'Diversity', 'Communication'],
|
||
|
|
thumbnail: 'https://images.unsplash.com/photo-1573164713714-d95e436ab8d6?w=600&h=400&fit=crop',
|
||
|
|
status: 'Available',
|
||
|
|
featured: false,
|
||
|
|
level: 'Intermediate',
|
||
|
|
format: 'Virtual',
|
||
|
|
rating: 4.6,
|
||
|
|
price: 'Free'
|
||
|
|
}
|
||
|
|
];
|
||
|
|
|
||
|
|
// Filter configurations
|
||
|
|
const categories = ['All Categories', 'Digital Transformation', 'Team Development', 'Strategy', 'Personal Development', 'Crisis Management', 'Future of Work', 'Technology Leadership', 'Sustainable Leadership', 'Global Leadership'];
|
||
|
|
const formats = ['All Formats', 'Virtual', 'Hybrid', 'In Person'];
|
||
|
|
const levels = ['All Levels', 'Beginner', 'Intermediate', 'Advanced'];
|
||
|
|
const statuses = ['All Status', 'Available', 'Live', 'Upcoming', 'Recorded', 'Featured'];
|
||
|
|
const sortOptions = [
|
||
|
|
{ value: 'Most Popular', label: 'Most Popular' },
|
||
|
|
{ value: 'newest', label: 'Newest First' },
|
||
|
|
{ value: 'oldest', label: 'Oldest First' },
|
||
|
|
{ value: 'title', label: 'Title A-Z' },
|
||
|
|
{ value: 'duration', label: 'Duration' },
|
||
|
|
{ value: 'rating', label: 'Highest Rated' }
|
||
|
|
];
|
||
|
|
|
||
|
|
export function WebinarsPage() {
|
||
|
|
const [searchTerm, setSearchTerm] = useState('');
|
||
|
|
const [selectedCategory, setSelectedCategory] = useState('All Categories');
|
||
|
|
const [selectedFormat, setSelectedFormat] = useState('All Formats');
|
||
|
|
const [selectedLevel, setSelectedLevel] = useState('All Levels');
|
||
|
|
const [selectedStatus, setSelectedStatus] = useState('All Status');
|
||
|
|
const [sortBy, setSortBy] = useState('Most Popular');
|
||
|
|
const [viewType, setViewType] = useState<'grid' | 'list'>('grid');
|
||
|
|
const [currentPage, setCurrentPage] = useState(1);
|
||
|
|
const webinarsPerPage = 9;
|
||
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
||
|
|
|
||
|
|
// Filter and sort webinars
|
||
|
|
const filteredWebinars = webinarsData.filter(webinar => {
|
||
|
|
const matchesSearch = webinar.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||
|
|
webinar.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||
|
|
webinar.presenter.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||
|
|
webinar.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase()));
|
||
|
|
const matchesCategory = selectedCategory === 'All Categories' || webinar.category === selectedCategory;
|
||
|
|
const matchesFormat = selectedFormat === 'All Formats' || webinar.format === selectedFormat;
|
||
|
|
const matchesLevel = selectedLevel === 'All Levels' || webinar.level === selectedLevel;
|
||
|
|
const matchesStatus = selectedStatus === 'All Status' ||
|
||
|
|
webinar.status === selectedStatus ||
|
||
|
|
(selectedStatus === 'Featured' && webinar.featured);
|
||
|
|
|
||
|
|
return matchesSearch && matchesCategory && matchesFormat && matchesLevel && matchesStatus;
|
||
|
|
}).sort((a, b) => {
|
||
|
|
switch (sortBy) {
|
||
|
|
case 'newest':
|
||
|
|
return new Date(b.date).getTime() - new Date(a.date).getTime();
|
||
|
|
case 'oldest':
|
||
|
|
return new Date(a.date).getTime() - new Date(b.date).getTime();
|
||
|
|
case 'title':
|
||
|
|
return a.title.localeCompare(b.title);
|
||
|
|
case 'duration':
|
||
|
|
return parseInt(b.duration) - parseInt(a.duration);
|
||
|
|
case 'rating':
|
||
|
|
return b.rating - a.rating;
|
||
|
|
default:
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Statistics
|
||
|
|
const stats = {
|
||
|
|
total: webinarsData.length,
|
||
|
|
available: webinarsData.filter(w => w.status === 'Available').length,
|
||
|
|
live: webinarsData.filter(w => w.status === 'Live').length,
|
||
|
|
upcoming: webinarsData.filter(w => w.status === 'Upcoming').length,
|
||
|
|
recorded: webinarsData.filter(w => w.status === 'Recorded').length,
|
||
|
|
featured: webinarsData.filter(w => w.featured).length,
|
||
|
|
avgRating: (webinarsData.reduce((sum, w) => sum + w.rating, 0) / webinarsData.length).toFixed(1)
|
||
|
|
};
|
||
|
|
|
||
|
|
// Paginate results
|
||
|
|
const totalPages = Math.ceil(filteredWebinars.length / webinarsPerPage);
|
||
|
|
const currentWebinars = filteredWebinars.slice((currentPage - 1) * webinarsPerPage, currentPage * webinarsPerPage);
|
||
|
|
|
||
|
|
const formatDate = (dateString: string) => {
|
||
|
|
return new Date(dateString).toLocaleDateString('en-US', {
|
||
|
|
year: 'numeric',
|
||
|
|
month: 'long',
|
||
|
|
day: 'numeric'
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
const clearAllFilters = () => {
|
||
|
|
setSearchTerm('');
|
||
|
|
setSelectedCategory('All Categories');
|
||
|
|
setSelectedFormat('All Formats');
|
||
|
|
setSelectedLevel('All Levels');
|
||
|
|
setSelectedStatus('All Status');
|
||
|
|
setSortBy('Most Popular');
|
||
|
|
};
|
||
|
|
|
||
|
|
const hasActiveFilters = searchTerm ||
|
||
|
|
selectedCategory !== 'All Categories' ||
|
||
|
|
selectedFormat !== 'All Formats' ||
|
||
|
|
selectedLevel !== 'All Levels' ||
|
||
|
|
selectedStatus !== 'All Status';
|
||
|
|
|
||
|
|
const renderStars = (rating: number) => {
|
||
|
|
return Array.from({ length: 5 }, (_, i) => (
|
||
|
|
<span key={i} className={`text-sm ${i < Math.floor(rating) ? 'text-yellow-400' : 'text-gray-300'}`}>★</span>
|
||
|
|
));
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div style={{ backgroundColor: '#FFFFFF' }}>
|
||
|
|
{/* Hero Section with Background Image */}
|
||
|
|
<section className="relative h-[500px] overflow-hidden">
|
||
|
|
{/* Background Image */}
|
||
|
|
<div className="absolute inset-0">
|
||
|
|
<ImageWithFallback
|
||
|
|
src="https://images.unsplash.com/photo-1552664730-d307ca884978?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxidXNpbmVzcyUyMHByZXNlbnRhdGlvbiUyMHdlYmluYXIlMjBjb25mZXJlbmNlfGVufDF8fHx8MTc1NTg1NDI3MHww&ixlib=rb-4.1.0&q=80&w=1080"
|
||
|
|
alt="Professional webinar and conference presentation"
|
||
|
|
className="w-full h-full object-cover"
|
||
|
|
/>
|
||
|
|
<div className="absolute inset-0 bg-black/60" />
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Hero Content */}
|
||
|
|
<div className="relative h-full flex flex-col justify-center section-margin-x">
|
||
|
|
<div className="text-center max-w-4xl mx-auto">
|
||
|
|
<div className="branded-tag-system-white mb-6">
|
||
|
|
<span className="dot"></span>
|
||
|
|
<span className="text">Expert Leadership Insights</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h1 className="text-h1-white mb-6">
|
||
|
|
Transform Your Leadership<br />
|
||
|
|
Through Expert Webcasts
|
||
|
|
</h1>
|
||
|
|
|
||
|
|
<p className="text-body-lg-white max-w-3xl mx-auto mb-8">
|
||
|
|
Access world-class leadership development content from industry experts.
|
||
|
|
Join thousands of leaders who are advancing their skills through our
|
||
|
|
comprehensive webcast library.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||
|
|
<PrimaryCTAButton
|
||
|
|
text="Browse All Webcasts"
|
||
|
|
onClick={() => {
|
||
|
|
const filtersSection = document.getElementById('webinars-filters');
|
||
|
|
if (filtersSection) {
|
||
|
|
filtersSection.scrollIntoView({ behavior: 'smooth' });
|
||
|
|
}
|
||
|
|
}}
|
||
|
|
className="cta-text-black"
|
||
|
|
/>
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="lg"
|
||
|
|
className="bg-white/10 text-white border-white/30 hover:bg-white/20 backdrop-blur-sm"
|
||
|
|
onClick={() => navigateTo('/contact?topic=webinars')}
|
||
|
|
>
|
||
|
|
<Calendar className="w-5 h-5 mr-2" />
|
||
|
|
Schedule a Session
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Statistics Strip at Bottom */}
|
||
|
|
<div className="absolute bottom-0 left-0 right-0">
|
||
|
|
<div className="bg-black/80 backdrop-blur-sm px-8 py-6">
|
||
|
|
<div className="section-margin-x">
|
||
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 text-center">
|
||
|
|
<div>
|
||
|
|
<div className="text-h2-white mb-2">{stats.total}+</div>
|
||
|
|
<div className="text-small-white">Expert Webcasts</div>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<div className="text-h2-white mb-2">{stats.live + stats.upcoming}</div>
|
||
|
|
<div className="text-small-white">Live & Upcoming</div>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<div className="text-h2-white mb-2">25K+</div>
|
||
|
|
<div className="text-small-white">Total Attendees</div>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<div className="text-h2-white mb-2">{stats.avgRating}/5</div>
|
||
|
|
<div className="text-small-white">Average Rating</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
{/* Search and Controls Section */}
|
||
|
|
<section id="webinars-filters" className="py-8" style={{ backgroundColor: '#FFFFFF' }}>
|
||
|
|
<div className="section-margin-x">
|
||
|
|
{/* Search and View Controls */}
|
||
|
|
<div className="flex flex-col lg:flex-row gap-6 mb-8">
|
||
|
|
{/* Search Bar */}
|
||
|
|
<div className="relative max-w-md flex-1">
|
||
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
||
|
|
<Input
|
||
|
|
type="text"
|
||
|
|
placeholder="Search webcasts, presenters, topics..."
|
||
|
|
value={searchTerm}
|
||
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||
|
|
className="pl-10 pr-4 py-3 text-body rounded-lg border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 transition-all duration-200 w-full bg-gray-50"
|
||
|
|
style={{
|
||
|
|
fontSize: 'var(--font-body)',
|
||
|
|
fontFamily: 'var(--font-family-base)',
|
||
|
|
height: '48px'
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Controls */}
|
||
|
|
<div className="flex items-center gap-4">
|
||
|
|
{/* View Toggle */}
|
||
|
|
<div className="flex items-center border border-gray-300 rounded-lg overflow-hidden">
|
||
|
|
<button
|
||
|
|
onClick={() => setViewType('grid')}
|
||
|
|
className={`p-2 transition-colors ${
|
||
|
|
viewType === 'grid'
|
||
|
|
? 'text-white'
|
||
|
|
: 'bg-white text-gray-600 hover:bg-gray-50'
|
||
|
|
}`}
|
||
|
|
style={{
|
||
|
|
backgroundColor: viewType === 'grid' ? 'var(--color-primary)' : undefined
|
||
|
|
}}
|
||
|
|
aria-label="Grid view"
|
||
|
|
>
|
||
|
|
<Grid className="w-4 h-4" />
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => setViewType('list')}
|
||
|
|
className={`p-2 transition-colors ${
|
||
|
|
viewType === 'list'
|
||
|
|
? 'text-white'
|
||
|
|
: 'bg-white text-gray-600 hover:bg-gray-50'
|
||
|
|
}`}
|
||
|
|
style={{
|
||
|
|
backgroundColor: viewType === 'list' ? 'var(--color-primary)' : undefined
|
||
|
|
}}
|
||
|
|
aria-label="List view"
|
||
|
|
>
|
||
|
|
<List className="w-4 h-4" />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Sort */}
|
||
|
|
<Select value={sortBy} onValueChange={setSortBy}>
|
||
|
|
<SelectTrigger className="w-48 text-body">
|
||
|
|
<SelectValue placeholder="Sort by" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
{sortOptions.map((option) => (
|
||
|
|
<SelectItem key={option.value} value={option.value}>
|
||
|
|
{option.label}
|
||
|
|
</SelectItem>
|
||
|
|
))}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Filters */}
|
||
|
|
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6">
|
||
|
|
<Select value={selectedCategory} onValueChange={setSelectedCategory}>
|
||
|
|
<SelectTrigger>
|
||
|
|
<SelectValue placeholder="Category" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
{categories.map((category) => (
|
||
|
|
<SelectItem key={category} value={category}>
|
||
|
|
{category}
|
||
|
|
</SelectItem>
|
||
|
|
))}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
|
||
|
|
<Select value={selectedFormat} onValueChange={setSelectedFormat}>
|
||
|
|
<SelectTrigger>
|
||
|
|
<SelectValue placeholder="Format" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
{formats.map((format) => (
|
||
|
|
<SelectItem key={format} value={format}>
|
||
|
|
{format}
|
||
|
|
</SelectItem>
|
||
|
|
))}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
|
||
|
|
<Select value={selectedLevel} onValueChange={setSelectedLevel}>
|
||
|
|
<SelectTrigger>
|
||
|
|
<SelectValue placeholder="Level" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
{levels.map((level) => (
|
||
|
|
<SelectItem key={level} value={level}>
|
||
|
|
{level}
|
||
|
|
</SelectItem>
|
||
|
|
))}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
|
||
|
|
<Select value={selectedStatus} onValueChange={setSelectedStatus}>
|
||
|
|
<SelectTrigger>
|
||
|
|
<SelectValue placeholder="Status" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
{statuses.map((status) => (
|
||
|
|
<SelectItem key={status} value={status}>
|
||
|
|
{status}
|
||
|
|
</SelectItem>
|
||
|
|
))}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
|
||
|
|
{hasActiveFilters && (
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
onClick={clearAllFilters}
|
||
|
|
className="text-gray-600 hover:text-gray-800"
|
||
|
|
>
|
||
|
|
<X className="w-4 h-4 mr-2" />
|
||
|
|
Clear All
|
||
|
|
</Button>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="text-small text-gray-600 mb-8">
|
||
|
|
Showing {currentWebinars.length} of {filteredWebinars.length} webcasts
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
{/* Webinars Content */}
|
||
|
|
<section className="pb-16" style={{ backgroundColor: '#FFFFFF' }}>
|
||
|
|
<div className="section-margin-x">
|
||
|
|
{currentWebinars.length === 0 ? (
|
||
|
|
<div className="text-center py-16">
|
||
|
|
<div className="w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-full flex items-center justify-center">
|
||
|
|
<Search className="w-8 h-8 text-gray-400" />
|
||
|
|
</div>
|
||
|
|
<h3 className="text-h4 mb-4">No webcasts found</h3>
|
||
|
|
<p className="text-body text-gray-600 mb-6">
|
||
|
|
Try adjusting your filters or search terms to find relevant content.
|
||
|
|
</p>
|
||
|
|
<Button onClick={clearAllFilters} variant="outline">
|
||
|
|
Clear All Filters
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<>
|
||
|
|
{/* Grid View */}
|
||
|
|
{viewType === 'grid' && (
|
||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||
|
|
{currentWebinars.map((webinar) => (
|
||
|
|
<Card
|
||
|
|
key={webinar.id}
|
||
|
|
className="overflow-hidden hover:shadow-xl transition-all duration-300 cursor-pointer group border-0 shadow-lg"
|
||
|
|
onClick={() => navigateTo(`/webinar/${webinar.slug}`)}
|
||
|
|
>
|
||
|
|
<div className="aspect-video w-full bg-gray-100 overflow-hidden relative">
|
||
|
|
<ImageWithFallback
|
||
|
|
src={webinar.thumbnail}
|
||
|
|
alt={webinar.title}
|
||
|
|
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
|
||
|
|
/>
|
||
|
|
|
||
|
|
{/* Status Badge */}
|
||
|
|
<div className="absolute top-4 left-4">
|
||
|
|
{webinar.status === 'Live' && (
|
||
|
|
<Badge className="bg-red-600 text-white border-red-600 animate-pulse">
|
||
|
|
LIVE
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
{webinar.status === 'Upcoming' && (
|
||
|
|
<Badge className="bg-blue-600 text-white border-blue-600">
|
||
|
|
Upcoming
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
{webinar.status === 'Recorded' && (
|
||
|
|
<Badge className="bg-green-600 text-white border-green-600">
|
||
|
|
Replay Available
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{webinar.featured && (
|
||
|
|
<div className="absolute top-4 right-4">
|
||
|
|
<Badge className="bg-yellow-500 text-white border-yellow-500">
|
||
|
|
<Award className="w-3 h-3 mr-1" />
|
||
|
|
Featured
|
||
|
|
</Badge>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Play Button Overlay */}
|
||
|
|
<div className="absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||
|
|
<Button
|
||
|
|
variant="secondary"
|
||
|
|
size="lg"
|
||
|
|
className="bg-white text-black hover:bg-gray-100"
|
||
|
|
>
|
||
|
|
<Play className="w-5 h-5 mr-2" />
|
||
|
|
{webinar.status === 'Live' ? 'Join Live' : webinar.status === 'Upcoming' ? 'Register' : 'Watch'}
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<CardContent className="p-6">
|
||
|
|
{/* Meta Info */}
|
||
|
|
<div className="flex items-center gap-2 mb-3">
|
||
|
|
<Badge variant="outline" className="text-xs">
|
||
|
|
{webinar.format}
|
||
|
|
</Badge>
|
||
|
|
<Badge variant="outline" className="text-xs">
|
||
|
|
{webinar.level}
|
||
|
|
</Badge>
|
||
|
|
<div className="flex items-center gap-1 ml-auto">
|
||
|
|
{renderStars(webinar.rating)}
|
||
|
|
<span className="text-xs text-gray-600 ml-1">{webinar.rating}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h3 className="text-h4 mb-3 group-hover:text-blue-600 transition-colors line-clamp-2">
|
||
|
|
{webinar.title}
|
||
|
|
</h3>
|
||
|
|
|
||
|
|
<p className="text-small text-gray-600 mb-4 line-clamp-2">
|
||
|
|
{webinar.description}
|
||
|
|
</p>
|
||
|
|
|
||
|
|
{/* Presenter Info */}
|
||
|
|
<div className="flex items-center mb-4">
|
||
|
|
<div className="w-10 h-10 bg-gray-200 rounded-full flex items-center justify-center mr-3">
|
||
|
|
<Users className="w-5 h-5 text-gray-400" />
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<div className="text-small font-medium">{webinar.presenter}</div>
|
||
|
|
<div className="text-xs text-gray-500">{webinar.presenterTitle}</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Details */}
|
||
|
|
<div className="flex items-center justify-between text-small text-gray-500 mb-4">
|
||
|
|
<div className="flex items-center gap-4">
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<Clock className="w-4 h-4" />
|
||
|
|
<span>{webinar.duration}</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<Users className="w-4 h-4" />
|
||
|
|
<span>{webinar.attendees}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<Globe className="w-4 h-4" />
|
||
|
|
<span>{webinar.format}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Date and Price */}
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<div className="text-small text-gray-600">
|
||
|
|
{formatDate(webinar.date)}
|
||
|
|
</div>
|
||
|
|
<div className="text-small font-medium text-green-600">
|
||
|
|
{webinar.price}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* List View */}
|
||
|
|
{viewType === 'list' && (
|
||
|
|
<div className="space-y-6">
|
||
|
|
{currentWebinars.map((webinar) => (
|
||
|
|
<Card
|
||
|
|
key={webinar.id}
|
||
|
|
className="overflow-hidden hover:shadow-xl transition-all duration-300 cursor-pointer border-0 shadow-lg"
|
||
|
|
onClick={() => navigateTo(`/webinar/${webinar.slug}`)}
|
||
|
|
>
|
||
|
|
<div className="flex">
|
||
|
|
<div className="w-80 h-48 bg-gray-100 overflow-hidden relative flex-shrink-0">
|
||
|
|
<ImageWithFallback
|
||
|
|
src={webinar.thumbnail}
|
||
|
|
alt={webinar.title}
|
||
|
|
className="w-full h-full object-cover"
|
||
|
|
/>
|
||
|
|
{webinar.featured && (
|
||
|
|
<div className="absolute top-4 right-4">
|
||
|
|
<Badge className="bg-yellow-500 text-white border-yellow-500">
|
||
|
|
<Award className="w-3 h-3 mr-1" />
|
||
|
|
Featured
|
||
|
|
</Badge>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
<CardContent className="flex-1 p-6">
|
||
|
|
<div className="flex items-start justify-between mb-4">
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Badge variant="outline" className="text-xs">
|
||
|
|
{webinar.format}
|
||
|
|
</Badge>
|
||
|
|
<Badge variant="outline" className="text-xs">
|
||
|
|
{webinar.level}
|
||
|
|
</Badge>
|
||
|
|
{webinar.status === 'Live' && (
|
||
|
|
<Badge className="bg-red-600 text-white border-red-600 animate-pulse">
|
||
|
|
LIVE
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
{webinar.status === 'Upcoming' && (
|
||
|
|
<Badge className="bg-blue-600 text-white border-blue-600">
|
||
|
|
Upcoming
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
{webinar.status === 'Recorded' && (
|
||
|
|
<Badge className="bg-green-600 text-white border-green-600">
|
||
|
|
Replay Available
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
{renderStars(webinar.rating)}
|
||
|
|
<span className="text-xs text-gray-600 ml-1">{webinar.rating}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h3 className="text-h4 mb-3 hover:text-blue-600 transition-colors">
|
||
|
|
{webinar.title}
|
||
|
|
</h3>
|
||
|
|
|
||
|
|
<p className="text-small text-gray-600 mb-4">
|
||
|
|
{webinar.description}
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<div className="flex items-center gap-6 text-small text-gray-500">
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<Clock className="w-4 h-4" />
|
||
|
|
<span>{webinar.duration}</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<Users className="w-4 h-4" />
|
||
|
|
<span>{webinar.attendees}</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<span>By {webinar.presenter}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-4">
|
||
|
|
<div className="text-small text-gray-600">
|
||
|
|
{formatDate(webinar.date)}
|
||
|
|
</div>
|
||
|
|
<div className="text-small font-medium text-green-600">
|
||
|
|
{webinar.price}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</div>
|
||
|
|
</Card>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Pagination */}
|
||
|
|
{totalPages > 1 && (
|
||
|
|
<div className="flex items-center justify-center gap-2 mt-12">
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
onClick={() => setCurrentPage(prev => Math.max(1, prev - 1))}
|
||
|
|
disabled={currentPage === 1}
|
||
|
|
>
|
||
|
|
<ChevronLeft className="w-4 h-4" />
|
||
|
|
Previous
|
||
|
|
</Button>
|
||
|
|
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
{Array.from({ length: Math.min(totalPages, 7) }, (_, i) => {
|
||
|
|
let page;
|
||
|
|
if (totalPages <= 7) {
|
||
|
|
page = i + 1;
|
||
|
|
} else if (currentPage <= 4) {
|
||
|
|
page = i + 1;
|
||
|
|
} else if (currentPage >= totalPages - 3) {
|
||
|
|
page = totalPages - 6 + i;
|
||
|
|
} else {
|
||
|
|
page = currentPage - 3 + i;
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Button
|
||
|
|
key={page}
|
||
|
|
variant={currentPage === page ? "default" : "outline"}
|
||
|
|
size="sm"
|
||
|
|
onClick={() => setCurrentPage(page)}
|
||
|
|
className="w-10 h-10 p-0"
|
||
|
|
style={{
|
||
|
|
backgroundColor: currentPage === page ? 'var(--color-primary)' : undefined,
|
||
|
|
color: currentPage === page ? 'white' : undefined
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{page}
|
||
|
|
</Button>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
onClick={() => setCurrentPage(prev => Math.min(totalPages, prev + 1))}
|
||
|
|
disabled={currentPage === totalPages}
|
||
|
|
>
|
||
|
|
Next
|
||
|
|
<ChevronRight className="w-4 h-4" />
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
{/* CTA Section */}
|
||
|
|
<section className="py-16 bg-gray-50">
|
||
|
|
<div className="section-margin-x text-center">
|
||
|
|
<div className="max-w-3xl mx-auto">
|
||
|
|
<h2 className="text-h2 mb-6">Ready to Transform Your Leadership?</h2>
|
||
|
|
<p className="text-body-lg text-gray-600 mb-8">
|
||
|
|
Join thousands of professionals who are advancing their careers through our expert-led webcasts.
|
||
|
|
Start your leadership transformation today.
|
||
|
|
</p>
|
||
|
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||
|
|
<PrimaryCTAButton
|
||
|
|
text="Get Started Today"
|
||
|
|
onClick={() => navigateTo('/contact?topic=leadership-development')}
|
||
|
|
className="cta-text-black"
|
||
|
|
/>
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="lg"
|
||
|
|
onClick={() => navigateTo('/about/our-expertise')}
|
||
|
|
>
|
||
|
|
<TrendingUp className="w-5 h-5 mr-2" />
|
||
|
|
Learn More About Us
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|