import { cx } from '@/utils/cx'; import { formatCurrency } from '@/lib/format'; import type { Campaign, Ad, Lead, LeadSource } from '@/types/entities'; import { CampaignStatusBadge } from '@/components/shared/status-badge'; import { BudgetBar } from './budget-bar'; import { HealthIndicator } from './health-indicator'; interface CampaignCardProps { campaign: Campaign; ads: Ad[]; leads: Lead[]; } const sourceColors: Record = { FACEBOOK_AD: 'bg-brand-solid', GOOGLE_AD: 'bg-success-solid', INSTAGRAM: 'bg-error-solid', GOOGLE_MY_BUSINESS: 'bg-warning-solid', WEBSITE: 'bg-fg-brand-primary', REFERRAL: 'bg-fg-tertiary', WHATSAPP: 'bg-success-solid', WALK_IN: 'bg-fg-quaternary', PHONE: 'bg-fg-secondary', OTHER: 'bg-fg-disabled', }; const sourceLabel = (source: LeadSource): string => source.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()); const formatDuration = (startDate: string | null, endDate: string | null): string => { if (!startDate) return '--'; const start = new Date(startDate); const end = endDate ? new Date(endDate) : new Date(); const diffDays = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); return `${diffDays}d`; }; export const CampaignCard = ({ campaign, ads, leads }: CampaignCardProps) => { const isPaused = campaign.campaignStatus === 'PAUSED'; const leadCount = campaign.leadCount ?? 0; const contactedCount = campaign.contactedCount ?? 0; const convertedCount = campaign.convertedCount ?? 0; const cac = convertedCount > 0 && campaign.amountSpent ? formatCurrency(campaign.amountSpent.amountMicros / convertedCount, campaign.amountSpent.currencyCode) : '--'; // Count leads per source const sourceCounts = leads.reduce>((acc, lead) => { const source = lead.leadSource ?? 'OTHER'; acc[source] = (acc[source] ?? 0) + 1; return acc; }, {}); return (
{/* Header */}

{campaign.campaignName ?? 'Untitled Campaign'}

{campaign.externalCampaignId ?? campaign.id.slice(0, 12)} · {ads.length} ad{ads.length !== 1 ? 's' : ''} {campaign.platform && ( <> · {campaign.platform} )}
{formatDuration(campaign.startDate, campaign.endDate)} {campaign.campaignStatus && }
{/* Metrics row */}

{leadCount}

Leads

{contactedCount}

Contacted

{convertedCount}

Converted

{cac}

CAC

{/* Budget bar */}
{/* Source breakdown */} {Object.keys(sourceCounts).length > 0 && (
{Object.entries(sourceCounts) .sort(([, a], [, b]) => b - a) .map(([source, count]) => (
{sourceLabel(source as LeadSource)} ({count})
))}
)} {/* Health indicator */}
); };