import Layout from "@/components/Layout"; import { useAuth } from "@/contexts/AuthContext"; import { useEffect, useMemo, useState } from "react"; import { Link, useNavigate, useParams } from "react-router-dom"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, } from "@/components/ui/breadcrumb"; import { aethexCollabService } from "@/lib/aethex-collab-service"; import LoadingScreen from "@/components/LoadingScreen"; import SEO from "@/components/SEO"; import { supabase } from "@/lib/supabase"; const columns: { key: "todo" | "doing" | "done" | "blocked"; title: string; hint: string; }[] = [ { key: "todo", title: "To do", hint: "Planned" }, { key: "doing", title: "In progress", hint: "Active" }, { key: "done", title: "Done", hint: "Completed" }, { key: "blocked", title: "Blocked", hint: "Needs attention" }, ]; export default function ProjectBoard() { const { user, loading } = useAuth(); const navigate = useNavigate(); const { projectId } = useParams<{ projectId: string }>(); const [isLoading, setIsLoading] = useState(true); const [tasks, setTasks] = useState([]); const [projectName, setProjectName] = useState(""); const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [creating, setCreating] = useState(false); const [members, setMembers] = useState([]); const [assigneeId, setAssigneeId] = useState(""); const [dueDate, setDueDate] = useState(""); const [q, setQ] = useState(""); const [filterAssignee, setFilterAssignee] = useState(""); const [filterStatus, setFilterStatus] = useState(""); useEffect(() => { if (!loading && !user) navigate("/login", { replace: true }); }, [loading, user, navigate]); const loadProject = async () => { if (!projectId) return; try { const { data } = await supabase .from("projects") .select("id,name,slug") .eq("id", projectId) .maybeSingle(); setProjectName((data as any)?.name || ""); } catch {} }; const load = async () => { if (!projectId) return; setIsLoading(true); try { const rows = await aethexCollabService.listProjectTasks(projectId); setTasks(rows); const m = await aethexCollabService.listProjectMembers(projectId); setMembers(m); } finally { setIsLoading(false); } }; useEffect(() => { loadProject(); load(); }, [projectId]); const grouped = useMemo(() => { const map: Record = { todo: [], doing: [], done: [], blocked: [], }; const normalized = tasks.filter((t) => { if ( q && !String(t.title || "") .toLowerCase() .includes(q.toLowerCase()) && !String(t.description || "") .toLowerCase() .includes(q.toLowerCase()) ) { return false; } if (filterAssignee && String(t.assignee_id || "") !== filterAssignee) return false; if (filterStatus && String(t.status || "") !== filterStatus) return false; return true; }); for (const t of normalized) { map[t.status || "todo"].push(t); } return map; }, [tasks, q, filterAssignee, filterStatus]); const handleCreate = async () => { if (!user?.id || !projectId) return; if (!title.trim()) return; setCreating(true); try { await aethexCollabService.createTask( projectId, title.trim(), description.trim() || null, assigneeId || null, dueDate || null, ); setTitle(""); setDescription(""); setAssigneeId(""); setDueDate(""); await load(); } finally { setCreating(false); } }; const move = async ( taskId: string, status: "todo" | "doing" | "done" | "blocked", ) => { await aethexCollabService.updateTaskStatus(taskId, status); await load(); }; if (loading || isLoading) return ( ); if (!user) return null; return ( <>
Projects {projectName ? ( {projectName} ) : ( Project )} Board

{projectName || "Project Board"}

Track tasks by status. Filters, assignees, and due dates enabled.

setQ(e.target.value)} />
{columns.map((col) => ( {col.title} {grouped[col.key].length} {col.hint} {grouped[col.key].length === 0 ? (

No tasks.

) : ( grouped[col.key].map((t) => (
{t.title}
{t.description ? (

{t.description}

) : null}
{t.assignee ? ( {t.assignee.full_name || t.assignee.username || "Assignee"} ) : ( Unassigned )} {t.due_date ? ( • Due{" "} {new Date(t.due_date).toLocaleDateString()} ) : null}
{columns.map((k) => ( ))}
)) )}
))}
Add task Keep titles concise; details optional. setTitle(e.target.value)} />