Files
helix-engage/src/components/campaigns/conversion-funnel.tsx
2026-03-16 15:01:00 +05:30

57 lines
2.3 KiB
TypeScript

import { cx } from '@/utils/cx';
import type { Campaign, Lead } from '@/types/entities';
interface ConversionFunnelProps {
campaign: Campaign;
leads: Lead[];
}
type FunnelStep = {
label: string;
count: number;
color: string;
};
export const ConversionFunnel = ({ campaign, leads }: ConversionFunnelProps) => {
const leadCount = campaign.leadCount ?? 0;
const contactedCount = campaign.contactedCount ?? 0;
const appointmentCount = leads.filter((l) => l.leadStatus === 'APPOINTMENT_SET').length;
const convertedCount = campaign.convertedCount ?? 0;
const steps: FunnelStep[] = [
{ label: 'Leads', count: leadCount, color: 'bg-brand-solid' },
{ label: 'Contacted', count: contactedCount, color: 'bg-brand-primary' },
{ label: 'Appointment Set', count: appointmentCount, color: 'bg-brand-primary_alt' },
{ label: 'Converted', count: convertedCount, color: 'bg-success-solid' },
];
const maxCount = Math.max(...steps.map((s) => s.count), 1);
return (
<div className="rounded-xl border border-secondary bg-primary p-4">
<h4 className="mb-3 text-sm font-bold text-primary">Conversion Funnel</h4>
<div className="space-y-2.5">
{steps.map((step) => {
const widthPercent = (step.count / maxCount) * 100;
return (
<div key={step.label} className="flex items-center gap-3">
<span className="w-24 shrink-0 text-xs text-tertiary">{step.label}</span>
<div className="flex-1">
<div className="h-5 rounded bg-secondary overflow-hidden">
<div
className={cx('h-full rounded transition-all duration-300', step.color)}
style={{ width: `${Math.max(widthPercent, 2)}%` }}
/>
</div>
</div>
<span className="w-10 shrink-0 text-right text-xs font-bold text-primary">
{step.count}
</span>
</div>
);
})}
</div>
</div>
);
};