diff options
Diffstat (limited to 'makima/frontend/src/routes/workflow.tsx')
| -rw-r--r-- | makima/frontend/src/routes/workflow.tsx | 250 |
1 files changed, 0 insertions, 250 deletions
diff --git a/makima/frontend/src/routes/workflow.tsx b/makima/frontend/src/routes/workflow.tsx deleted file mode 100644 index e122092..0000000 --- a/makima/frontend/src/routes/workflow.tsx +++ /dev/null @@ -1,250 +0,0 @@ -import { useState, useCallback, useEffect, useMemo } from "react"; -import { useNavigate } from "react-router"; -import { Masthead } from "../components/Masthead"; -import { WorkflowBoard } from "../components/workflow/WorkflowBoard"; -import { useContracts } from "../hooks/useContracts"; -import { useAuth } from "../contexts/AuthContext"; -import type { ContractPhase, ContractStatus, ContractSummary } from "../lib/api"; - -type StatusFilter = "all" | ContractStatus; - -export default function WorkflowPage() { - const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth(); - const navigate = useNavigate(); - - // Redirect to login if not authenticated (when auth is configured) - useEffect(() => { - if (!authLoading && isAuthConfigured && !isAuthenticated) { - navigate("/login"); - } - }, [authLoading, isAuthConfigured, isAuthenticated, navigate]); - - // Show loading while checking auth - if (authLoading) { - return ( - <div className="relative z-10 min-h-screen flex flex-col bg-[#0a1628]"> - <Masthead showNav /> - <main className="flex-1 flex items-center justify-center"> - <p className="text-[#7788aa] font-mono text-sm">Loading...</p> - </main> - </div> - ); - } - - // Don't render if not authenticated (will redirect) - if (isAuthConfigured && !isAuthenticated) { - return null; - } - - return <WorkflowPageContent />; -} - -function WorkflowPageContent() { - const navigate = useNavigate(); - const { contracts, loading, error, changePhase, saveContract, editContract, removeContract } = useContracts(); - const [statusFilter, setStatusFilter] = useState<StatusFilter>("all"); - const [isCreating, setIsCreating] = useState(false); - const [newContractName, setNewContractName] = useState(""); - - // Filter contracts by status - const filteredContracts = useMemo(() => { - if (statusFilter === "all") { - return contracts; - } - return contracts.filter((c) => c.status === statusFilter); - }, [contracts, statusFilter]); - - const handleContractClick = useCallback( - (contractId: string) => { - navigate(`/contracts/${contractId}`); - }, - [navigate] - ); - - const handlePhaseChange = useCallback( - async (contractId: string, newPhase: ContractPhase) => { - await changePhase(contractId, newPhase); - }, - [changePhase] - ); - - // Context menu handlers - const handleContextMarkComplete = useCallback( - async (contract: ContractSummary) => { - await editContract(contract.id, { status: "completed", version: contract.version }); - }, - [editContract] - ); - - const handleContextMarkActive = useCallback( - async (contract: ContractSummary) => { - await editContract(contract.id, { status: "active", version: contract.version }); - }, - [editContract] - ); - - const handleContextArchive = useCallback( - async (contract: ContractSummary) => { - await editContract(contract.id, { status: "archived", version: contract.version }); - }, - [editContract] - ); - - const handleContextDelete = useCallback( - async (contract: ContractSummary) => { - if (confirm(`Are you sure you want to delete "${contract.name}"?`)) { - await removeContract(contract.id); - } - }, - [removeContract] - ); - - const handleContextGoToSupervisor = useCallback( - (contract: ContractSummary) => { - if (contract.supervisorTaskId) { - navigate(`/mesh/${contract.supervisorTaskId}`); - } - }, - [navigate] - ); - - const handleCreateContract = useCallback(async () => { - if (!newContractName.trim()) return; - const contract = await saveContract({ - name: newContractName.trim(), - }); - if (contract) { - setNewContractName(""); - setIsCreating(false); - navigate(`/contracts/${contract.id}`); - } - }, [newContractName, saveContract, navigate]); - - const handleCancelCreate = useCallback(() => { - setNewContractName(""); - setIsCreating(false); - }, []); - - return ( - <div className="relative z-10 h-screen flex flex-col bg-[#0a1628]"> - <Masthead showNav /> - <main className="flex-1 flex flex-col p-4 pt-2 gap-4 overflow-hidden"> - {error && ( - <div className="p-3 bg-red-400/10 border border-red-400/30 text-red-400 font-mono text-sm shrink-0"> - {error} - </div> - )} - - {/* Header with filter and create button */} - <div className="flex items-center justify-between shrink-0"> - <div className="flex items-center gap-4"> - <h1 className="font-mono text-sm text-[#75aafc] uppercase tracking-wider"> - Board - </h1> - {/* Status filter */} - <div className="flex items-center gap-1"> - {(["all", "active", "completed", "archived"] as StatusFilter[]).map( - (status) => ( - <button - key={status} - onClick={() => setStatusFilter(status)} - className={` - px-2 py-1 font-mono text-[10px] uppercase transition-colors - ${ - statusFilter === status - ? "bg-[rgba(117,170,252,0.1)] text-[#9bc3ff] border border-[rgba(117,170,252,0.3)]" - : "text-[#555] border border-transparent hover:text-[#75aafc]" - } - `} - > - {status} - </button> - ) - )} - </div> - </div> - <button - onClick={() => setIsCreating(true)} - className="px-3 py-1.5 font-mono text-xs text-[#9bc3ff] border border-[rgba(117,170,252,0.25)] hover:border-[#3f6fb3] transition-colors" - > - + New Contract - </button> - </div> - - {/* Create contract modal */} - {isCreating && ( - <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"> - <div className="w-full max-w-md p-6 bg-[#0a1628] border border-[rgba(117,170,252,0.3)]"> - <h3 className="font-mono text-sm text-[#75aafc] uppercase mb-4"> - Create Contract - </h3> - <div className="space-y-4"> - <input - type="text" - value={newContractName} - onChange={(e) => setNewContractName(e.target.value)} - placeholder="Contract name" - className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] font-mono text-sm focus:outline-none focus:border-[#75aafc]" - autoFocus - onKeyDown={(e) => { - if (e.key === "Enter") handleCreateContract(); - if (e.key === "Escape") handleCancelCreate(); - }} - /> - <div className="flex gap-2 justify-end"> - <button - onClick={handleCancelCreate} - className="px-4 py-2 font-mono text-xs text-[#9bc3ff] hover:text-[#dbe7ff] transition-colors" - > - Cancel - </button> - <button - onClick={handleCreateContract} - disabled={!newContractName.trim()} - className="px-4 py-2 font-mono text-xs text-[#dbe7ff] bg-[#0f3c78] border border-[#3f6fb3] hover:bg-[#153667] transition-colors disabled:opacity-50 disabled:cursor-not-allowed" - > - Create - </button> - </div> - </div> - </div> - </div> - )} - - {/* Board */} - <div className="flex-1 min-h-0 overflow-hidden"> - {loading ? ( - <div className="h-full flex items-center justify-center"> - <p className="font-mono text-sm text-[#555]">Loading...</p> - </div> - ) : filteredContracts.length === 0 && statusFilter === "all" ? ( - <div className="h-full flex items-center justify-center"> - <div className="text-center"> - <p className="font-mono text-sm text-[#555] mb-4"> - No contracts yet - </p> - <button - onClick={() => setIsCreating(true)} - className="px-4 py-2 font-mono text-xs text-[#dbe7ff] bg-[#0f3c78] border border-[#3f6fb3] hover:bg-[#153667] transition-colors uppercase" - > - + Create First Contract - </button> - </div> - </div> - ) : ( - <WorkflowBoard - contracts={filteredContracts} - onContractClick={handleContractClick} - onPhaseChange={handlePhaseChange} - onMarkComplete={handleContextMarkComplete} - onMarkActive={handleContextMarkActive} - onArchive={handleContextArchive} - onDelete={handleContextDelete} - onGoToSupervisor={handleContextGoToSupervisor} - /> - )} - </div> - </main> - </div> - ); -} |
