diff options
| author | soryu <soryu@soryu.co> | 2026-01-19 17:55:22 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-19 17:55:22 +0000 |
| commit | 52d121269195f0e799d0ab4241e4facc3c7c0596 (patch) | |
| tree | 13d3dcdd743cf15f31d6d87097bf51ebfd01a305 /makima/frontend/src/components/contracts/ContractList.tsx | |
| parent | 164941cbd591b46f69a034bb9b86521fd7700ddb (diff) | |
| download | soryu-52d121269195f0e799d0ab4241e4facc3c7c0596.tar.gz soryu-52d121269195f0e799d0ab4241e4facc3c7c0596.zip | |
Add right-click context menu for contracts on contracts and board pages (#8)
Implement a reusable ContractContextMenu component that provides:
- Mark as Complete/Active/Archive status actions (conditionally shown)
- Go to Supervisor Task link (when supervisor exists)
- Delete action with confirmation
Integrate context menu into:
- ContractList.tsx on the contracts page
- WorkflowBoard on the workflow/board page via PhaseColumn and WorkflowContractCard
Features match ElementContextMenu patterns:
- Fixed positioning with z-50
- Click outside and Escape key close handlers
- Viewport overflow prevention
- Dark theme colors (#0a1628, #0d1b2d, #75aafc, #9bc3ff)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/frontend/src/components/contracts/ContractList.tsx')
| -rw-r--r-- | makima/frontend/src/components/contracts/ContractList.tsx | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/makima/frontend/src/components/contracts/ContractList.tsx b/makima/frontend/src/components/contracts/ContractList.tsx index 3a7b163..ebde497 100644 --- a/makima/frontend/src/components/contracts/ContractList.tsx +++ b/makima/frontend/src/components/contracts/ContractList.tsx @@ -2,6 +2,7 @@ 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[]; @@ -9,6 +10,11 @@ interface ContractListProps { 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> = { @@ -23,8 +29,26 @@ export function ContractList({ 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" @@ -92,6 +116,7 @@ export function ContractList({ <button key={contract.id} onClick={() => onSelect(contract.id)} + onContextMenu={(e) => handleContextMenu(e, contract)} className={` w-full text-left p-4 transition-colors ${ @@ -139,6 +164,21 @@ export function ContractList({ </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> ); } |
