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>
);
}