68 lines
3.1 KiB
JavaScript
68 lines
3.1 KiB
JavaScript
import React from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
const STAGES = [
|
|
{ key: 'applied', label: 'Applied', color: 'bg-[#D1E0D7]', text: 'text-[#333F48]' },
|
|
{ key: 'ai_screened', label: 'AI Screened', color: 'bg-[#F8E08E]', text: 'text-[#333F48]' },
|
|
{ key: 'shortlisted', label: 'Shortlisted', color: 'bg-[#F9E547]', text: 'text-[#0838E0]' },
|
|
{ key: 'interview', label: 'Interviewed', color: 'bg-[#333F48]', text: 'text-white' },
|
|
{ key: 'hired', label: 'Hired', color: 'bg-[#0838E0]', text: 'text-white' },
|
|
];
|
|
|
|
export default function PipelineFunnel({ applications }) {
|
|
const counts = STAGES.map((s) => {
|
|
if (s.key === 'ai_screened') {
|
|
return applications.filter(a => ['ai_screened', 'shortlisted', 'interview', 'hired'].includes(a.status)).length;
|
|
}
|
|
if (s.key === 'shortlisted') {
|
|
return applications.filter(a => ['shortlisted', 'interview', 'hired'].includes(a.status)).length;
|
|
}
|
|
if (s.key === 'interview') {
|
|
return applications.filter(a => ['interview', 'hired'].includes(a.status)).length;
|
|
}
|
|
return applications.filter(a => a.status === s.key).length;
|
|
});
|
|
|
|
const max = Math.max(...counts, 1);
|
|
const total = counts[0] || 1;
|
|
|
|
return (
|
|
<div className="glass-card border border-white/60 rounded-2xl p-6 shadow-sm">
|
|
<h3 className="font-heading font-semibold text-[#111827] text-[16px] mb-1">Pipeline Stages</h3>
|
|
<p className="text-[12px] text-[#6B7280] mb-5">Candidate progression through hiring funnel</p>
|
|
|
|
<div className="space-y-4">
|
|
{STAGES.map((stage, i) => {
|
|
const count = counts[i];
|
|
const width = (count / max) * 100;
|
|
const convRate = i === 0 ? 100 : Math.round((count / total) * 100);
|
|
const stepRate = i === 0 ? 100 : (counts[i - 1] ? Math.round((count / counts[i - 1]) * 100) : 0);
|
|
return (
|
|
<div key={stage.key}>
|
|
<div className="flex items-center justify-between mb-1.5">
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-[13px] font-medium text-[#374151]">{stage.label}</span>
|
|
{i > 0 && stepRate <= 100 && (
|
|
<span className="text-[10px] text-[#9CA3AF]">→ {stepRate}% from prev</span>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-[11px] text-[#9CA3AF]">{convRate}% of total</span>
|
|
<span className="text-[15px] font-bold text-[#111827] w-8 text-right">{count}</span>
|
|
</div>
|
|
</div>
|
|
<div className="h-7 bg-[#F3F4F6] rounded-lg overflow-hidden">
|
|
<div
|
|
className={cn('h-full rounded-lg flex items-center px-3 transition-all duration-700', stage.color)}
|
|
style={{ width: `${Math.max(width, count > 0 ? 6 : 0)}%` }}
|
|
>
|
|
<span className={cn('text-[11px] font-semibold', stage.text)}>{count > 0 ? count : ''}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |