ddec3a927a
Major timeline enhancements: - Right-click drag multi-selection with floating action bar (batch delete/assign) - DemandPopover for demand strip details (replaces broken "Loading" modal) - ResourceHoverCard on name hover showing skills, rates, role, chapter - Merged heatmap+vacation tooltips into unified TimelineTooltip component - Fixed overbooking blink animation (date normalization, z-index ordering) - Fixed dark mode sticky column bleed-through in project view - System roles admin page, notification task management, performance review docs Co-Authored-By: claude-flow <ruv@ruv.net>
53 lines
2.6 KiB
TypeScript
53 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
|
|
import type {
|
|
EstimateVersionView,
|
|
EstimateWorkspaceView,
|
|
} from "~/components/estimates/EstimateWorkspace.types.js";
|
|
|
|
function EmptyState({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<div className="rounded-3xl border border-dashed border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 px-5 py-10 text-center text-sm text-gray-400">
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AssumptionsTab({ estimate }: { estimate: EstimateWorkspaceView }) {
|
|
const versions = estimate.versions as EstimateVersionView[];
|
|
const latestVersion = versions[0] ?? null;
|
|
const assumptions = latestVersion?.assumptions ?? [];
|
|
|
|
if (assumptions.length === 0) {
|
|
return <EmptyState>No assumptions captured for the current version yet.</EmptyState>;
|
|
}
|
|
|
|
return (
|
|
<div className="rounded-3xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-sm">
|
|
<div className="border-b border-gray-100 dark:border-gray-700/50 px-6 py-4">
|
|
<h2 className="text-sm font-semibold uppercase tracking-wide text-gray-600 dark:text-gray-400">Commercial and delivery assumptions <InfoTooltip content="Preconditions that affect the estimate validity. If any assumption changes, the estimate may need revision." /></h2>
|
|
</div>
|
|
<div className="divide-y divide-gray-100 dark:divide-gray-700/50">
|
|
{assumptions.map((assumption) => (
|
|
<div key={assumption.id} className="grid gap-3 px-6 py-4 md:grid-cols-[160px,1fr,1fr]">
|
|
<div>
|
|
<p className="text-xs uppercase tracking-wide text-gray-400">Category <InfoTooltip content="Groups assumptions by topic, e.g. 'commercial', 'delivery', 'technical'." /></p>
|
|
<p className="mt-1 text-sm font-medium text-gray-900 dark:text-gray-100">{assumption.category}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-xs uppercase tracking-wide text-gray-400">Label <InfoTooltip content="Human-readable description of the assumption. The key below is the machine-readable identifier." /></p>
|
|
<p className="mt-1 text-sm text-gray-800 dark:text-gray-200">{assumption.label}</p>
|
|
<p className="mt-1 text-xs text-gray-400">{assumption.key}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-xs uppercase tracking-wide text-gray-400">Value <InfoTooltip content="The concrete value or condition for this assumption." /></p>
|
|
<p className="mt-1 text-sm text-gray-800 dark:text-gray-200">{String(assumption.value)}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|