"use client"; import { EstimateVersionStatus } from "@capakraken/shared"; import { clsx } from "clsx"; import { VersionCompare } from "~/components/estimates/VersionCompare.js"; import type { EstimateMetricView, EstimateVersionView, EstimateWorkspaceView, } from "~/components/estimates/EstimateWorkspace.types.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { formatDateLong, formatMoney } from "~/lib/format.js"; const VERSION_STYLES: Record = { WORKING: "bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300", BASELINE: "bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300", SUBMITTED: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300", APPROVED: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300", SUPERSEDED: "bg-zinc-200 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300", }; function formatMetricValue(metric: EstimateMetricView) { if (metric.valueCents != null) { return formatMoney(metric.valueCents, metric.currency ?? "EUR"); } if (metric.key === "margin_percent") { return `${metric.valueDecimal.toFixed(0)}%`; } return new Intl.NumberFormat("de-DE", { maximumFractionDigits: 1 }).format(metric.valueDecimal); } function EmptyState({ children }: { children: React.ReactNode }) { return (
{children}
); } export interface VersionsTabProps { estimate: EstimateWorkspaceView; canEdit: boolean; hasLinkedProject: boolean; onSubmitVersion: (versionId: string) => void; onApproveVersion: (versionId: string) => void; onCreateRevision: (versionId: string) => void; onCreatePlanningHandoff: (versionId: string) => void; isSubmitting: boolean; isApproving: boolean; isCreatingRevision: boolean; isCreatingPlanningHandoff: boolean; } export function VersionsTab({ estimate, canEdit, hasLinkedProject, onSubmitVersion, onApproveVersion, onCreateRevision, onCreatePlanningHandoff, isSubmitting, isApproving, isCreatingRevision, isCreatingPlanningHandoff, }: VersionsTabProps) { const versions = estimate.versions as EstimateVersionView[]; const hasWorkingVersion = versions.some( (version) => version.status === EstimateVersionStatus.WORKING, ); if (versions.length === 0) { return No versions available for this estimate yet.; } return (
Versions are immutable snapshots of the estimate for comparison and audit.
{versions.map((version) => (
v{version.versionNumber} {version.status}

{version.label ?? "Unlabeled version"}

{version.notes &&

{version.notes}

}

Updated {formatDateLong(version.updatedAt)}

{version.lockedAt && (

Locked {formatDateLong(version.lockedAt)}

)}

{version.demandLines.length} lines

{canEdit && (
{version.status === EstimateVersionStatus.WORKING && ( )} {version.status === EstimateVersionStatus.SUBMITTED && ( )} {version.status !== EstimateVersionStatus.WORKING && !hasWorkingVersion && ( )} {version.status === EstimateVersionStatus.APPROVED && ( )}
)} {version.status === EstimateVersionStatus.APPROVED && !hasLinkedProject && (

Link this estimate to a project before handing approved demand into planning.

)} {version.metrics.length > 0 && (
{version.metrics.map((metric) => (

{metric.label}

{formatMetricValue(metric)}

))}
)}
))} {versions.length >= 2 && }
); }