summaryrefslogblamecommitdiff
path: root/makima/frontend/src/components/directives/DirectiveContractsTab.tsx
blob: 59ebfc805271e4189f33add51605dd2e2bc15dec (plain) (tree)


































































































































                                                                                                                                                                         
import { useNavigate } from "react-router";
import type {
  DirectiveWithChains,
  StepContractSummary,
  ContractPhase,
} from "../../lib/api";
import { PhaseProgressBarCompact } from "../contracts/PhaseProgressBar";

interface DirectiveContractsTabProps {
  directive: DirectiveWithChains;
}

const statusColors: Record<string, string> = {
  active: "text-green-400",
  completed: "text-blue-400",
  archived: "text-[#555]",
};

function ContractCard({
  summary,
  label,
}: {
  summary: StepContractSummary;
  label: string;
}) {
  const navigate = useNavigate();

  const progressPct =
    summary.taskCount > 0
      ? Math.round((summary.tasksDone / summary.taskCount) * 100)
      : 0;

  return (
    <div
      className="border border-dashed border-[rgba(117,170,252,0.25)] bg-[rgba(117,170,252,0.03)] p-3 cursor-pointer hover:bg-[rgba(117,170,252,0.06)] transition-colors"
      onClick={() => navigate(`/contracts/${summary.id}`)}
    >
      <div className="flex items-center justify-between mb-1.5">
        <div className="flex items-center gap-2 min-w-0">
          <span className="font-mono text-[11px] text-[#dbe7ff] truncate">
            {summary.name}
          </span>
          <span className="font-mono text-[9px] text-[#7788aa] uppercase shrink-0">
            {summary.contractType}
          </span>
        </div>
        <div className="flex items-center gap-2 shrink-0">
          <span
            className={`font-mono text-[9px] uppercase ${statusColors[summary.status] || "text-[#888]"}`}
          >
            {summary.status}
          </span>
          <span className="font-mono text-[9px] text-[#75aafc]">&rarr;</span>
        </div>
      </div>

      <div className="flex items-center gap-2 mb-1.5">
        <span className="font-mono text-[9px] text-[#7788aa] uppercase shrink-0">
          {label}
        </span>
        <PhaseProgressBarCompact
          currentPhase={summary.phase as ContractPhase}
        />
      </div>

      {/* Task progress bar */}
      <div className="flex items-center gap-2">
        <div className="flex-1 h-1 bg-[rgba(117,170,252,0.1)] rounded-full overflow-hidden">
          <div
            className="h-full bg-[#3f6fb3] rounded-full transition-all"
            style={{ width: `${progressPct}%` }}
          />
        </div>
        <span className="font-mono text-[9px] text-[#7788aa] shrink-0">
          {summary.tasksDone}/{summary.taskCount} tasks
        </span>
      </div>
    </div>
  );
}

export function DirectiveContractsTab({
  directive,
}: DirectiveContractsTabProps) {
  // Collect all contract summaries
  const contracts: { summary: StepContractSummary; label: string }[] = [];

  if (directive.orchestratorContractSummary) {
    contracts.push({
      summary: directive.orchestratorContractSummary,
      label: "Planning",
    });
  }

  for (const chain of directive.chains) {
    for (const step of chain.steps) {
      if (step.contractSummary) {
        contracts.push({
          summary: step.contractSummary,
          label: step.name,
        });
      }
    }
  }

  if (contracts.length === 0) {
    return (
      <div className="text-center py-8">
        <p className="font-mono text-xs text-[#7788aa]">
          {directive.status === "draft"
            ? "No contracts yet. Start the directive to begin planning."
            : directive.status === "planning"
              ? "Planning in progress... contracts will appear when steps are created."
              : "No contracts associated with this directive."}
        </p>
      </div>
    );
  }

  return (
    <div className="space-y-2">
      {contracts.map((c) => (
        <ContractCard
          key={c.summary.id}
          summary={c.summary}
          label={c.label}
        />
      ))}
    </div>
  );
}