299 lines
12 KiB
TypeScript
299 lines
12 KiB
TypeScript
import React from 'react';
|
|
import { Button } from '../ui/button';
|
|
import { Badge } from '../ui/badge';
|
|
import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar';
|
|
import {
|
|
Star,
|
|
Clock,
|
|
Users,
|
|
Play,
|
|
CheckCircle,
|
|
Heart,
|
|
BookOpen,
|
|
ChevronRight,
|
|
MoreHorizontal
|
|
} from 'lucide-react';
|
|
import { Course } from '../../pages/learner/data/libraryData';
|
|
import { ImageWithFallback } from '../figma/ImageWithFallback';
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
interface HorizontalCourseCardProps {
|
|
course: Course;
|
|
userType: 'individual' | 'corporate';
|
|
onEnroll?: (courseId: string) => void;
|
|
onContinue?: (courseId: string) => void;
|
|
onBookmark?: (courseId: string) => void;
|
|
}
|
|
|
|
// Course images based on course category
|
|
const getCourseImage = (category: string) => {
|
|
const patterns = {
|
|
'Leadership': (
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
<div className="absolute inset-0 opacity-100">
|
|
<ImageWithFallback
|
|
src="https://images.unsplash.com/photo-1658198420916-951923730cdd?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxsZWFkZXJzaGlwJTIwYm9va3N8ZW58MXx8fHwxNzU1ODQzNDIxfDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
|
|
alt=""
|
|
className="w-full h-full object-cover object-right"
|
|
/>
|
|
</div>
|
|
</div>
|
|
),
|
|
'Personal Development': (
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
<div className="absolute inset-0 opacity-100">
|
|
<ImageWithFallback
|
|
src="https://images.unsplash.com/photo-1668092547893-6402c0387885?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxidXNpbmVzcyUyMGVkdWNhdGlvbiUyMGxlYXJuaW5nfGVufDF8fHx8MTc1NTg0MzQwOHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
|
|
alt=""
|
|
className="w-full h-full object-cover object-center"
|
|
/>
|
|
</div>
|
|
</div>
|
|
),
|
|
'Team Management': (
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
<div className="absolute inset-0 opacity-100">
|
|
<ImageWithFallback
|
|
src="https://images.unsplash.com/photo-1668092547893-6402c0387885?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHhidXNpbmVzcyUyMGVkdWNhdGlvbiUyMGxlYXJuaW5nfGVufDF8fHx8MTc1NTg0MzQwOHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
|
|
alt=""
|
|
className="w-full h-full object-cover object-center"
|
|
/>
|
|
</div>
|
|
</div>
|
|
),
|
|
'Digital Leadership': (
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
<div className="absolute inset-0 opacity-100">
|
|
<ImageWithFallback
|
|
src="https://images.unsplash.com/photo-1588912914078-2fe5224fd8b8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxvbmxpbmUlMjBjb3Vyc2UlMjBsYXB0b3B8ZW58MXx8fHwxNzU1NzIwMTYyfDA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
|
|
alt=""
|
|
className="w-full h-full object-cover object-center"
|
|
/>
|
|
</div>
|
|
</div>
|
|
),
|
|
'Communication': (
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
<div className="absolute inset-0 opacity-100">
|
|
<ImageWithFallback
|
|
src="https://images.unsplash.com/photo-1668092547893-6402c0387885?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxidXNpbmVzcyUyMGVkdWNhdGlvbiUyMGxlYXJuaW5nfGVufDF8fHx8MTc1NTg0MzQwOHww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
|
|
alt=""
|
|
className="w-full h-full object-cover object-center"
|
|
/>
|
|
</div>
|
|
</div>
|
|
)
|
|
};
|
|
|
|
return patterns[category as keyof typeof patterns] || patterns.Leadership;
|
|
};
|
|
|
|
export function HorizontalCourseCard({ course, userType, onEnroll, onContinue, onBookmark }: HorizontalCourseCardProps) {
|
|
const courseImage = getCourseImage(course.category);
|
|
const navigate = useNavigate();
|
|
|
|
|
|
// Navigate to course details page with proper query parameters
|
|
const handleCourseNavigation = () => {
|
|
navigate(`/course?view=${userType}&courseId=${course.id}`);
|
|
};
|
|
|
|
return (
|
|
<div className="bg-background border border-border rounded-lg overflow-hidden hover:shadow-lg transition-all duration-200"
|
|
style={{ height: '260px', minHeight: '260px' }}>
|
|
<div className="flex h-full">
|
|
{/* Left Image Section - 50% width, full height */}
|
|
<div className="w-1/2 relative overflow-hidden">
|
|
{/* Course image overlay */}
|
|
{courseImage}
|
|
|
|
{/* Status indicators - Positioned better for larger image area */}
|
|
<div className="absolute top-3 left-3 flex flex-wrap gap-1.5 z-10 max-w-[70%]">
|
|
{course.isFeatured && (
|
|
<Badge className="text-sm bg-white/90 text-foreground hover:bg-white font-medium">
|
|
Featured
|
|
</Badge>
|
|
)}
|
|
{course.isPremium && (
|
|
<Badge variant="secondary" className="text-sm bg-[#F8C301]/90 text-[#26231A] font-medium">
|
|
Premium
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
|
|
{/* Course status indicator */}
|
|
<div className="absolute top-3 right-3 z-10">
|
|
{course.status === 'completed' && (
|
|
<div className="bg-success/90 backdrop-blur-sm p-1.5 rounded-full">
|
|
<CheckCircle className="h-4 w-4 text-white" />
|
|
</div>
|
|
)}
|
|
{course.status === 'bookmarked' && (
|
|
<div className="bg-[#F8C301]/90 backdrop-blur-sm p-1.5 rounded-full">
|
|
<Heart className="h-4 w-4 text-[#26231A] fill-current" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Content Section - 50% width with increased spacing */}
|
|
<div className="w-1/2 p-5 flex flex-col justify-between">
|
|
{/* Top Content - Title and Description stay with original spacing */}
|
|
<div>
|
|
{/* Course Title - Increased to text-xl (20px) as requested */}
|
|
<h3 className="text-xl font-semibold text-foreground line-clamp-2 leading-tight mb-2">
|
|
{course.title}
|
|
</h3>
|
|
|
|
{/* Description with 8px spacing from title as requested */}
|
|
<p className="text-sm text-muted-foreground line-clamp-2 leading-relaxed mb-4">
|
|
{course.description}
|
|
</p>
|
|
|
|
{/* Elements after description - Increased vertical spacing to 12px (space-y-3) */}
|
|
<div className="space-y-3">
|
|
{/* Created by section - Updated font size for Avatar text */}
|
|
<div className="flex items-center gap-2">
|
|
<Avatar className="w-5 h-5 flex-shrink-0">
|
|
<AvatarImage src={course.instructor.avatar} />
|
|
<AvatarFallback className="text-sm">
|
|
{course.instructor.name.split(' ').map(n => n[0]).join('')}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
<span className="text-sm text-muted-foreground">Created by:</span>
|
|
<span className="text-sm font-medium text-foreground truncate">{course.instructor.name}</span>
|
|
</div>
|
|
|
|
{/* Badges below created by - Updated to text-sm (14px minimum) with brand colors */}
|
|
<div className="flex flex-wrap gap-1.5">
|
|
<Badge
|
|
variant="outline"
|
|
className={`text-sm font-medium ${
|
|
course.level === 'Beginner' ? 'border-success text-success bg-success/5' :
|
|
course.level === 'Intermediate' ? 'border-primary text-primary bg-primary/5' :
|
|
course.level === 'Advanced' ? 'border-[#26231A] text-[#26231A] bg-[#26231A]/5' :
|
|
'border-[#F8C301] text-[#26231A] bg-[#F8C301]/10'
|
|
}`}
|
|
>
|
|
{course.level}
|
|
</Badge>
|
|
<Badge
|
|
variant="outline"
|
|
className={`text-sm font-medium ${
|
|
course.category === 'Leadership' ? 'border-primary text-primary bg-primary/5' :
|
|
course.category === 'Digital Leadership' ? 'border-[#F8C301] text-[#26231A] bg-[#F8C301]/10' :
|
|
course.category === 'Strategy' ? 'border-[#26231A] text-[#26231A] bg-[#26231A]/5' :
|
|
'border-[#F8C301] text-[#26231A] bg-[#F8C301]/10'
|
|
}`}
|
|
>
|
|
{course.category}
|
|
</Badge>
|
|
</div>
|
|
|
|
{/* Combined lessons, duration, and rating section - All in one container */}
|
|
<div className="flex items-center justify-between text-sm text-muted-foreground">
|
|
{/* Left side: Duration and Lessons */}
|
|
<div className="flex items-center gap-4">
|
|
<div className="flex items-center gap-1">
|
|
<Clock className="h-3.5 w-3.5 flex-shrink-0" />
|
|
<span>{course.duration}</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<BookOpen className="h-3.5 w-3.5 flex-shrink-0" />
|
|
<span>{course.lessonsCount} lessons</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right side: Rating stars */}
|
|
<div className="flex items-center gap-1 flex-shrink-0">
|
|
{[...Array(5)].map((_, i) => (
|
|
<Star
|
|
key={i}
|
|
className={`h-3.5 w-3.5 ${
|
|
i < Math.floor(course.rating)
|
|
? 'text-[#F8C301] fill-current'
|
|
: 'text-muted-foreground'
|
|
}`}
|
|
/>
|
|
))}
|
|
<span className="text-sm font-medium ml-1 text-foreground">{course.rating}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom Section - CTA buttons only with reduced spacing */}
|
|
<div className="mt-auto">
|
|
{/* CTA buttons below everything else - wider for consistency */}
|
|
<div className="flex items-center gap-2">
|
|
{course.status === 'not-started' && (
|
|
<Button
|
|
onClick={handleCourseNavigation}
|
|
size="sm"
|
|
className="flex-1 text-base font-medium min-h-[36px]"
|
|
>
|
|
Start Course
|
|
<ChevronRight className="h-4 w-4 ml-1" />
|
|
</Button>
|
|
)}
|
|
|
|
{course.status === 'in-progress' && (
|
|
<Button
|
|
onClick={handleCourseNavigation}
|
|
size="sm"
|
|
className="flex-1 text-base font-medium min-h-[36px]"
|
|
>
|
|
Continue
|
|
<Play className="h-4 w-4 ml-1" />
|
|
</Button>
|
|
)}
|
|
|
|
{course.status === 'completed' && (
|
|
<Button
|
|
variant="outline"
|
|
onClick={handleCourseNavigation}
|
|
size="sm"
|
|
className="flex-1 text-base font-medium min-h-[36px]"
|
|
>
|
|
Review
|
|
<ChevronRight className="h-4 w-4 ml-1" />
|
|
</Button>
|
|
)}
|
|
|
|
{course.status === 'bookmarked' && (
|
|
<Button
|
|
onClick={handleCourseNavigation}
|
|
size="sm"
|
|
className="flex-1 text-base font-medium min-h-[36px]"
|
|
>
|
|
Start Course
|
|
<ChevronRight className="h-4 w-4 ml-1" />
|
|
</Button>
|
|
)}
|
|
|
|
{/* Secondary action buttons - optimized sizing */}
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => onBookmark?.(course.id)}
|
|
className="min-h-[36px] min-w-[36px] hover:bg-muted flex-shrink-0"
|
|
aria-label="Bookmark course"
|
|
>
|
|
<Heart className={`h-4 w-4 ${course.status === 'bookmarked' ? 'fill-current text-[#F8C301]' : 'text-muted-foreground'}`} />
|
|
</Button>
|
|
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="min-h-[36px] min-w-[36px] hover:bg-muted flex-shrink-0"
|
|
aria-label="More options"
|
|
>
|
|
<MoreHorizontal className="h-4 w-4 text-muted-foreground" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |