import { useState, useMemo } from "react";
import type { Order, OrderStatus, OrderPriority, OrderType } from "../../lib/api";
import { OrderContextMenu } from "./OrderContextMenu";
const STATUS_BADGE: Record<OrderStatus, { color: string; label: string }> = {
open: { color: "text-[#75aafc] border-[rgba(117,170,252,0.4)]", label: "OPEN" },
in_progress: { color: "text-yellow-400 border-yellow-800", label: "IN PROGRESS" },
under_review: { color: "text-purple-400 border-purple-800", label: "REVIEW" },
done: { color: "text-emerald-400 border-emerald-800", label: "DONE" },
archived: { color: "text-[#556677] border-[#2a3a5a]", label: "ARCHIVED" },
};
const PRIORITY_COLOR: Record<OrderPriority, string> = {
critical: "bg-red-400",
high: "bg-orange-400",
medium: "bg-yellow-400",
low: "bg-[#75aafc]",
none: "bg-[#556677]",
};
const TYPE_BADGE: Record<OrderType, { color: string; label: string }> = {
feature: { color: "text-[#75aafc] border-[rgba(117,170,252,0.3)]", label: "FEAT" },
bug: { color: "text-red-400 border-red-800", label: "BUG" },
spike: { color: "text-yellow-400 border-yellow-800", label: "SPIKE" },
chore: { color: "text-[#7788aa] border-[#2a3a5a]", label: "CHORE" },
improvement: { color: "text-emerald-400 border-emerald-800", label: "IMPROVE" },
};
interface OrderListProps {
orders: Order[];
selectedId: string | null;
onSelect: (id: string) => void;
onCreate: () => void;
statusFilter: OrderStatus | undefined;
onStatusFilter: (s: OrderStatus | undefined) => void;
typeFilter: OrderType | undefined;
onTypeFilter: (t: OrderType | undefined) => void;
onChangeStatus?: (order: Order, status: OrderStatus) => void;
onDelete?: (order: Order) => void;
onGoToDirective?: (order: Order) => void;
}
const STATUS_OPTIONS: (OrderStatus | "all")[] = ["all", "open", "in_progress", "under_review", "done", "archived"];
const TYPE_OPTIONS: (OrderType | "all")[] = ["all", "feature", "bug", "spike", "chore", "improvement"];
export function OrderList({
orders,
selectedId,
onSelect,
onCreate,
statusFilter,
onStatusFilter,
typeFilter,
onTypeFilter,
onChangeStatus,
onDelete,
onGoToDirective,
}: OrderListProps) {
const [search, setSearch] = useState("");
const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | null>(null);
const [contextMenuOrder, setContextMenuOrder] = useState<Order | null>(null);
const handleContextMenu = (e: React.MouseEvent, order: Order) => {
e.preventDefault();
setContextMenuPosition({ x: e.clientX, y: e.clientY });
setContextMenuOrder(order);
};
const closeContextMenu = () => {
setContextMenuPosition(null);
setContextMenuOrder(null);
};
const filtered = useMemo(() => {
if (!search.trim()) return orders;
const q = search.toLowerCase();
return orders.filter(
(o) =>
o.title.toLowerCase().includes(q) ||
(o.description && o.description.toLowerCase().includes(q)) ||
o.labels.some((l) => l.toLowerCase().includes(q)) ||
(o.directiveName && o.directiveName.toLowerCase().includes(q)),
);
}, [orders, search]);
return (
<div className="flex flex-col h-full">
{/* Header */}
<div className="flex items-center justify-between px-3 py-2 border-b border-dashed border-[rgba(117,170,252,0.2)]">
<span className="text-[11px] font-mono text-[#9bc3ff] uppercase tracking-wide">
Orders
</span>
<button
type="button"
onClick={onCreate}
className="text-[11px] font-mono text-[#75aafc] hover:text-white bg-transparent border border-[rgba(117,170,252,0.3)] rounded px-2 py-0.5 hover:border-[rgba(117,170,252,0.6)] transition-colors"
>
+ New
</button>
</div>
{/* Search */}
<div className="px-3 py-1.5 border-b border-[rgba(117,170,252,0.1)]">
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Search orders..."
className="w-full bg-transparent border-none outline-none text-[11px] font-mono text-white placeholder:text-[#556677]"
/>
</div>
{/* Filters */}
<div className="px-3 py-1.5 border-b border-[rgba(117,170,252,0.1)] flex flex-col gap-1">
<div className="flex items-center gap-1 flex-wrap">
<span className="text-[9px] font-mono text-[#556677] uppercase w-[38px] shrink-0">
Status
</span>
{STATUS_OPTIONS.map((s) => (
<button
key={s}
type="button"
onClick={() => onStatusFilter(s === "all" ? undefined : s)}
className={`text-[9px] font-mono px-1.5 py-0.5 rounded transition-colors ${
(s === "all" && !statusFilter) || s === statusFilter
? "text-white bg-[rgba(117,170,252,0.15)] border border-[rgba(117,170,252,0.4)]"
: "text-[#556677] hover:text-[#7788aa] border border-transparent"
}`}
>
{s === "all" ? "ALL" : s === "in_progress" ? "WIP" : s === "under_review" ? "REVIEW" : s.toUpperCase()}
</button>
))}
</div>
<div className="flex items-center gap-1 flex-wrap">
<span className="text-[9px] font-mono text-[#556677] uppercase w-[38px] shrink-0">
Type
</span>
{TYPE_OPTIONS.map((t) => (
<button
key={t}
type="button"
onClick={() => onTypeFilter(t === "all" ? undefined : t)}
className={`text-[9px] font-mono px-1.5 py-0.5 rounded transition-colors ${
(t === "all" && !typeFilter) || t === typeFilter
? "text-white bg-[rgba(117,170,252,0.15)] border border-[rgba(117,170,252,0.4)]"
: "text-[#556677] hover:text-[#7788aa] border border-transparent"
}`}
>
{t === "all" ? "ALL" : t.toUpperCase()}
</button>
))}
</div>
</div>
{/* List */}
<div className="flex-1 overflow-y-auto">
{filtered.length === 0 ? (
<div className="px-3 py-6 text-center text-[#556677] font-mono text-[11px]">
No orders found
</div>
) : (
filtered.map((o) => {
const statusBadge = STATUS_BADGE[o.status] || STATUS_BADGE.open;
const typeBadge = TYPE_BADGE[o.orderType] || TYPE_BADGE.feature;
const priorityColor = PRIORITY_COLOR[o.priority] || PRIORITY_COLOR.none;
return (
<button
key={o.id}
type="button"
onClick={() => onSelect(o.id)}
onContextMenu={(e) => handleContextMenu(e, o)}
className={`w-full text-left px-3 py-2.5 border-b border-[rgba(117,170,252,0.1)] hover:bg-[rgba(117,170,252,0.05)] transition-colors ${
selectedId === o.id ? "bg-[rgba(117,170,252,0.1)]" : ""
}`}
>
<div className="flex items-start gap-2 mb-1">
{/* Priority dot */}
<span
className={`w-2 h-2 rounded-full ${priorityColor} shrink-0 mt-[3px]`}
title={o.priority}
/>
<span className="text-[12px] font-mono text-white truncate flex-1">
{o.title}
{o.directiveName && (
<span className="text-[9px] font-mono text-[#556677] truncate block">
{o.directiveName}
</span>
)}
</span>
</div>
<div className="flex items-center gap-1.5 pl-4">
<span
className={`text-[9px] font-mono ${statusBadge.color} border rounded px-1.5 py-0.5`}
>
{statusBadge.label}
</span>
<span
className={`text-[9px] font-mono ${typeBadge.color} border rounded px-1.5 py-0.5`}
>
{typeBadge.label}
</span>
{o.labels.length > 0 && (
<span className="text-[9px] font-mono text-[#556677] truncate">
{o.labels.slice(0, 2).join(", ")}
{o.labels.length > 2 && ` +${o.labels.length - 2}`}
</span>
)}
</div>
</button>
);
})
)}
</div>
{/* Context Menu */}
{contextMenuPosition && contextMenuOrder && (
<OrderContextMenu
x={contextMenuPosition.x}
y={contextMenuPosition.y}
order={contextMenuOrder}
onClose={closeContextMenu}
onChangeStatus={(status) => onChangeStatus?.(contextMenuOrder, status)}
onDelete={() => onDelete?.(contextMenuOrder)}
onGoToDirective={() => onGoToDirective?.(contextMenuOrder)}
/>
)}
</div>
);
}