feat(plan): GanttPlanView top-level component

Composes one ProjectSection per section with a single shared
timeline range. Renders the 'Nothing scheduled yet' empty
state when no section has any dated cards or subtasks.
This commit is contained in:
Dave 2026-09-21 16:16:40 +02:00
parent 812af63e66
commit 621a1d419a

View file

@ -0,0 +1,56 @@
"use client";
import { useMemo } from "react";
import { ProjectSection } from "@/components/roadmap/project-section";
import { timelineRange } from "@/lib/roadmap/timeline";
import type { PlanSection } from "@/lib/roadmap/load";
/**
* Top-level Gantt view. Computes one shared timeline range across every
* project section so a card in one project and a card in another share
* the same month/week axis. When every card and every subtask has no
* dates, shows the "Nothing scheduled yet" empty state.
*/
export function GanttPlanView({ sections }: { sections: PlanSection[] }) {
const range = useMemo(() => {
let n = 0;
const items: { id: string; startDate: string; targetDate: string }[] = [];
for (const s of sections) {
for (const c of s.cards) {
if (c.startDate || c.targetDate) {
items.push({ id: `c-${++n}`, startDate: c.startDate, targetDate: c.targetDate });
}
for (const st of c.datedSubtasks) {
items.push({ id: `s-${++n}`, startDate: st.startDate, targetDate: st.targetDate });
}
}
}
return timelineRange(items);
}, [sections]);
if (sections.length === 0) {
return (
<div className="rounded-[var(--radius-tile)] border-2 border-dashed border-[var(--border-subtle)] px-4 py-12 text-center text-[var(--text-muted)]">
<h2 className="text-base font-medium text-[var(--text-primary)]">
Nothing scheduled yet
</h2>
<p className="mx-auto mt-1.5 max-w-sm text-sm">
Set a start date and target date on a card to see it appear here.
</p>
</div>
);
}
return (
<div className="space-y-4">
{sections.map((section) => (
<ProjectSection
key={section.project.id}
section={section}
range={range}
/>
))}
</div>
);
}