import { useState } from "react";
import type { ContractSummary, ContractStatus } from "../../lib/api";
import { PhaseBadge } from "./PhaseBadge";
import { PhaseProgressBarCompact } from "./PhaseProgressBar";
import { ContractContextMenu } from "./ContractContextMenu";
interface ContractListProps {
contracts: ContractSummary[];
loading: boolean;
onSelect: (id: string) => void;
onCreate: () => void;
selectedId?: string;
onMarkComplete?: (contract: ContractSummary) => void;
onMarkActive?: (contract: ContractSummary) => void;
onArchive?: (contract: ContractSummary) => void;
onDelete?: (contract: ContractSummary) => void;
onGoToSupervisor?: (contract: ContractSummary) => void;
}
const statusColors: Record<ContractStatus, string> = {
active: "text-green-400",
completed: "text-blue-400",
archived: "text-[#555]",
};
export function ContractList({
contracts,
loading,
onSelect,
onCreate,
selectedId,
onMarkComplete,
onMarkActive,
onArchive,
onDelete,
onGoToSupervisor,
}: ContractListProps) {
const [filter, setFilter] = useState<ContractStatus | "all">("all");
const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | null>(null);
const [contextMenuContract, setContextMenuContract] = useState<ContractSummary | null>(null);
const handleContextMenu = (e: React.MouseEvent, contract: ContractSummary) => {
e.preventDefault();
setContextMenuPosition({ x: e.clientX, y: e.clientY });
setContextMenuContract(contract);
};
const closeContextMenu = () => {
setContextMenuPosition(null);
setContextMenuContract(null);
};
const filteredContracts =
filter === "all"
? contracts
: contracts.filter((c) => c.status === filter);
if (loading) {
return (
<div className="panel h-full flex items-center justify-center">
<div className="font-mono text-[#9bc3ff] text-sm">Loading...</div>
</div>
);
}
return (
<div className="panel h-full flex flex-col min-h-0">
{/* Header */}
<div className="p-4 border-b border-dashed border-[rgba(117,170,252,0.35)]">
<div className="flex items-center justify-between mb-3">
<h2 className="font-mono text-sm text-[#75aafc] uppercase tracking-wider">
Contracts
</h2>
<button
onClick={onCreate}
className="px-3 py-1.5 font-mono text-xs text-[#dbe7ff] bg-[#0f3c78] border border-[#3f6fb3] hover:bg-[#153667] transition-colors uppercase"
>
+ New
</button>
</div>
{/* Filter tabs */}
<div className="flex gap-1">
{(["all", "active", "completed", "archived"] as const).map((status) => (
<button
key={status}
onClick={() => setFilter(status)}
className={`
px-2 py-1 font-mono text-[10px] uppercase tracking-wider transition-colors
${
filter === status
? "bg-[rgba(117,170,252,0.1)] text-[#9bc3ff] border border-[rgba(117,170,252,0.3)]"
: "text-[#555] hover:text-[#75aafc]"
}
`}
>
{status}
</button>
))}
</div>
</div>
{/* Contract list */}
<div className="flex-1 min-h-0 overflow-y-auto">
{filteredContracts.length === 0 ? (
<div className="p-4 text-center">
<p className="font-mono text-sm text-[#555]">
{filter === "all"
? "No contracts yet"
: `No ${filter} contracts`}
</p>
</div>
) : (
<div className="divide-y divide-[rgba(117,170,252,0.15)]">
{filteredContracts.map((contract) => (
<button
key={contract.id}
onClick={() => onSelect(contract.id)}
onContextMenu={(e) => handleContextMenu(e, contract)}
className={`
w-full text-left p-4 transition-colors
${
selectedId === contract.id
? "bg-[rgba(117,170,252,0.1)]"
: "hover:bg-[rgba(117,170,252,0.05)]"
}
`}
>
<div className="flex items-start justify-between gap-2 mb-2">
<div className="flex items-center gap-2 min-w-0">
<h3 className="font-mono text-sm text-[#dbe7ff] truncate">
{contract.name}
</h3>
{contract.localOnly && (
<span className="px-1.5 py-0.5 font-mono text-[9px] uppercase text-amber-400 border border-amber-400/30 bg-amber-400/10 shrink-0">
Local
</span>
)}
</div>
<span
className={`text-[10px] font-mono uppercase shrink-0 ${
statusColors[contract.status]
}`}
>
{contract.status}
</span>
</div>
{contract.description && (
<p className="font-mono text-xs text-[#555] mb-2 line-clamp-2">
{contract.description}
</p>
)}
<div className="flex items-center justify-between">
<PhaseProgressBarCompact currentPhase={contract.phase} contractType={contract.contractType} />
<div className="flex items-center gap-3 text-[10px] font-mono text-[#555]">
{contract.fileCount > 0 && (
<span>{contract.fileCount} files</span>
)}
{contract.taskCount > 0 && (
<span>{contract.taskCount} tasks</span>
)}
{contract.repositoryCount > 0 && (
<span>{contract.repositoryCount} repos</span>
)}
</div>
</div>
</button>
))}
</div>
)}
</div>
{/* Context Menu */}
{contextMenuPosition && contextMenuContract && (
<ContractContextMenu
x={contextMenuPosition.x}
y={contextMenuPosition.y}
contract={contextMenuContract}
onClose={closeContextMenu}
onMarkComplete={() => onMarkComplete?.(contextMenuContract)}
onMarkActive={() => onMarkActive?.(contextMenuContract)}
onArchive={() => onArchive?.(contextMenuContract)}
onDelete={() => onDelete?.(contextMenuContract)}
onGoToSupervisor={() => onGoToSupervisor?.(contextMenuContract)}
/>
)}
</div>
);
}
export function ContractCard({
contract,
onClick,
}: {
contract: ContractSummary;
onClick: () => void;
}) {
return (
<button
onClick={onClick}
className="w-full text-left p-4 border border-[rgba(117,170,252,0.2)] hover:border-[rgba(117,170,252,0.4)] transition-colors"
>
<div className="flex items-start justify-between gap-2 mb-2">
<h3 className="font-mono text-sm text-[#dbe7ff]">{contract.name}</h3>
<PhaseBadge phase={contract.phase} />
</div>
{contract.description && (
<p className="font-mono text-xs text-[#555] mb-3 line-clamp-2">
{contract.description}
</p>
)}
<div className="flex items-center gap-4 text-[10px] font-mono text-[#555]">
<span>{contract.fileCount} files</span>
<span>{contract.taskCount} tasks</span>
<span>{contract.repositoryCount} repos</span>
</div>
</button>
);
}