Files
MOPC-Portal/src/components/charts/cross-round-comparison.tsx

158 lines
6.1 KiB
TypeScript
Raw Normal View History

'use client'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Progress } from '@/components/ui/progress'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import { scoreGradient } from './chart-theme'
import { ArrowRight } from 'lucide-react'
interface StageComparison {
roundId: string
roundName: string
projectCount: number
evaluationCount: number
completionRate: number
averageScore: number | null
scoreDistribution: { score: number; count: number }[]
}
interface CrossStageComparisonProps {
data: StageComparison[]
}
export function CrossStageComparisonChart({
data,
}: CrossStageComparisonProps) {
if (!data?.length) {
return (
<Card>
<CardContent className="flex items-center justify-center py-12">
<p className="text-muted-foreground">No comparison data available</p>
</CardContent>
</Card>
)
}
const maxProjects = Math.max(...data.map((d) => d.projectCount), 1)
return (
<Card>
<CardHeader>
<CardTitle className="text-base">Round Progression</CardTitle>
</CardHeader>
<CardContent>
{/* Pipeline funnel visualization */}
<div className="flex items-center gap-2 mb-6 overflow-x-auto pb-2">
{data.map((round, idx) => (
<div key={round.roundId} className="flex items-center gap-2">
<div className="flex flex-col items-center min-w-[100px]">
<div
className="rounded-lg bg-[#053d57] flex items-center justify-center text-white font-bold text-lg tabular-nums transition-all"
style={{
width: `${Math.max(60, (round.projectCount / maxProjects) * 120)}px`,
height: `${Math.max(40, (round.projectCount / maxProjects) * 60)}px`,
}}
>
{round.projectCount}
</div>
<p className="text-xs text-muted-foreground mt-1.5 text-center leading-tight max-w-[100px] truncate">
{round.roundName}
</p>
</div>
{idx < data.length - 1 && (
<div className="flex flex-col items-center shrink-0">
<ArrowRight className="h-4 w-4 text-muted-foreground" />
{data[idx + 1].projectCount < round.projectCount && (
<span className="text-[10px] text-rose-500 tabular-nums font-medium">
-{round.projectCount - data[idx + 1].projectCount}
</span>
)}
</div>
)}
</div>
))}
</div>
{/* Detailed metrics table */}
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Round</TableHead>
<TableHead className="text-right tabular-nums">Projects</TableHead>
<TableHead className="text-right tabular-nums">Evaluations</TableHead>
<TableHead>Completion</TableHead>
<TableHead className="text-right">Avg Score</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((round, idx) => {
const prevCount = idx > 0 ? data[idx - 1].projectCount : null
const attrition = prevCount !== null && prevCount > 0
? Math.round(((prevCount - round.projectCount) / prevCount) * 100)
: null
return (
<TableRow key={round.roundId}>
<TableCell>
<div className="flex items-center gap-2">
<span className="font-medium text-sm">{round.roundName}</span>
{attrition !== null && attrition > 0 && (
<Badge variant="outline" className="text-[10px] text-rose-600 border-rose-200">
-{attrition}%
</Badge>
)}
</div>
</TableCell>
<TableCell className="text-right tabular-nums font-medium">
{round.projectCount}
</TableCell>
<TableCell className="text-right tabular-nums">
{round.evaluationCount > 0 ? round.evaluationCount : '—'}
</TableCell>
<TableCell>
{round.evaluationCount > 0 ? (
<div className="flex items-center gap-2">
<Progress value={round.completionRate} className="w-16 h-2" />
<span className="text-xs tabular-nums text-muted-foreground">
{round.completionRate}%
</span>
</div>
) : (
<span className="text-xs text-muted-foreground"></span>
)}
</TableCell>
<TableCell className="text-right">
{round.averageScore !== null ? (
<span
className="inline-flex items-center justify-center rounded-md px-2 py-0.5 text-xs font-semibold tabular-nums min-w-[36px]"
style={{
backgroundColor: scoreGradient(round.averageScore),
color: '#ffffff',
}}
>
{round.averageScore.toFixed(1)}
</span>
) : (
<span className="text-xs text-muted-foreground"></span>
)}
</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</div>
</CardContent>
</Card>
)
}