import { FlaskConical, Play, Send, CheckCircle, XCircle, RotateCcw, Loader2, Shield, ShieldCheck, } from "lucide-react"; import type { Test, TestState, User } from "../../types/models"; import LiveTimer from "./LiveTimer"; // ── Progress steps ───────────────────────────────────────────────── const PROGRESS_STEPS: { key: TestState; label: string }[] = [ { key: "draft", label: "Draft" }, { key: "red_executing", label: "Red Exec" }, { key: "blue_evaluating", label: "Blue Eval" }, { key: "in_review", label: "Review" }, { key: "validated", label: "Validated" }, ]; const STATE_INDEX: Record = { draft: 0, red_executing: 1, blue_evaluating: 2, in_review: 3, validated: 4, rejected: -1, }; // ── Badge colors ─────────────────────────────────────────────────── const STATE_BADGE: Record = { draft: "bg-gray-800/50 text-gray-400 border-gray-600/30", red_executing: "bg-orange-900/50 text-orange-400 border-orange-500/30", blue_evaluating: "bg-indigo-900/50 text-indigo-400 border-indigo-500/30", in_review: "bg-blue-900/50 text-blue-400 border-blue-500/30", validated: "bg-green-900/50 text-green-400 border-green-500/30", rejected: "bg-red-900/50 text-red-400 border-red-500/30", }; // ── Props ────────────────────────────────────────────────────────── interface TestDetailHeaderProps { test: Test; user: User | null; isTransitioning: boolean; onStartExecution: () => void; onSubmitRed: () => void; onSubmitBlue: () => void; onStartBlueWork: () => void; onOpenValidateModal: (side: "red" | "blue") => void; onReopen: () => void; onPauseTimer: () => void; onResumeTimer: () => void; isTogglingTimer: boolean; } // ── Component ────────────────────────────────────────────────────── export default function TestDetailHeader({ test, user, isTransitioning, onStartExecution, onSubmitRed, onSubmitBlue, onStartBlueWork, onOpenValidateModal, onReopen, onPauseTimer, onResumeTimer, isTogglingTimer, }: TestDetailHeaderProps) { const role = user?.role ?? ""; const currentIdx = STATE_INDEX[test.state]; const formatDate = (d: string | null) => { if (!d) return null; return new Date(d).toLocaleDateString("en-US", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); }; // ── Contextual action buttons ──────────────────────────────────── const renderActions = () => { const buttons: React.ReactNode[] = []; // Red Team in draft -> Start Execution if ( test.state === "draft" && (role === "red_tech" || role === "red_lead" || role === "admin") ) { buttons.push( , ); } // Red Team in red_executing -> Submit to Blue Team (requires ≥1 red evidence) if ( test.state === "red_executing" && (role === "red_tech" || role === "red_lead" || role === "admin") ) { const hasRedEvidence = (test.red_evidences?.length ?? 0) > 0; buttons.push(
{!hasRedEvidence && ( ⚠ Upload evidence first )}
, ); } // Blue Team in blue_evaluating: // - if not picked up yet: show "Start Evaluation" button // - if already picked up: show "Submit for Review" button if ( test.state === "blue_evaluating" && (role === "blue_tech" || role === "blue_lead" || role === "admin") ) { if (!test.blue_work_started_at) { buttons.push( , ); } else { // Submit for Review requires ≥1 blue evidence const hasBlueEvidence = (test.blue_evidences?.length ?? 0) > 0; buttons.push(
{!hasBlueEvidence && ( ⚠ Upload evidence first )}
, ); } } // Red Lead in in_review -> Validate Red if ( test.state === "in_review" && (role === "red_lead" || role === "admin") && !test.red_validation_status ) { buttons.push( , ); } // Blue Lead in in_review -> Validate Blue if ( test.state === "in_review" && (role === "blue_lead" || role === "admin") && !test.blue_validation_status ) { buttons.push( , ); } // Leads/admin on rejected -> Reopen if ( test.state === "rejected" && (role === "red_lead" || role === "blue_lead" || role === "admin") ) { buttons.push( , ); } return buttons.length > 0 ? (
{buttons}
) : null; }; // ── Dual validation indicators ─────────────────────────────────── const renderValidationIndicators = () => { if (test.state !== "in_review" && test.state !== "validated" && test.state !== "rejected") { return null; } const redStatus = test.red_validation_status; const blueStatus = test.blue_validation_status; const indicator = (label: string, status: string | null) => { if (status === "approved") return ( {label}: Approved ); if (status === "rejected") return ( {label}: Rejected ); return ( {label}: Pending ); }; return (
{indicator("Red Lead", redStatus)} {indicator("Blue Lead", blueStatus)}
); }; // ── Live timer ─────────────────────────────────────────────────── const canControlTimer = (test.state === "red_executing" && (role === "red_tech" || role === "red_lead" || role === "admin")) || (test.state === "blue_evaluating" && (role === "blue_tech" || role === "blue_lead" || role === "admin")); const renderLiveTimer = () => { if (test.state === "red_executing" && test.red_started_at) { return ( ); } if (test.state === "blue_evaluating" && test.blue_work_started_at) { return ( ); } return null; }; // ── Render ─────────────────────────────────────────────────────── return (
{/* Top row: name + badge + actions */}

{test.name}

{test.state.replace(/_/g, " ")}

Created {formatDate(test.created_at)}

{renderValidationIndicators()}
{renderLiveTimer()} {renderActions()}
{/* Progress bar */} {test.state !== "rejected" && (
{PROGRESS_STEPS.map((step, idx) => { const isCompleted = idx < currentIdx; const isCurrent = idx === currentIdx; return (
{/* Connector left */} {idx > 0 && (
)} {/* Dot */}
{/* Connector right */} {idx < PROGRESS_STEPS.length - 1 && (
)}
{step.label}
); })}
)} {/* Rejected banner */} {test.state === "rejected" && (
This test was rejected and needs to be reopened to restart the workflow.
)}
); }