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:
parent
812af63e66
commit
621a1d419a
1 changed files with 56 additions and 0 deletions
56
src/components/roadmap/gantt-plan-view.tsx
Normal file
56
src/components/roadmap/gantt-plan-view.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue