'use client'; import { useMemo } from 'react'; interface Section { id: string; name: string; kind: 'section' | 'milestone'; status: 'planned' | 'in_progress' | 'complete'; targetDate: string | null; sortOrder: number; } interface ProjectTimelineProps { sections: Section[]; projectTargetDate: string | null; } const statusColors: Record = { planned: 'bg-gray-200 dark:bg-gray-700', in_progress: 'bg-blue-400 dark:bg-blue-600', complete: 'bg-green-400 dark:bg-green-600', }; const kindBadge: Record = { section: 'bg-muted text-muted-foreground', milestone: 'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200', }; export function ProjectTimeline({ sections, projectTargetDate }: ProjectTimelineProps) { const { startDate, totalDays } = useMemo(() => { if (sections.length === 0) return { startDate: new Date(), totalDays: 30 }; const dates = sections .filter((s) => s.targetDate) .map((s) => new Date(s.targetDate!)); if (projectTargetDate) dates.push(new Date(projectTargetDate)); if (dates.length === 0) { // No dates at all — show a default 30-day window const now = new Date(); return { startDate: now, totalDays: 30 }; } const minDate = new Date(Math.min(...dates.map((d) => d.getTime()))); const maxDate = new Date(Math.max(...dates.map((d) => d.getTime()))); const diff = Math.max((maxDate.getTime() - minDate.getTime()) / (1000 * 60 * 60 * 24), 14); return { startDate: minDate, totalDays: Math.ceil(diff) }; }, [sections, projectTargetDate]); if (sections.length === 0) return null; return (

Timeline

{/* Header row */}
Section
{Array.from({ length: Math.min(totalDays, 60) }).map((_, i) => (
))}
{/* Section rows */}
{sections.map((section) => { if (!section.targetDate) return null; const sectionDate = new Date(section.targetDate); const dayOffset = Math.max( 0, Math.round((sectionDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) ); const barWidth = Math.max(8, Math.min(100, (1 / Math.max(totalDays, 1)) * 100)); return (
{section.kind === 'milestone' ? 'M' : 'S'} {section.name}
); })}
{/* Project target date marker */} {projectTargetDate && (
Target date {new Date(projectTargetDate).toLocaleDateString()}
)}
); }