108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
import { useState } from 'react';
|
|
import { ChevronRight, Users, Trophy, UserPlus } from 'lucide-react';
|
|
import type { TeamSummaryViewModel } from '@/lib/view-models/TeamSummaryViewModel';
|
|
import TeamCard from './TeamCard';
|
|
|
|
type SkillLevel = 'pro' | 'advanced' | 'intermediate' | 'beginner';
|
|
type TeamSpecialization = 'endurance' | 'sprint' | 'mixed';
|
|
|
|
interface SkillLevelConfig {
|
|
id: SkillLevel;
|
|
label: string;
|
|
icon: React.ElementType;
|
|
color: string;
|
|
bgColor: string;
|
|
borderColor: string;
|
|
description: string;
|
|
}
|
|
|
|
interface SkillLevelSectionProps {
|
|
level: SkillLevelConfig;
|
|
teams: TeamSummaryViewModel[];
|
|
onTeamClick: (id: string) => void;
|
|
defaultExpanded?: boolean;
|
|
}
|
|
|
|
export default function SkillLevelSection({
|
|
level,
|
|
teams,
|
|
onTeamClick,
|
|
defaultExpanded = false
|
|
}: SkillLevelSectionProps) {
|
|
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
const recruitingTeams = teams.filter((t) => t.isRecruiting);
|
|
const displayedTeams = isExpanded ? teams : teams.slice(0, 3);
|
|
const Icon = level.icon;
|
|
|
|
if (teams.length === 0) return null;
|
|
|
|
const specialization = (teamSpecialization: string | undefined): TeamSpecialization | undefined => {
|
|
if (teamSpecialization === 'endurance' || teamSpecialization === 'sprint' || teamSpecialization === 'mixed') {
|
|
return teamSpecialization;
|
|
}
|
|
return undefined;
|
|
};
|
|
|
|
return (
|
|
<div className="mb-8">
|
|
{/* Section Header */}
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className={`flex h-11 w-11 items-center justify-center rounded-xl ${level.bgColor} border ${level.borderColor}`}>
|
|
<Icon className={`w-5 h-5 ${level.color}`} />
|
|
</div>
|
|
<div>
|
|
<div className="flex items-center gap-2">
|
|
<h2 className="text-xl font-bold text-white">{level.label}</h2>
|
|
<span className="px-2 py-0.5 rounded-full text-xs bg-charcoal-outline/50 text-gray-400">
|
|
{teams.length} {teams.length === 1 ? 'team' : 'teams'}
|
|
</span>
|
|
{recruitingTeams.length > 0 && (
|
|
<span className="flex items-center gap-1 px-2 py-0.5 rounded-full text-xs bg-performance-green/10 text-performance-green border border-performance-green/20">
|
|
<UserPlus className="w-3 h-3" />
|
|
{recruitingTeams.length} recruiting
|
|
</span>
|
|
)}
|
|
</div>
|
|
<p className="text-sm text-gray-500">{level.description}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{teams.length > 3 && (
|
|
<button
|
|
type="button"
|
|
onClick={() => setIsExpanded(!isExpanded)}
|
|
className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-sm text-gray-400 hover:text-white hover:bg-iron-gray/50 transition-all"
|
|
>
|
|
{isExpanded ? 'Show less' : `View all ${teams.length}`}
|
|
<ChevronRight className={`w-4 h-4 transition-transform ${isExpanded ? 'rotate-90' : ''}`} />
|
|
</button>
|
|
)}
|
|
</div>
|
|
|
|
{/* Teams Grid */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{displayedTeams.map((team) => (
|
|
<TeamCard
|
|
key={team.id}
|
|
id={team.id}
|
|
name={team.name}
|
|
description={team.description ?? ''}
|
|
logo={team.logoUrl}
|
|
memberCount={team.memberCount}
|
|
rating={team.rating}
|
|
totalWins={team.totalWins}
|
|
totalRaces={team.totalRaces}
|
|
performanceLevel={team.performanceLevel as SkillLevel}
|
|
isRecruiting={team.isRecruiting}
|
|
specialization={specialization(team.specialization)}
|
|
region={team.region ?? ''}
|
|
languages={team.languages}
|
|
category={team.category}
|
|
onClick={() => onTeamClick(team.id)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |